summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:23:02 +0200
committerMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:23:02 +0200
commit8fcc691d6fa80c9ddf38bf0d34b803bab0e421d5 (patch)
treeba71646a10b518372d110532d86fcf0b98edc14f
parent3bb719bbf3cdb97b3901f3baaa2da9d02a5c3cdb (diff)
parent8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (diff)
downloadgolang-8fcc691d6fa80c9ddf38bf0d34b803bab0e421d5.tar.gz
Merge tag 'upstream/1.3' into debian-sid
Upstream version 1.3
-rw-r--r--AUTHORS73
-rw-r--r--CONTRIBUTORS90
-rw-r--r--VERSION2
-rw-r--r--api/except.txt313
-rw-r--r--api/go1.3.txt2053
-rw-r--r--api/next.txt117
-rw-r--r--doc/Makefile32
-rw-r--r--doc/articles/race_detector.html388
-rw-r--r--doc/articles/wiki/Makefile10
-rw-r--r--doc/articles/wiki/final.go23
-rw-r--r--doc/articles/wiki/index.html2
-rwxr-xr-xdoc/articles/wiki/test.bash26
-rw-r--r--doc/asm.html11
-rw-r--r--doc/codewalk/sharemem.xml2
-rw-r--r--doc/contrib.html42
-rw-r--r--doc/contribute.html92
-rw-r--r--doc/debugging_with_gdb.html21
-rw-r--r--doc/devel/release.html36
-rw-r--r--doc/docs.html7
-rw-r--r--doc/effective_go.html99
-rw-r--r--doc/gccgo_install.html4
-rw-r--r--doc/go1.3.html599
-rw-r--r--doc/go1.html2
-rw-r--r--doc/go_faq.html39
-rw-r--r--doc/go_mem.html37
-rw-r--r--doc/go_spec.html511
-rw-r--r--doc/gopher/README3
-rw-r--r--doc/help.html2
-rw-r--r--doc/install-source.html25
-rw-r--r--doc/install.html33
-rw-r--r--doc/root.html1
-rw-r--r--include/bio.h4
-rw-r--r--include/bootexec.h169
-rw-r--r--include/link.h616
-rw-r--r--include/mach.h411
-rw-r--r--include/plan9/386/u.h2
-rw-r--r--include/plan9/amd64/u.h2
-rw-r--r--include/plan9/bio.h8
-rw-r--r--include/plan9/errno.h (renamed from include/plan9/ureg_amd64.h)6
-rw-r--r--include/plan9/fmt.h64
-rw-r--r--include/plan9/libc.h7
-rw-r--r--include/plan9/link.h (renamed from include/plan9/mach.h)4
-rwxr-xr-xinclude/plan9/mklibc.rc8
-rw-r--r--include/plan9/stdarg.h3
-rw-r--r--include/plan9/utf.h (renamed from include/plan9/ureg_x86.h)4
-rw-r--r--include/u.h2
-rw-r--r--include/ureg_amd64.h58
-rw-r--r--include/ureg_arm.h49
-rw-r--r--include/ureg_x86.h53
-rwxr-xr-xlib/time/update.bash6
-rw-r--r--lib/time/zoneinfo.zipbin374754 -> 358933 bytes
-rw-r--r--misc/bash/go17
-rwxr-xr-xmisc/benchcmp127
-rw-r--r--misc/cgo/errors/err3.go18
-rwxr-xr-xmisc/cgo/errors/test.bash1
-rw-r--r--misc/cgo/nocgo/nocgo.go22
-rw-r--r--misc/cgo/nocgo/nocgo_test.go14
-rw-r--r--misc/cgo/test/backdoor/backdoor.go1
-rw-r--r--misc/cgo/test/backdoor/backdoor_gccgo.go11
-rw-r--r--misc/cgo/test/backdoor/runtime.c7
-rw-r--r--misc/cgo/test/cgo_linux_test.go1
-rw-r--r--misc/cgo/test/cgo_test.go3
-rw-r--r--misc/cgo/test/issue6833.go27
-rw-r--r--misc/cgo/test/issue6833_c.c10
-rw-r--r--misc/cgo/test/issue6997_linux.c26
-rw-r--r--misc/cgo/test/issue6997_linux.go40
-rw-r--r--misc/cgo/test/issue7234_test.go21
-rw-r--r--misc/cgo/test/issue7560.go44
-rw-r--r--misc/cgo/test/issue7665.go25
-rw-r--r--misc/cgo/test/issue7695_test.go27
-rw-r--r--misc/cgo/test/issue7786.go51
-rw-r--r--misc/cgo/test/issue8148.go31
-rw-r--r--misc/cgo/test/issue8331.h7
-rw-r--r--misc/cgo/test/issue8331a.go15
-rw-r--r--misc/cgo/test/issue8331b.go13
-rwxr-xr-xmisc/cgo/testcdefs/test.bash2
-rw-r--r--misc/cgo/testso/cgoso_c.c5
-rw-r--r--misc/cgo/testso/cgoso_unix.go20
-rw-r--r--misc/cgo/testtls/tls.go14
-rw-r--r--misc/emacs/go-mode.el63
-rw-r--r--misc/goplay/Makefile6
-rw-r--r--misc/goplay/README1
-rw-r--r--misc/goplay/doc.go23
-rw-r--r--misc/goplay/goplay.go288
-rw-r--r--misc/makerelease/darwin/Distribution (renamed from misc/dist/darwin/Distribution)0
-rw-r--r--misc/makerelease/darwin/Resources/bg.png (renamed from misc/dist/darwin/Resources/bg.png)bin11466 -> 11466 bytes
-rw-r--r--misc/makerelease/darwin/etc/paths.d/go (renamed from misc/dist/darwin/etc/paths.d/go)0
-rwxr-xr-xmisc/makerelease/darwin/scripts/postinstall (renamed from misc/dist/darwin/scripts/postinstall)0
-rwxr-xr-xmisc/makerelease/darwin/scripts/preinstall (renamed from misc/dist/darwin/scripts/preinstall)0
-rw-r--r--misc/makerelease/makerelease.go (renamed from misc/dist/bindist.go)303
-rw-r--r--misc/makerelease/windows/LICENSE.rtf (renamed from misc/dist/windows/LICENSE.rtf)bin1687 -> 1687 bytes
-rw-r--r--misc/makerelease/windows/README.txt (renamed from misc/dist/windows/README.txt)0
-rw-r--r--misc/makerelease/windows/images/Banner.jpg (renamed from misc/dist/windows/images/Banner.jpg)bin6643 -> 6643 bytes
-rw-r--r--misc/makerelease/windows/images/Dialog.jpg (renamed from misc/dist/windows/images/Dialog.jpg)bin16428 -> 16428 bytes
-rw-r--r--misc/makerelease/windows/images/DialogLeft.jpg (renamed from misc/dist/windows/images/DialogLeft.jpg)bin12961 -> 12961 bytes
-rw-r--r--misc/makerelease/windows/images/gopher.ico (renamed from misc/dist/windows/images/gopher.ico)bin30166 -> 30166 bytes
-rw-r--r--misc/makerelease/windows/installer.wxs (renamed from misc/dist/windows/installer.wxs)0
-rw-r--r--misc/nacl/README63
-rwxr-xr-xmisc/nacl/go_nacl_386_exec10
-rwxr-xr-xmisc/nacl/go_nacl_amd64p32_exec10
-rw-r--r--misc/nacl/mkzip.go220
-rw-r--r--misc/nacl/testdata/bin/placeholder0
-rw-r--r--misc/nacl/testdata/empty0
-rw-r--r--misc/nacl/testdata/group8
-rw-r--r--misc/nacl/testdata/hosts1
-rw-r--r--misc/nacl/testdata/mime.types1596
-rw-r--r--misc/nacl/testzip.proto113
-rw-r--r--misc/notepadplus/functionList.xml7
-rwxr-xr-xmisc/pprof9
-rw-r--r--misc/vim/autoload/go/complete.vim2
-rw-r--r--misc/vim/ftplugin/go.vim4
-rw-r--r--misc/vim/ftplugin/go/fmt.vim2
-rw-r--r--misc/vim/indent/go.vim20
-rw-r--r--misc/vim/readme.txt8
-rw-r--r--misc/zsh/go5
-rwxr-xr-xsrc/all.bash2
-rw-r--r--src/cmd/5a/a.h48
-rw-r--r--src/cmd/5a/a.y30
-rw-r--r--src/cmd/5a/lex.c377
-rw-r--r--src/cmd/5a/y.tab.c981
-rw-r--r--src/cmd/5a/y.tab.h38
-rw-r--r--src/cmd/5c/gc.h83
-rw-r--r--src/cmd/5c/list.c303
-rw-r--r--src/cmd/5c/peep.c44
-rw-r--r--src/cmd/5c/reg.c20
-rw-r--r--src/cmd/5c/swt.c285
-rw-r--r--src/cmd/5c/txt.c44
-rw-r--r--src/cmd/5g/cgen.c66
-rw-r--r--src/cmd/5g/galign.c9
-rw-r--r--src/cmd/5g/gg.h50
-rw-r--r--src/cmd/5g/ggen.c195
-rw-r--r--src/cmd/5g/gobj.c264
-rw-r--r--src/cmd/5g/gsubr.c66
-rw-r--r--src/cmd/5g/list.c342
-rw-r--r--src/cmd/5g/opt.h1
-rw-r--r--src/cmd/5g/peep.c156
-rw-r--r--src/cmd/5g/prog.c10
-rw-r--r--src/cmd/5g/reg.c267
-rw-r--r--src/cmd/5l/5.out.h85
-rw-r--r--src/cmd/5l/asm.c1542
-rw-r--r--src/cmd/5l/l.h349
-rw-r--r--src/cmd/5l/list.c427
-rw-r--r--src/cmd/5l/noop.c671
-rw-r--r--src/cmd/5l/obj.c731
-rw-r--r--src/cmd/5l/optab.c277
-rw-r--r--src/cmd/5l/pass.c409
-rw-r--r--src/cmd/5l/prof.c211
-rw-r--r--src/cmd/5l/softfloat.c91
-rw-r--r--src/cmd/5l/span.c937
-rw-r--r--src/cmd/6a/a.h54
-rw-r--r--src/cmd/6a/a.y28
-rw-r--r--src/cmd/6a/lex.c382
-rw-r--r--src/cmd/6a/y.tab.c1457
-rw-r--r--src/cmd/6a/y.tab.h50
-rw-r--r--src/cmd/6c/gc.h75
-rw-r--r--src/cmd/6c/list.c355
-rw-r--r--src/cmd/6c/peep.c16
-rw-r--r--src/cmd/6c/reg.c31
-rw-r--r--src/cmd/6c/sgen.c2
-rw-r--r--src/cmd/6c/swt.c297
-rw-r--r--src/cmd/6c/txt.c75
-rw-r--r--src/cmd/6g/cgen.c100
-rw-r--r--src/cmd/6g/galign.c28
-rw-r--r--src/cmd/6g/gg.h49
-rw-r--r--src/cmd/6g/ggen.c236
-rw-r--r--src/cmd/6g/gobj.c260
-rw-r--r--src/cmd/6g/gsubr.c104
-rw-r--r--src/cmd/6g/opt.h1
-rw-r--r--src/cmd/6g/peep.c26
-rw-r--r--src/cmd/6g/prog.c7
-rw-r--r--src/cmd/6g/reg.c253
-rw-r--r--src/cmd/6l/6.out.h44
-rw-r--r--src/cmd/6l/asm.c299
-rw-r--r--src/cmd/6l/l.h374
-rw-r--r--src/cmd/6l/list.c396
-rw-r--r--src/cmd/6l/obj.c701
-rw-r--r--src/cmd/6l/optab.c1369
-rw-r--r--src/cmd/6l/pass.c991
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1846
-rw-r--r--src/cmd/8a/a.h55
-rw-r--r--src/cmd/8a/a.y26
-rw-r--r--src/cmd/8a/lex.c380
-rw-r--r--src/cmd/8a/y.tab.c1446
-rw-r--r--src/cmd/8a/y.tab.h50
-rw-r--r--src/cmd/8c/gc.h75
-rw-r--r--src/cmd/8c/list.c316
-rw-r--r--src/cmd/8c/peep.c16
-rw-r--r--src/cmd/8c/reg.c29
-rw-r--r--src/cmd/8c/swt.c273
-rw-r--r--src/cmd/8c/txt.c49
-rw-r--r--src/cmd/8g/cgen.c43
-rw-r--r--src/cmd/8g/galign.c9
-rw-r--r--src/cmd/8g/gg.h47
-rw-r--r--src/cmd/8g/ggen.c175
-rw-r--r--src/cmd/8g/gobj.c259
-rw-r--r--src/cmd/8g/gsubr.c69
-rw-r--r--src/cmd/8g/opt.h3
-rw-r--r--src/cmd/8g/peep.c24
-rw-r--r--src/cmd/8g/prog.c21
-rw-r--r--src/cmd/8g/reg.c261
-rw-r--r--src/cmd/8l/8.out.h50
-rw-r--r--src/cmd/8l/asm.c393
-rw-r--r--src/cmd/8l/l.h330
-rw-r--r--src/cmd/8l/list.c313
-rw-r--r--src/cmd/8l/obj.c698
-rw-r--r--src/cmd/8l/optab.c1030
-rw-r--r--src/cmd/8l/pass.c858
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1507
-rw-r--r--src/cmd/addr2line/addr2line_test.go115
-rw-r--r--src/cmd/addr2line/main.c90
-rw-r--r--src/cmd/addr2line/main.go253
-rw-r--r--src/cmd/api/goapi.go2
-rw-r--r--src/cmd/api/run.go4
-rw-r--r--src/cmd/cc/cc.h38
-rw-r--r--src/cmd/cc/lex.c127
-rw-r--r--src/cmd/cc/lexbody76
-rw-r--r--src/cmd/cc/macbody56
-rw-r--r--src/cmd/cc/pgen.c133
-rw-r--r--src/cmd/cc/pswt.c29
-rw-r--r--src/cmd/cc/sub.c10
-rw-r--r--src/cmd/cgo/doc.go28
-rw-r--r--src/cmd/cgo/gcc.go84
-rw-r--r--src/cmd/cgo/out.go47
-rw-r--r--src/cmd/dist/a.h5
-rw-r--r--src/cmd/dist/arm.c12
-rw-r--r--src/cmd/dist/build.c267
-rw-r--r--src/cmd/dist/buildgc.c10
-rw-r--r--src/cmd/dist/buildgo.c2
-rw-r--r--src/cmd/dist/buildruntime.c98
-rw-r--r--src/cmd/dist/goc2c.c116
-rw-r--r--src/cmd/dist/unix.c9
-rw-r--r--src/cmd/dist/windows.c22
-rw-r--r--src/cmd/gc/align.c10
-rw-r--r--src/cmd/gc/array.c129
-rw-r--r--src/cmd/gc/bits.c2
-rw-r--r--src/cmd/gc/builtin.c30
-rw-r--r--src/cmd/gc/bv.c134
-rw-r--r--src/cmd/gc/closure.c20
-rw-r--r--src/cmd/gc/const.c92
-rw-r--r--src/cmd/gc/dcl.c28
-rw-r--r--src/cmd/gc/doc.go6
-rw-r--r--src/cmd/gc/esc.c190
-rw-r--r--src/cmd/gc/export.c5
-rw-r--r--src/cmd/gc/fmt.c115
-rw-r--r--src/cmd/gc/gen.c95
-rw-r--r--src/cmd/gc/go.h126
-rw-r--r--src/cmd/gc/go.y6
-rw-r--r--src/cmd/gc/inl.c3
-rw-r--r--src/cmd/gc/lex.c97
-rw-r--r--src/cmd/gc/md5.c4
-rw-r--r--src/cmd/gc/md5.h2
-rw-r--r--src/cmd/gc/mparith1.c44
-rw-r--r--src/cmd/gc/mparith2.c10
-rw-r--r--src/cmd/gc/mparith3.c115
-rw-r--r--src/cmd/gc/obj.c281
-rw-r--r--src/cmd/gc/order.c930
-rw-r--r--src/cmd/gc/pgen.c398
-rw-r--r--src/cmd/gc/plive.c1985
-rw-r--r--src/cmd/gc/popt.c79
-rw-r--r--src/cmd/gc/racewalk.c3
-rw-r--r--src/cmd/gc/range.c77
-rw-r--r--src/cmd/gc/reflect.c149
-rw-r--r--src/cmd/gc/runtime.go31
-rw-r--r--src/cmd/gc/select.c116
-rw-r--r--src/cmd/gc/sinit.c98
-rw-r--r--src/cmd/gc/subr.c63
-rw-r--r--src/cmd/gc/swt.c2
-rw-r--r--src/cmd/gc/typecheck.c255
-rw-r--r--src/cmd/gc/walk.c453
-rw-r--r--src/cmd/gc/y.tab.c1762
-rw-r--r--src/cmd/gc/y.tab.h46
-rw-r--r--src/cmd/go/build.go626
-rw-r--r--src/cmd/go/clean.go41
-rw-r--r--src/cmd/go/context.go36
-rw-r--r--src/cmd/go/discovery.go3
-rw-r--r--src/cmd/go/doc.go116
-rw-r--r--src/cmd/go/env.go34
-rw-r--r--src/cmd/go/get.go11
-rw-r--r--src/cmd/go/help.go46
-rw-r--r--src/cmd/go/list.go55
-rw-r--r--src/cmd/go/main.go6
-rw-r--r--src/cmd/go/pkg.go33
-rw-r--r--src/cmd/go/pkg_test.go73
-rw-r--r--src/cmd/go/run.go39
-rw-r--r--src/cmd/go/signal_unix.go2
-rwxr-xr-xsrc/cmd/go/test.bash211
-rw-r--r--src/cmd/go/test.go142
-rw-r--r--src/cmd/go/testdata/cgocover/p.go19
-rw-r--r--src/cmd/go/testdata/cgocover/p_test.go7
-rw-r--r--src/cmd/go/testdata/dep_test.go7
-rw-r--r--src/cmd/go/testdata/src/notest/hello.go6
-rw-r--r--src/cmd/go/testdata/src/testcycle/p1/p1.go7
-rw-r--r--src/cmd/go/testdata/src/testcycle/p1/p1_test.go6
-rw-r--r--src/cmd/go/testdata/src/testcycle/p2/p2.go7
-rw-r--r--src/cmd/go/testdata/src/testcycle/p3/p3.go5
-rw-r--r--src/cmd/go/testdata/src/testcycle/p3/p3_test.go10
-rw-r--r--src/cmd/go/testdata/src/xtestonly/f.go3
-rw-r--r--src/cmd/go/testdata/src/xtestonly/f_test.go12
-rw-r--r--src/cmd/go/testdata/standalone_test.go6
-rw-r--r--src/cmd/go/testdata/testonly/p_test.go1
-rw-r--r--src/cmd/go/testflag.go23
-rw-r--r--src/cmd/go/vcs.go10
-rw-r--r--src/cmd/gofmt/doc.go11
-rw-r--r--src/cmd/gofmt/gofmt.go39
-rw-r--r--src/cmd/gofmt/gofmt_test.go1
-rw-r--r--src/cmd/gofmt/long_test.go2
-rw-r--r--src/cmd/gofmt/rewrite.go27
-rw-r--r--src/cmd/gofmt/testdata/typeswitch.golden2
-rw-r--r--src/cmd/gofmt/testdata/typeswitch.input2
-rw-r--r--src/cmd/ld/data.c714
-rw-r--r--src/cmd/ld/decodesym.c109
-rw-r--r--src/cmd/ld/doc.go4
-rw-r--r--src/cmd/ld/dwarf.c602
-rw-r--r--src/cmd/ld/dwarf.h8
-rw-r--r--src/cmd/ld/elf.c277
-rw-r--r--src/cmd/ld/elf.h15
-rw-r--r--src/cmd/ld/go.c157
-rw-r--r--src/cmd/ld/ldelf.c64
-rw-r--r--src/cmd/ld/ldmacho.c56
-rw-r--r--src/cmd/ld/ldpe.c60
-rw-r--r--src/cmd/ld/lib.c1625
-rw-r--r--src/cmd/ld/lib.h388
-rw-r--r--src/cmd/ld/macho.c123
-rw-r--r--src/cmd/ld/pass.c104
-rw-r--r--src/cmd/ld/pcln.c244
-rw-r--r--src/cmd/ld/pe.c212
-rw-r--r--src/cmd/ld/pe.h2
-rw-r--r--src/cmd/ld/pobj.c197
-rw-r--r--src/cmd/ld/symtab.c244
-rw-r--r--src/cmd/ld/textflag.h2
-rw-r--r--src/cmd/nm/Makefile5
-rw-r--r--src/cmd/nm/debug_goobj.go670
-rw-r--r--src/cmd/nm/doc.go56
-rw-r--r--src/cmd/nm/elf.go57
-rw-r--r--src/cmd/nm/goobj.go67
-rw-r--r--src/cmd/nm/macho.go69
-rw-r--r--src/cmd/nm/nm.c401
-rw-r--r--src/cmd/nm/nm.go184
-rw-r--r--src/cmd/nm/nm_test.go99
-rw-r--r--src/cmd/nm/pe.go98
-rw-r--r--src/cmd/nm/plan9obj.go48
-rw-r--r--src/cmd/objdump/Makefile10
-rw-r--r--src/cmd/objdump/armasm.go10821
-rw-r--r--src/cmd/objdump/elf.go65
-rw-r--r--src/cmd/objdump/macho.go77
-rw-r--r--src/cmd/objdump/main.c68
-rw-r--r--src/cmd/objdump/main.go519
-rw-r--r--src/cmd/objdump/objdump_test.go193
-rw-r--r--src/cmd/objdump/pe.go99
-rw-r--r--src/cmd/objdump/plan9obj.go63
-rw-r--r--src/cmd/objdump/testdata/fmthello.go7
-rw-r--r--src/cmd/objdump/x86.go13800
-rw-r--r--src/cmd/pack/Makefile5
-rw-r--r--src/cmd/pack/ar.c1727
-rw-r--r--src/cmd/pack/doc.go40
-rw-r--r--src/cmd/pack/pack.go486
-rw-r--r--src/cmd/pack/pack_test.go402
-rw-r--r--src/cmd/yacc/Makefile8
-rw-r--r--src/cmd/yacc/expr.y2
-rw-r--r--src/cmd/yacc/yacc.go15
-rw-r--r--src/lib9/_exits.c2
-rw-r--r--src/lib9/_p9dir.c2
-rw-r--r--src/lib9/atoi.c2
-rw-r--r--src/lib9/await.c1
-rw-r--r--src/lib9/cleanname.c2
-rw-r--r--src/lib9/create.c2
-rw-r--r--src/lib9/ctime.c2
-rw-r--r--src/lib9/dirfstat.c2
-rw-r--r--src/lib9/dirfwstat.c2
-rw-r--r--src/lib9/dirstat.c2
-rw-r--r--src/lib9/dirwstat.c2
-rw-r--r--src/lib9/dup.c2
-rw-r--r--src/lib9/errstr.c3
-rw-r--r--src/lib9/exec.c2
-rw-r--r--src/lib9/execl.c2
-rw-r--r--src/lib9/exitcode.c2
-rw-r--r--src/lib9/exits.c2
-rw-r--r--src/lib9/fmt/dorfmt.c1
-rw-r--r--src/lib9/fmt/errfmt.c32
-rw-r--r--src/lib9/fmt/fltfmt.c6
-rw-r--r--src/lib9/fmt/fmtfd.c2
-rw-r--r--src/lib9/fmtlock2.c2
-rw-r--r--src/lib9/getenv.c2
-rw-r--r--src/lib9/getwd.c2
-rw-r--r--src/lib9/jmp.c1
-rw-r--r--src/lib9/main.c4
-rw-r--r--src/lib9/nan.c2
-rw-r--r--src/lib9/notify.c1
-rw-r--r--src/lib9/nulldir.c2
-rw-r--r--src/lib9/open.c2
-rw-r--r--src/lib9/readn.c2
-rw-r--r--src/lib9/rfork.c1
-rw-r--r--src/lib9/run_plan9.c2
-rw-r--r--src/lib9/run_unix.c2
-rw-r--r--src/lib9/seek.c2
-rw-r--r--src/lib9/strecpy.c2
-rw-r--r--src/lib9/sysfatal.c2
-rw-r--r--src/lib9/tempdir_plan9.c2
-rw-r--r--src/lib9/tempdir_unix.c2
-rw-r--r--src/lib9/time.c2
-rw-r--r--src/lib9/tokenize.c2
-rw-r--r--src/lib9/utf/Makefile4
-rw-r--r--src/lib9/utf/runetype.c2
-rw-r--r--src/lib9/utf/runetypebody-6.3.0.h (renamed from src/lib9/utf/runetypebody-6.2.0.h)3
-rw-r--r--src/lib9/utf/utfdef.h1
-rw-r--r--src/lib9/utf/utfecpy.c4
-rw-r--r--src/lib9/utf/utflen.c1
-rw-r--r--src/lib9/utf/utfrrune.c4
-rw-r--r--src/lib9/utf/utfrune.c4
-rw-r--r--src/lib9/utf/utfutf.c3
-rw-r--r--src/libbio/bgetc.c2
-rw-r--r--src/libbio/bgetrune.c1
-rw-r--r--src/libbio/bputrune.c4
-rw-r--r--src/libbio/bseek.c2
-rw-r--r--src/liblink/Makefile (renamed from src/libmach/Makefile)2
-rw-r--r--src/liblink/asm5.c2458
-rw-r--r--src/liblink/asm6.c3585
-rw-r--r--src/liblink/asm8.c2785
-rw-r--r--src/liblink/data.c370
-rw-r--r--src/liblink/go.c74
-rw-r--r--src/liblink/ld.c258
-rw-r--r--src/liblink/list5.c356
-rw-r--r--src/liblink/list6.c (renamed from src/cmd/6g/list.c)220
-rw-r--r--src/liblink/list8.c (renamed from src/cmd/8g/list.c)216
-rw-r--r--src/liblink/obj.c296
-rw-r--r--src/liblink/obj5.c1068
-rw-r--r--src/liblink/obj6.c1171
-rw-r--r--src/liblink/obj8.c859
-rw-r--r--src/liblink/objfile.c746
-rw-r--r--src/liblink/pass.c115
-rw-r--r--src/liblink/pcln.c365
-rw-r--r--src/liblink/sym.c271
-rw-r--r--src/libmach/5.c92
-rw-r--r--src/libmach/5db.c1095
-rw-r--r--src/libmach/5obj.c171
-rw-r--r--src/libmach/6.c145
-rw-r--r--src/libmach/6obj.c173
-rw-r--r--src/libmach/8.c108
-rw-r--r--src/libmach/8db.c2447
-rw-r--r--src/libmach/8obj.c170
-rw-r--r--src/libmach/access.c241
-rw-r--r--src/libmach/darwin.c897
-rw-r--r--src/libmach/dragonfly.c62
-rw-r--r--src/libmach/elf.h182
-rw-r--r--src/libmach/executable.c1525
-rw-r--r--src/libmach/fakeobj.c29
-rw-r--r--src/libmach/freebsd.c62
-rw-r--r--src/libmach/linux.c1014
-rw-r--r--src/libmach/machdata.c477
-rw-r--r--src/libmach/macho.h100
-rw-r--r--src/libmach/map.c183
-rw-r--r--src/libmach/netbsd.c56
-rw-r--r--src/libmach/obj.c393
-rw-r--r--src/libmach/obj.h53
-rw-r--r--src/libmach/openbsd.c56
-rw-r--r--src/libmach/plan9.c72
-rw-r--r--src/libmach/setmach.c203
-rw-r--r--src/libmach/swap.c107
-rw-r--r--src/libmach/sym.c1883
-rw-r--r--src/libmach/windows.c87
-rwxr-xr-xsrc/make.bash22
-rwxr-xr-xsrc/make.rc3
-rwxr-xr-xsrc/nacltest.bash56
-rw-r--r--src/pkg/archive/tar/common.go3
-rw-r--r--src/pkg/archive/tar/reader.go465
-rw-r--r--src/pkg/archive/tar/reader_test.go368
-rw-r--r--src/pkg/archive/tar/stat_atim.go2
-rw-r--r--src/pkg/archive/tar/stat_unix.go2
-rw-r--r--src/pkg/archive/tar/tar_test.go4
-rw-r--r--src/pkg/archive/tar/testdata/sparse-formats.tarbin0 -> 17920 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer-big-long.tarbin0 -> 4096 bytes
-rw-r--r--src/pkg/archive/tar/testdata/xattrs.tarbin0 -> 5120 bytes
-rw-r--r--src/pkg/archive/tar/writer.go10
-rw-r--r--src/pkg/archive/tar/writer_test.go63
-rw-r--r--src/pkg/archive/zip/reader.go2
-rw-r--r--src/pkg/archive/zip/reader_test.go28
-rw-r--r--src/pkg/archive/zip/register.go41
-rw-r--r--src/pkg/archive/zip/struct.go4
-rw-r--r--src/pkg/archive/zip/testdata/zip64-2.zipbin0 -> 266 bytes
-rw-r--r--src/pkg/archive/zip/writer_test.go18
-rw-r--r--src/pkg/bufio/bufio.go147
-rw-r--r--src/pkg/bufio/bufio_test.go343
-rw-r--r--src/pkg/bufio/scan.go6
-rw-r--r--src/pkg/bufio/scan_test.go14
-rw-r--r--src/pkg/bytes/bytes.go10
-rw-r--r--src/pkg/bytes/bytes_test.go36
-rw-r--r--src/pkg/bytes/compare_test.go4
-rw-r--r--src/pkg/bytes/reader.go52
-rw-r--r--src/pkg/bytes/reader_test.go82
-rw-r--r--src/pkg/compress/bzip2/bzip2_test.go12
-rw-r--r--src/pkg/compress/bzip2/huffman.go32
-rw-r--r--src/pkg/compress/flate/fixedhuff.go4
-rw-r--r--src/pkg/compress/flate/flate_test.go2
-rw-r--r--src/pkg/compress/flate/inflate.go4
-rw-r--r--src/pkg/compress/flate/reader_test.go2
-rw-r--r--src/pkg/compress/gzip/gunzip.go15
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go36
-rw-r--r--src/pkg/compress/gzip/gzip.go8
-rw-r--r--src/pkg/compress/gzip/gzip_test.go2
-rw-r--r--src/pkg/compress/lzw/reader.go4
-rw-r--r--src/pkg/compress/lzw/reader_test.go4
-rw-r--r--src/pkg/compress/lzw/writer.go4
-rw-r--r--src/pkg/compress/zlib/example_test.go2
-rw-r--r--src/pkg/compress/zlib/reader.go3
-rw-r--r--src/pkg/compress/zlib/reader_test.go2
-rw-r--r--src/pkg/compress/zlib/writer.go4
-rw-r--r--src/pkg/compress/zlib/writer_test.go2
-rw-r--r--src/pkg/container/heap/example_pq_test.go22
-rw-r--r--src/pkg/container/heap/heap.go4
-rw-r--r--src/pkg/container/list/example_test.go2
-rw-r--r--src/pkg/container/list/list.go10
-rw-r--r--src/pkg/container/list/list_test.go56
-rw-r--r--src/pkg/container/ring/ring_test.go8
-rw-r--r--src/pkg/crypto/aes/aes_test.go28
-rw-r--r--src/pkg/crypto/aes/cipher.go12
-rw-r--r--src/pkg/crypto/aes/cipher_asm.go2
-rw-r--r--src/pkg/crypto/cipher/benchmark_test.go139
-rw-r--r--src/pkg/crypto/cipher/cbc.go55
-rw-r--r--src/pkg/crypto/cipher/cbc_aes_test.go46
-rw-r--r--src/pkg/crypto/cipher/cfb.go60
-rw-r--r--src/pkg/crypto/cipher/cfb_test.go8
-rw-r--r--src/pkg/crypto/cipher/cipher.go10
-rw-r--r--src/pkg/crypto/cipher/ctr.go55
-rw-r--r--src/pkg/crypto/cipher/gcm.go27
-rw-r--r--src/pkg/crypto/cipher/gcm_test.go16
-rw-r--r--src/pkg/crypto/cipher/ofb.go42
-rw-r--r--src/pkg/crypto/cipher/xor.go84
-rw-r--r--src/pkg/crypto/cipher/xor_test.go28
-rw-r--r--src/pkg/crypto/dsa/dsa.go12
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa.go12
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go66
-rw-r--r--src/pkg/crypto/md5/example_test.go6
-rw-r--r--src/pkg/crypto/md5/gen.go9
-rw-r--r--src/pkg/crypto/md5/md5_test.go13
-rw-r--r--src/pkg/crypto/md5/md5block.go8
-rw-r--r--src/pkg/crypto/md5/md5block_amd64p32.s184
-rw-r--r--src/pkg/crypto/md5/md5block_decl.go2
-rw-r--r--src/pkg/crypto/md5/md5block_generic.go9
-rw-r--r--src/pkg/crypto/rand/rand_unix.go2
-rw-r--r--src/pkg/crypto/rand/util.go8
-rw-r--r--src/pkg/crypto/rand/util_test.go65
-rw-r--r--src/pkg/crypto/rc4/rc4.go17
-rw-r--r--src/pkg/crypto/rc4/rc4_amd64p32.s192
-rw-r--r--src/pkg/crypto/rc4/rc4_asm.go2
-rw-r--r--src/pkg/crypto/rc4/rc4_ref.go11
-rw-r--r--src/pkg/crypto/rc4/rc4_test.go19
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go12
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15_test.go22
-rw-r--r--src/pkg/crypto/rsa/pss.go6
-rw-r--r--src/pkg/crypto/rsa/rsa.go14
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go2
-rw-r--r--src/pkg/crypto/sha1/example_test.go9
-rw-r--r--src/pkg/crypto/sha1/sha1.go10
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go27
-rw-r--r--src/pkg/crypto/sha1/sha1block.go10
-rw-r--r--src/pkg/crypto/sha1/sha1block_386.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64p32.s216
-rw-r--r--src/pkg/crypto/sha1/sha1block_arm.s217
-rw-r--r--src/pkg/crypto/sha1/sha1block_decl.go2
-rw-r--r--src/pkg/crypto/sha1/sha1block_generic.go9
-rw-r--r--src/pkg/crypto/sha256/sha256.go12
-rw-r--r--src/pkg/crypto/sha256/sha256_test.go18
-rw-r--r--src/pkg/crypto/sha256/sha256block.go2
-rw-r--r--src/pkg/crypto/sha256/sha256block_386.s283
-rw-r--r--src/pkg/crypto/sha256/sha256block_amd64.s256
-rw-r--r--src/pkg/crypto/sha256/sha256block_decl.go11
-rw-r--r--src/pkg/crypto/sha512/sha512.go10
-rw-r--r--src/pkg/crypto/sha512/sha512_test.go18
-rw-r--r--src/pkg/crypto/sha512/sha512block.go2
-rw-r--r--src/pkg/crypto/sha512/sha512block_amd64.s273
-rw-r--r--src/pkg/crypto/sha512/sha512block_decl.go11
-rw-r--r--src/pkg/crypto/subtle/constant_time.go4
-rw-r--r--src/pkg/crypto/tls/common.go153
-rw-r--r--src/pkg/crypto/tls/conn.go169
-rw-r--r--src/pkg/crypto/tls/example_test.go57
-rw-r--r--src/pkg/crypto/tls/generate_cert.go13
-rw-r--r--src/pkg/crypto/tls/handshake_client.go362
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go3351
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go115
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go4
-rw-r--r--src/pkg/crypto/tls/handshake_server.go60
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go3838
-rw-r--r--src/pkg/crypto/tls/handshake_test.go167
-rw-r--r--src/pkg/crypto/tls/key_agreement.go79
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA129
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA125
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA128
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA124
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES87
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES97
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES99
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA134
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA127
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA133
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA126
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM84
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES99
-rw-r--r--src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC483
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES83
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES84
-rw-r--r--src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC479
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES84
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES79
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES82
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC476
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC476
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA91
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA101
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven122
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven121
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven81
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES89
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket87
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES83
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES87
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM93
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC479
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-Resume36
-rw-r--r--src/pkg/crypto/tls/testdata/Server-TLSv12-SNI76
-rw-r--r--src/pkg/crypto/tls/tls.go86
-rw-r--r--src/pkg/crypto/tls/tls_test.go130
-rw-r--r--src/pkg/crypto/x509/example_test.go91
-rw-r--r--src/pkg/crypto/x509/pkix/pkix.go7
-rw-r--r--src/pkg/crypto/x509/root_cgo_darwin.go79
-rw-r--r--src/pkg/crypto/x509/root_darwin.go78
-rw-r--r--src/pkg/crypto/x509/root_darwin_test.go50
-rw-r--r--src/pkg/crypto/x509/root_nocgo_darwin.go11
-rw-r--r--src/pkg/crypto/x509/root_stub.go14
-rw-r--r--src/pkg/crypto/x509/root_unix.go2
-rw-r--r--src/pkg/crypto/x509/verify.go3
-rw-r--r--src/pkg/crypto/x509/verify_test.go367
-rw-r--r--src/pkg/crypto/x509/x509.go602
-rw-r--r--src/pkg/crypto/x509/x509_test.go241
-rw-r--r--src/pkg/crypto/x509/x509_test_import.go53
-rw-r--r--src/pkg/database/sql/convert.go50
-rw-r--r--src/pkg/database/sql/convert_test.go56
-rw-r--r--src/pkg/database/sql/driver/driver.go2
-rw-r--r--src/pkg/database/sql/example_test.go1
-rw-r--r--src/pkg/database/sql/fakedb_test.go32
-rw-r--r--src/pkg/database/sql/sql.go166
-rw-r--r--src/pkg/database/sql/sql_test.go137
-rw-r--r--src/pkg/debug/dwarf/const.go35
-rw-r--r--src/pkg/debug/dwarf/entry.go16
-rw-r--r--src/pkg/debug/dwarf/open.go11
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.elf4bin0 -> 9496 bytes
-rw-r--r--src/pkg/debug/dwarf/type.go75
-rw-r--r--src/pkg/debug/dwarf/type_test.go2
-rw-r--r--src/pkg/debug/dwarf/typeunit.go166
-rw-r--r--src/pkg/debug/dwarf/unit.go2
-rw-r--r--src/pkg/debug/elf/elf.go2
-rw-r--r--src/pkg/debug/elf/elf_test.go2
-rw-r--r--src/pkg/debug/elf/file.go106
-rw-r--r--src/pkg/debug/elf/file_test.go6
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.objbin0 -> 1900 bytes
-rw-r--r--src/pkg/debug/elf/testdata/hello.c7
-rw-r--r--src/pkg/debug/gosym/pclntab.go27
-rw-r--r--src/pkg/debug/gosym/symtab.go7
-rw-r--r--src/pkg/debug/macho/fat.go146
-rw-r--r--src/pkg/debug/macho/file.go23
-rw-r--r--src/pkg/debug/macho/file_test.go43
-rw-r--r--src/pkg/debug/macho/macho.go23
-rw-r--r--src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-execbin0 -> 28992 bytes
-rw-r--r--src/pkg/debug/pe/file.go56
-rw-r--r--src/pkg/debug/pe/file_test.go139
-rw-r--r--src/pkg/debug/pe/pe.go72
-rw-r--r--src/pkg/debug/pe/testdata/gcc-amd64-mingw-execbin0 -> 37376 bytes
-rw-r--r--src/pkg/debug/pe/testdata/gcc-amd64-mingw-objbin0 -> 736 bytes
-rw-r--r--src/pkg/debug/plan9obj/file.go325
-rw-r--r--src/pkg/debug/plan9obj/file_test.go81
-rw-r--r--src/pkg/debug/plan9obj/plan9obj.go36
-rwxr-xr-xsrc/pkg/debug/plan9obj/testdata/386-plan9-execbin0 -> 37232 bytes
-rwxr-xr-xsrc/pkg/debug/plan9obj/testdata/amd64-plan9-execbin0 -> 34279 bytes
-rw-r--r--src/pkg/debug/plan9obj/testdata/hello.c8
-rw-r--r--src/pkg/encoding/ascii85/ascii85.go12
-rw-r--r--src/pkg/encoding/ascii85/ascii85_test.go21
-rw-r--r--src/pkg/encoding/asn1/asn1.go43
-rw-r--r--src/pkg/encoding/asn1/asn1_test.go75
-rw-r--r--src/pkg/encoding/asn1/marshal.go57
-rw-r--r--src/pkg/encoding/asn1/marshal_test.go9
-rw-r--r--src/pkg/encoding/base32/base32.go12
-rw-r--r--src/pkg/encoding/base32/base32_test.go8
-rw-r--r--src/pkg/encoding/base64/base64.go39
-rw-r--r--src/pkg/encoding/base64/base64_test.go27
-rw-r--r--src/pkg/encoding/binary/binary.go1
-rw-r--r--src/pkg/encoding/binary/binary_test.go28
-rw-r--r--src/pkg/encoding/binary/varint_test.go8
-rw-r--r--src/pkg/encoding/csv/reader.go6
-rw-r--r--src/pkg/encoding/csv/writer_test.go2
-rw-r--r--src/pkg/encoding/gob/codec_test.go56
-rw-r--r--src/pkg/encoding/gob/decode.go21
-rw-r--r--src/pkg/encoding/gob/decoder.go8
-rw-r--r--src/pkg/encoding/gob/encode.go2
-rw-r--r--src/pkg/encoding/gob/encoder_test.go4
-rw-r--r--src/pkg/encoding/gob/gobencdec_test.go19
-rw-r--r--src/pkg/encoding/hex/hex.go3
-rw-r--r--src/pkg/encoding/hex/hex_test.go6
-rw-r--r--src/pkg/encoding/json/decode.go16
-rw-r--r--src/pkg/encoding/json/decode_test.go42
-rw-r--r--src/pkg/encoding/json/encode.go41
-rw-r--r--src/pkg/encoding/json/encode_test.go31
-rw-r--r--src/pkg/encoding/json/example_test.go32
-rw-r--r--src/pkg/encoding/json/fold.go143
-rw-r--r--src/pkg/encoding/json/fold_test.go116
-rw-r--r--src/pkg/encoding/json/indent.go5
-rw-r--r--src/pkg/encoding/json/scanner_test.go22
-rw-r--r--src/pkg/encoding/json/stream.go5
-rw-r--r--src/pkg/encoding/xml/marshal.go11
-rw-r--r--src/pkg/encoding/xml/marshal_test.go115
-rw-r--r--src/pkg/encoding/xml/read.go11
-rw-r--r--src/pkg/encoding/xml/read_test.go27
-rw-r--r--src/pkg/encoding/xml/typeinfo.go3
-rw-r--r--src/pkg/encoding/xml/xml.go2
-rw-r--r--src/pkg/expvar/expvar.go62
-rw-r--r--src/pkg/expvar/expvar_test.go32
-rw-r--r--src/pkg/flag/flag.go6
-rw-r--r--src/pkg/fmt/doc.go58
-rw-r--r--src/pkg/fmt/fmt_test.go234
-rw-r--r--src/pkg/fmt/format.go139
-rw-r--r--src/pkg/fmt/print.go53
-rw-r--r--src/pkg/fmt/scan.go10
-rw-r--r--src/pkg/go/ast/commentmap.go2
-rw-r--r--src/pkg/go/ast/example_test.go74
-rw-r--r--src/pkg/go/build/build.go17
-rw-r--r--src/pkg/go/build/deps_test.go17
-rw-r--r--src/pkg/go/build/doc.go9
-rw-r--r--src/pkg/go/build/syslist.go4
-rw-r--r--src/pkg/go/doc/comment.go49
-rw-r--r--src/pkg/go/doc/comment_test.go106
-rw-r--r--src/pkg/go/doc/example.go15
-rw-r--r--src/pkg/go/parser/error_test.go21
-rw-r--r--src/pkg/go/parser/interface.go7
-rw-r--r--src/pkg/go/parser/parser.go75
-rw-r--r--src/pkg/go/parser/parser_test.go15
-rw-r--r--src/pkg/go/parser/short_test.go25
-rw-r--r--src/pkg/go/printer/nodes.go72
-rw-r--r--src/pkg/go/printer/printer.go125
-rw-r--r--src/pkg/go/printer/printer_test.go6
-rw-r--r--src/pkg/go/printer/testdata/comments.golden13
-rw-r--r--src/pkg/go/printer/testdata/comments.input12
-rw-r--r--src/pkg/go/printer/testdata/comments2.golden26
-rw-r--r--src/pkg/go/printer/testdata/comments2.input28
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden18
-rw-r--r--src/pkg/go/printer/testdata/declarations.input21
-rw-r--r--src/pkg/go/scanner/scanner.go118
-rw-r--r--src/pkg/go/scanner/scanner_test.go103
-rw-r--r--src/pkg/hash/crc32/crc32_amd64p32.s64
-rw-r--r--src/pkg/hash/crc32/crc32_amd64x.go (renamed from src/pkg/hash/crc32/crc32_amd64.go)2
-rw-r--r--src/pkg/hash/fnv/fnv.go3
-rw-r--r--src/pkg/html/escape_test.go18
-rw-r--r--src/pkg/html/template/attr.go4
-rw-r--r--src/pkg/html/template/content.go3
-rw-r--r--src/pkg/html/template/context.go4
-rw-r--r--src/pkg/html/template/escape.go52
-rw-r--r--src/pkg/html/template/escape_test.go32
-rw-r--r--src/pkg/html/template/html.go4
-rw-r--r--src/pkg/html/template/js.go2
-rw-r--r--src/pkg/html/template/template.go8
-rw-r--r--src/pkg/image/color/palette/gen.go4
-rw-r--r--src/pkg/image/color/palette/palette.go4
-rw-r--r--src/pkg/image/gif/reader.go22
-rw-r--r--src/pkg/image/gif/reader_test.go4
-rw-r--r--src/pkg/image/jpeg/huffman.go6
-rw-r--r--src/pkg/image/jpeg/reader_test.go27
-rw-r--r--src/pkg/image/jpeg/scan.go21
-rw-r--r--src/pkg/image/png/reader.go10
-rw-r--r--src/pkg/image/testdata/video-001.separate.dc.progression.jpegbin0 -> 14288 bytes
-rw-r--r--src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpegbin0 -> 14312 bytes
-rw-r--r--src/pkg/io/io.go1
-rw-r--r--src/pkg/io/io_test.go20
-rw-r--r--src/pkg/io/ioutil/blackhole.go23
-rw-r--r--src/pkg/io/ioutil/ioutil.go14
-rw-r--r--src/pkg/io/multi.go11
-rw-r--r--src/pkg/io/multi_test.go27
-rw-r--r--src/pkg/log/example_test.go21
-rw-r--r--src/pkg/log/syslog/syslog.go5
-rw-r--r--src/pkg/log/syslog/syslog_test.go2
-rw-r--r--src/pkg/log/syslog/syslog_unix.go2
-rw-r--r--src/pkg/math/abs_amd64p32.s (renamed from include/plan9/ureg_arm.h)4
-rw-r--r--src/pkg/math/asin_amd64p32.s5
-rw-r--r--src/pkg/math/atan2_amd64p32.s5
-rw-r--r--src/pkg/math/atan_amd64p32.s5
-rw-r--r--src/pkg/math/big/arith.go14
-rw-r--r--src/pkg/math/big/arith_amd64p32.s41
-rw-r--r--src/pkg/math/big/arith_arm.s109
-rw-r--r--src/pkg/math/big/int.go37
-rw-r--r--src/pkg/math/big/int_test.go66
-rw-r--r--src/pkg/math/big/nat.go11
-rw-r--r--src/pkg/math/big/nat_test.go27
-rw-r--r--src/pkg/math/big/rat.go21
-rw-r--r--src/pkg/math/big/rat_test.go65
-rw-r--r--src/pkg/math/cmplx/cmath_test.go13
-rw-r--r--src/pkg/math/cmplx/pow.go18
-rw-r--r--src/pkg/math/cmplx/sqrt.go1
-rw-r--r--src/pkg/math/dim_amd64p32.s5
-rw-r--r--src/pkg/math/exp2_amd64p32.s5
-rw-r--r--src/pkg/math/exp_amd64p32.s5
-rw-r--r--src/pkg/math/expm1_amd64p32.s5
-rw-r--r--src/pkg/math/floor_amd64p32.s5
-rw-r--r--src/pkg/math/frexp_amd64p32.s5
-rw-r--r--src/pkg/math/hypot_amd64p32.s5
-rw-r--r--src/pkg/math/ldexp_amd64p32.s5
-rw-r--r--src/pkg/math/log10_amd64p32.s5
-rw-r--r--src/pkg/math/log1p_amd64p32.s5
-rw-r--r--src/pkg/math/log_amd64p32.s5
-rw-r--r--src/pkg/math/mod_amd64p32.s5
-rw-r--r--src/pkg/math/modf_amd64p32.s5
-rw-r--r--src/pkg/math/rand/rand.go52
-rw-r--r--src/pkg/math/rand/rand_test.go39
-rw-r--r--src/pkg/math/rand/regress_test.go355
-rw-r--r--src/pkg/math/remainder_amd64p32.s5
-rw-r--r--src/pkg/math/sin_amd64p32.s5
-rw-r--r--src/pkg/math/sincos_amd64p32.s5
-rw-r--r--src/pkg/math/sqrt_amd64p32.s5
-rw-r--r--src/pkg/math/tan_amd64p32.s5
-rw-r--r--src/pkg/mime/mediatype.go10
-rw-r--r--src/pkg/mime/mediatype_test.go1
-rw-r--r--src/pkg/mime/multipart/example_test.go53
-rw-r--r--src/pkg/mime/multipart/formdata_test.go3
-rw-r--r--src/pkg/mime/multipart/multipart.go10
-rw-r--r--src/pkg/mime/multipart/quotedprintable_test.go2
-rw-r--r--src/pkg/mime/type_unix.go2
-rw-r--r--src/pkg/net/cgo_bsd.go2
-rw-r--r--src/pkg/net/cgo_unix_test.go24
-rw-r--r--src/pkg/net/conn_test.go39
-rw-r--r--src/pkg/net/dial.go25
-rw-r--r--src/pkg/net/dial_test.go93
-rw-r--r--src/pkg/net/dialgoogle_test.go26
-rw-r--r--src/pkg/net/dnsclient.go4
-rw-r--r--src/pkg/net/dnsclient_test.go69
-rw-r--r--src/pkg/net/dnsclient_unix.go103
-rw-r--r--src/pkg/net/dnsclient_unix_test.go134
-rw-r--r--src/pkg/net/dnsconfig_unix.go9
-rw-r--r--src/pkg/net/dnsconfig_unix_test.go46
-rw-r--r--src/pkg/net/fd_mutex_test.go27
-rw-r--r--src/pkg/net/fd_plan9.go115
-rw-r--r--src/pkg/net/fd_poll_nacl.go94
-rw-r--r--src/pkg/net/fd_poll_runtime.go7
-rw-r--r--src/pkg/net/fd_unix.go58
-rw-r--r--src/pkg/net/fd_unix_test.go2
-rw-r--r--src/pkg/net/fd_windows.go14
-rw-r--r--src/pkg/net/file_plan9.go10
-rw-r--r--src/pkg/net/file_test.go8
-rw-r--r--src/pkg/net/file_unix.go4
-rw-r--r--src/pkg/net/hosts_test.go2
-rw-r--r--src/pkg/net/http/cgi/host.go27
-rw-r--r--src/pkg/net/http/cgi/matryoshka_test.go137
-rw-r--r--src/pkg/net/http/chunked.go58
-rw-r--r--src/pkg/net/http/chunked_test.go112
-rw-r--r--src/pkg/net/http/client.go111
-rw-r--r--src/pkg/net/http/client_test.go275
-rw-r--r--src/pkg/net/http/cookie.go58
-rw-r--r--src/pkg/net/http/cookie_test.go107
-rw-r--r--src/pkg/net/http/export_test.go18
-rw-r--r--src/pkg/net/http/fcgi/child.go19
-rw-r--r--src/pkg/net/http/fs.go18
-rw-r--r--src/pkg/net/http/fs_test.go70
-rw-r--r--src/pkg/net/http/header.go19
-rw-r--r--src/pkg/net/http/header_test.go9
-rw-r--r--src/pkg/net/http/httptest/server_test.go23
-rw-r--r--src/pkg/net/http/httputil/chunked.go74
-rw-r--r--src/pkg/net/http/httputil/chunked_test.go120
-rw-r--r--src/pkg/net/http/httputil/dump.go35
-rw-r--r--src/pkg/net/http/httputil/dump_test.go87
-rw-r--r--src/pkg/net/http/httputil/httputil.go32
-rw-r--r--src/pkg/net/http/httputil/persist.go21
-rw-r--r--src/pkg/net/http/httputil/reverseproxy.go4
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go16
-rw-r--r--src/pkg/net/http/proxy_test.go19
-rw-r--r--src/pkg/net/http/race.go11
-rw-r--r--src/pkg/net/http/request.go139
-rw-r--r--src/pkg/net/http/request_test.go133
-rw-r--r--src/pkg/net/http/requestwrite_test.go42
-rw-r--r--src/pkg/net/http/response.go68
-rw-r--r--src/pkg/net/http/response_test.go20
-rw-r--r--src/pkg/net/http/responsewrite_test.go123
-rw-r--r--src/pkg/net/http/serve_test.go586
-rw-r--r--src/pkg/net/http/server.go270
-rw-r--r--src/pkg/net/http/transfer.go155
-rw-r--r--src/pkg/net/http/transfer_test.go33
-rw-r--r--src/pkg/net/http/transport.go393
-rw-r--r--src/pkg/net/http/transport_test.go529
-rw-r--r--src/pkg/net/interface.go10
-rw-r--r--src/pkg/net/interface_linux.go58
-rw-r--r--src/pkg/net/interface_stub.go2
-rw-r--r--src/pkg/net/ip.go3
-rw-r--r--src/pkg/net/ip_test.go1
-rw-r--r--src/pkg/net/ipraw_test.go4
-rw-r--r--src/pkg/net/iprawsock_posix.go18
-rw-r--r--src/pkg/net/ipsock.go6
-rw-r--r--src/pkg/net/ipsock_plan9.go66
-rw-r--r--src/pkg/net/ipsock_posix.go9
-rw-r--r--src/pkg/net/lookup_plan9.go46
-rw-r--r--src/pkg/net/lookup_unix.go2
-rw-r--r--src/pkg/net/mail/message.go20
-rw-r--r--src/pkg/net/mail/message_test.go17
-rw-r--r--src/pkg/net/multicast_test.go8
-rw-r--r--src/pkg/net/net.go15
-rw-r--r--src/pkg/net/net_test.go25
-rw-r--r--src/pkg/net/net_windows_test.go4
-rw-r--r--src/pkg/net/netgo_unix_test.go24
-rw-r--r--src/pkg/net/packetconn_test.go32
-rw-r--r--src/pkg/net/parse.go2
-rw-r--r--src/pkg/net/port_unix.go12
-rw-r--r--src/pkg/net/protoconn_test.go6
-rw-r--r--src/pkg/net/rpc/client.go14
-rw-r--r--src/pkg/net/rpc/client_test.go36
-rw-r--r--src/pkg/net/rpc/jsonrpc/all_test.go35
-rw-r--r--src/pkg/net/rpc/jsonrpc/server.go6
-rw-r--r--src/pkg/net/rpc/server.go5
-rw-r--r--src/pkg/net/rpc/server_test.go38
-rw-r--r--src/pkg/net/sendfile_dragonfly.go2
-rw-r--r--src/pkg/net/sendfile_freebsd.go2
-rw-r--r--src/pkg/net/sendfile_stub.go2
-rw-r--r--src/pkg/net/server_test.go86
-rw-r--r--src/pkg/net/smtp/example_test.go61
-rw-r--r--src/pkg/net/smtp/smtp.go8
-rw-r--r--src/pkg/net/smtp/smtp_test.go144
-rw-r--r--src/pkg/net/sock_bsd.go2
-rw-r--r--src/pkg/net/sock_cloexec.go47
-rw-r--r--src/pkg/net/sock_posix.go2
-rw-r--r--src/pkg/net/sock_solaris.go13
-rw-r--r--src/pkg/net/sockopt_bsd.go15
-rw-r--r--src/pkg/net/sockopt_plan9.go13
-rw-r--r--src/pkg/net/sockopt_posix.go2
-rw-r--r--src/pkg/net/sockopt_solaris.go32
-rw-r--r--src/pkg/net/sockoptip_bsd.go2
-rw-r--r--src/pkg/net/sockoptip_posix.go2
-rw-r--r--src/pkg/net/sockoptip_stub.go39
-rw-r--r--src/pkg/net/sys_cloexec.go18
-rw-r--r--src/pkg/net/tcp_test.go53
-rw-r--r--src/pkg/net/tcpsock_plan9.go29
-rw-r--r--src/pkg/net/tcpsock_posix.go21
-rw-r--r--src/pkg/net/tcpsockopt_dragonfly.go29
-rw-r--r--src/pkg/net/tcpsockopt_plan9.go18
-rw-r--r--src/pkg/net/tcpsockopt_posix.go2
-rw-r--r--src/pkg/net/tcpsockopt_solaris.go27
-rw-r--r--src/pkg/net/tcpsockopt_unix.go2
-rw-r--r--src/pkg/net/tcpsockopt_windows.go17
-rw-r--r--src/pkg/net/testdata/resolv.conf5
-rw-r--r--src/pkg/net/textproto/reader.go112
-rw-r--r--src/pkg/net/textproto/reader_test.go28
-rw-r--r--src/pkg/net/timeout_test.go25
-rw-r--r--src/pkg/net/udp_test.go4
-rw-r--r--src/pkg/net/udpsock.go4
-rw-r--r--src/pkg/net/udpsock_plan9.go3
-rw-r--r--src/pkg/net/udpsock_posix.go10
-rw-r--r--src/pkg/net/unicast_posix_test.go7
-rw-r--r--src/pkg/net/unix_test.go69
-rw-r--r--src/pkg/net/unixsock_posix.go28
-rw-r--r--src/pkg/net/url/url.go2
-rw-r--r--src/pkg/net/url/url_test.go11
-rw-r--r--src/pkg/net/z_last_test.go37
-rw-r--r--src/pkg/os/dir_unix.go2
-rw-r--r--src/pkg/os/doc.go3
-rw-r--r--src/pkg/os/env_unix_test.go2
-rw-r--r--src/pkg/os/error_unix.go2
-rw-r--r--src/pkg/os/exec/exec.go88
-rw-r--r--src/pkg/os/exec/exec_test.go151
-rw-r--r--src/pkg/os/exec/lp_unix.go2
-rw-r--r--src/pkg/os/exec/lp_unix_test.go2
-rw-r--r--src/pkg/os/exec/lp_windows_test.go474
-rw-r--r--src/pkg/os/exec_plan9.go9
-rw-r--r--src/pkg/os/exec_posix.go2
-rw-r--r--src/pkg/os/exec_unix.go5
-rw-r--r--src/pkg/os/file.go8
-rw-r--r--src/pkg/os/file_plan9.go33
-rw-r--r--src/pkg/os/file_posix.go7
-rw-r--r--src/pkg/os/file_unix.go59
-rw-r--r--src/pkg/os/file_windows.go15
-rw-r--r--src/pkg/os/getwd.go28
-rw-r--r--src/pkg/os/os_test.go156
-rw-r--r--src/pkg/os/os_unix_test.go40
-rw-r--r--src/pkg/os/path_test.go5
-rw-r--r--src/pkg/os/path_unix.go2
-rw-r--r--src/pkg/os/pipe_bsd.go2
-rw-r--r--src/pkg/os/signal/example_test.go4
-rw-r--r--src/pkg/os/signal/sig.s2
-rw-r--r--src/pkg/os/signal/signal_test.go2
-rw-r--r--src/pkg/os/signal/signal_unix.go2
-rw-r--r--src/pkg/os/signal/signal_windows_test.go11
-rw-r--r--src/pkg/os/stat_nacl.go62
-rw-r--r--src/pkg/os/stat_solaris.go61
-rw-r--r--src/pkg/os/sys_bsd.go2
-rw-r--r--src/pkg/os/sys_darwin.go31
-rw-r--r--src/pkg/os/sys_freebsd.go23
-rw-r--r--src/pkg/os/sys_nacl.go9
-rw-r--r--src/pkg/os/sys_solaris.go11
-rw-r--r--src/pkg/os/sys_unix.go11
-rw-r--r--src/pkg/os/user/lookup_unix.go2
-rw-r--r--src/pkg/path/filepath/export_test.go7
-rw-r--r--src/pkg/path/filepath/match.go2
-rw-r--r--src/pkg/path/filepath/match_test.go53
-rw-r--r--src/pkg/path/filepath/path.go38
-rw-r--r--src/pkg/path/filepath/path_test.go63
-rw-r--r--src/pkg/path/filepath/path_unix.go2
-rw-r--r--src/pkg/path/filepath/path_windows_test.go4
-rw-r--r--src/pkg/reflect/all_test.go223
-rw-r--r--src/pkg/reflect/asm_amd64p32.s27
-rw-r--r--src/pkg/reflect/deepequal.go3
-rw-r--r--src/pkg/reflect/export_test.go1
-rw-r--r--src/pkg/reflect/makefunc.go8
-rw-r--r--src/pkg/reflect/type.go131
-rw-r--r--src/pkg/reflect/value.go968
-rw-r--r--src/pkg/regexp/all_test.go65
-rw-r--r--src/pkg/regexp/example_test.go4
-rw-r--r--src/pkg/regexp/exec.go121
-rw-r--r--src/pkg/regexp/onepass.go582
-rw-r--r--src/pkg/regexp/onepass_test.go208
-rw-r--r--src/pkg/regexp/regexp.go20
-rw-r--r--src/pkg/regexp/syntax/doc.go4
-rwxr-xr-xsrc/pkg/regexp/syntax/make_perl_groups.pl4
-rw-r--r--src/pkg/regexp/syntax/parse.go3
-rw-r--r--src/pkg/regexp/syntax/parse_test.go4
-rw-r--r--src/pkg/regexp/syntax/perl_groups.go4
-rw-r--r--src/pkg/regexp/syntax/prog.go54
-rw-r--r--src/pkg/regexp/syntax/prog_test.go4
-rw-r--r--src/pkg/runtime/alg.goc (renamed from src/pkg/runtime/alg.c)40
-rw-r--r--src/pkg/runtime/append_test.go19
-rw-r--r--src/pkg/runtime/arch_386.h5
-rw-r--r--src/pkg/runtime/arch_amd64.h9
-rw-r--r--src/pkg/runtime/arch_amd64p32.h16
-rw-r--r--src/pkg/runtime/arch_arm.h1
-rw-r--r--src/pkg/runtime/asm_386.s849
-rw-r--r--src/pkg/runtime/asm_amd64.s893
-rw-r--r--src/pkg/runtime/asm_amd64p32.s1073
-rw-r--r--src/pkg/runtime/asm_arm.s477
-rw-r--r--src/pkg/runtime/atomic_amd64x.c (renamed from src/pkg/runtime/atomic_amd64.c)2
-rw-r--r--src/pkg/runtime/atomic_arm.c13
-rw-r--r--src/pkg/runtime/callback_windows.c3
-rw-r--r--src/pkg/runtime/cgo/asm_nacl_amd64p32.s13
-rw-r--r--src/pkg/runtime/cgo/gcc_dragonfly_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_dragonfly_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_arm.c9
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_arm.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_arm.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_386.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_amd64.c4
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_386.c16
-rw-r--r--src/pkg/runtime/cgo/gcc_windows_amd64.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h1
-rw-r--r--src/pkg/runtime/cgocall.c53
-rw-r--r--src/pkg/runtime/chan.goc (renamed from src/pkg/runtime/chan.c)528
-rw-r--r--src/pkg/runtime/chan.h75
-rw-r--r--src/pkg/runtime/chan_test.go637
-rw-r--r--src/pkg/runtime/complex.goc (renamed from src/pkg/runtime/complex.c)8
-rw-r--r--src/pkg/runtime/cpuprof.goc (renamed from src/pkg/runtime/cpuprof.c)11
-rw-r--r--src/pkg/runtime/crash_test.go96
-rw-r--r--src/pkg/runtime/debug/garbage.go20
-rw-r--r--src/pkg/runtime/debug/heapdump_test.go33
-rw-r--r--src/pkg/runtime/debug/stack.go6
-rw-r--r--src/pkg/runtime/defs.c14
-rw-r--r--src/pkg/runtime/defs_freebsd.go6
-rw-r--r--src/pkg/runtime/defs_freebsd_386.h6
-rw-r--r--src/pkg/runtime/defs_freebsd_amd64.h6
-rw-r--r--src/pkg/runtime/defs_freebsd_arm.h36
-rw-r--r--src/pkg/runtime/defs_nacl_386.h63
-rw-r--r--src/pkg/runtime/defs_nacl_amd64p32.h90
-rw-r--r--src/pkg/runtime/defs_openbsd_386.h8
-rw-r--r--src/pkg/runtime/defs_openbsd_amd64.h9
-rw-r--r--src/pkg/runtime/defs_solaris.go156
-rw-r--r--src/pkg/runtime/defs_solaris_amd64.go48
-rw-r--r--src/pkg/runtime/defs_solaris_amd64.h254
-rw-r--r--src/pkg/runtime/env_plan9.c10
-rw-r--r--src/pkg/runtime/env_posix.c17
-rw-r--r--src/pkg/runtime/error.go7
-rw-r--r--src/pkg/runtime/export_test.go34
-rw-r--r--src/pkg/runtime/extern.go28
-rw-r--r--src/pkg/runtime/funcdata.h6
-rw-r--r--src/pkg/runtime/futex_test.go75
-rw-r--r--src/pkg/runtime/gc_test.go83
-rw-r--r--src/pkg/runtime/hash_test.go6
-rw-r--r--src/pkg/runtime/hashmap.goc (renamed from src/pkg/runtime/hashmap.c)707
-rw-r--r--src/pkg/runtime/hashmap.h147
-rw-r--r--src/pkg/runtime/hashmap_fast.c90
-rw-r--r--src/pkg/runtime/heapdump.c981
-rw-r--r--src/pkg/runtime/iface.goc (renamed from src/pkg/runtime/iface.c)239
-rw-r--r--src/pkg/runtime/lfstack.goc (renamed from src/pkg/runtime/lfstack.c)24
-rw-r--r--src/pkg/runtime/lfstack_test.go12
-rw-r--r--src/pkg/runtime/lock_futex.c12
-rw-r--r--src/pkg/runtime/lock_sema.c11
-rw-r--r--src/pkg/runtime/malloc.goc604
-rw-r--r--src/pkg/runtime/malloc.h215
-rw-r--r--src/pkg/runtime/map_test.go66
-rw-r--r--src/pkg/runtime/mapspeed_test.go30
-rw-r--r--src/pkg/runtime/mcache.c123
-rw-r--r--src/pkg/runtime/mcentral.c205
-rw-r--r--src/pkg/runtime/mem.go3
-rw-r--r--src/pkg/runtime/mem_darwin.c13
-rw-r--r--src/pkg/runtime/mem_dragonfly.c19
-rw-r--r--src/pkg/runtime/mem_freebsd.c19
-rw-r--r--src/pkg/runtime/mem_linux.c30
-rw-r--r--src/pkg/runtime/mem_nacl.c118
-rw-r--r--src/pkg/runtime/mem_netbsd.c17
-rw-r--r--src/pkg/runtime/mem_openbsd.c17
-rw-r--r--src/pkg/runtime/mem_plan9.c13
-rw-r--r--src/pkg/runtime/mem_solaris.c99
-rw-r--r--src/pkg/runtime/mem_windows.c43
-rw-r--r--src/pkg/runtime/memclr_386.s127
-rw-r--r--src/pkg/runtime/memclr_amd64.s116
-rw-r--r--src/pkg/runtime/memclr_arm.s6
-rw-r--r--src/pkg/runtime/memclr_plan9_386.s50
-rw-r--r--src/pkg/runtime/memclr_plan9_amd64.s48
-rw-r--r--src/pkg/runtime/memmove_386.s2
-rw-r--r--src/pkg/runtime/memmove_amd64.s2
-rw-r--r--src/pkg/runtime/memmove_nacl_amd64p32.s46
-rw-r--r--src/pkg/runtime/memmove_plan9_386.s127
-rw-r--r--src/pkg/runtime/memmove_plan9_amd64.s126
-rw-r--r--src/pkg/runtime/memmove_test.go179
-rw-r--r--src/pkg/runtime/mfinal.c219
-rw-r--r--src/pkg/runtime/mfinal_test.go175
-rw-r--r--src/pkg/runtime/mgc0.c1814
-rw-r--r--src/pkg/runtime/mgc0.go12
-rw-r--r--src/pkg/runtime/mgc0.h41
-rw-r--r--src/pkg/runtime/mheap.c506
-rw-r--r--src/pkg/runtime/mknacl.sh15
-rw-r--r--src/pkg/runtime/mprof.goc271
-rw-r--r--src/pkg/runtime/msize.c36
-rw-r--r--src/pkg/runtime/netpoll.goc169
-rw-r--r--src/pkg/runtime/netpoll_epoll.c7
-rw-r--r--src/pkg/runtime/netpoll_kqueue.c7
-rw-r--r--src/pkg/runtime/netpoll_nacl.c37
-rw-r--r--src/pkg/runtime/netpoll_solaris.c268
-rw-r--r--src/pkg/runtime/netpoll_windows.c15
-rw-r--r--src/pkg/runtime/norace_test.go36
-rw-r--r--src/pkg/runtime/os_darwin.c14
-rw-r--r--src/pkg/runtime/os_darwin.h2
-rw-r--r--src/pkg/runtime/os_dragonfly.c14
-rw-r--r--src/pkg/runtime/os_dragonfly.h1
-rw-r--r--src/pkg/runtime/os_freebsd.c20
-rw-r--r--src/pkg/runtime/os_freebsd.h1
-rw-r--r--src/pkg/runtime/os_linux.c13
-rw-r--r--src/pkg/runtime/os_linux.h1
-rw-r--r--src/pkg/runtime/os_linux_arm.c2
-rw-r--r--src/pkg/runtime/os_nacl.c278
-rw-r--r--src/pkg/runtime/os_nacl.h162
-rw-r--r--src/pkg/runtime/os_netbsd.c14
-rw-r--r--src/pkg/runtime/os_netbsd.h1
-rw-r--r--src/pkg/runtime/os_openbsd.c16
-rw-r--r--src/pkg/runtime/os_openbsd.h1
-rw-r--r--src/pkg/runtime/os_plan9.c101
-rw-r--r--src/pkg/runtime/os_plan9.h9
-rw-r--r--src/pkg/runtime/os_plan9_386.c135
-rw-r--r--src/pkg/runtime/os_plan9_amd64.c106
-rw-r--r--src/pkg/runtime/os_solaris.c583
-rw-r--r--src/pkg/runtime/os_solaris.h51
-rw-r--r--src/pkg/runtime/os_windows.c101
-rw-r--r--src/pkg/runtime/os_windows_386.c48
-rw-r--r--src/pkg/runtime/os_windows_amd64.c44
-rw-r--r--src/pkg/runtime/panic.c326
-rw-r--r--src/pkg/runtime/parfor.c28
-rw-r--r--src/pkg/runtime/pprof/pprof.go2
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go29
-rw-r--r--src/pkg/runtime/print.c63
-rw-r--r--src/pkg/runtime/proc.c717
-rw-r--r--src/pkg/runtime/proc.p526
-rw-r--r--src/pkg/runtime/proc_test.go66
-rw-r--r--src/pkg/runtime/race.c394
-rw-r--r--src/pkg/runtime/race.h3
-rw-r--r--src/pkg/runtime/race/README2
-rw-r--r--src/pkg/runtime/race/race.go118
-rw-r--r--src/pkg/runtime/race/race_darwin_amd64.sysobin192988 -> 222964 bytes
-rw-r--r--src/pkg/runtime/race/race_linux_amd64.sysobin195144 -> 243208 bytes
-rw-r--r--src/pkg/runtime/race/race_test.go17
-rw-r--r--src/pkg/runtime/race/race_windows_amd64.sysobin161295 -> 210859 bytes
-rw-r--r--src/pkg/runtime/race/testdata/chan_test.go207
-rw-r--r--src/pkg/runtime/race/testdata/finalizer_test.go22
-rw-r--r--src/pkg/runtime/race/testdata/map_test.go79
-rw-r--r--src/pkg/runtime/race/testdata/mop_test.go22
-rw-r--r--src/pkg/runtime/race0.c6
-rw-r--r--src/pkg/runtime/race_amd64.s240
-rw-r--r--src/pkg/runtime/rdebug.goc27
-rw-r--r--src/pkg/runtime/rt0_freebsd_arm.s5
-rw-r--r--src/pkg/runtime/rt0_nacl_386.s22
-rw-r--r--src/pkg/runtime/rt0_nacl_amd64p32.s30
-rw-r--r--src/pkg/runtime/rt0_solaris_amd64.s18
-rw-r--r--src/pkg/runtime/runtime-gdb.py160
-rw-r--r--src/pkg/runtime/runtime.c120
-rw-r--r--src/pkg/runtime/runtime.h254
-rw-r--r--src/pkg/runtime/runtime1.goc114
-rw-r--r--src/pkg/runtime/runtime_test.go82
-rw-r--r--src/pkg/runtime/runtime_unix_test.go56
-rw-r--r--src/pkg/runtime/sema.goc6
-rw-r--r--src/pkg/runtime/signal_386.c9
-rw-r--r--src/pkg/runtime/signal_amd64x.c (renamed from src/pkg/runtime/signal_amd64.c)33
-rw-r--r--src/pkg/runtime/signal_arm.c7
-rw-r--r--src/pkg/runtime/signal_nacl_386.h23
-rw-r--r--src/pkg/runtime/signal_nacl_amd64p32.h31
-rw-r--r--src/pkg/runtime/signal_solaris_amd64.h31
-rw-r--r--src/pkg/runtime/signal_unix.c3
-rw-r--r--src/pkg/runtime/signals_freebsd.h2
-rw-r--r--src/pkg/runtime/signals_linux.h2
-rw-r--r--src/pkg/runtime/signals_nacl.h50
-rw-r--r--src/pkg/runtime/signals_plan9.h60
-rw-r--r--src/pkg/runtime/signals_solaris.h94
-rw-r--r--src/pkg/runtime/slice.goc (renamed from src/pkg/runtime/slice.c)74
-rw-r--r--src/pkg/runtime/softfloat_arm.c4
-rw-r--r--src/pkg/runtime/sqrt.go150
-rw-r--r--src/pkg/runtime/stack.c711
-rw-r--r--src/pkg/runtime/stack.h5
-rw-r--r--src/pkg/runtime/stack_gen_test.go1473
-rw-r--r--src/pkg/runtime/stack_test.go1661
-rw-r--r--src/pkg/runtime/string.goc102
-rw-r--r--src/pkg/runtime/symtab.goc (renamed from src/pkg/runtime/symtab.c)27
-rw-r--r--src/pkg/runtime/sys_darwin_386.s3
-rw-r--r--src/pkg/runtime/sys_dragonfly_386.s4
-rw-r--r--src/pkg/runtime/sys_dragonfly_amd64.s4
-rw-r--r--src/pkg/runtime/sys_freebsd_386.s11
-rw-r--r--src/pkg/runtime/sys_freebsd_amd64.s6
-rw-r--r--src/pkg/runtime/sys_freebsd_arm.s9
-rw-r--r--src/pkg/runtime/sys_linux_386.s6
-rw-r--r--src/pkg/runtime/sys_linux_amd64.s4
-rw-r--r--src/pkg/runtime/sys_linux_arm.s2
-rw-r--r--src/pkg/runtime/sys_nacl_386.s243
-rw-r--r--src/pkg/runtime/sys_nacl_amd64p32.s413
-rw-r--r--src/pkg/runtime/sys_openbsd_386.s56
-rw-r--r--src/pkg/runtime/sys_openbsd_amd64.s22
-rw-r--r--src/pkg/runtime/sys_plan9_386.s15
-rw-r--r--src/pkg/runtime/sys_plan9_amd64.s2
-rw-r--r--src/pkg/runtime/sys_solaris_amd64.s267
-rw-r--r--src/pkg/runtime/sys_windows_386.s123
-rw-r--r--src/pkg/runtime/sys_windows_amd64.s126
-rw-r--r--src/pkg/runtime/sys_x86.c30
-rw-r--r--src/pkg/runtime/syscall_nacl.h71
-rw-r--r--src/pkg/runtime/syscall_solaris.goc374
-rw-r--r--src/pkg/runtime/syscall_windows.goc19
-rw-r--r--src/pkg/runtime/syscall_windows_test.go249
-rw-r--r--src/pkg/runtime/time.goc32
-rw-r--r--src/pkg/runtime/traceback_arm.c116
-rw-r--r--src/pkg/runtime/traceback_x86.c207
-rw-r--r--src/pkg/runtime/type.go1
-rw-r--r--src/pkg/runtime/type.h8
-rw-r--r--src/pkg/runtime/typekind.h3
-rw-r--r--src/pkg/runtime/vlop_arm.s13
-rw-r--r--src/pkg/runtime/vlrt_386.c12
-rw-r--r--src/pkg/runtime/vlrt_arm.c7
-rw-r--r--src/pkg/sort/sort.go6
-rw-r--r--src/pkg/strconv/atob_test.go34
-rw-r--r--src/pkg/strconv/atof.go11
-rw-r--r--src/pkg/strconv/atoi.go8
-rw-r--r--src/pkg/strconv/isprint.go4
-rw-r--r--src/pkg/strconv/makeisprint.go3
-rw-r--r--src/pkg/strconv/quote.go3
-rw-r--r--src/pkg/strconv/quote_example_test.go35
-rw-r--r--src/pkg/strconv/quote_test.go1
-rw-r--r--src/pkg/strings/example_test.go32
-rw-r--r--src/pkg/strings/reader.go52
-rw-r--r--src/pkg/strings/reader_test.go56
-rw-r--r--src/pkg/strings/replace.go2
-rw-r--r--src/pkg/strings/strings_test.go30
-rw-r--r--src/pkg/sync/atomic/asm_386.s14
-rw-r--r--src/pkg/sync/atomic/asm_amd64.s4
-rw-r--r--src/pkg/sync/atomic/asm_amd64p32.s159
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s12
-rw-r--r--src/pkg/sync/atomic/atomic_test.go7
-rw-r--r--src/pkg/sync/atomic/export_linux_arm_test.go2
-rw-r--r--src/pkg/sync/mutex_test.go72
-rw-r--r--src/pkg/sync/once_test.go25
-rw-r--r--src/pkg/sync/pool.go223
-rw-r--r--src/pkg/sync/pool_test.go151
-rw-r--r--src/pkg/sync/runtime_sema_test.go85
-rw-r--r--src/pkg/sync/rwmutex_test.go79
-rw-r--r--src/pkg/sync/waitgroup.go10
-rw-r--r--src/pkg/sync/waitgroup_test.go125
-rw-r--r--src/pkg/syscall/asm_darwin_386.s13
-rw-r--r--src/pkg/syscall/asm_darwin_amd64.s11
-rw-r--r--src/pkg/syscall/asm_freebsd_386.s13
-rw-r--r--src/pkg/syscall/asm_freebsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_freebsd_arm.s51
-rw-r--r--src/pkg/syscall/asm_linux_386.s17
-rw-r--r--src/pkg/syscall/asm_linux_amd64.s21
-rw-r--r--src/pkg/syscall/asm_linux_arm.s4
-rw-r--r--src/pkg/syscall/asm_nacl_386.s43
-rw-r--r--src/pkg/syscall/asm_nacl_amd64p32.s41
-rw-r--r--src/pkg/syscall/asm_netbsd_386.s13
-rw-r--r--src/pkg/syscall/asm_netbsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_openbsd_386.s13
-rw-r--r--src/pkg/syscall/asm_openbsd_amd64.s13
-rw-r--r--src/pkg/syscall/asm_plan9_386.s9
-rw-r--r--src/pkg/syscall/asm_plan9_amd64.s11
-rw-r--r--src/pkg/syscall/asm_solaris_amd64.s7
-rw-r--r--src/pkg/syscall/consistency_unix_test.go34
-rw-r--r--src/pkg/syscall/dir_plan9.go9
-rw-r--r--src/pkg/syscall/env_unix.go2
-rw-r--r--src/pkg/syscall/exec_linux.go6
-rw-r--r--src/pkg/syscall/exec_plan9.go2
-rw-r--r--src/pkg/syscall/exec_solaris.go243
-rw-r--r--src/pkg/syscall/exec_unix.go4
-rw-r--r--src/pkg/syscall/fd_nacl.go326
-rw-r--r--src/pkg/syscall/flock.go22
-rw-r--r--src/pkg/syscall/flock_linux_32bit.go13
-rw-r--r--src/pkg/syscall/fs_nacl.go815
-rw-r--r--src/pkg/syscall/lsf_linux.go4
-rwxr-xr-xsrc/pkg/syscall/mkall.sh61
-rw-r--r--src/pkg/syscall/mkall_windows.bat21
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh79
-rwxr-xr-xsrc/pkg/syscall/mkerrors_windows.sh202
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl10
-rwxr-xr-xsrc/pkg/syscall/mksyscall_solaris.pl (renamed from src/pkg/syscall/mksyscall_windows.pl)118
-rw-r--r--src/pkg/syscall/mksyscall_windows.go662
-rwxr-xr-xsrc/pkg/syscall/mksysnum_dragonfly.pl2
-rwxr-xr-xsrc/pkg/syscall/mksysnum_freebsd.pl13
-rw-r--r--src/pkg/syscall/mmap_unix_test.go22
-rw-r--r--src/pkg/syscall/net_nacl.go912
-rw-r--r--src/pkg/syscall/rlimit_linux_test.go41
-rw-r--r--src/pkg/syscall/route_bsd.go9
-rw-r--r--src/pkg/syscall/route_dragonfly.go2
-rw-r--r--src/pkg/syscall/route_freebsd.go12
-rw-r--r--src/pkg/syscall/route_freebsd_32bit.go24
-rw-r--r--src/pkg/syscall/route_freebsd_64bit.go14
-rw-r--r--src/pkg/syscall/route_netbsd.go2
-rw-r--r--src/pkg/syscall/route_openbsd.go2
-rw-r--r--src/pkg/syscall/so_solaris.go260
-rw-r--r--src/pkg/syscall/sockcmsg_unix.go8
-rw-r--r--src/pkg/syscall/srpc_nacl.go822
-rw-r--r--src/pkg/syscall/syscall_bsd.go98
-rw-r--r--src/pkg/syscall/syscall_bsd_test.go34
-rw-r--r--src/pkg/syscall/syscall_darwin.go21
-rw-r--r--src/pkg/syscall/syscall_dragonfly.go16
-rw-r--r--src/pkg/syscall/syscall_freebsd.go39
-rw-r--r--src/pkg/syscall/syscall_linux.go65
-rw-r--r--src/pkg/syscall/syscall_linux_386.go31
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go36
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go26
-rw-r--r--src/pkg/syscall/syscall_nacl.go311
-rw-r--r--src/pkg/syscall/syscall_nacl_386.go32
-rw-r--r--src/pkg/syscall/syscall_nacl_amd64p32.go32
-rw-r--r--src/pkg/syscall/syscall_openbsd.go22
-rw-r--r--src/pkg/syscall/syscall_openbsd_386.go4
-rw-r--r--src/pkg/syscall/syscall_openbsd_amd64.go6
-rw-r--r--src/pkg/syscall/syscall_plan9.go2
-rw-r--r--src/pkg/syscall/syscall_solaris.go523
-rw-r--r--src/pkg/syscall/syscall_solaris_amd64.go37
-rw-r--r--src/pkg/syscall/syscall_unix.go31
-rw-r--r--src/pkg/syscall/syscall_unix_test.go (renamed from src/pkg/syscall/passfd_test.go)120
-rw-r--r--src/pkg/syscall/syscall_windows.go27
-rw-r--r--src/pkg/syscall/tables_nacl.go324
-rw-r--r--src/pkg/syscall/time_nacl_386.s11
-rw-r--r--src/pkg/syscall/time_nacl_amd64p32.s11
-rw-r--r--src/pkg/syscall/types_dragonfly.go9
-rw-r--r--src/pkg/syscall/types_freebsd.go110
-rw-r--r--src/pkg/syscall/types_linux.go2
-rw-r--r--src/pkg/syscall/types_netbsd.go5
-rw-r--r--src/pkg/syscall/types_openbsd.go5
-rw-r--r--src/pkg/syscall/types_solaris.go222
-rw-r--r--src/pkg/syscall/unzip_nacl.go685
-rw-r--r--src/pkg/syscall/zerrors_dragonfly_386.go5
-rw-r--r--src/pkg/syscall/zerrors_dragonfly_amd64.go5
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go33
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go34
-rw-r--r--src/pkg/syscall/zerrors_freebsd_arm.go35
-rw-r--r--src/pkg/syscall/zerrors_netbsd_386.go51
-rw-r--r--src/pkg/syscall/zerrors_netbsd_amd64.go51
-rw-r--r--src/pkg/syscall/zerrors_netbsd_arm.go36
-rw-r--r--src/pkg/syscall/zerrors_openbsd_386.go66
-rw-r--r--src/pkg/syscall/zerrors_openbsd_amd64.go63
-rw-r--r--src/pkg/syscall/zerrors_solaris_amd64.go1414
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go102
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go102
-rw-r--r--src/pkg/syscall/zsyscall_dragonfly_386.go34
-rw-r--r--src/pkg/syscall/zsyscall_dragonfly_amd64.go34
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go45
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go45
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_arm.go120
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go15
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go15
-rw-r--r--src/pkg/syscall/zsyscall_nacl_386.go63
-rw-r--r--src/pkg/syscall/zsyscall_nacl_amd64p32.go63
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_386.go17
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_amd64.go17
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_arm.go28
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_386.go68
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_amd64.go68
-rw-r--r--src/pkg/syscall/zsyscall_solaris_amd64.go883
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go6
-rw-r--r--src/pkg/syscall/zsyscall_windows_amd64.go6
-rw-r--r--src/pkg/syscall/zsysctl_openbsd.go28
-rw-r--r--src/pkg/syscall/zsysnum_dragonfly_386.go5
-rw-r--r--src/pkg/syscall/zsysnum_dragonfly_amd64.go5
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go20
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go20
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_arm.go27
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_386.go57
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_amd64.go57
-rw-r--r--src/pkg/syscall/zsysnum_solaris_amd64.go11
-rw-r--r--src/pkg/syscall/ztypes_dragonfly_386.go14
-rw-r--r--src/pkg/syscall/ztypes_dragonfly_amd64.go14
-rw-r--r--src/pkg/syscall/ztypes_freebsd_386.go55
-rw-r--r--src/pkg/syscall/ztypes_freebsd_amd64.go55
-rw-r--r--src/pkg/syscall/ztypes_freebsd_arm.go120
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go8
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go10
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_386.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_amd64.go10
-rw-r--r--src/pkg/syscall/ztypes_netbsd_arm.go39
-rw-r--r--src/pkg/syscall/ztypes_openbsd_386.go55
-rw-r--r--src/pkg/syscall/ztypes_openbsd_amd64.go56
-rw-r--r--src/pkg/syscall/ztypes_solaris_amd64.go365
-rw-r--r--src/pkg/syscall/ztypes_windows.go9
-rw-r--r--src/pkg/testing/benchmark.go102
-rw-r--r--src/pkg/testing/benchmark_test.go53
-rw-r--r--src/pkg/testing/testing.go47
-rw-r--r--src/pkg/text/scanner/scanner.go6
-rw-r--r--src/pkg/text/scanner/scanner_test.go41
-rw-r--r--src/pkg/text/tabwriter/tabwriter.go12
-rw-r--r--src/pkg/text/tabwriter/tabwriter_test.go39
-rw-r--r--src/pkg/text/template/doc.go2
-rw-r--r--src/pkg/text/template/exec.go11
-rw-r--r--src/pkg/text/template/exec_test.go30
-rw-r--r--src/pkg/text/template/multi_test.go12
-rw-r--r--src/pkg/text/template/template.go2
-rw-r--r--src/pkg/time/format.go9
-rw-r--r--src/pkg/time/format_test.go511
-rw-r--r--src/pkg/time/internal_test.go20
-rw-r--r--src/pkg/time/sleep.go12
-rw-r--r--src/pkg/time/sleep_test.go31
-rw-r--r--src/pkg/time/sys_unix.go2
-rw-r--r--src/pkg/time/tick.go3
-rw-r--r--src/pkg/time/tick_test.go18
-rw-r--r--src/pkg/time/time.go2
-rw-r--r--src/pkg/time/time_test.go553
-rw-r--r--src/pkg/time/zoneinfo.go87
-rw-r--r--src/pkg/time/zoneinfo_plan9.go2
-rw-r--r--src/pkg/time/zoneinfo_read.go8
-rw-r--r--src/pkg/time/zoneinfo_test.go63
-rw-r--r--src/pkg/time/zoneinfo_unix.go2
-rw-r--r--src/pkg/time/zoneinfo_windows.go8
-rw-r--r--src/pkg/unicode/letter.go4
-rw-r--r--src/pkg/unicode/letter_test.go16
-rw-r--r--src/pkg/unicode/maketables.go8
-rw-r--r--src/pkg/unicode/script_test.go2
-rw-r--r--src/pkg/unicode/tables.go65
-rw-r--r--src/pkg/unicode/utf16/utf16.go2
-rw-r--r--src/pkg/unicode/utf16/utf16_test.go48
-rw-r--r--src/pkg/unicode/utf8/example_test.go4
-rw-r--r--src/pkg/unicode/utf8/utf8.go32
-rwxr-xr-xsrc/race.bash6
-rw-r--r--src/race.bat10
-rwxr-xr-xsrc/run.bash54
-rw-r--r--src/run.bat17
-rwxr-xr-xsrc/run.rc8
-rw-r--r--test/bench/shootout/threadring.c12
-rwxr-xr-xtest/bench/shootout/timing.sh157
-rw-r--r--test/cmp.go59
-rw-r--r--test/cmp6.go13
-rw-r--r--test/const1.go8
-rw-r--r--test/const5.go4
-rw-r--r--test/deferfin.go12
-rw-r--r--test/divmod.go2
-rw-r--r--test/escape2.go155
-rw-r--r--test/escape5.go8
-rw-r--r--test/fixedbugs/bug176.go2
-rw-r--r--test/fixedbugs/bug191.dir/a.go4
-rw-r--r--test/fixedbugs/bug191.dir/b.go4
-rw-r--r--test/fixedbugs/bug191.dir/main.go3
-rw-r--r--test/fixedbugs/bug191.go2
-rw-r--r--test/fixedbugs/bug191.out2
-rw-r--r--test/fixedbugs/bug385_32.go4
-rw-r--r--test/fixedbugs/bug385_64.go2
-rw-r--r--test/fixedbugs/bug462.go2
-rw-r--r--test/fixedbugs/bug476.go2
-rw-r--r--test/fixedbugs/bug480.dir/a.go (renamed from src/pkg/runtime/export_test.c)20
-rw-r--r--test/fixedbugs/bug480.dir/b.go13
-rw-r--r--test/fixedbugs/bug480.go9
-rw-r--r--test/fixedbugs/bug481.go18
-rw-r--r--test/fixedbugs/bug482.go20
-rw-r--r--test/fixedbugs/bug483.go36
-rw-r--r--test/fixedbugs/bug484.go90
-rw-r--r--test/fixedbugs/bug485.go39
-rw-r--r--test/fixedbugs/issue1304.go23
-rw-r--r--test/fixedbugs/issue3705.go2
-rw-r--r--test/fixedbugs/issue4251.go6
-rw-r--r--test/fixedbugs/issue4388.go56
-rw-r--r--test/fixedbugs/issue4405.go8
-rw-r--r--test/fixedbugs/issue4429.go2
-rw-r--r--test/fixedbugs/issue4510.dir/f1.go2
-rw-r--r--test/fixedbugs/issue4517d.go2
-rw-r--r--test/fixedbugs/issue4545.go2
-rw-r--r--test/fixedbugs/issue4610.go4
-rw-r--r--test/fixedbugs/issue4618.go5
-rw-r--r--test/fixedbugs/issue4654.go44
-rw-r--r--test/fixedbugs/issue4667.go4
-rw-r--r--test/fixedbugs/issue4776.go2
-rw-r--r--test/fixedbugs/issue4813.go12
-rw-r--r--test/fixedbugs/issue4847.go2
-rw-r--r--test/fixedbugs/issue5089.go4
-rw-r--r--test/fixedbugs/issue5172.go4
-rw-r--r--test/fixedbugs/issue5358.go2
-rw-r--r--test/fixedbugs/issue5493.go5
-rw-r--r--test/fixedbugs/issue5581.go2
-rw-r--r--test/fixedbugs/issue5793.go36
-rw-r--r--test/fixedbugs/issue5957.dir/c.go10
-rw-r--r--test/fixedbugs/issue6295.dir/p0.go13
-rw-r--r--test/fixedbugs/issue6295.dir/p1.go26
-rw-r--r--test/fixedbugs/issue6295.dir/p2.go19
-rw-r--r--test/fixedbugs/issue6295.go10
-rw-r--r--test/fixedbugs/issue6402.go13
-rw-r--r--test/fixedbugs/issue6403.go14
-rw-r--r--test/fixedbugs/issue6405.go13
-rw-r--r--test/fixedbugs/issue6406.go12
-rw-r--r--test/fixedbugs/issue6500.go29
-rw-r--r--test/fixedbugs/issue6572.go21
-rw-r--r--test/fixedbugs/issue6789.dir/a.go14
-rw-r--r--test/fixedbugs/issue6789.dir/b.go12
-rw-r--r--test/fixedbugs/issue6789.go10
-rw-r--r--test/fixedbugs/issue6847.go85
-rw-r--r--test/fixedbugs/issue6889.go103
-rw-r--r--test/fixedbugs/issue6899.go13
-rw-r--r--test/fixedbugs/issue6899.out1
-rw-r--r--test/fixedbugs/issue6902.go21
-rw-r--r--test/fixedbugs/issue6964.go11
-rw-r--r--test/fixedbugs/issue7023.dir/a.go10
-rw-r--r--test/fixedbugs/issue7023.dir/b.go11
-rw-r--r--test/fixedbugs/issue7023.go10
-rw-r--r--test/fixedbugs/issue7044.go43
-rw-r--r--test/fixedbugs/issue7050.go19
-rw-r--r--test/fixedbugs/issue7083.go22
-rw-r--r--test/fixedbugs/issue7129.go21
-rw-r--r--test/fixedbugs/issue7150.go17
-rw-r--r--test/fixedbugs/issue7153.go11
-rw-r--r--test/fixedbugs/issue7214.go30
-rw-r--r--test/fixedbugs/issue7223.go20
-rw-r--r--test/fixedbugs/issue7272.go48
-rw-r--r--test/fixedbugs/issue7310.go15
-rw-r--r--test/fixedbugs/issue7316.go37
-rw-r--r--test/fixedbugs/issue7346.go14
-rw-r--r--test/fixedbugs/issue7366.go21
-rw-r--r--test/fixedbugs/issue7405.go51
-rw-r--r--test/fixedbugs/issue7419.go25
-rw-r--r--test/fixedbugs/issue7525.go19
-rw-r--r--test/fixedbugs/issue7538a.go15
-rw-r--r--test/fixedbugs/issue7538b.go13
-rw-r--r--test/fixedbugs/issue7547.go17
-rw-r--r--test/fixedbugs/issue7550.go27
-rw-r--r--test/fixedbugs/issue7590.go21
-rw-r--r--test/fixedbugs/issue7648.dir/a.go11
-rw-r--r--test/fixedbugs/issue7648.dir/b.go11
-rw-r--r--test/fixedbugs/issue7648.go9
-rw-r--r--test/fixedbugs/issue7675.go24
-rw-r--r--test/fixedbugs/issue7742.go18
-rw-r--r--test/fixedbugs/issue7794.go12
-rw-r--r--test/fixedbugs/issue7863.go60
-rw-r--r--test/fixedbugs/issue7867.go43
-rw-r--r--test/fixedbugs/issue7884.go15
-rw-r--r--test/fixedbugs/issue7944.go40
-rw-r--r--test/fixedbugs/issue7995.go25
-rw-r--r--test/fixedbugs/issue7995b.dir/x1.go16
-rw-r--r--test/fixedbugs/issue7995b.dir/x2.go10
-rw-r--r--test/fixedbugs/issue7995b.go9
-rw-r--r--test/fixedbugs/issue7996.go14
-rw-r--r--test/fixedbugs/issue7997.go53
-rw-r--r--test/fixedbugs/issue7998.go23
-rw-r--r--test/fixedbugs/issue8004.go59
-rw-r--r--test/fixedbugs/issue8011.go18
-rw-r--r--test/fixedbugs/issue8028.go27
-rw-r--r--test/fixedbugs/issue8036.go45
-rw-r--r--test/fixedbugs/issue8039.go23
-rw-r--r--test/fixedbugs/issue8047.go29
-rw-r--r--test/fixedbugs/issue8047b.go22
-rw-r--r--test/fixedbugs/issue8048.go107
-rw-r--r--test/fixedbugs/issue8073.go15
-rw-r--r--test/fixedbugs/issue8076.go17
-rw-r--r--test/fixedbugs/issue8132.go32
-rw-r--r--test/fixedbugs/issue8139.go50
-rw-r--r--test/fixedbugs/issue8155.go48
-rw-r--r--test/fixedbugs/issue8158.go41
-rw-r--r--test/float_lit2.go164
-rw-r--r--test/float_lit3.go48
-rw-r--r--test/funcdup.go24
-rw-r--r--test/funcdup2.go12
-rw-r--r--test/gc2.go4
-rw-r--r--test/gcstring.go48
-rw-r--r--test/import1.go2
-rw-r--r--test/import4.dir/empty.go2
-rw-r--r--test/import4.dir/import4.go4
-rw-r--r--test/live.go624
-rw-r--r--test/live1.go46
-rw-r--r--test/live2.go39
-rw-r--r--test/method4.dir/prog.go9
-rw-r--r--test/nilptr3.go102
-rw-r--r--test/nilptr4.go24
-rw-r--r--test/nosplit.go314
-rw-r--r--test/reorder2.go169
-rwxr-xr-xtest/run2
-rw-r--r--test/run.go139
-rw-r--r--test/sigchld.go2
-rw-r--r--test/slice3err.go56
-rw-r--r--test/string_lit.go5
-rw-r--r--test/syntax/semi1.go2
-rw-r--r--test/syntax/semi2.go2
-rw-r--r--test/syntax/semi3.go2
-rw-r--r--test/syntax/semi4.go2
-rw-r--r--test/tinyfin.go62
-rw-r--r--test/typecheck.go4
1607 files changed, 127248 insertions, 67171 deletions
diff --git a/AUTHORS b/AUTHORS
index c3fd330e8..d4fbbd143 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@ Aaron France <aaron.l.france@gmail.com>
Abhinav Gupta <abhinav.g90@gmail.com>
Adrian Nos <nos.adrian@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
+Adrien Bustany <adrien-xx-google@bustany.org>
Akshat Kumar <seed@mail.nanosouffle.net>
Albert Strasheim <fullung@gmail.com>
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
@@ -19,12 +20,15 @@ Aleksandar Dezelin <dezelin@gmail.com>
Alex A Skinner <alex@lx.lc>
Alex Brainman <alex.brainman@gmail.com>
Alex Jin <toalexjin@gmail.com>
+Alexander Larsson <alexander.larsson@gmail.com>
Alexander Orlov <alexander.orlov@loxal.net>
Alexander Reece <awreece@gmail.com>
Alexander Surma <surma@surmair.de>
+Alexander Zhavnerchik <alex.vizor@gmail.com>
Alexandre Normand <alexandre.normand@gmail.com>
Alexei Sholik <alcosholik@gmail.com>
Alexey Borzenkov <snaury@gmail.com>
+Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
Andrei Vieru <euvieru@gmail.com>
@@ -35,16 +39,21 @@ Andrew Lutomirski <andy@luto.us>
Andrew Pritchard <awpritchard@gmail.com>
Andrew Radev <andrey.radev@gmail.com>
Andrew Skiba <skibaa@gmail.com>
+Andrew Szeto <andrew@jabagawee.com>
Andrew Wilkins <axwalk@gmail.com>
Andrey Mirtchovski <mirtchovski@gmail.com>
Andriy Lytvynov <lytvynov.a.v@gmail.com>
Andy Davis <andy@bigandian.com>
+Anfernee Yongkun Gui <anfernee.gui@gmail.com>
Anh Hai Trinh <anh.hai.trinh@gmail.com>
Anschel Schaffer-Cohen <anschelsc@gmail.com>
Anthony Eufemio <anthony.eufemio@gmail.com>
Anthony Martin <ality@pbrane.org>
Anthony Starks <ajstarks@gmail.com>
+Apisak Darakananda <pongad@gmail.com>
+Aram Hăvărneanu <aram@mgk.ro>
Arnaud Ysmal <arnaud.ysmal@gmail.com>
+Arne Hormann <arnehormann@gmail.com>
Aron Nopanen <aron.nopanen@gmail.com>
Arvindh Rajesh Tamilmani <art@a-30.net>
Ato Araki <ato.araki@gmail.com>
@@ -53,18 +62,23 @@ Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us>
Benny Siegert <bsiegert@gmail.com>
Berengar Lehr <berengar.lehr@gmx.de>
+Billie Harold Cleek <bhcleek@gmail.com>
Bjorn Tillenius <bjorn@tillenius.me>
Bjorn Tipling <bjorn.tipling@gmail.com>
Blake Mizerany <blake.mizerany@gmail.com>
Bobby Powers <bobbypowers@gmail.com>
+Brendan Daniel Tracey <tracey.brendan@gmail.com>
Brian Dellisanti <briandellisanti@gmail.com>
Brian G. Merrell <bgmerrell@gmail.com>
Brian Gitonga Marete <marete@toshnix.com>
Brian Ketelsen <bketelsen@gmail.com>
Caine Tighe <arctanofyourface@gmail.com>
Caleb Spare <cespare@gmail.com>
+Carl Chatfield <carlchatfield@gmail.com>
Carlos Castillo <cookieo9@gmail.com>
+Case Nelson <case.nelson@gmail.com>
Casey Marshall <casey.marshall@gmail.com>
+Cezar Sá Espinola <cezarsa@gmail.com>
ChaiShushan <chaishushan@gmail.com>
Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com>
@@ -75,6 +89,7 @@ Chris Jones <chris@cjones.org>
Chris Lennert <calennert@gmail.com>
Christian Himpel <chressie@googlemail.com>
Christine Hansmann <chhansmann@gmail.com>
+Christoffer Buchholz <christoffer.buchholz@gmail.com>
Christoph Hack <christoph@tux21b.org>
Christopher Cahoon <chris.cahoon@gmail.com>
Christopher Nielsen <m4dh4tt3r@gmail.com>
@@ -89,19 +104,25 @@ Dan Peterson <dpiddy@gmail.com>
Dan Sinclair <dan.sinclair@gmail.com>
Daniel Fleischman <danielfleischman@gmail.com>
Daniel Krech <eikeon@eikeon.com>
+Daniel Lidén <daniel.liden.87@gmail.com>
Daniel Morsing <daniel.morsing@gmail.com>
Daniel Theophanes <kardianos@gmail.com>
Darren Elwood <darren@textnode.com>
Dave Cheney <dave@cheney.net>
David Bürgin <676c7473@gmail.com>
+David Calavera <david.calavera@gmail.com>
David du Colombier <0intro@gmail.com>
David Forsythe <dforsythe@gmail.com>
David G. Andersen <dave.andersen@gmail.com>
David Jakob Fritz <david.jakob.fritz@gmail.com>
+David Thomas <davidthomas426@gmail.com>
David Titarenco <david.titarenco@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
+Denis Brandolini <denis.brandolini@gmail.com>
Devon H. O'Dell <devon.odell@gmail.com>
+Dhiru Kholia <dhiru.kholia@gmail.com>
Dimitri Tcaciuc <dtcaciuc@gmail.com>
+Dmitri Shuralyov <shurcooL@gmail.com>
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
Dmitry Chestnykh <dchest@gmail.com>
Dominik Honnef <dominik.honnef@gmail.com>
@@ -121,36 +142,46 @@ Eric Clark <zerohp@gmail.com>
Eric Milliken <emilliken@gmail.com>
Eric Roshan-Eisner <eric.d.eisner@gmail.com>
Erik St. Martin <alakriti@gmail.com>
+Erik Westrup <erik.westrup@gmail.com>
Esko Luontola <esko.luontola@gmail.com>
Evan Shaw <chickencha@gmail.com>
Ewan Chou <coocood@gmail.com>
+Fabrizio Milo <mistobaan@gmail.com>
Fan Hongjian <fan.howard@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
+Felix Geisendörfer <haimuiba@gmail.com>
Firmansyah Adiputra <frm.adiputra@gmail.com>
Florian Uekermann <florian@uekermann-online.de>
Florian Weimer <fw@deneb.enyo.de>
Francisco Souza <franciscossouza@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com>
+Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Gary Burd <gary@beagledreams.com>
+Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com>
Gerasimos Dimitriadis <gedimitr@gmail.com>
Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
Giles Lean <giles.lean@pobox.com>
Google Inc.
+Gordon Klaus <gordon.klaus@gmail.com>
+Graham King <graham4king@gmail.com>
Graham Miller <graham.miller@gmail.com>
Greg Ward <greg@gerg.ca>
+Guillaume J. Charmes <guillaume@charmes.net>
Gustav Paul <gustav.paul@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net>
Gwenael Treguier <gwenn.kahz@gmail.com>
Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
+Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
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>
+Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
James David Chalfant <james.chalfant@gmail.com>
James Fysh <james.fysh@gmail.com>
James Gray <james@james4k.com>
@@ -165,7 +196,9 @@ Jan Newmarch <jan.newmarch@gmail.com>
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
Jani Monoses <jani.monoses@ubuntu.com>
Jaroslavas Počepko <jp@webmaster.ms>
+Jason Del Ponte <delpontej@gmail.com>
Jason Travis <infomaniac7@gmail.com>
+Jay Weisskopf <jay@jayschwa.net>
Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org>
Jeff Sickel <jas@corpus-callosum.com>
@@ -177,6 +210,7 @@ Jingcheng Zhang <diogin@gmail.com>
Joakim Sernbrant <serbaut@gmail.com>
Joe Poirier <jdpoirier@gmail.com>
John Asmuth <jasmuth@gmail.com>
+John C Barstow <jbowtie@amathaine.com>
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
John Shahid <jvshahid@gmail.com>
@@ -190,6 +224,7 @@ Joseph Holsten <joseph@josephholsten.com>
Josh Bleecher Snyder <josharian@gmail.com>
Josh Goebel <dreamer3@gmail.com>
Josh Holland <jrh@joshh.co.uk>
+Joshua Chase <jcjoshuachase@gmail.com>
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
Julian Phillips <julian@quantumfyre.co.uk>
Julien Schmidt <google@julienschmidt.com>
@@ -198,55 +233,75 @@ Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
Katrina Owen <katrina.owen@gmail.com>
Kei Son <hey.calmdown@gmail.com>
Keith Rarick <kr@xph.us>
+Kelsey Hightower <kelsey.hightower@gmail.com>
+Kelvin Foo Chuan Lyi <vmirage@gmail.com>
Ken Friedenbach <kenliz@cruzio.com>
Ken Rockot <ken@oz.gs>
Kevin Ballard <kevin@sb.org>
Kyle Consalus <consalus@gmail.com>
+Kyle Isom <kyle@gokyle.net>
Kyle Lemons <kyle@kylelemons.net>
L Campbell <unpantsu@gmail.com>
Lai Jiangshan <eag0628@gmail.com>
+Linaro Limited
Lorenzo Stoakes <lstoakes@gmail.com>
Luca Greco <luca.greco@alcacoop.it>
Lucio De Re <lucio.dere@gmail.com>
Luit van Drongelen <luitvd@gmail.com>
+Luka Zakrajšek <tr00.g33k@gmail.com>
+Luke Curley <qpingu@gmail.com>
+Marc Weistroff <marc@weistroff.net>
Marco Hennings <marco.hennings@freiheit.com>
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
+Marko Tiikkaja <marko@joh.to>
Markus Duft <markus.duft@salomon.at>
Markus Sonderegger <marraison@gmail.com>
+Markus Zimmermann <zimmski@gmail.com>
Martin Neubauer <m.ne@gmx.net>
+Martin Olsson <martin@minimum.se>
Mateusz Czapliński <czapkofan@gmail.com>
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Mats Lidell <mats.lidell@cag.se>
+Matt Aimonetti <mattaimonetti@gmail.com>
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>
+Maxim Khitrov <max@mxcrypt.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Chaten <mchaten@gmail.com>
Michael Elkins <michael.elkins@gmail.com>
-Michael Gehring <mg@ebfe.org>
+Michael Fraenkel <michael.fraenkel@gmail.com>
+Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
Michael Hoisie <hoisie@gmail.com>
Michael Lewis <mikelikespie@gmail.com>
+Michael Pearson <mipearson@gmail.com>
Michael Stapelberg <michael@stapelberg.de>
Michael Teichgräber <mteichgraeber@gmx.de>
Michał Derkacz <ziutek@lnet.pl>
Miek Gieben <miek@miek.nl>
+Mihai Borobocea <MihaiBorobocea@gmail.com>
Mikael Tillenius <mikti42@gmail.com>
+Mike Andrews <mra@xoba.com>
Mike Rosset <mike.rosset@gmail.com>
+Mikhail Panchenko <m@mihasya.com>
Miki Tebeka <miki.tebeka@gmail.com>
Mikio Hara <mikioh.mikioh@gmail.com>
Mikkel Krautz <mikkel@krautz.dk>
Miquel Sabaté Solà <mikisabate@gmail.com>
+Moov Corporation
Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
ngmoco, LLC
+Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>
Nicholas Waples <nwaples@gmail.com>
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
+Nicolas Kaiser <nikai@nikai.net>
Nicolas Owens <mischief@offblast.org>
Nigel Kerr <nigel.kerr@gmail.com>
Noah Campbell <noahcampbell@gmail.com>
@@ -261,24 +316,32 @@ Pascal S. de Kloe <pascal@quies.net>
Patrick Crosby <patrick@stathat.com>
Patrick Gavlin <pgavlin@gmail.com>
Patrick Higgins <patrick.allen.higgins@gmail.com>
+Patrick Mézard <patrick@mezard.eu>
Patrick Mylund Nielsen <patrick@patrickmn.com>
Patrick Smith <pat42smith@gmail.com>
+Paul A Querna <paul.querna@gmail.com>
+Paul Hammond <paul@paulhammond.org>
Paul Lalonde <paul.a.lalonde@gmail.com>
Paul Sbarra <Sbarra.Paul@gmail.com>
Paul van Brouwershaven <paul@vanbrouwershaven.com>
+Pavel Zinovkin <pavel.zinovkin@gmail.com>
Petar Maymounkov <petarm@gmail.com>
Peter Armitage <peter.armitage@gmail.com>
Peter Froehlich <peter.hans.froehlich@gmail.com>
Peter Kleiweg <pkleiweg@xs4all.nl>
Peter Mundy <go.peter.90@gmail.com>
Péter Surányi <speter.go1@gmail.com>
+Péter Szilágyi <peterke@gmail.com>
Peter Waller <peter.waller@gmail.com>
Peter Williams <pwil3058@gmail.com>
Philip K. Warren <pkwarren@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk>
+Pietro Gagliardi <pietro10@mac.com>
+Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Raif S. Naffah <go@naffah-raif.name>
Rémy Oudompheng <oudomphe@phare.normalesup.org>
+Richard Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
Richard Musiol <mail@richard-musiol.de>
Rick Arnold <rickarnoldjr@gmail.com>
@@ -295,8 +358,10 @@ Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
+Rowan Worth <sqweek@gmail.com>
Ryan Hitchman <hitchmanr@gmail.com>
Ryan Slade <ryanslade@gmail.com>
+S.Çağlar Onur <caglar@10ur.org>
Sanjay Menakuru <balasanjay@gmail.com>
Scott Ferguson <scottwferg@gmail.com>
Scott Lawrence <bytbox@gmail.com>
@@ -311,12 +376,14 @@ Shenghou Ma <minux.ma@gmail.com>
Shivakumar GN <shivakumar.gn@gmail.com>
Sokolov Yura <funny.falcon@gmail.com>
Spring Mc <heresy.mc@gmail.com>
+StalkR <stalkr@stalkr.net>
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
Stéphane Travostino <stephane.travostino@gmail.com>
Stephen McQuay <stephen@mcquay.me>
Stephen Weinberg <stephen@q5comm.com>
Steve McCoy <mccoyst@gmail.com>
Steven Elliot Harris <seharris@gmail.com>
+Steven Hartland <steven.hartland@multiplay.co.uk>
Sven Almgren <sven@tras.se>
Szabolcs Nagy <nsz@port70.net>
Tad Glines <tad.glines@gmail.com>
@@ -328,6 +395,8 @@ Thomas Kappler <tkappler@gmail.com>
Timo Savola <timo.savola@gmail.com>
Tobias Columbus <tobias.columbus@gmail.com>
Tor Andersson <tor.andersson@gmail.com>
+Travis Cline <travis.cline@gmail.com>
+Tudor Golubenco <tudor.g@gmail.com>
Tw <tw19881113@gmail.com>
Tyler Bunnell <tylerbunnell@gmail.com>
Ugorji Nwoke <ugorji@gmail.com>
@@ -342,6 +411,7 @@ Volker Dobler <dr.volker.dobler@gmail.com>
Wei Guangjing <vcc.163@gmail.com>
Willem van der Schyff <willemvds@gmail.com>
William Josephson <wjosephson@gmail.com>
+William Orr <will@worrbase.com> <ay1244@gmail.com>
Xing Xing <mikespook@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
@@ -352,3 +422,4 @@ Yuusei Kuwana <kuwana@kumama.org>
Yuval Pavel Zholkover <paulzhol@gmail.com>
Ziad Hatahet <hatahet@gmail.com>
Zorion Arrizabalaga <zorionk@gmail.com>
+申习之 <bronze1man@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 4d4a73e72..372229848 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -37,6 +37,7 @@ Abhinav Gupta <abhinav.g90@gmail.com>
Adam Langley <agl@golang.org>
Adrian Nos <nos.adrian@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
+Adrien Bustany <adrien-xx-google@bustany.org>
Akshat Kumar <seed@mail.nanosouffle.net>
Alan Donovan <adonovan@google.com>
Albert Strasheim <fullung@gmail.com>
@@ -46,13 +47,16 @@ Alex A Skinner <alex@lx.lc>
Alex Brainman <alex.brainman@gmail.com>
Alex Bramley <abramley@google.com>
Alex Jin <toalexjin@gmail.com>
+Alexander Larsson <alexander.larsson@gmail.com>
Alexander Orlov <alexander.orlov@loxal.net>
Alexander Reece <awreece@gmail.com>
Alexander Surma <surma@surmair.de>
+Alexander Zhavnerchik <alex.vizor@gmail.com>
Alexandre Normand <alexandre.normand@gmail.com>
Alexandru Moșoi <brtzsnr@gmail.com>
Alexei Sholik <alcosholik@gmail.com>
Alexey Borzenkov <snaury@gmail.com>
+Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Alexis Imperial-Legrand <ail@google.com>
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
@@ -67,16 +71,21 @@ Andrew Lutomirski <andy@luto.us>
Andrew Pritchard <awpritchard@gmail.com>
Andrew Radev <andrey.radev@gmail.com>
Andrew Skiba <skibaa@gmail.com>
+Andrew Szeto <andrew@jabagawee.com>
Andrew Wilkins <axwalk@gmail.com>
Andrey Mirtchovski <mirtchovski@gmail.com>
Andriy Lytvynov <lytvynov.a.v@gmail.com>
Andy Davis <andy@bigandian.com>
+Anfernee Yongkun Gui <anfernee.gui@gmail.com>
Anh Hai Trinh <anh.hai.trinh@gmail.com>
Anschel Schaffer-Cohen <anschelsc@gmail.com>
Anthony Eufemio <anthony.eufemio@gmail.com>
Anthony Martin <ality@pbrane.org>
Anthony Starks <ajstarks@gmail.com>
+Apisak Darakananda <pongad@gmail.com>
+Aram Hăvărneanu <aram@mgk.ro>
Arnaud Ysmal <arnaud.ysmal@gmail.com>
+Arne Hormann <arnehormann@gmail.com>
Aron Nopanen <aron.nopanen@gmail.com>
Arvindh Rajesh Tamilmani <art@a-30.net>
Asim Shankar <asimshankar@gmail.com>
@@ -93,25 +102,32 @@ Benny Siegert <bsiegert@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de>
Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
Bill Thiede <couchmoney@gmail.com>
+Billie Harold Cleek <bhcleek@gmail.com>
Bjorn Tillenius <bjorn@tillenius.me>
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 Daniel Tracey <tracey.brendan@gmail.com>
Brendan O'Dea <bod@golang.org>
Brian Dellisanti <briandellisanti@gmail.com>
Brian G. Merrell <bgmerrell@gmail.com>
Brian Gitonga Marete <marete@toshnix.com>
Brian Ketelsen <bketelsen@gmail.com>
Brian Slesinsky <skybrian@google.com>
+Burcu Dogan <jbd@google.com>
Caine Tighe <arctanofyourface@gmail.com>
Caleb Spare <cespare@gmail.com>
+Carl Chatfield <carlchatfield@gmail.com>
Carl Mastrangelo <notcarl@google.com>
Carl Shapiro <cshapiro@google.com> <cshapiro@golang.org>
Carlos Castillo <cookieo9@gmail.com>
Cary Hull <chull@google.com>
+Case Nelson <case.nelson@gmail.com>
Casey Marshall <casey.marshall@gmail.com>
+Catalin Patulea <catalinp@google.com>
+Cezar Sá Espinola <cezarsa@gmail.com>
ChaiShushan <chaishushan@gmail.com>
Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com>
@@ -124,6 +140,7 @@ Chris Lennert <calennert@gmail.com>
Chris Manghane <cmang@golang.org>
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
Christine Hansmann <chhansmann@gmail.com>
+Christoffer Buchholz <christoffer.buchholz@gmail.com>
Christoph Hack <christoph@tux21b.org>
Christopher Cahoon <chris.cahoon@gmail.com>
Christopher Nielsen <m4dh4tt3r@gmail.com>
@@ -141,6 +158,7 @@ Dan Peterson <dpiddy@gmail.com>
Dan Sinclair <dan.sinclair@gmail.com>
Daniel Fleischman <danielfleischman@gmail.com>
Daniel Krech <eikeon@eikeon.com>
+Daniel Lidén <daniel.liden.87@gmail.com>
Daniel Morsing <daniel.morsing@gmail.com>
Daniel Nadasi <dnadasi@google.com>
Daniel Theophanes <kardianos@gmail.com>
@@ -150,8 +168,11 @@ Dave Cheney <dave@cheney.net>
Dave Day <djd@golang.org>
Dave Grijalva <dgrijalva@ngmoco.com>
David Anderson <danderson@google.com>
+David Barnett <dbarnett@google.com>
David Bürgin <676c7473@gmail.com>
-David Crawshaw <david.crawshaw@zentus.com> <crawshaw@google.com>
+David Calavera <david.calavera@gmail.com>
+David Covert <davidhcovert@gmail.com>
+David Crawshaw <david.crawshaw@zentus.com> <crawshaw@google.com> <crawshaw@golang.org>
David du Colombier <0intro@gmail.com>
David Forsythe <dforsythe@gmail.com>
David G. Andersen <dave.andersen@gmail.com>
@@ -159,10 +180,14 @@ David Jakob Fritz <david.jakob.fritz@gmail.com>
David McLeish <davemc@google.com>
David Presotto <presotto@gmail.com>
David Symonds <dsymonds@golang.org>
+David Thomas <davidthomas426@gmail.com>
David Titarenco <david.titarenco@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
+Denis Brandolini <denis.brandolini@gmail.com>
Devon H. O'Dell <devon.odell@gmail.com>
+Dhiru Kholia <dhiru.kholia@gmail.com>
Dimitri Tcaciuc <dtcaciuc@gmail.com>
+Dmitri Shuralyov <shurcooL@gmail.com>
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
Dmitriy Vyukov <dvyukov@google.com>
Dmitry Chestnykh <dchest@gmail.com>
@@ -183,12 +208,15 @@ Eric Clark <zerohp@gmail.com>
Eric Milliken <emilliken@gmail.com>
Eric Roshan-Eisner <eric.d.eisner@gmail.com>
Erik St. Martin <alakriti@gmail.com>
+Erik Westrup <erik.westrup@gmail.com>
Esko Luontola <esko.luontola@gmail.com>
Evan Martin <evan.martin@gmail.com>
Evan Shaw <chickencha@gmail.com>
Ewan Chou <coocood@gmail.com>
+Fabrizio Milo <mistobaan@gmail.com>
Fan Hongjian <fan.howard@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
+Felix Geisendörfer <haimuiba@gmail.com>
Firmansyah Adiputra <frm.adiputra@gmail.com>
Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
Florian Weimer <fw@deneb.enyo.de>
@@ -196,16 +224,21 @@ Folke Behrens <folke@google.com>
Francesc Campoy <campoy@golang.org>
Francisco Souza <franciscossouza@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com>
+Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Fumitoshi Ukai <ukai@google.com>
Gaal Yahas <gaal@google.com>
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
+Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com>
Gerasimos Dimitriadis <gedimitr@gmail.com>
Gideon Jan-Wessel Redelinghuys <gjredelinghuys@gmail.com>
Giles Lean <giles.lean@pobox.com>
+Gordon Klaus <gordon.klaus@gmail.com>
+Graham King <graham4king@gmail.com>
Graham Miller <graham.miller@gmail.com>
Greg Ward <greg@gerg.ca>
+Guillaume J. Charmes <guillaume@charmes.net>
Gustav Paul <gustav.paul@gmail.com>
Gustavo Franco <gustavorfranco@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
@@ -213,6 +246,7 @@ Gwenael Treguier <gwenn.kahz@gmail.com>
Han-Wen Nienhuys <hanwen@google.com>
Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
+Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com>
Hossein Sheikh Attar <hattar@google.com>
@@ -223,6 +257,7 @@ Isaac Wagner <ibw@isaacwagner.me>
Ivan Krasin <krasin@golang.org>
Jacob Baskin <jbaskin@google.com>
Jakob Borg <jakob@nym.se>
+Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
James Aguilar <jaguilar@google.com>
James David Chalfant <james.chalfant@gmail.com>
James Fysh <james.fysh@gmail.com>
@@ -242,7 +277,9 @@ Jan Newmarch <jan.newmarch@gmail.com>
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
Jaroslavas Počepko <jp@webmaster.ms>
+Jason Del Ponte <delpontej@gmail.com>
Jason Travis <infomaniac7@gmail.com>
+Jay Weisskopf <jay@jayschwa.net>
Jean-Marc Eurin <jmeurin@google.com>
Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
@@ -260,9 +297,11 @@ Joel Sing <jsing@google.com>
Johan Euphrosine <proppy@google.com>
John Asmuth <jasmuth@gmail.com>
John Beisley <huin@google.com>
+John C Barstow <jbowtie@amathaine.com>
John DeNero <denero@google.com>
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
+John Newlin <jnewlin@google.com>
John Shahid <jvshahid@gmail.com>
Jonathan Allie <jonallie@google.com>
Jonathan Feinberg <feinberg@google.com>
@@ -282,6 +321,7 @@ Josh Bleecher Snyder <josharian@gmail.com>
Josh Goebel <dreamer3@gmail.com>
Josh Hoak <jhoak@google.com>
Josh Holland <jrh@joshh.co.uk>
+Joshua Chase <jcjoshuachase@gmail.com>
JP Sugarbroad <jpsugar@google.com>
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
Julian Phillips <julian@quantumfyre.co.uk>
@@ -289,9 +329,12 @@ Julien Schmidt <google@julienschmidt.com>
Kai Backman <kaib@golang.org>
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
Katrina Owen <katrina.owen@gmail.com>
+Kay Zhu <kayzhu@google.com>
Kei Son <hey.calmdown@gmail.com>
Keith Randall <khr@golang.org>
Keith Rarick <kr@xph.us>
+Kelsey Hightower <kelsey.hightower@gmail.com>
+Kelvin Foo Chuan Lyi <vmirage@gmail.com>
Ken Friedenbach <kenliz@cruzio.com>
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
Ken Thompson <ken@golang.org>
@@ -299,6 +342,7 @@ Kevin Ballard <kevin@sb.org>
Kevin Klues <klueska@gmail.com> <klueska@google.com>
Kirklin McDonald <kirklin.mcdonald@gmail.com>
Kyle Consalus <consalus@gmail.com>
+Kyle Isom <kyle@gokyle.net>
Kyle Lemons <kyle@kylelemons.net> <kevlar@google.com>
L Campbell <unpantsu@gmail.com>
Lai Jiangshan <eag0628@gmail.com>
@@ -308,19 +352,27 @@ Louis Kruger <louisk@google.com>
Luca Greco <luca.greco@alcacoop.it>
Lucio De Re <lucio.dere@gmail.com>
Luit van Drongelen <luitvd@gmail.com>
+Luka Zakrajšek <tr00.g33k@gmail.com>
+Luke Curley <qpingu@gmail.com>
Luuk van Dijk <lvd@golang.org> <lvd@google.com>
+Manoj Dayaram <platform-dev@moovweb.com> <manoj.dayaram@moovweb.com>
Manu Garg <manugarg@google.com>
+Marc Weistroff <marc@weistroff.net>
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>
+Marko Tiikkaja <marko@joh.to>
Markus Duft <markus.duft@salomon.at>
Markus Sonderegger <marraison@gmail.com>
+Markus Zimmermann <zimmski@gmail.com>
Martin Neubauer <m.ne@gmx.net>
+Martin Olsson <martin@minimum.se>
Mateusz Czapliński <czapkofan@gmail.com>
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
+Matt Aimonetti <mattaimonetti@gmail.com>
Matt Brown <mdbrown@google.com>
Matt Jibson <matt.jibson@gmail.com>
Matt Joiner <anacrolix@gmail.com>
@@ -329,15 +381,20 @@ Matt Reiferson <mreiferson@gmail.com>
Matthew Cottingham <mattcottingham@gmail.com>
Matthew Dempsky <mdempsky@google.com>
Matthew Horsnell <matthew.horsnell@gmail.com>
+Maxim Khitrov <max@mxcrypt.com>
Maxim Pimenov <mpimenov@google.com>
Maxim Ushakov <ushakov@google.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Chaten <mchaten@gmail.com>
Michael Elkins <michael.elkins@gmail.com>
-Michael Gehring <mg@ebfe.org>
+Michael Fraenkel <michael.fraenkel@gmail.com>
+Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
Michael Hoisie <hoisie@gmail.com>
+Michael Hudson-Doyle <michael.hudson@linaro.org>
+Michael Kelly <mjk@google.com>
Michael Lewis <mikelikespie@gmail.com>
Michael Matloob <matloob@google.com>
+Michael Pearson <mipearson@gmail.com>
Michael Piatek <piatek@google.com>
Michael Shields <mshields@google.com>
Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
@@ -345,10 +402,13 @@ Michael T. Jones <mtj@google.com> <michael.jones@gmail.com>
Michael Teichgräber <mteichgraeber@gmx.de> <mt4swm@googlemail.com>
Michał Derkacz <ziutek@lnet.pl>
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
+Mihai Borobocea <MihaiBorobocea@gmail.com>
Mikael Tillenius <mikti42@gmail.com>
+Mike Andrews <mra@xoba.com>
Mike Rosset <mike.rosset@gmail.com>
Mike Samuel <mikesamuel@gmail.com>
Mike Solomon <msolo@gmail.com>
+Mikhail Panchenko <m@mihasya.com>
Miki Tebeka <miki.tebeka@gmail.com>
Mikio Hara <mikioh.mikioh@gmail.com>
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
@@ -357,10 +417,12 @@ Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
+Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>
Nicholas Waples <nwaples@gmail.com>
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
+Nicolas Kaiser <nikai@nikai.net>
Nicolas Owens <mischief@offblast.org>
Nigel Kerr <nigel.kerr@gmail.com>
Nigel Tao <nigeltao@golang.org>
@@ -376,32 +438,42 @@ Pascal S. de Kloe <pascal@quies.net>
Patrick Crosby <patrick@stathat.com>
Patrick Gavlin <pgavlin@gmail.com>
Patrick Higgins <patrick.allen.higgins@gmail.com>
+Patrick Mézard <patrick@mezard.eu>
Patrick Mylund Nielsen <patrick@patrickmn.com>
+Patrick Riley <pfr@google.com>
Patrick Smith <pat42smith@gmail.com>
+Paul A Querna <paul.querna@gmail.com>
Paul Borman <borman@google.com>
Paul Chang <paulchang@google.com>
+Paul Hammond <paul@paulhammond.org>
Paul Lalonde <paul.a.lalonde@gmail.com>
Paul Sbarra <Sbarra.Paul@gmail.com>
Paul van Brouwershaven <paul@vanbrouwershaven.com>
+Pavel Zinovkin <pavel.zinovkin@gmail.com>
Pawel Szczur <filemon@google.com>
Petar Maymounkov <petarm@gmail.com>
Peter Armitage <peter.armitage@gmail.com>
+Peter Collingbourne <pcc@google.com>
Peter Froehlich <peter.hans.froehlich@gmail.com>
Peter Kleiweg <pkleiweg@xs4all.nl>
Peter McKenzie <petermck@google.com>
Peter Mundy <go.peter.90@gmail.com>
Péter Surányi <speter.go1@gmail.com>
Péter Szabó <pts@google.com>
+Péter Szilágyi <peterke@gmail.com>
Peter Waller <peter.waller@gmail.com>
Peter Weinberger <pjw@golang.org>
Peter Williams <pwil3058@gmail.com>
Phil Pennock <pdp@golang.org>
Philip K. Warren <pkwarren@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk>
+Pietro Gagliardi <pietro10@mac.com>
+Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Raif S. Naffah <go@naffah-raif.name>
Raph Levien <raph@google.com>
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
+Richard Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
Rick Arnold <rickarnoldjr@gmail.com>
@@ -413,6 +485,7 @@ Robert Figueiredo <robfig@gmail.com>
Robert Griesemer <gri@golang.org>
Robert Hencke <robert.hencke@gmail.com>
Robert Obryk <robryk@gmail.com>
+Robert Sesek <rsesek@google.com>
Robert Snedegar <roberts@google.com>
Robin Eklind <r.eklind.87@gmail.com>
Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
@@ -421,16 +494,20 @@ Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
+Rowan Worth <sqweek@gmail.com>
+Rui Ueyama <ruiu@google.com>
Russ Cox <rsc@golang.org>
Ryan Barrett <ryanb@google.com>
Ryan Hitchman <hitchmanr@gmail.com>
Ryan Slade <ryanslade@gmail.com>
+S.Çağlar Onur <caglar@10ur.org>
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
Sanjay Menakuru <balasanjay@gmail.com>
Scott Ferguson <scottwferg@gmail.com>
Scott Lawrence <bytbox@gmail.com>
Scott Schwartz <scotts@golang.org>
+Sean Burford <sburford@google.com>
Sebastien Binet <seb.binet@gmail.com>
Sébastien Paolacci <sebastien.paolacci@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru>
@@ -439,10 +516,11 @@ Sergio Luis O. B. Correia <sergio@correia.cc>
Shane Hansen <shanemhansen@gmail.com>
Shawn Ledbetter <sledbetter@google.com>
Shawn Smith <shawn.p.smith@gmail.com>
-Shenghou Ma <minux.ma@gmail.com>
+Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
Shivakumar GN <shivakumar.gn@gmail.com>
Sokolov Yura <funny.falcon@gmail.com>
Spring Mc <heresy.mc@gmail.com>
+StalkR <stalkr@stalkr.net>
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
Stéphane Travostino <stephane.travostino@gmail.com>
Stephen Ma <stephenm@golang.org>
@@ -450,6 +528,7 @@ Stephen McQuay <stephen@mcquay.me>
Stephen Weinberg <stephen@q5comm.com>
Steve McCoy <mccoyst@gmail.com>
Steven Elliot Harris <seharris@gmail.com>
+Steven Hartland <steven.hartland@multiplay.co.uk>
Sugu Sougoumarane <ssougou@gmail.com>
Sven Almgren <sven@tras.se>
Szabolcs Nagy <nsz@port70.net>
@@ -465,7 +544,9 @@ Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
Todd Wang <toddwang@gmail.com>
Tom Szymanski <tgs@google.com>
Tor Andersson <tor.andersson@gmail.com>
+Travis Cline <travis.cline@gmail.com>
Trevor Strohman <trevor.strohman@gmail.com>
+Tudor Golubenco <tudor.g@gmail.com>
Tw <tw19881113@gmail.com>
Tyler Bunnell <tylerbunnell@gmail.com>
Ugorji Nwoke <ugorji@gmail.com>
@@ -484,7 +565,9 @@ Will Norris <willnorris@google.com>
Willem van der Schyff <willemvds@gmail.com>
William Chan <willchan@chromium.org>
William Josephson <wjosephson@gmail.com>
+William Orr <will@worrbase.com> <ay1244@gmail.com>
Xing Xing <mikespook@gmail.com>
+Yan Zou <yzou@google.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yissakhar Z. Beck <yissakhar.beck@gmail.com>
Yongjian Xu <i3dmaster@gmail.com>
@@ -495,3 +578,4 @@ Yuval Pavel Zholkover <paulzhol@gmail.com>
Yves Junqueira <yves.junqueira@gmail.com>
Ziad Hatahet <hatahet@gmail.com>
Zorion Arrizabalaga <zorionk@gmail.com>
+申习之 <bronze1man@gmail.com>
diff --git a/VERSION b/VERSION
index 39dbf6463..9c3a7a187 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.2.1 \ No newline at end of file
+go1.3 \ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 92a52789d..1a8296635 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -5,6 +5,10 @@ pkg syscall (darwin-amd64), func Fchflags(string, int) error
pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error
pkg syscall (freebsd-386), func Fchflags(string, int) error
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
+pkg syscall (freebsd-arm), func Fchflags(string, int) error
+pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
+pkg syscall (netbsd-arm), func Fchflags(string, int) error
+pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
pkg testing, func RegisterCover(Cover)
pkg text/template/parse, type DotNode bool
pkg text/template/parse, type Node interface { Copy, String, Type }
@@ -14,3 +18,312 @@ pkg syscall (darwin-386), const ImplementsGetwd = false
pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
pkg syscall (darwin-amd64), const ImplementsGetwd = false
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
+pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074283118
+pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148024941
+pkg syscall (openbsd-386), const RTF_FMASK = 63496
+pkg syscall (openbsd-386), const RTM_VERSION = 4
+pkg syscall (openbsd-386), const SIOCBRDGDADDR = 2150132039
+pkg syscall (openbsd-386), const SIOCBRDGGPARAM = 3224922456
+pkg syscall (openbsd-386), const SIOCBRDGSADDR = 3223873860
+pkg syscall (openbsd-386), const SYS_CLOCK_GETRES = 234
+pkg syscall (openbsd-386), const SYS_CLOCK_GETTIME = 232
+pkg syscall (openbsd-386), const SYS_CLOCK_SETTIME = 233
+pkg syscall (openbsd-386), const SYS_FHSTATFS = 309
+pkg syscall (openbsd-386), const SYS_FSTAT = 292
+pkg syscall (openbsd-386), const SYS_FSTATAT = 316
+pkg syscall (openbsd-386), const SYS_FSTATFS = 308
+pkg syscall (openbsd-386), const SYS_FUTIMENS = 327
+pkg syscall (openbsd-386), const SYS_FUTIMES = 206
+pkg syscall (openbsd-386), const SYS_GETDIRENTRIES = 312
+pkg syscall (openbsd-386), const SYS_GETDIRENTRIES ideal-int
+pkg syscall (openbsd-386), const SYS_GETFSSTAT = 306
+pkg syscall (openbsd-386), const SYS_GETITIMER = 86
+pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117
+pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
+pkg syscall (openbsd-386), const SYS_KEVENT = 270
+pkg syscall (openbsd-386), const SYS_LSTAT = 293
+pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
+pkg syscall (openbsd-386), const SYS_SELECT = 93
+pkg syscall (openbsd-386), const SYS_SETITIMER = 83
+pkg syscall (openbsd-386), const SYS_SETTIMEOFDAY = 122
+pkg syscall (openbsd-386), const SYS_STAT = 291
+pkg syscall (openbsd-386), const SYS_STATFS = 307
+pkg syscall (openbsd-386), const SYS_UTIMENSAT = 326
+pkg syscall (openbsd-386), const SYS_UTIMES = 138
+pkg syscall (openbsd-386), const SYS_WAIT4 = 7
+pkg syscall (openbsd-386), const SYS___THRSLEEP = 300
+pkg syscall (openbsd-386), const SizeofIfData = 208
+pkg syscall (openbsd-386), const SizeofIfMsghdr = 232
+pkg syscall (openbsd-386), const SizeofRtMetrics = 48
+pkg syscall (openbsd-386), const SizeofRtMsghdr = 88
+pkg syscall (openbsd-386), const TIOCGTSTAMP = 1074295899
+pkg syscall (openbsd-386), type Dirent struct, Fileno uint32
+pkg syscall (openbsd-386), type FdSet struct, Bits [32]int32
+pkg syscall (openbsd-386), type Kevent_t struct, Data int32
+pkg syscall (openbsd-386), type Mclpool struct, Grown uint32
+pkg syscall (openbsd-386), type RtMetrics struct, Expire uint32
+pkg syscall (openbsd-386), type Stat_t struct, Ino uint32
+pkg syscall (openbsd-386), type Stat_t struct, Lspare0 int32
+pkg syscall (openbsd-386), type Stat_t struct, Lspare1 int32
+pkg syscall (openbsd-386), type Stat_t struct, Qspare [2]int64
+pkg syscall (openbsd-386), type Statfs_t struct, F_ctime uint32
+pkg syscall (openbsd-386), type Statfs_t struct, F_spare [3]uint32
+pkg syscall (openbsd-386), type Timespec struct, Sec int32
+pkg syscall (openbsd-386), type Timeval struct, Sec int32
+pkg syscall (openbsd-386-cgo), const BIOCGRTIMEOUT = 1074283118
+pkg syscall (openbsd-386-cgo), const BIOCSRTIMEOUT = 2148024941
+pkg syscall (openbsd-386-cgo), const RTF_FMASK = 63496
+pkg syscall (openbsd-386-cgo), const RTM_VERSION = 4
+pkg syscall (openbsd-386-cgo), const SIOCBRDGDADDR = 2150132039
+pkg syscall (openbsd-386-cgo), const SIOCBRDGGPARAM = 3224922456
+pkg syscall (openbsd-386-cgo), const SIOCBRDGSADDR = 3223873860
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETRES = 234
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETTIME = 232
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_SETTIME = 233
+pkg syscall (openbsd-386-cgo), const SYS_FHSTATFS = 309
+pkg syscall (openbsd-386-cgo), const SYS_FSTAT = 292
+pkg syscall (openbsd-386-cgo), const SYS_FSTATAT = 316
+pkg syscall (openbsd-386-cgo), const SYS_FSTATFS = 308
+pkg syscall (openbsd-386-cgo), const SYS_FUTIMENS = 327
+pkg syscall (openbsd-386-cgo), const SYS_FUTIMES = 206
+pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES = 312
+pkg syscall (openbsd-386-cgo), const SYS_GETDIRENTRIES ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_GETFSSTAT = 306
+pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86
+pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117
+pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116
+pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270
+pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293
+pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
+pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93
+pkg syscall (openbsd-386-cgo), const SYS_SETITIMER = 83
+pkg syscall (openbsd-386-cgo), const SYS_SETTIMEOFDAY = 122
+pkg syscall (openbsd-386-cgo), const SYS_STAT = 291
+pkg syscall (openbsd-386-cgo), const SYS_STATFS = 307
+pkg syscall (openbsd-386-cgo), const SYS_UTIMENSAT = 326
+pkg syscall (openbsd-386-cgo), const SYS_UTIMES = 138
+pkg syscall (openbsd-386-cgo), const SYS_WAIT4 = 7
+pkg syscall (openbsd-386-cgo), const SYS___THRSLEEP = 300
+pkg syscall (openbsd-386-cgo), const SizeofIfData = 208
+pkg syscall (openbsd-386-cgo), const SizeofIfMsghdr = 232
+pkg syscall (openbsd-386-cgo), const SizeofRtMetrics = 48
+pkg syscall (openbsd-386-cgo), const SizeofRtMsghdr = 88
+pkg syscall (openbsd-386-cgo), const TIOCGTSTAMP = 1074295899
+pkg syscall (openbsd-386-cgo), type Dirent struct, Fileno uint32
+pkg syscall (openbsd-386-cgo), type FdSet struct, Bits [32]int32
+pkg syscall (openbsd-386-cgo), type Kevent_t struct, Data int32
+pkg syscall (openbsd-386-cgo), type Mclpool struct, Grown uint32
+pkg syscall (openbsd-386-cgo), type RtMetrics struct, Expire uint32
+pkg syscall (openbsd-386-cgo), type Stat_t struct, Ino uint32
+pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare0 int32
+pkg syscall (openbsd-386-cgo), type Stat_t struct, Lspare1 int32
+pkg syscall (openbsd-386-cgo), type Stat_t struct, Qspare [2]int64
+pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_ctime uint32
+pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_spare [3]uint32
+pkg syscall (openbsd-386-cgo), type Timespec struct, Sec int32
+pkg syscall (openbsd-386-cgo), type Timeval struct, Sec int32
+pkg syscall (openbsd-amd64), const CCR0_FLUSH = 16
+pkg syscall (openbsd-amd64), const CCR0_FLUSH ideal-int
+pkg syscall (openbsd-amd64), const CPUID_CFLUSH = 524288
+pkg syscall (openbsd-amd64), const CPUID_CFLUSH ideal-int
+pkg syscall (openbsd-amd64), const EFER_LMA = 1024
+pkg syscall (openbsd-amd64), const EFER_LMA ideal-int
+pkg syscall (openbsd-amd64), const EFER_LME = 256
+pkg syscall (openbsd-amd64), const EFER_LME ideal-int
+pkg syscall (openbsd-amd64), const EFER_NXE = 2048
+pkg syscall (openbsd-amd64), const EFER_NXE ideal-int
+pkg syscall (openbsd-amd64), const EFER_SCE = 1
+pkg syscall (openbsd-amd64), const EFER_SCE ideal-int
+pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH = 21
+pkg syscall (openbsd-amd64), const PMC5_PIPELINE_FLUSH ideal-int
+pkg syscall (openbsd-amd64), const RTF_FMASK = 63496
+pkg syscall (openbsd-amd64), const RTM_VERSION = 4
+pkg syscall (openbsd-amd64), const SIOCBRDGDADDR = 2150132039
+pkg syscall (openbsd-amd64), const SIOCBRDGSADDR = 3223873860
+pkg syscall (openbsd-amd64), const SYS_CLOCK_GETRES = 234
+pkg syscall (openbsd-amd64), const SYS_CLOCK_GETTIME = 232
+pkg syscall (openbsd-amd64), const SYS_CLOCK_SETTIME = 233
+pkg syscall (openbsd-amd64), const SYS_FHSTATFS = 309
+pkg syscall (openbsd-amd64), const SYS_FSTAT = 292
+pkg syscall (openbsd-amd64), const SYS_FSTATAT = 316
+pkg syscall (openbsd-amd64), const SYS_FSTATFS = 308
+pkg syscall (openbsd-amd64), const SYS_FUTIMENS = 327
+pkg syscall (openbsd-amd64), const SYS_FUTIMES = 206
+pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES = 312
+pkg syscall (openbsd-amd64), const SYS_GETDIRENTRIES ideal-int
+pkg syscall (openbsd-amd64), const SYS_GETFSSTAT = 306
+pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86
+pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117
+pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
+pkg syscall (openbsd-amd64), const SYS_KEVENT = 270
+pkg syscall (openbsd-amd64), const SYS_LSTAT = 293
+pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
+pkg syscall (openbsd-amd64), const SYS_SELECT = 93
+pkg syscall (openbsd-amd64), const SYS_SETITIMER = 83
+pkg syscall (openbsd-amd64), const SYS_SETTIMEOFDAY = 122
+pkg syscall (openbsd-amd64), const SYS_STAT = 291
+pkg syscall (openbsd-amd64), const SYS_STATFS = 307
+pkg syscall (openbsd-amd64), const SYS_UTIMENSAT = 326
+pkg syscall (openbsd-amd64), const SYS_UTIMES = 138
+pkg syscall (openbsd-amd64), const SYS_WAIT4 = 7
+pkg syscall (openbsd-amd64), const SYS___THRSLEEP = 300
+pkg syscall (openbsd-amd64), const SizeofRtMetrics = 48
+pkg syscall (openbsd-amd64), const SizeofRtMsghdr = 88
+pkg syscall (openbsd-amd64), type Dirent struct, Fileno uint32
+pkg syscall (openbsd-amd64), type FdSet struct, Bits [32]int32
+pkg syscall (openbsd-amd64), type Kevent_t struct, Data int32
+pkg syscall (openbsd-amd64), type Kevent_t struct, Ident uint32
+pkg syscall (openbsd-amd64), type Mclpool struct, Grown uint32
+pkg syscall (openbsd-amd64), type RtMetrics struct, Expire uint32
+pkg syscall (openbsd-amd64), type Stat_t struct, Ino uint32
+pkg syscall (openbsd-amd64), type Stat_t struct, Lspare0 int32
+pkg syscall (openbsd-amd64), type Stat_t struct, Lspare1 int32
+pkg syscall (openbsd-amd64), type Stat_t struct, Qspare [2]int64
+pkg syscall (openbsd-amd64), type Statfs_t struct, F_ctime uint32
+pkg syscall (openbsd-amd64), type Statfs_t struct, F_spare [3]uint32
+pkg syscall (openbsd-amd64), type Statfs_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (openbsd-amd64), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (openbsd-amd64), type Timespec struct, Sec int32
+pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH = 16
+pkg syscall (openbsd-amd64-cgo), const CCR0_FLUSH ideal-int
+pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH = 524288
+pkg syscall (openbsd-amd64-cgo), const CPUID_CFLUSH ideal-int
+pkg syscall (openbsd-amd64-cgo), const EFER_LMA = 1024
+pkg syscall (openbsd-amd64-cgo), const EFER_LMA ideal-int
+pkg syscall (openbsd-amd64-cgo), const EFER_LME = 256
+pkg syscall (openbsd-amd64-cgo), const EFER_LME ideal-int
+pkg syscall (openbsd-amd64-cgo), const EFER_NXE = 2048
+pkg syscall (openbsd-amd64-cgo), const EFER_NXE ideal-int
+pkg syscall (openbsd-amd64-cgo), const EFER_SCE = 1
+pkg syscall (openbsd-amd64-cgo), const EFER_SCE ideal-int
+pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH = 21
+pkg syscall (openbsd-amd64-cgo), const PMC5_PIPELINE_FLUSH ideal-int
+pkg syscall (openbsd-amd64-cgo), const RTF_FMASK = 63496
+pkg syscall (openbsd-amd64-cgo), const RTM_VERSION = 4
+pkg syscall (openbsd-amd64-cgo), const SIOCBRDGDADDR = 2150132039
+pkg syscall (openbsd-amd64-cgo), const SIOCBRDGSADDR = 3223873860
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETRES = 234
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETTIME = 232
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_SETTIME = 233
+pkg syscall (openbsd-amd64-cgo), const SYS_FHSTATFS = 309
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTAT = 292
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTATAT = 316
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTATFS = 308
+pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMENS = 327
+pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMES = 206
+pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES = 312
+pkg syscall (openbsd-amd64-cgo), const SYS_GETDIRENTRIES ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_GETFSSTAT = 306
+pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86
+pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117
+pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116
+pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270
+pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293
+pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
+pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93
+pkg syscall (openbsd-amd64-cgo), const SYS_SETITIMER = 83
+pkg syscall (openbsd-amd64-cgo), const SYS_SETTIMEOFDAY = 122
+pkg syscall (openbsd-amd64-cgo), const SYS_STAT = 291
+pkg syscall (openbsd-amd64-cgo), const SYS_STATFS = 307
+pkg syscall (openbsd-amd64-cgo), const SYS_UTIMENSAT = 326
+pkg syscall (openbsd-amd64-cgo), const SYS_UTIMES = 138
+pkg syscall (openbsd-amd64-cgo), const SYS_WAIT4 = 7
+pkg syscall (openbsd-amd64-cgo), const SYS___THRSLEEP = 300
+pkg syscall (openbsd-amd64-cgo), const SizeofRtMetrics = 48
+pkg syscall (openbsd-amd64-cgo), const SizeofRtMsghdr = 88
+pkg syscall (openbsd-amd64-cgo), type Dirent struct, Fileno uint32
+pkg syscall (openbsd-amd64-cgo), type FdSet struct, Bits [32]int32
+pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Data int32
+pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Ident uint32
+pkg syscall (openbsd-amd64-cgo), type Mclpool struct, Grown uint32
+pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Expire uint32
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Ino uint32
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare0 int32
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Lspare1 int32
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Qspare [2]int64
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_ctime uint32
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
+pkg unicode, const Version = "6.2.0"
+pkg syscall (freebsd-386), const AF_MAX = 38
+pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-386), const ELAST = 94
+pkg syscall (freebsd-386), const O_CLOEXEC = 0
+pkg syscall (freebsd-386-cgo), const AF_MAX = 38
+pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-386-cgo), const ELAST = 94
+pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-amd64), const AF_MAX = 38
+pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-amd64), const ELAST = 94
+pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
+pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
+pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-amd64-cgo), const ELAST = 94
+pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm), const AF_MAX = 38
+pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (freebsd-arm), const ELAST = 94
+pkg syscall (freebsd-arm), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
+pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
+pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
+pkg syscall (freebsd-arm), const SizeofIfData = 88
+pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
+pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
+pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
+pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
+pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
+pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (freebsd-arm-cgo), const ELAST = 94
+pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
+pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
+pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
+pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
+pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
+pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
+pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm), const SizeofIfData = 132
+pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
+pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
+pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
diff --git a/api/go1.3.txt b/api/go1.3.txt
new file mode 100644
index 000000000..0474277c4
--- /dev/null
+++ b/api/go1.3.txt
@@ -0,0 +1,2053 @@
+pkg archive/tar, const TypeGNUSparse = 83
+pkg archive/tar, const TypeGNUSparse ideal-char
+pkg archive/tar, type Header struct, Xattrs map[string]string
+pkg compress/gzip, method (*Reader) Reset(io.Reader) error
+pkg crypto/tls, const CurveP256 = 23
+pkg crypto/tls, const CurveP256 CurveID
+pkg crypto/tls, const CurveP384 = 24
+pkg crypto/tls, const CurveP384 CurveID
+pkg crypto/tls, const CurveP521 = 25
+pkg crypto/tls, const CurveP521 CurveID
+pkg crypto/tls, func DialWithDialer(*net.Dialer, string, string, *Config) (*Conn, error)
+pkg crypto/tls, func NewLRUClientSessionCache(int) ClientSessionCache
+pkg crypto/tls, type ClientSessionCache interface { Get, Put }
+pkg crypto/tls, type ClientSessionCache interface, Get(string) (*ClientSessionState, bool)
+pkg crypto/tls, type ClientSessionCache interface, Put(string, *ClientSessionState)
+pkg crypto/tls, type ClientSessionState struct
+pkg crypto/tls, type Config struct, ClientSessionCache ClientSessionCache
+pkg crypto/tls, type Config struct, CurvePreferences []CurveID
+pkg crypto/tls, type ConnectionState struct, Version uint16
+pkg crypto/tls, type CurveID uint16
+pkg crypto/x509, func CreateCertificateRequest(io.Reader, *CertificateRequest, interface{}) ([]uint8, error)
+pkg crypto/x509, func ParseCertificateRequest([]uint8) (*CertificateRequest, error)
+pkg crypto/x509, type CertificateRequest struct
+pkg crypto/x509, type CertificateRequest struct, Attributes []pkix.AttributeTypeAndValueSET
+pkg crypto/x509, type CertificateRequest struct, DNSNames []string
+pkg crypto/x509, type CertificateRequest struct, EmailAddresses []string
+pkg crypto/x509, type CertificateRequest struct, Extensions []pkix.Extension
+pkg crypto/x509, type CertificateRequest struct, ExtraExtensions []pkix.Extension
+pkg crypto/x509, type CertificateRequest struct, IPAddresses []net.IP
+pkg crypto/x509, type CertificateRequest struct, PublicKey interface{}
+pkg crypto/x509, type CertificateRequest struct, PublicKeyAlgorithm PublicKeyAlgorithm
+pkg crypto/x509, type CertificateRequest struct, Raw []uint8
+pkg crypto/x509, type CertificateRequest struct, RawSubject []uint8
+pkg crypto/x509, type CertificateRequest struct, RawSubjectPublicKeyInfo []uint8
+pkg crypto/x509, type CertificateRequest struct, RawTBSCertificateRequest []uint8
+pkg crypto/x509, type CertificateRequest struct, Signature []uint8
+pkg crypto/x509, type CertificateRequest struct, SignatureAlgorithm SignatureAlgorithm
+pkg crypto/x509, type CertificateRequest struct, Subject pkix.Name
+pkg crypto/x509, type CertificateRequest struct, Version int
+pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct
+pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct, Type asn1.ObjectIdentifier
+pkg crypto/x509/pkix, type AttributeTypeAndValueSET struct, Value [][]AttributeTypeAndValue
+pkg debug/dwarf, const TagCondition = 63
+pkg debug/dwarf, const TagCondition Tag
+pkg debug/dwarf, const TagRvalueReferenceType = 66
+pkg debug/dwarf, const TagRvalueReferenceType Tag
+pkg debug/dwarf, const TagSharedType = 64
+pkg debug/dwarf, const TagSharedType Tag
+pkg debug/dwarf, const TagTemplateAlias = 67
+pkg debug/dwarf, const TagTemplateAlias Tag
+pkg debug/dwarf, const TagTypeUnit = 65
+pkg debug/dwarf, const TagTypeUnit Tag
+pkg debug/dwarf, method (*Data) AddTypes(string, []uint8) error
+pkg debug/macho, const CpuArm = 12
+pkg debug/macho, const CpuArm Cpu
+pkg debug/macho, const CpuPpc = 18
+pkg debug/macho, const CpuPpc Cpu
+pkg debug/macho, const CpuPpc64 = 16777234
+pkg debug/macho, const CpuPpc64 Cpu
+pkg debug/macho, const MagicFat = 3405691582
+pkg debug/macho, const MagicFat uint32
+pkg debug/macho, const TypeBundle = 8
+pkg debug/macho, const TypeBundle Type
+pkg debug/macho, const TypeDylib = 6
+pkg debug/macho, const TypeDylib Type
+pkg debug/macho, func NewFatFile(io.ReaderAt) (*FatFile, error)
+pkg debug/macho, func OpenFat(string) (*FatFile, error)
+pkg debug/macho, method (*FatFile) Close() error
+pkg debug/macho, method (FatArch) Close() error
+pkg debug/macho, method (FatArch) DWARF() (*dwarf.Data, error)
+pkg debug/macho, method (FatArch) ImportedLibraries() ([]string, error)
+pkg debug/macho, method (FatArch) ImportedSymbols() ([]string, error)
+pkg debug/macho, method (FatArch) Section(string) *Section
+pkg debug/macho, method (FatArch) Segment(string) *Segment
+pkg debug/macho, type FatArch struct
+pkg debug/macho, type FatArch struct, embedded *File
+pkg debug/macho, type FatArch struct, embedded FatArchHeader
+pkg debug/macho, type FatArchHeader struct
+pkg debug/macho, type FatArchHeader struct, Align uint32
+pkg debug/macho, type FatArchHeader struct, Cpu Cpu
+pkg debug/macho, type FatArchHeader struct, Offset uint32
+pkg debug/macho, type FatArchHeader struct, Size uint32
+pkg debug/macho, type FatArchHeader struct, SubCpu uint32
+pkg debug/macho, type FatFile struct
+pkg debug/macho, type FatFile struct, Arches []FatArch
+pkg debug/macho, type FatFile struct, Magic uint32
+pkg debug/macho, var ErrNotFat *FormatError
+pkg debug/pe, type DataDirectory struct
+pkg debug/pe, type DataDirectory struct, Size uint32
+pkg debug/pe, type DataDirectory struct, VirtualAddress uint32
+pkg debug/pe, type File struct, OptionalHeader interface{}
+pkg debug/pe, type OptionalHeader32 struct
+pkg debug/pe, type OptionalHeader32 struct, AddressOfEntryPoint uint32
+pkg debug/pe, type OptionalHeader32 struct, BaseOfCode uint32
+pkg debug/pe, type OptionalHeader32 struct, BaseOfData uint32
+pkg debug/pe, type OptionalHeader32 struct, CheckSum uint32
+pkg debug/pe, type OptionalHeader32 struct, DataDirectory [16]DataDirectory
+pkg debug/pe, type OptionalHeader32 struct, DllCharacteristics uint16
+pkg debug/pe, type OptionalHeader32 struct, FileAlignment uint32
+pkg debug/pe, type OptionalHeader32 struct, ImageBase uint32
+pkg debug/pe, type OptionalHeader32 struct, LoaderFlags uint32
+pkg debug/pe, type OptionalHeader32 struct, Magic uint16
+pkg debug/pe, type OptionalHeader32 struct, MajorImageVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, MajorLinkerVersion uint8
+pkg debug/pe, type OptionalHeader32 struct, MajorOperatingSystemVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, MajorSubsystemVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, MinorImageVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, MinorLinkerVersion uint8
+pkg debug/pe, type OptionalHeader32 struct, MinorOperatingSystemVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, MinorSubsystemVersion uint16
+pkg debug/pe, type OptionalHeader32 struct, NumberOfRvaAndSizes uint32
+pkg debug/pe, type OptionalHeader32 struct, SectionAlignment uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfCode uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfHeaders uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfHeapCommit uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfHeapReserve uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfImage uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfInitializedData uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfStackCommit uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfStackReserve uint32
+pkg debug/pe, type OptionalHeader32 struct, SizeOfUninitializedData uint32
+pkg debug/pe, type OptionalHeader32 struct, Subsystem uint16
+pkg debug/pe, type OptionalHeader32 struct, Win32VersionValue uint32
+pkg debug/pe, type OptionalHeader64 struct
+pkg debug/pe, type OptionalHeader64 struct, AddressOfEntryPoint uint32
+pkg debug/pe, type OptionalHeader64 struct, BaseOfCode uint32
+pkg debug/pe, type OptionalHeader64 struct, CheckSum uint32
+pkg debug/pe, type OptionalHeader64 struct, DataDirectory [16]DataDirectory
+pkg debug/pe, type OptionalHeader64 struct, DllCharacteristics uint16
+pkg debug/pe, type OptionalHeader64 struct, FileAlignment uint32
+pkg debug/pe, type OptionalHeader64 struct, ImageBase uint64
+pkg debug/pe, type OptionalHeader64 struct, LoaderFlags uint32
+pkg debug/pe, type OptionalHeader64 struct, Magic uint16
+pkg debug/pe, type OptionalHeader64 struct, MajorImageVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, MajorLinkerVersion uint8
+pkg debug/pe, type OptionalHeader64 struct, MajorOperatingSystemVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, MajorSubsystemVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, MinorImageVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, MinorLinkerVersion uint8
+pkg debug/pe, type OptionalHeader64 struct, MinorOperatingSystemVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, MinorSubsystemVersion uint16
+pkg debug/pe, type OptionalHeader64 struct, NumberOfRvaAndSizes uint32
+pkg debug/pe, type OptionalHeader64 struct, SectionAlignment uint32
+pkg debug/pe, type OptionalHeader64 struct, SizeOfCode uint32
+pkg debug/pe, type OptionalHeader64 struct, SizeOfHeaders uint32
+pkg debug/pe, type OptionalHeader64 struct, SizeOfHeapCommit uint64
+pkg debug/pe, type OptionalHeader64 struct, SizeOfHeapReserve uint64
+pkg debug/pe, type OptionalHeader64 struct, SizeOfImage uint32
+pkg debug/pe, type OptionalHeader64 struct, SizeOfInitializedData uint32
+pkg debug/pe, type OptionalHeader64 struct, SizeOfStackCommit uint64
+pkg debug/pe, type OptionalHeader64 struct, SizeOfStackReserve uint64
+pkg debug/pe, type OptionalHeader64 struct, SizeOfUninitializedData uint32
+pkg debug/pe, type OptionalHeader64 struct, Subsystem uint16
+pkg debug/pe, type OptionalHeader64 struct, Win32VersionValue uint32
+pkg debug/plan9obj, const Magic386 = 491
+pkg debug/plan9obj, const Magic386 ideal-int
+pkg debug/plan9obj, const Magic64 = 32768
+pkg debug/plan9obj, const Magic64 ideal-int
+pkg debug/plan9obj, const MagicAMD64 = 35479
+pkg debug/plan9obj, const MagicAMD64 ideal-int
+pkg debug/plan9obj, const MagicARM = 1607
+pkg debug/plan9obj, const MagicARM ideal-int
+pkg debug/plan9obj, func NewFile(io.ReaderAt) (*File, error)
+pkg debug/plan9obj, func Open(string) (*File, error)
+pkg debug/plan9obj, method (*File) Close() error
+pkg debug/plan9obj, method (*File) Section(string) *Section
+pkg debug/plan9obj, method (*File) Symbols() ([]Sym, error)
+pkg debug/plan9obj, method (*Section) Data() ([]uint8, error)
+pkg debug/plan9obj, method (*Section) Open() io.ReadSeeker
+pkg debug/plan9obj, method (Section) ReadAt([]uint8, int64) (int, error)
+pkg debug/plan9obj, type File struct
+pkg debug/plan9obj, type File struct, Sections []*Section
+pkg debug/plan9obj, type File struct, embedded FileHeader
+pkg debug/plan9obj, type FileHeader struct
+pkg debug/plan9obj, type FileHeader struct, Bss uint32
+pkg debug/plan9obj, type FileHeader struct, Entry uint64
+pkg debug/plan9obj, type FileHeader struct, Magic uint32
+pkg debug/plan9obj, type FileHeader struct, PtrSize int
+pkg debug/plan9obj, type Section struct
+pkg debug/plan9obj, type Section struct, embedded SectionHeader
+pkg debug/plan9obj, type Section struct, embedded io.ReaderAt
+pkg debug/plan9obj, type SectionHeader struct
+pkg debug/plan9obj, type SectionHeader struct, Name string
+pkg debug/plan9obj, type SectionHeader struct, Offset uint32
+pkg debug/plan9obj, type SectionHeader struct, Size uint32
+pkg debug/plan9obj, type Sym struct
+pkg debug/plan9obj, type Sym struct, Name string
+pkg debug/plan9obj, type Sym struct, Type int32
+pkg debug/plan9obj, type Sym struct, Value uint64
+pkg encoding/asn1, method (ObjectIdentifier) String() string
+pkg go/build, type Package struct, MFiles []string
+pkg math/big, method (*Int) MarshalText() ([]uint8, error)
+pkg math/big, method (*Int) UnmarshalText([]uint8) error
+pkg math/big, method (*Rat) MarshalText() ([]uint8, error)
+pkg math/big, method (*Rat) UnmarshalText([]uint8) error
+pkg net, type Dialer struct, KeepAlive time.Duration
+pkg net/http, const StateActive = 1
+pkg net/http, const StateActive ConnState
+pkg net/http, const StateClosed = 4
+pkg net/http, const StateClosed ConnState
+pkg net/http, const StateHijacked = 3
+pkg net/http, const StateHijacked ConnState
+pkg net/http, const StateIdle = 2
+pkg net/http, const StateIdle ConnState
+pkg net/http, const StateNew = 0
+pkg net/http, const StateNew ConnState
+pkg net/http, method (*Server) SetKeepAlivesEnabled(bool)
+pkg net/http, method (ConnState) String() string
+pkg net/http, type Client struct, Timeout time.Duration
+pkg net/http, type ConnState int
+pkg net/http, type Response struct, TLS *tls.ConnectionState
+pkg net/http, type Server struct, ConnState func(net.Conn, ConnState)
+pkg net/http, type Server struct, ErrorLog *log.Logger
+pkg net/http, type Transport struct, TLSHandshakeTimeout time.Duration
+pkg regexp/syntax, method (*Inst) MatchRunePos(int32) int
+pkg regexp/syntax, method (InstOp) String() string
+pkg runtime/debug, func SetPanicOnFault(bool) bool
+pkg runtime/debug, func WriteHeapDump(uintptr)
+pkg sync, method (*Pool) Get() interface{}
+pkg sync, method (*Pool) Put(interface{})
+pkg sync, type Pool struct
+pkg sync, type Pool struct, New func() interface{}
+pkg syscall (darwin-386), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (darwin-386), func Mlock([]uint8) error
+pkg syscall (darwin-386), func Mlockall(int) error
+pkg syscall (darwin-386), func Mprotect([]uint8, int) error
+pkg syscall (darwin-386), func Munlock([]uint8) error
+pkg syscall (darwin-386), func Munlockall() error
+pkg syscall (darwin-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (darwin-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (darwin-386-cgo), func Mlock([]uint8) error
+pkg syscall (darwin-386-cgo), func Mlockall(int) error
+pkg syscall (darwin-386-cgo), func Mprotect([]uint8, int) error
+pkg syscall (darwin-386-cgo), func Munlock([]uint8) error
+pkg syscall (darwin-386-cgo), func Munlockall() error
+pkg syscall (darwin-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (darwin-amd64), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (darwin-amd64), func Mlock([]uint8) error
+pkg syscall (darwin-amd64), func Mlockall(int) error
+pkg syscall (darwin-amd64), func Mprotect([]uint8, int) error
+pkg syscall (darwin-amd64), func Munlock([]uint8) error
+pkg syscall (darwin-amd64), func Munlockall() error
+pkg syscall (darwin-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (darwin-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (darwin-amd64-cgo), func Mlock([]uint8) error
+pkg syscall (darwin-amd64-cgo), func Mlockall(int) error
+pkg syscall (darwin-amd64-cgo), func Mprotect([]uint8, int) error
+pkg syscall (darwin-amd64-cgo), func Munlock([]uint8) error
+pkg syscall (darwin-amd64-cgo), func Munlockall() error
+pkg syscall (darwin-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-386), const AF_INET6_SDP = 42
+pkg syscall (freebsd-386), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-386), const AF_INET_SDP = 40
+pkg syscall (freebsd-386), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-386), const AF_MAX = 42
+pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 246
+pkg syscall (freebsd-386), const DLT_MPEG_2_TS = 243
+pkg syscall (freebsd-386), const DLT_MPEG_2_TS ideal-int
+pkg syscall (freebsd-386), const DLT_NFC_LLCP = 245
+pkg syscall (freebsd-386), const DLT_NFC_LLCP ideal-int
+pkg syscall (freebsd-386), const DLT_NG40 = 244
+pkg syscall (freebsd-386), const DLT_NG40 ideal-int
+pkg syscall (freebsd-386), const ELAST = 96
+pkg syscall (freebsd-386), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-386), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-386), const EOWNERDEAD = 96
+pkg syscall (freebsd-386), const EOWNERDEAD Errno
+pkg syscall (freebsd-386), const EV_DROP = 4096
+pkg syscall (freebsd-386), const EV_DROP ideal-int
+pkg syscall (freebsd-386), const IPPROTO_MPLS = 137
+pkg syscall (freebsd-386), const IPPROTO_MPLS ideal-int
+pkg syscall (freebsd-386), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-386), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-386), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-386), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-386), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-386), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-386), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-386), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-386), const NAME_MAX = 255
+pkg syscall (freebsd-386), const NAME_MAX ideal-int
+pkg syscall (freebsd-386), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-386), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-386), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-386), const RT_NORTREF = 2
+pkg syscall (freebsd-386), const RT_NORTREF ideal-int
+pkg syscall (freebsd-386), const SIGLIBRT = 33
+pkg syscall (freebsd-386), const SIGLIBRT Signal
+pkg syscall (freebsd-386), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-386), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-386), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-386), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-386), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-386), const SO_VENDOR ideal-int
+pkg syscall (freebsd-386), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-386), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-386), const SYS_BINDAT = 538
+pkg syscall (freebsd-386), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-386), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-386), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-386), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-386), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-386), const SYS_PIPE2 = 542
+pkg syscall (freebsd-386), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-386), const SYS_PROCCTL = 544
+pkg syscall (freebsd-386), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-386), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-386), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-386), const WEXITED = 16
+pkg syscall (freebsd-386), const WEXITED ideal-int
+pkg syscall (freebsd-386), const WTRAPPED = 32
+pkg syscall (freebsd-386), const WTRAPPED ideal-int
+pkg syscall (freebsd-386), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-386), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-386), type Termios struct
+pkg syscall (freebsd-386), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-386), type Termios struct, Cflag uint32
+pkg syscall (freebsd-386), type Termios struct, Iflag uint32
+pkg syscall (freebsd-386), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-386), type Termios struct, Lflag uint32
+pkg syscall (freebsd-386), type Termios struct, Oflag uint32
+pkg syscall (freebsd-386), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-386-cgo), const AF_INET6_SDP = 42
+pkg syscall (freebsd-386-cgo), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-386-cgo), const AF_INET_SDP = 40
+pkg syscall (freebsd-386-cgo), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-386-cgo), const AF_MAX = 42
+pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 246
+pkg syscall (freebsd-386-cgo), const DLT_MPEG_2_TS = 243
+pkg syscall (freebsd-386-cgo), const DLT_MPEG_2_TS ideal-int
+pkg syscall (freebsd-386-cgo), const DLT_NFC_LLCP = 245
+pkg syscall (freebsd-386-cgo), const DLT_NFC_LLCP ideal-int
+pkg syscall (freebsd-386-cgo), const DLT_NG40 = 244
+pkg syscall (freebsd-386-cgo), const DLT_NG40 ideal-int
+pkg syscall (freebsd-386-cgo), const ELAST = 96
+pkg syscall (freebsd-386-cgo), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-386-cgo), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-386-cgo), const EOWNERDEAD = 96
+pkg syscall (freebsd-386-cgo), const EOWNERDEAD Errno
+pkg syscall (freebsd-386-cgo), const EV_DROP = 4096
+pkg syscall (freebsd-386-cgo), const EV_DROP ideal-int
+pkg syscall (freebsd-386-cgo), const IPPROTO_MPLS = 137
+pkg syscall (freebsd-386-cgo), const IPPROTO_MPLS ideal-int
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-386-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-386-cgo), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-386-cgo), const NAME_MAX = 255
+pkg syscall (freebsd-386-cgo), const NAME_MAX ideal-int
+pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-386-cgo), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-386-cgo), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-386-cgo), const RT_NORTREF = 2
+pkg syscall (freebsd-386-cgo), const RT_NORTREF ideal-int
+pkg syscall (freebsd-386-cgo), const SIGLIBRT = 33
+pkg syscall (freebsd-386-cgo), const SIGLIBRT Signal
+pkg syscall (freebsd-386-cgo), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-386-cgo), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-386-cgo), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-386-cgo), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-386-cgo), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-386-cgo), const SO_VENDOR ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-386-cgo), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_BINDAT = 538
+pkg syscall (freebsd-386-cgo), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-386-cgo), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-386-cgo), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_PIPE2 = 542
+pkg syscall (freebsd-386-cgo), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-386-cgo), const SYS_PROCCTL = 544
+pkg syscall (freebsd-386-cgo), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-386-cgo), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-386-cgo), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-386-cgo), const WEXITED = 16
+pkg syscall (freebsd-386-cgo), const WEXITED ideal-int
+pkg syscall (freebsd-386-cgo), const WTRAPPED = 32
+pkg syscall (freebsd-386-cgo), const WTRAPPED ideal-int
+pkg syscall (freebsd-386-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-386-cgo), type Termios struct
+pkg syscall (freebsd-386-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-386-cgo), type Termios struct, Cflag uint32
+pkg syscall (freebsd-386-cgo), type Termios struct, Iflag uint32
+pkg syscall (freebsd-386-cgo), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-386-cgo), type Termios struct, Lflag uint32
+pkg syscall (freebsd-386-cgo), type Termios struct, Oflag uint32
+pkg syscall (freebsd-386-cgo), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-amd64), const AF_INET6_SDP = 42
+pkg syscall (freebsd-amd64), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-amd64), const AF_INET_SDP = 40
+pkg syscall (freebsd-amd64), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-amd64), const AF_MAX = 42
+pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 246
+pkg syscall (freebsd-amd64), const DLT_MPEG_2_TS = 243
+pkg syscall (freebsd-amd64), const DLT_MPEG_2_TS ideal-int
+pkg syscall (freebsd-amd64), const DLT_NFC_LLCP = 245
+pkg syscall (freebsd-amd64), const DLT_NFC_LLCP ideal-int
+pkg syscall (freebsd-amd64), const DLT_NG40 = 244
+pkg syscall (freebsd-amd64), const DLT_NG40 ideal-int
+pkg syscall (freebsd-amd64), const ELAST = 96
+pkg syscall (freebsd-amd64), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-amd64), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-amd64), const EOWNERDEAD = 96
+pkg syscall (freebsd-amd64), const EOWNERDEAD Errno
+pkg syscall (freebsd-amd64), const EV_DROP = 4096
+pkg syscall (freebsd-amd64), const EV_DROP ideal-int
+pkg syscall (freebsd-amd64), const IPPROTO_MPLS = 137
+pkg syscall (freebsd-amd64), const IPPROTO_MPLS ideal-int
+pkg syscall (freebsd-amd64), const MAP_32BIT = 524288
+pkg syscall (freebsd-amd64), const MAP_32BIT ideal-int
+pkg syscall (freebsd-amd64), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-amd64), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-amd64), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-amd64), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-amd64), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-amd64), const NAME_MAX = 255
+pkg syscall (freebsd-amd64), const NAME_MAX ideal-int
+pkg syscall (freebsd-amd64), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-amd64), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-amd64), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-amd64), const RT_NORTREF = 2
+pkg syscall (freebsd-amd64), const RT_NORTREF ideal-int
+pkg syscall (freebsd-amd64), const SIGLIBRT = 33
+pkg syscall (freebsd-amd64), const SIGLIBRT Signal
+pkg syscall (freebsd-amd64), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-amd64), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-amd64), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-amd64), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-amd64), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-amd64), const SO_VENDOR ideal-int
+pkg syscall (freebsd-amd64), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-amd64), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-amd64), const SYS_BINDAT = 538
+pkg syscall (freebsd-amd64), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-amd64), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-amd64), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-amd64), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-amd64), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-amd64), const SYS_PIPE2 = 542
+pkg syscall (freebsd-amd64), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-amd64), const SYS_PROCCTL = 544
+pkg syscall (freebsd-amd64), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-amd64), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-amd64), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-amd64), const WEXITED = 16
+pkg syscall (freebsd-amd64), const WEXITED ideal-int
+pkg syscall (freebsd-amd64), const WTRAPPED = 32
+pkg syscall (freebsd-amd64), const WTRAPPED ideal-int
+pkg syscall (freebsd-amd64), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-amd64), type Termios struct
+pkg syscall (freebsd-amd64), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-amd64), type Termios struct, Cflag uint32
+pkg syscall (freebsd-amd64), type Termios struct, Iflag uint32
+pkg syscall (freebsd-amd64), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-amd64), type Termios struct, Lflag uint32
+pkg syscall (freebsd-amd64), type Termios struct, Oflag uint32
+pkg syscall (freebsd-amd64), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-amd64-cgo), const AF_INET6_SDP = 42
+pkg syscall (freebsd-amd64-cgo), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-amd64-cgo), const AF_INET_SDP = 40
+pkg syscall (freebsd-amd64-cgo), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-amd64-cgo), const AF_MAX = 42
+pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 246
+pkg syscall (freebsd-amd64-cgo), const DLT_MPEG_2_TS = 243
+pkg syscall (freebsd-amd64-cgo), const DLT_MPEG_2_TS ideal-int
+pkg syscall (freebsd-amd64-cgo), const DLT_NFC_LLCP = 245
+pkg syscall (freebsd-amd64-cgo), const DLT_NFC_LLCP ideal-int
+pkg syscall (freebsd-amd64-cgo), const DLT_NG40 = 244
+pkg syscall (freebsd-amd64-cgo), const DLT_NG40 ideal-int
+pkg syscall (freebsd-amd64-cgo), const ELAST = 96
+pkg syscall (freebsd-amd64-cgo), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-amd64-cgo), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-amd64-cgo), const EOWNERDEAD = 96
+pkg syscall (freebsd-amd64-cgo), const EOWNERDEAD Errno
+pkg syscall (freebsd-amd64-cgo), const EV_DROP = 4096
+pkg syscall (freebsd-amd64-cgo), const EV_DROP ideal-int
+pkg syscall (freebsd-amd64-cgo), const IPPROTO_MPLS = 137
+pkg syscall (freebsd-amd64-cgo), const IPPROTO_MPLS ideal-int
+pkg syscall (freebsd-amd64-cgo), const MAP_32BIT = 524288
+pkg syscall (freebsd-amd64-cgo), const MAP_32BIT ideal-int
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-amd64-cgo), const NAME_MAX = 255
+pkg syscall (freebsd-amd64-cgo), const NAME_MAX ideal-int
+pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-amd64-cgo), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-amd64-cgo), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-amd64-cgo), const RT_NORTREF = 2
+pkg syscall (freebsd-amd64-cgo), const RT_NORTREF ideal-int
+pkg syscall (freebsd-amd64-cgo), const SIGLIBRT = 33
+pkg syscall (freebsd-amd64-cgo), const SIGLIBRT Signal
+pkg syscall (freebsd-amd64-cgo), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-amd64-cgo), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-amd64-cgo), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-amd64-cgo), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-amd64-cgo), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-amd64-cgo), const SO_VENDOR ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-amd64-cgo), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_BINDAT = 538
+pkg syscall (freebsd-amd64-cgo), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-amd64-cgo), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-amd64-cgo), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_PIPE2 = 542
+pkg syscall (freebsd-amd64-cgo), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-amd64-cgo), const SYS_PROCCTL = 544
+pkg syscall (freebsd-amd64-cgo), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-amd64-cgo), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-amd64-cgo), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-amd64-cgo), const WEXITED = 16
+pkg syscall (freebsd-amd64-cgo), const WEXITED ideal-int
+pkg syscall (freebsd-amd64-cgo), const WTRAPPED = 32
+pkg syscall (freebsd-amd64-cgo), const WTRAPPED ideal-int
+pkg syscall (freebsd-amd64-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-amd64-cgo), type Termios struct
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Cflag uint32
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Iflag uint32
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Lflag uint32
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Oflag uint32
+pkg syscall (freebsd-amd64-cgo), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-arm), const AF_INET6_SDP = 42
+pkg syscall (freebsd-arm), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-arm), const AF_INET_SDP = 40
+pkg syscall (freebsd-arm), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-arm), const AF_MAX = 42
+pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074807406
+pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148549229
+pkg syscall (freebsd-arm), const ELAST = 96
+pkg syscall (freebsd-arm), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-arm), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-arm), const EOWNERDEAD = 96
+pkg syscall (freebsd-arm), const EOWNERDEAD Errno
+pkg syscall (freebsd-arm), const EV_DROP = 4096
+pkg syscall (freebsd-arm), const EV_DROP ideal-int
+pkg syscall (freebsd-arm), const IFT_CARP = 248
+pkg syscall (freebsd-arm), const IFT_CARP ideal-int
+pkg syscall (freebsd-arm), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-arm), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-arm), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-arm), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-arm), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-arm), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-arm), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-arm), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-arm), const NAME_MAX = 255
+pkg syscall (freebsd-arm), const NAME_MAX ideal-int
+pkg syscall (freebsd-arm), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-arm), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-arm), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151704858
+pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274795323
+pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151704902
+pkg syscall (freebsd-arm), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-arm), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-arm), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-arm), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-arm), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-arm), const SO_VENDOR ideal-int
+pkg syscall (freebsd-arm), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-arm), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-arm), const SYS_BINDAT = 538
+pkg syscall (freebsd-arm), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_GETRIGHTS = 515
+pkg syscall (freebsd-arm), const SYS_CAP_GETRIGHTS ideal-int
+pkg syscall (freebsd-arm), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-arm), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-arm), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-arm), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-arm), const SYS_PIPE2 = 542
+pkg syscall (freebsd-arm), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-arm), const SYS_PROCCTL = 544
+pkg syscall (freebsd-arm), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-arm), const SizeofBpfHdr = 32
+pkg syscall (freebsd-arm), const SizeofIfData = 96
+pkg syscall (freebsd-arm), const SizeofIfMsghdr = 112
+pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 54
+pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 106
+pkg syscall (freebsd-arm), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-arm), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074820185
+pkg syscall (freebsd-arm), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-arm), func Fchflags(int, int) error
+pkg syscall (freebsd-arm), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [6]uint8
+pkg syscall (freebsd-arm), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm), type IfData struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm), type Termios struct
+pkg syscall (freebsd-arm), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-arm), type Termios struct, Cflag uint32
+pkg syscall (freebsd-arm), type Termios struct, Iflag uint32
+pkg syscall (freebsd-arm), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-arm), type Termios struct, Lflag uint32
+pkg syscall (freebsd-arm), type Termios struct, Oflag uint32
+pkg syscall (freebsd-arm), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-arm), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm), type Timeval struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), const AF_INET6_SDP = 42
+pkg syscall (freebsd-arm-cgo), const AF_INET6_SDP ideal-int
+pkg syscall (freebsd-arm-cgo), const AF_INET_SDP = 40
+pkg syscall (freebsd-arm-cgo), const AF_INET_SDP ideal-int
+pkg syscall (freebsd-arm-cgo), const AF_MAX = 42
+pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074807406
+pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148549229
+pkg syscall (freebsd-arm-cgo), const ELAST = 96
+pkg syscall (freebsd-arm-cgo), const ENOTRECOVERABLE = 95
+pkg syscall (freebsd-arm-cgo), const ENOTRECOVERABLE Errno
+pkg syscall (freebsd-arm-cgo), const EOWNERDEAD = 96
+pkg syscall (freebsd-arm-cgo), const EOWNERDEAD Errno
+pkg syscall (freebsd-arm-cgo), const EV_DROP = 4096
+pkg syscall (freebsd-arm-cgo), const EV_DROP ideal-int
+pkg syscall (freebsd-arm-cgo), const IFT_CARP = 248
+pkg syscall (freebsd-arm-cgo), const IFT_CARP ideal-int
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNED_SUPER = 16777216
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNED_SUPER ideal-int
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (freebsd-arm-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (freebsd-arm-cgo), const MSG_CMSG_CLOEXEC = 262144
+pkg syscall (freebsd-arm-cgo), const MSG_CMSG_CLOEXEC ideal-int
+pkg syscall (freebsd-arm-cgo), const NAME_MAX = 255
+pkg syscall (freebsd-arm-cgo), const NAME_MAX ideal-int
+pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 1048576
+pkg syscall (freebsd-arm-cgo), const RTF_GWFLAG_COMPAT = 2147483648
+pkg syscall (freebsd-arm-cgo), const RTF_GWFLAG_COMPAT ideal-int
+pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151704858
+pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274795323
+pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151704902
+pkg syscall (freebsd-arm-cgo), const SOCK_CLOEXEC = 268435456
+pkg syscall (freebsd-arm-cgo), const SOCK_CLOEXEC ideal-int
+pkg syscall (freebsd-arm-cgo), const SOCK_NONBLOCK = 536870912
+pkg syscall (freebsd-arm-cgo), const SOCK_NONBLOCK ideal-int
+pkg syscall (freebsd-arm-cgo), const SO_VENDOR = 2147483648
+pkg syscall (freebsd-arm-cgo), const SO_VENDOR ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_ACCEPT4 = 541
+pkg syscall (freebsd-arm-cgo), const SYS_ACCEPT4 ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_BINDAT = 538
+pkg syscall (freebsd-arm-cgo), const SYS_BINDAT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_GETRIGHTS = 515
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_GETRIGHTS ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CHFLAGSAT = 540
+pkg syscall (freebsd-arm-cgo), const SYS_CHFLAGSAT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CONNECTAT = 539
+pkg syscall (freebsd-arm-cgo), const SYS_CONNECTAT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_PIPE2 = 542
+pkg syscall (freebsd-arm-cgo), const SYS_PIPE2 ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_PROCCTL = 544
+pkg syscall (freebsd-arm-cgo), const SYS_PROCCTL ideal-int
+pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 32
+pkg syscall (freebsd-arm-cgo), const SizeofIfData = 96
+pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 112
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 54
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 106
+pkg syscall (freebsd-arm-cgo), const TCP_VENDOR = 2147483648
+pkg syscall (freebsd-arm-cgo), const TCP_VENDOR ideal-int
+pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074820185
+pkg syscall (freebsd-arm-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (freebsd-arm-cgo), func Fchflags(int, int) error
+pkg syscall (freebsd-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (freebsd-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [6]uint8
+pkg syscall (freebsd-arm-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), type IfData struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), type Termios struct
+pkg syscall (freebsd-arm-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (freebsd-arm-cgo), type Termios struct, Cflag uint32
+pkg syscall (freebsd-arm-cgo), type Termios struct, Iflag uint32
+pkg syscall (freebsd-arm-cgo), type Termios struct, Ispeed uint32
+pkg syscall (freebsd-arm-cgo), type Termios struct, Lflag uint32
+pkg syscall (freebsd-arm-cgo), type Termios struct, Oflag uint32
+pkg syscall (freebsd-arm-cgo), type Termios struct, Ospeed uint32
+pkg syscall (freebsd-arm-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), type Timeval struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-386), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-386), type Flock_t struct
+pkg syscall (linux-386), type Flock_t struct, Len int64
+pkg syscall (linux-386), type Flock_t struct, Pid int32
+pkg syscall (linux-386), type Flock_t struct, Start int64
+pkg syscall (linux-386), type Flock_t struct, Type int16
+pkg syscall (linux-386), type Flock_t struct, Whence int16
+pkg syscall (linux-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-386-cgo), type Flock_t struct
+pkg syscall (linux-386-cgo), type Flock_t struct, Len int64
+pkg syscall (linux-386-cgo), type Flock_t struct, Pid int32
+pkg syscall (linux-386-cgo), type Flock_t struct, Start int64
+pkg syscall (linux-386-cgo), type Flock_t struct, Type int16
+pkg syscall (linux-386-cgo), type Flock_t struct, Whence int16
+pkg syscall (linux-amd64), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-amd64), type Flock_t struct
+pkg syscall (linux-amd64), type Flock_t struct, Len int64
+pkg syscall (linux-amd64), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-amd64), type Flock_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (linux-amd64), type Flock_t struct, Pid int32
+pkg syscall (linux-amd64), type Flock_t struct, Start int64
+pkg syscall (linux-amd64), type Flock_t struct, Type int16
+pkg syscall (linux-amd64), type Flock_t struct, Whence int16
+pkg syscall (linux-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-amd64-cgo), type Flock_t struct
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Len int64
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Pid int32
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Start int64
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Type int16
+pkg syscall (linux-amd64-cgo), type Flock_t struct, Whence int16
+pkg syscall (linux-arm), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-arm), type Flock_t struct
+pkg syscall (linux-arm), type Flock_t struct, Len int64
+pkg syscall (linux-arm), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-arm), type Flock_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (linux-arm), type Flock_t struct, Pid int32
+pkg syscall (linux-arm), type Flock_t struct, Start int64
+pkg syscall (linux-arm), type Flock_t struct, Type int16
+pkg syscall (linux-arm), type Flock_t struct, Whence int16
+pkg syscall (linux-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (linux-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (linux-arm-cgo), type Flock_t struct
+pkg syscall (linux-arm-cgo), type Flock_t struct, Len int64
+pkg syscall (linux-arm-cgo), type Flock_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-arm-cgo), type Flock_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (linux-arm-cgo), type Flock_t struct, Pid int32
+pkg syscall (linux-arm-cgo), type Flock_t struct, Start int64
+pkg syscall (linux-arm-cgo), type Flock_t struct, Type int16
+pkg syscall (linux-arm-cgo), type Flock_t struct, Whence int16
+pkg syscall (netbsd-386), const CLONE_CSIGNAL = 255
+pkg syscall (netbsd-386), const CLONE_CSIGNAL ideal-int
+pkg syscall (netbsd-386), const CLONE_FILES = 1024
+pkg syscall (netbsd-386), const CLONE_FILES ideal-int
+pkg syscall (netbsd-386), const CLONE_FS = 512
+pkg syscall (netbsd-386), const CLONE_FS ideal-int
+pkg syscall (netbsd-386), const CLONE_PID = 4096
+pkg syscall (netbsd-386), const CLONE_PID ideal-int
+pkg syscall (netbsd-386), const CLONE_PTRACE = 8192
+pkg syscall (netbsd-386), const CLONE_PTRACE ideal-int
+pkg syscall (netbsd-386), const CLONE_SIGHAND = 2048
+pkg syscall (netbsd-386), const CLONE_SIGHAND ideal-int
+pkg syscall (netbsd-386), const CLONE_VFORK = 16384
+pkg syscall (netbsd-386), const CLONE_VFORK ideal-int
+pkg syscall (netbsd-386), const CLONE_VM = 256
+pkg syscall (netbsd-386), const CLONE_VM ideal-int
+pkg syscall (netbsd-386), const MADV_DONTNEED = 4
+pkg syscall (netbsd-386), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-386), const MADV_FREE = 6
+pkg syscall (netbsd-386), const MADV_FREE ideal-int
+pkg syscall (netbsd-386), const MADV_NORMAL = 0
+pkg syscall (netbsd-386), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-386), const MADV_RANDOM = 1
+pkg syscall (netbsd-386), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-386), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-386), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-386), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-386), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-386), const MADV_WILLNEED = 3
+pkg syscall (netbsd-386), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-386), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-386), const MAP_ANON = 4096
+pkg syscall (netbsd-386), const MAP_ANON ideal-int
+pkg syscall (netbsd-386), const MAP_FILE = 0
+pkg syscall (netbsd-386), const MAP_FILE ideal-int
+pkg syscall (netbsd-386), const MAP_FIXED = 16
+pkg syscall (netbsd-386), const MAP_FIXED ideal-int
+pkg syscall (netbsd-386), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-386), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT = 128
+pkg syscall (netbsd-386), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-386), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-386), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-386), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-386), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-386), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-386), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-386), const MAP_NORESERVE = 64
+pkg syscall (netbsd-386), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-386), const MAP_PRIVATE = 2
+pkg syscall (netbsd-386), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-386), const MAP_RENAME = 32
+pkg syscall (netbsd-386), const MAP_RENAME ideal-int
+pkg syscall (netbsd-386), const MAP_SHARED = 1
+pkg syscall (netbsd-386), const MAP_SHARED ideal-int
+pkg syscall (netbsd-386), const MAP_STACK = 8192
+pkg syscall (netbsd-386), const MAP_STACK ideal-int
+pkg syscall (netbsd-386), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-386), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-386), const MAP_WIRED = 2048
+pkg syscall (netbsd-386), const MAP_WIRED ideal-int
+pkg syscall (netbsd-386), const MCL_CURRENT = 1
+pkg syscall (netbsd-386), const MCL_CURRENT ideal-int
+pkg syscall (netbsd-386), const MCL_FUTURE = 2
+pkg syscall (netbsd-386), const MCL_FUTURE ideal-int
+pkg syscall (netbsd-386), const MS_ASYNC = 1
+pkg syscall (netbsd-386), const MS_ASYNC ideal-int
+pkg syscall (netbsd-386), const MS_INVALIDATE = 2
+pkg syscall (netbsd-386), const MS_INVALIDATE ideal-int
+pkg syscall (netbsd-386), const MS_SYNC = 4
+pkg syscall (netbsd-386), const MS_SYNC ideal-int
+pkg syscall (netbsd-386), const PROT_EXEC = 4
+pkg syscall (netbsd-386), const PROT_EXEC ideal-int
+pkg syscall (netbsd-386), const PROT_NONE = 0
+pkg syscall (netbsd-386), const PROT_NONE ideal-int
+pkg syscall (netbsd-386), const PROT_READ = 1
+pkg syscall (netbsd-386), const PROT_READ ideal-int
+pkg syscall (netbsd-386), const PROT_WRITE = 2
+pkg syscall (netbsd-386), const PROT_WRITE ideal-int
+pkg syscall (netbsd-386), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-386), type Termios struct
+pkg syscall (netbsd-386), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-386), type Termios struct, Cflag uint32
+pkg syscall (netbsd-386), type Termios struct, Iflag uint32
+pkg syscall (netbsd-386), type Termios struct, Ispeed int32
+pkg syscall (netbsd-386), type Termios struct, Lflag uint32
+pkg syscall (netbsd-386), type Termios struct, Oflag uint32
+pkg syscall (netbsd-386), type Termios struct, Ospeed int32
+pkg syscall (netbsd-386-cgo), const CLONE_CSIGNAL = 255
+pkg syscall (netbsd-386-cgo), const CLONE_CSIGNAL ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_FILES = 1024
+pkg syscall (netbsd-386-cgo), const CLONE_FILES ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_FS = 512
+pkg syscall (netbsd-386-cgo), const CLONE_FS ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_PID = 4096
+pkg syscall (netbsd-386-cgo), const CLONE_PID ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_PTRACE = 8192
+pkg syscall (netbsd-386-cgo), const CLONE_PTRACE ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_SIGHAND = 2048
+pkg syscall (netbsd-386-cgo), const CLONE_SIGHAND ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_VFORK = 16384
+pkg syscall (netbsd-386-cgo), const CLONE_VFORK ideal-int
+pkg syscall (netbsd-386-cgo), const CLONE_VM = 256
+pkg syscall (netbsd-386-cgo), const CLONE_VM ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_DONTNEED = 4
+pkg syscall (netbsd-386-cgo), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_FREE = 6
+pkg syscall (netbsd-386-cgo), const MADV_FREE ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_NORMAL = 0
+pkg syscall (netbsd-386-cgo), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_RANDOM = 1
+pkg syscall (netbsd-386-cgo), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-386-cgo), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-386-cgo), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-386-cgo), const MADV_WILLNEED = 3
+pkg syscall (netbsd-386-cgo), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-386-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_ANON = 4096
+pkg syscall (netbsd-386-cgo), const MAP_ANON ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_FILE = 0
+pkg syscall (netbsd-386-cgo), const MAP_FILE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_FIXED = 16
+pkg syscall (netbsd-386-cgo), const MAP_FIXED ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-386-cgo), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT = 128
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-386-cgo), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_NORESERVE = 64
+pkg syscall (netbsd-386-cgo), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_PRIVATE = 2
+pkg syscall (netbsd-386-cgo), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_RENAME = 32
+pkg syscall (netbsd-386-cgo), const MAP_RENAME ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_SHARED = 1
+pkg syscall (netbsd-386-cgo), const MAP_SHARED ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_STACK = 8192
+pkg syscall (netbsd-386-cgo), const MAP_STACK ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-386-cgo), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-386-cgo), const MAP_WIRED = 2048
+pkg syscall (netbsd-386-cgo), const MAP_WIRED ideal-int
+pkg syscall (netbsd-386-cgo), const MCL_CURRENT = 1
+pkg syscall (netbsd-386-cgo), const MCL_CURRENT ideal-int
+pkg syscall (netbsd-386-cgo), const MCL_FUTURE = 2
+pkg syscall (netbsd-386-cgo), const MCL_FUTURE ideal-int
+pkg syscall (netbsd-386-cgo), const MS_ASYNC = 1
+pkg syscall (netbsd-386-cgo), const MS_ASYNC ideal-int
+pkg syscall (netbsd-386-cgo), const MS_INVALIDATE = 2
+pkg syscall (netbsd-386-cgo), const MS_INVALIDATE ideal-int
+pkg syscall (netbsd-386-cgo), const MS_SYNC = 4
+pkg syscall (netbsd-386-cgo), const MS_SYNC ideal-int
+pkg syscall (netbsd-386-cgo), const PROT_EXEC = 4
+pkg syscall (netbsd-386-cgo), const PROT_EXEC ideal-int
+pkg syscall (netbsd-386-cgo), const PROT_NONE = 0
+pkg syscall (netbsd-386-cgo), const PROT_NONE ideal-int
+pkg syscall (netbsd-386-cgo), const PROT_READ = 1
+pkg syscall (netbsd-386-cgo), const PROT_READ ideal-int
+pkg syscall (netbsd-386-cgo), const PROT_WRITE = 2
+pkg syscall (netbsd-386-cgo), const PROT_WRITE ideal-int
+pkg syscall (netbsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-386-cgo), type Termios struct
+pkg syscall (netbsd-386-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-386-cgo), type Termios struct, Cflag uint32
+pkg syscall (netbsd-386-cgo), type Termios struct, Iflag uint32
+pkg syscall (netbsd-386-cgo), type Termios struct, Ispeed int32
+pkg syscall (netbsd-386-cgo), type Termios struct, Lflag uint32
+pkg syscall (netbsd-386-cgo), type Termios struct, Oflag uint32
+pkg syscall (netbsd-386-cgo), type Termios struct, Ospeed int32
+pkg syscall (netbsd-amd64), const CLONE_CSIGNAL = 255
+pkg syscall (netbsd-amd64), const CLONE_CSIGNAL ideal-int
+pkg syscall (netbsd-amd64), const CLONE_FILES = 1024
+pkg syscall (netbsd-amd64), const CLONE_FILES ideal-int
+pkg syscall (netbsd-amd64), const CLONE_FS = 512
+pkg syscall (netbsd-amd64), const CLONE_FS ideal-int
+pkg syscall (netbsd-amd64), const CLONE_PID = 4096
+pkg syscall (netbsd-amd64), const CLONE_PID ideal-int
+pkg syscall (netbsd-amd64), const CLONE_PTRACE = 8192
+pkg syscall (netbsd-amd64), const CLONE_PTRACE ideal-int
+pkg syscall (netbsd-amd64), const CLONE_SIGHAND = 2048
+pkg syscall (netbsd-amd64), const CLONE_SIGHAND ideal-int
+pkg syscall (netbsd-amd64), const CLONE_VFORK = 16384
+pkg syscall (netbsd-amd64), const CLONE_VFORK ideal-int
+pkg syscall (netbsd-amd64), const CLONE_VM = 256
+pkg syscall (netbsd-amd64), const CLONE_VM ideal-int
+pkg syscall (netbsd-amd64), const MADV_DONTNEED = 4
+pkg syscall (netbsd-amd64), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-amd64), const MADV_FREE = 6
+pkg syscall (netbsd-amd64), const MADV_FREE ideal-int
+pkg syscall (netbsd-amd64), const MADV_NORMAL = 0
+pkg syscall (netbsd-amd64), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-amd64), const MADV_RANDOM = 1
+pkg syscall (netbsd-amd64), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-amd64), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-amd64), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-amd64), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-amd64), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-amd64), const MADV_WILLNEED = 3
+pkg syscall (netbsd-amd64), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-amd64), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-amd64), const MAP_ANON = 4096
+pkg syscall (netbsd-amd64), const MAP_ANON ideal-int
+pkg syscall (netbsd-amd64), const MAP_FILE = 0
+pkg syscall (netbsd-amd64), const MAP_FILE ideal-int
+pkg syscall (netbsd-amd64), const MAP_FIXED = 16
+pkg syscall (netbsd-amd64), const MAP_FIXED ideal-int
+pkg syscall (netbsd-amd64), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-amd64), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT = 128
+pkg syscall (netbsd-amd64), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-amd64), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-amd64), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-amd64), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-amd64), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-amd64), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-amd64), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-amd64), const MAP_NORESERVE = 64
+pkg syscall (netbsd-amd64), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-amd64), const MAP_PRIVATE = 2
+pkg syscall (netbsd-amd64), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-amd64), const MAP_RENAME = 32
+pkg syscall (netbsd-amd64), const MAP_RENAME ideal-int
+pkg syscall (netbsd-amd64), const MAP_SHARED = 1
+pkg syscall (netbsd-amd64), const MAP_SHARED ideal-int
+pkg syscall (netbsd-amd64), const MAP_STACK = 8192
+pkg syscall (netbsd-amd64), const MAP_STACK ideal-int
+pkg syscall (netbsd-amd64), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-amd64), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-amd64), const MAP_WIRED = 2048
+pkg syscall (netbsd-amd64), const MAP_WIRED ideal-int
+pkg syscall (netbsd-amd64), const MCL_CURRENT = 1
+pkg syscall (netbsd-amd64), const MCL_CURRENT ideal-int
+pkg syscall (netbsd-amd64), const MCL_FUTURE = 2
+pkg syscall (netbsd-amd64), const MCL_FUTURE ideal-int
+pkg syscall (netbsd-amd64), const MS_ASYNC = 1
+pkg syscall (netbsd-amd64), const MS_ASYNC ideal-int
+pkg syscall (netbsd-amd64), const MS_INVALIDATE = 2
+pkg syscall (netbsd-amd64), const MS_INVALIDATE ideal-int
+pkg syscall (netbsd-amd64), const MS_SYNC = 4
+pkg syscall (netbsd-amd64), const MS_SYNC ideal-int
+pkg syscall (netbsd-amd64), const PROT_EXEC = 4
+pkg syscall (netbsd-amd64), const PROT_EXEC ideal-int
+pkg syscall (netbsd-amd64), const PROT_NONE = 0
+pkg syscall (netbsd-amd64), const PROT_NONE ideal-int
+pkg syscall (netbsd-amd64), const PROT_READ = 1
+pkg syscall (netbsd-amd64), const PROT_READ ideal-int
+pkg syscall (netbsd-amd64), const PROT_WRITE = 2
+pkg syscall (netbsd-amd64), const PROT_WRITE ideal-int
+pkg syscall (netbsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-amd64), type Termios struct
+pkg syscall (netbsd-amd64), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-amd64), type Termios struct, Cflag uint32
+pkg syscall (netbsd-amd64), type Termios struct, Iflag uint32
+pkg syscall (netbsd-amd64), type Termios struct, Ispeed int32
+pkg syscall (netbsd-amd64), type Termios struct, Lflag uint32
+pkg syscall (netbsd-amd64), type Termios struct, Oflag uint32
+pkg syscall (netbsd-amd64), type Termios struct, Ospeed int32
+pkg syscall (netbsd-amd64-cgo), const CLONE_CSIGNAL = 255
+pkg syscall (netbsd-amd64-cgo), const CLONE_CSIGNAL ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_FILES = 1024
+pkg syscall (netbsd-amd64-cgo), const CLONE_FILES ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_FS = 512
+pkg syscall (netbsd-amd64-cgo), const CLONE_FS ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_PID = 4096
+pkg syscall (netbsd-amd64-cgo), const CLONE_PID ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_PTRACE = 8192
+pkg syscall (netbsd-amd64-cgo), const CLONE_PTRACE ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_SIGHAND = 2048
+pkg syscall (netbsd-amd64-cgo), const CLONE_SIGHAND ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_VFORK = 16384
+pkg syscall (netbsd-amd64-cgo), const CLONE_VFORK ideal-int
+pkg syscall (netbsd-amd64-cgo), const CLONE_VM = 256
+pkg syscall (netbsd-amd64-cgo), const CLONE_VM ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_DONTNEED = 4
+pkg syscall (netbsd-amd64-cgo), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_FREE = 6
+pkg syscall (netbsd-amd64-cgo), const MADV_FREE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_NORMAL = 0
+pkg syscall (netbsd-amd64-cgo), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_RANDOM = 1
+pkg syscall (netbsd-amd64-cgo), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-amd64-cgo), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-amd64-cgo), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-amd64-cgo), const MADV_WILLNEED = 3
+pkg syscall (netbsd-amd64-cgo), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-amd64-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_ANON = 4096
+pkg syscall (netbsd-amd64-cgo), const MAP_ANON ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_FILE = 0
+pkg syscall (netbsd-amd64-cgo), const MAP_FILE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_FIXED = 16
+pkg syscall (netbsd-amd64-cgo), const MAP_FIXED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-amd64-cgo), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT = 128
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-amd64-cgo), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_NORESERVE = 64
+pkg syscall (netbsd-amd64-cgo), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_PRIVATE = 2
+pkg syscall (netbsd-amd64-cgo), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_RENAME = 32
+pkg syscall (netbsd-amd64-cgo), const MAP_RENAME ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_SHARED = 1
+pkg syscall (netbsd-amd64-cgo), const MAP_SHARED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_STACK = 8192
+pkg syscall (netbsd-amd64-cgo), const MAP_STACK ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-amd64-cgo), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MAP_WIRED = 2048
+pkg syscall (netbsd-amd64-cgo), const MAP_WIRED ideal-int
+pkg syscall (netbsd-amd64-cgo), const MCL_CURRENT = 1
+pkg syscall (netbsd-amd64-cgo), const MCL_CURRENT ideal-int
+pkg syscall (netbsd-amd64-cgo), const MCL_FUTURE = 2
+pkg syscall (netbsd-amd64-cgo), const MCL_FUTURE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MS_ASYNC = 1
+pkg syscall (netbsd-amd64-cgo), const MS_ASYNC ideal-int
+pkg syscall (netbsd-amd64-cgo), const MS_INVALIDATE = 2
+pkg syscall (netbsd-amd64-cgo), const MS_INVALIDATE ideal-int
+pkg syscall (netbsd-amd64-cgo), const MS_SYNC = 4
+pkg syscall (netbsd-amd64-cgo), const MS_SYNC ideal-int
+pkg syscall (netbsd-amd64-cgo), const PROT_EXEC = 4
+pkg syscall (netbsd-amd64-cgo), const PROT_EXEC ideal-int
+pkg syscall (netbsd-amd64-cgo), const PROT_NONE = 0
+pkg syscall (netbsd-amd64-cgo), const PROT_NONE ideal-int
+pkg syscall (netbsd-amd64-cgo), const PROT_READ = 1
+pkg syscall (netbsd-amd64-cgo), const PROT_READ ideal-int
+pkg syscall (netbsd-amd64-cgo), const PROT_WRITE = 2
+pkg syscall (netbsd-amd64-cgo), const PROT_WRITE ideal-int
+pkg syscall (netbsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-amd64-cgo), type Termios struct
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Cflag uint32
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Iflag uint32
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Ispeed int32
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Lflag uint32
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Oflag uint32
+pkg syscall (netbsd-amd64-cgo), type Termios struct, Ospeed int32
+pkg syscall (netbsd-arm), const MADV_DONTNEED = 4
+pkg syscall (netbsd-arm), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-arm), const MADV_FREE = 6
+pkg syscall (netbsd-arm), const MADV_FREE ideal-int
+pkg syscall (netbsd-arm), const MADV_NORMAL = 0
+pkg syscall (netbsd-arm), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-arm), const MADV_RANDOM = 1
+pkg syscall (netbsd-arm), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-arm), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-arm), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-arm), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-arm), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-arm), const MADV_WILLNEED = 3
+pkg syscall (netbsd-arm), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-arm), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-arm), const MAP_ANON = 4096
+pkg syscall (netbsd-arm), const MAP_ANON ideal-int
+pkg syscall (netbsd-arm), const MAP_FILE = 0
+pkg syscall (netbsd-arm), const MAP_FILE ideal-int
+pkg syscall (netbsd-arm), const MAP_FIXED = 16
+pkg syscall (netbsd-arm), const MAP_FIXED ideal-int
+pkg syscall (netbsd-arm), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-arm), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT = 128
+pkg syscall (netbsd-arm), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-arm), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-arm), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-arm), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-arm), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-arm), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-arm), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-arm), const MAP_NORESERVE = 64
+pkg syscall (netbsd-arm), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-arm), const MAP_PRIVATE = 2
+pkg syscall (netbsd-arm), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-arm), const MAP_RENAME = 32
+pkg syscall (netbsd-arm), const MAP_RENAME ideal-int
+pkg syscall (netbsd-arm), const MAP_SHARED = 1
+pkg syscall (netbsd-arm), const MAP_SHARED ideal-int
+pkg syscall (netbsd-arm), const MAP_STACK = 8192
+pkg syscall (netbsd-arm), const MAP_STACK ideal-int
+pkg syscall (netbsd-arm), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-arm), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-arm), const MAP_WIRED = 2048
+pkg syscall (netbsd-arm), const MAP_WIRED ideal-int
+pkg syscall (netbsd-arm), const PROT_EXEC = 4
+pkg syscall (netbsd-arm), const PROT_EXEC ideal-int
+pkg syscall (netbsd-arm), const PROT_NONE = 0
+pkg syscall (netbsd-arm), const PROT_NONE ideal-int
+pkg syscall (netbsd-arm), const PROT_READ = 1
+pkg syscall (netbsd-arm), const PROT_READ ideal-int
+pkg syscall (netbsd-arm), const PROT_WRITE = 2
+pkg syscall (netbsd-arm), const PROT_WRITE ideal-int
+pkg syscall (netbsd-arm), const SizeofIfData = 136
+pkg syscall (netbsd-arm), func Fchflags(int, int) error
+pkg syscall (netbsd-arm), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-arm), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-arm), type Kevent_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (netbsd-arm), type Stat_t struct, Pad_cgo_2 [4]uint8
+pkg syscall (netbsd-arm), type Termios struct
+pkg syscall (netbsd-arm), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-arm), type Termios struct, Cflag uint32
+pkg syscall (netbsd-arm), type Termios struct, Iflag uint32
+pkg syscall (netbsd-arm), type Termios struct, Ispeed int32
+pkg syscall (netbsd-arm), type Termios struct, Lflag uint32
+pkg syscall (netbsd-arm), type Termios struct, Oflag uint32
+pkg syscall (netbsd-arm), type Termios struct, Ospeed int32
+pkg syscall (netbsd-arm), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm), type Timeval struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm-cgo), const MADV_DONTNEED = 4
+pkg syscall (netbsd-arm-cgo), const MADV_DONTNEED ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_FREE = 6
+pkg syscall (netbsd-arm-cgo), const MADV_FREE ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_NORMAL = 0
+pkg syscall (netbsd-arm-cgo), const MADV_NORMAL ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_RANDOM = 1
+pkg syscall (netbsd-arm-cgo), const MADV_RANDOM ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_SEQUENTIAL = 2
+pkg syscall (netbsd-arm-cgo), const MADV_SEQUENTIAL ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_SPACEAVAIL = 5
+pkg syscall (netbsd-arm-cgo), const MADV_SPACEAVAIL ideal-int
+pkg syscall (netbsd-arm-cgo), const MADV_WILLNEED = 3
+pkg syscall (netbsd-arm-cgo), const MADV_WILLNEED ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_16MB = 402653184
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_16MB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_1TB = 671088640
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_1TB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_256TB = 805306368
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_256TB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_4GB = 536870912
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_4GB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64KB = 268435456
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64KB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64PB = 939524096
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_64PB ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_MASK = -16777216
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_MASK ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_SHIFT = 24
+pkg syscall (netbsd-arm-cgo), const MAP_ALIGNMENT_SHIFT ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_ANON = 4096
+pkg syscall (netbsd-arm-cgo), const MAP_ANON ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_FILE = 0
+pkg syscall (netbsd-arm-cgo), const MAP_FILE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_FIXED = 16
+pkg syscall (netbsd-arm-cgo), const MAP_FIXED ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_HASSEMAPHORE = 512
+pkg syscall (netbsd-arm-cgo), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT = 128
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_COPY = 1
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_COPY ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DEFAULT = 1
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DEFAULT ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_NONE = 2
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_NONE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_SHARE = 0
+pkg syscall (netbsd-arm-cgo), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_NORESERVE = 64
+pkg syscall (netbsd-arm-cgo), const MAP_NORESERVE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_PRIVATE = 2
+pkg syscall (netbsd-arm-cgo), const MAP_PRIVATE ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_RENAME = 32
+pkg syscall (netbsd-arm-cgo), const MAP_RENAME ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_SHARED = 1
+pkg syscall (netbsd-arm-cgo), const MAP_SHARED ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_STACK = 8192
+pkg syscall (netbsd-arm-cgo), const MAP_STACK ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_TRYFIXED = 1024
+pkg syscall (netbsd-arm-cgo), const MAP_TRYFIXED ideal-int
+pkg syscall (netbsd-arm-cgo), const MAP_WIRED = 2048
+pkg syscall (netbsd-arm-cgo), const MAP_WIRED ideal-int
+pkg syscall (netbsd-arm-cgo), const PROT_EXEC = 4
+pkg syscall (netbsd-arm-cgo), const PROT_EXEC ideal-int
+pkg syscall (netbsd-arm-cgo), const PROT_NONE = 0
+pkg syscall (netbsd-arm-cgo), const PROT_NONE ideal-int
+pkg syscall (netbsd-arm-cgo), const PROT_READ = 1
+pkg syscall (netbsd-arm-cgo), const PROT_READ ideal-int
+pkg syscall (netbsd-arm-cgo), const PROT_WRITE = 2
+pkg syscall (netbsd-arm-cgo), const PROT_WRITE ideal-int
+pkg syscall (netbsd-arm-cgo), const SizeofIfData = 136
+pkg syscall (netbsd-arm-cgo), func Fchflags(int, int) error
+pkg syscall (netbsd-arm-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (netbsd-arm-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (netbsd-arm-cgo), type Kevent_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_1 [4]uint8
+pkg syscall (netbsd-arm-cgo), type Stat_t struct, Pad_cgo_2 [4]uint8
+pkg syscall (netbsd-arm-cgo), type Termios struct
+pkg syscall (netbsd-arm-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (netbsd-arm-cgo), type Termios struct, Cflag uint32
+pkg syscall (netbsd-arm-cgo), type Termios struct, Iflag uint32
+pkg syscall (netbsd-arm-cgo), type Termios struct, Ispeed int32
+pkg syscall (netbsd-arm-cgo), type Termios struct, Lflag uint32
+pkg syscall (netbsd-arm-cgo), type Termios struct, Oflag uint32
+pkg syscall (netbsd-arm-cgo), type Termios struct, Ospeed int32
+pkg syscall (netbsd-arm-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
+pkg syscall (netbsd-arm-cgo), type Timeval struct, Pad_cgo_0 [4]uint8
+pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (openbsd-386), const IPPROTO_DIVERT_INIT = 2
+pkg syscall (openbsd-386), const IPPROTO_DIVERT_INIT ideal-int
+pkg syscall (openbsd-386), const IPPROTO_DIVERT_RESP = 1
+pkg syscall (openbsd-386), const IPPROTO_DIVERT_RESP ideal-int
+pkg syscall (openbsd-386), const IPV6_RECVDSTPORT = 64
+pkg syscall (openbsd-386), const IPV6_RECVDSTPORT ideal-int
+pkg syscall (openbsd-386), const IP_DIVERTFL = 4130
+pkg syscall (openbsd-386), const IP_DIVERTFL ideal-int
+pkg syscall (openbsd-386), const MADV_DONTNEED = 4
+pkg syscall (openbsd-386), const MADV_DONTNEED ideal-int
+pkg syscall (openbsd-386), const MADV_FREE = 6
+pkg syscall (openbsd-386), const MADV_FREE ideal-int
+pkg syscall (openbsd-386), const MADV_NORMAL = 0
+pkg syscall (openbsd-386), const MADV_NORMAL ideal-int
+pkg syscall (openbsd-386), const MADV_RANDOM = 1
+pkg syscall (openbsd-386), const MADV_RANDOM ideal-int
+pkg syscall (openbsd-386), const MADV_SEQUENTIAL = 2
+pkg syscall (openbsd-386), const MADV_SEQUENTIAL ideal-int
+pkg syscall (openbsd-386), const MADV_SPACEAVAIL = 5
+pkg syscall (openbsd-386), const MADV_SPACEAVAIL ideal-int
+pkg syscall (openbsd-386), const MADV_WILLNEED = 3
+pkg syscall (openbsd-386), const MADV_WILLNEED ideal-int
+pkg syscall (openbsd-386), const MAP_ANON = 4096
+pkg syscall (openbsd-386), const MAP_ANON ideal-int
+pkg syscall (openbsd-386), const MAP_COPY = 4
+pkg syscall (openbsd-386), const MAP_COPY ideal-int
+pkg syscall (openbsd-386), const MAP_FILE = 0
+pkg syscall (openbsd-386), const MAP_FILE ideal-int
+pkg syscall (openbsd-386), const MAP_FIXED = 16
+pkg syscall (openbsd-386), const MAP_FIXED ideal-int
+pkg syscall (openbsd-386), const MAP_FLAGMASK = 8183
+pkg syscall (openbsd-386), const MAP_FLAGMASK ideal-int
+pkg syscall (openbsd-386), const MAP_HASSEMAPHORE = 512
+pkg syscall (openbsd-386), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (openbsd-386), const MAP_INHERIT = 128
+pkg syscall (openbsd-386), const MAP_INHERIT ideal-int
+pkg syscall (openbsd-386), const MAP_INHERIT_COPY = 1
+pkg syscall (openbsd-386), const MAP_INHERIT_COPY ideal-int
+pkg syscall (openbsd-386), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (openbsd-386), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (openbsd-386), const MAP_INHERIT_NONE = 2
+pkg syscall (openbsd-386), const MAP_INHERIT_NONE ideal-int
+pkg syscall (openbsd-386), const MAP_INHERIT_SHARE = 0
+pkg syscall (openbsd-386), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (openbsd-386), const MAP_NOEXTEND = 256
+pkg syscall (openbsd-386), const MAP_NOEXTEND ideal-int
+pkg syscall (openbsd-386), const MAP_NORESERVE = 64
+pkg syscall (openbsd-386), const MAP_NORESERVE ideal-int
+pkg syscall (openbsd-386), const MAP_PRIVATE = 2
+pkg syscall (openbsd-386), const MAP_PRIVATE ideal-int
+pkg syscall (openbsd-386), const MAP_RENAME = 32
+pkg syscall (openbsd-386), const MAP_RENAME ideal-int
+pkg syscall (openbsd-386), const MAP_SHARED = 1
+pkg syscall (openbsd-386), const MAP_SHARED ideal-int
+pkg syscall (openbsd-386), const MAP_TRYFIXED = 1024
+pkg syscall (openbsd-386), const MAP_TRYFIXED ideal-int
+pkg syscall (openbsd-386), const MCL_CURRENT = 1
+pkg syscall (openbsd-386), const MCL_CURRENT ideal-int
+pkg syscall (openbsd-386), const MCL_FUTURE = 2
+pkg syscall (openbsd-386), const MCL_FUTURE ideal-int
+pkg syscall (openbsd-386), const MS_ASYNC = 1
+pkg syscall (openbsd-386), const MS_ASYNC ideal-int
+pkg syscall (openbsd-386), const MS_INVALIDATE = 4
+pkg syscall (openbsd-386), const MS_INVALIDATE ideal-int
+pkg syscall (openbsd-386), const MS_SYNC = 2
+pkg syscall (openbsd-386), const MS_SYNC ideal-int
+pkg syscall (openbsd-386), const PROT_EXEC = 4
+pkg syscall (openbsd-386), const PROT_EXEC ideal-int
+pkg syscall (openbsd-386), const PROT_NONE = 0
+pkg syscall (openbsd-386), const PROT_NONE ideal-int
+pkg syscall (openbsd-386), const PROT_READ = 1
+pkg syscall (openbsd-386), const PROT_READ ideal-int
+pkg syscall (openbsd-386), const PROT_WRITE = 2
+pkg syscall (openbsd-386), const PROT_WRITE ideal-int
+pkg syscall (openbsd-386), const RTF_FMASK = 1112072
+pkg syscall (openbsd-386), const RTM_VERSION = 5
+pkg syscall (openbsd-386), const SIOCBRDGDADDR = 2166909255
+pkg syscall (openbsd-386), const SIOCBRDGGPARAM = 3225184600
+pkg syscall (openbsd-386), const SIOCBRDGSADDR = 3240651076
+pkg syscall (openbsd-386), const SIOCGETVLAN = 3223349648
+pkg syscall (openbsd-386), const SIOCGETVLAN ideal-int
+pkg syscall (openbsd-386), const SIOCGIFHARDMTU = 3223349669
+pkg syscall (openbsd-386), const SIOCGIFHARDMTU ideal-int
+pkg syscall (openbsd-386), const SIOCGLIFPHYTTL = 3223349673
+pkg syscall (openbsd-386), const SIOCGLIFPHYTTL ideal-int
+pkg syscall (openbsd-386), const SIOCGSPPPPARAMS = 3223349652
+pkg syscall (openbsd-386), const SIOCGSPPPPARAMS ideal-int
+pkg syscall (openbsd-386), const SIOCGVNETID = 3223349671
+pkg syscall (openbsd-386), const SIOCGVNETID ideal-int
+pkg syscall (openbsd-386), const SIOCSETVLAN = 2149607823
+pkg syscall (openbsd-386), const SIOCSETVLAN ideal-int
+pkg syscall (openbsd-386), const SIOCSLIFPHYTTL = 2149607848
+pkg syscall (openbsd-386), const SIOCSLIFPHYTTL ideal-int
+pkg syscall (openbsd-386), const SIOCSSPPPPARAMS = 2149607827
+pkg syscall (openbsd-386), const SIOCSSPPPPARAMS ideal-int
+pkg syscall (openbsd-386), const SIOCSVNETID = 2149607846
+pkg syscall (openbsd-386), const SIOCSVNETID ideal-int
+pkg syscall (openbsd-386), const SYS_CLOCK_GETRES = 89
+pkg syscall (openbsd-386), const SYS_CLOCK_GETTIME = 87
+pkg syscall (openbsd-386), const SYS_CLOCK_SETTIME = 88
+pkg syscall (openbsd-386), const SYS_FHSTATFS = 65
+pkg syscall (openbsd-386), const SYS_FSTAT = 53
+pkg syscall (openbsd-386), const SYS_FSTATAT = 42
+pkg syscall (openbsd-386), const SYS_FSTATFS = 64
+pkg syscall (openbsd-386), const SYS_FUTIMENS = 85
+pkg syscall (openbsd-386), const SYS_FUTIMES = 77
+pkg syscall (openbsd-386), const SYS_GETDENTS = 99
+pkg syscall (openbsd-386), const SYS_GETDENTS ideal-int
+pkg syscall (openbsd-386), const SYS_GETFSSTAT = 62
+pkg syscall (openbsd-386), const SYS_GETITIMER = 70
+pkg syscall (openbsd-386), const SYS_GETRUSAGE = 19
+pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 67
+pkg syscall (openbsd-386), const SYS_KEVENT = 72
+pkg syscall (openbsd-386), const SYS_LSTAT = 40
+pkg syscall (openbsd-386), const SYS_NANOSLEEP = 91
+pkg syscall (openbsd-386), const SYS_PPOLL = 109
+pkg syscall (openbsd-386), const SYS_PPOLL ideal-int
+pkg syscall (openbsd-386), const SYS_PSELECT = 110
+pkg syscall (openbsd-386), const SYS_PSELECT ideal-int
+pkg syscall (openbsd-386), const SYS_SELECT = 71
+pkg syscall (openbsd-386), const SYS_SETITIMER = 69
+pkg syscall (openbsd-386), const SYS_SETTIMEOFDAY = 68
+pkg syscall (openbsd-386), const SYS_STAT = 38
+pkg syscall (openbsd-386), const SYS_STATFS = 63
+pkg syscall (openbsd-386), const SYS_UTIMENSAT = 84
+pkg syscall (openbsd-386), const SYS_UTIMES = 76
+pkg syscall (openbsd-386), const SYS_UTRACE = 209
+pkg syscall (openbsd-386), const SYS_UTRACE ideal-int
+pkg syscall (openbsd-386), const SYS_WAIT4 = 11
+pkg syscall (openbsd-386), const SYS___THRSLEEP = 94
+pkg syscall (openbsd-386), const SizeofIfData = 212
+pkg syscall (openbsd-386), const SizeofIfMsghdr = 236
+pkg syscall (openbsd-386), const SizeofRtMetrics = 56
+pkg syscall (openbsd-386), const SizeofRtMsghdr = 96
+pkg syscall (openbsd-386), const TCP_NOPUSH = 16
+pkg syscall (openbsd-386), const TCP_NOPUSH ideal-int
+pkg syscall (openbsd-386), const TIOCGSID = 1074033763
+pkg syscall (openbsd-386), const TIOCGSID ideal-int
+pkg syscall (openbsd-386), const TIOCGTSTAMP = 1074558043
+pkg syscall (openbsd-386), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (openbsd-386), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (openbsd-386), type Dirent struct, Fileno uint64
+pkg syscall (openbsd-386), type Dirent struct, Off int64
+pkg syscall (openbsd-386), type Dirent struct, X__d_padding [4]uint8
+pkg syscall (openbsd-386), type FdSet struct, Bits [32]uint32
+pkg syscall (openbsd-386), type Kevent_t struct, Data int64
+pkg syscall (openbsd-386), type Mclpool struct, Grown int32
+pkg syscall (openbsd-386), type RtMetrics struct, Expire int64
+pkg syscall (openbsd-386), type RtMetrics struct, Pad uint32
+pkg syscall (openbsd-386), type Stat_t struct, Ino uint64
+pkg syscall (openbsd-386), type Statfs_t struct, F_ctime uint64
+pkg syscall (openbsd-386), type Statfs_t struct, F_mntfromspec [90]int8
+pkg syscall (openbsd-386), type Statfs_t struct, Pad_cgo_0 [2]uint8
+pkg syscall (openbsd-386), type Termios struct
+pkg syscall (openbsd-386), type Termios struct, Cc [20]uint8
+pkg syscall (openbsd-386), type Termios struct, Cflag uint32
+pkg syscall (openbsd-386), type Termios struct, Iflag uint32
+pkg syscall (openbsd-386), type Termios struct, Ispeed int32
+pkg syscall (openbsd-386), type Termios struct, Lflag uint32
+pkg syscall (openbsd-386), type Termios struct, Oflag uint32
+pkg syscall (openbsd-386), type Termios struct, Ospeed int32
+pkg syscall (openbsd-386), type Timespec struct, Sec int64
+pkg syscall (openbsd-386), type Timeval struct, Sec int64
+pkg syscall (openbsd-386-cgo), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (openbsd-386-cgo), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_INIT = 2
+pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_INIT ideal-int
+pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_RESP = 1
+pkg syscall (openbsd-386-cgo), const IPPROTO_DIVERT_RESP ideal-int
+pkg syscall (openbsd-386-cgo), const IPV6_RECVDSTPORT = 64
+pkg syscall (openbsd-386-cgo), const IPV6_RECVDSTPORT ideal-int
+pkg syscall (openbsd-386-cgo), const IP_DIVERTFL = 4130
+pkg syscall (openbsd-386-cgo), const IP_DIVERTFL ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_DONTNEED = 4
+pkg syscall (openbsd-386-cgo), const MADV_DONTNEED ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_FREE = 6
+pkg syscall (openbsd-386-cgo), const MADV_FREE ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_NORMAL = 0
+pkg syscall (openbsd-386-cgo), const MADV_NORMAL ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_RANDOM = 1
+pkg syscall (openbsd-386-cgo), const MADV_RANDOM ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_SEQUENTIAL = 2
+pkg syscall (openbsd-386-cgo), const MADV_SEQUENTIAL ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_SPACEAVAIL = 5
+pkg syscall (openbsd-386-cgo), const MADV_SPACEAVAIL ideal-int
+pkg syscall (openbsd-386-cgo), const MADV_WILLNEED = 3
+pkg syscall (openbsd-386-cgo), const MADV_WILLNEED ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_ANON = 4096
+pkg syscall (openbsd-386-cgo), const MAP_ANON ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_COPY = 4
+pkg syscall (openbsd-386-cgo), const MAP_COPY ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_FILE = 0
+pkg syscall (openbsd-386-cgo), const MAP_FILE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_FIXED = 16
+pkg syscall (openbsd-386-cgo), const MAP_FIXED ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_FLAGMASK = 8183
+pkg syscall (openbsd-386-cgo), const MAP_FLAGMASK ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_HASSEMAPHORE = 512
+pkg syscall (openbsd-386-cgo), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT = 128
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_COPY = 1
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_COPY ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_NONE = 2
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_NONE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_SHARE = 0
+pkg syscall (openbsd-386-cgo), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_NOEXTEND = 256
+pkg syscall (openbsd-386-cgo), const MAP_NOEXTEND ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_NORESERVE = 64
+pkg syscall (openbsd-386-cgo), const MAP_NORESERVE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_PRIVATE = 2
+pkg syscall (openbsd-386-cgo), const MAP_PRIVATE ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_RENAME = 32
+pkg syscall (openbsd-386-cgo), const MAP_RENAME ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_SHARED = 1
+pkg syscall (openbsd-386-cgo), const MAP_SHARED ideal-int
+pkg syscall (openbsd-386-cgo), const MAP_TRYFIXED = 1024
+pkg syscall (openbsd-386-cgo), const MAP_TRYFIXED ideal-int
+pkg syscall (openbsd-386-cgo), const MCL_CURRENT = 1
+pkg syscall (openbsd-386-cgo), const MCL_CURRENT ideal-int
+pkg syscall (openbsd-386-cgo), const MCL_FUTURE = 2
+pkg syscall (openbsd-386-cgo), const MCL_FUTURE ideal-int
+pkg syscall (openbsd-386-cgo), const MS_ASYNC = 1
+pkg syscall (openbsd-386-cgo), const MS_ASYNC ideal-int
+pkg syscall (openbsd-386-cgo), const MS_INVALIDATE = 4
+pkg syscall (openbsd-386-cgo), const MS_INVALIDATE ideal-int
+pkg syscall (openbsd-386-cgo), const MS_SYNC = 2
+pkg syscall (openbsd-386-cgo), const MS_SYNC ideal-int
+pkg syscall (openbsd-386-cgo), const PROT_EXEC = 4
+pkg syscall (openbsd-386-cgo), const PROT_EXEC ideal-int
+pkg syscall (openbsd-386-cgo), const PROT_NONE = 0
+pkg syscall (openbsd-386-cgo), const PROT_NONE ideal-int
+pkg syscall (openbsd-386-cgo), const PROT_READ = 1
+pkg syscall (openbsd-386-cgo), const PROT_READ ideal-int
+pkg syscall (openbsd-386-cgo), const PROT_WRITE = 2
+pkg syscall (openbsd-386-cgo), const PROT_WRITE ideal-int
+pkg syscall (openbsd-386-cgo), const RTF_FMASK = 1112072
+pkg syscall (openbsd-386-cgo), const RTM_VERSION = 5
+pkg syscall (openbsd-386-cgo), const SIOCBRDGDADDR = 2166909255
+pkg syscall (openbsd-386-cgo), const SIOCBRDGGPARAM = 3225184600
+pkg syscall (openbsd-386-cgo), const SIOCBRDGSADDR = 3240651076
+pkg syscall (openbsd-386-cgo), const SIOCGETVLAN = 3223349648
+pkg syscall (openbsd-386-cgo), const SIOCGETVLAN ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCGIFHARDMTU = 3223349669
+pkg syscall (openbsd-386-cgo), const SIOCGIFHARDMTU ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCGLIFPHYTTL = 3223349673
+pkg syscall (openbsd-386-cgo), const SIOCGLIFPHYTTL ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCGSPPPPARAMS = 3223349652
+pkg syscall (openbsd-386-cgo), const SIOCGSPPPPARAMS ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCGVNETID = 3223349671
+pkg syscall (openbsd-386-cgo), const SIOCGVNETID ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCSETVLAN = 2149607823
+pkg syscall (openbsd-386-cgo), const SIOCSETVLAN ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCSLIFPHYTTL = 2149607848
+pkg syscall (openbsd-386-cgo), const SIOCSLIFPHYTTL ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCSSPPPPARAMS = 2149607827
+pkg syscall (openbsd-386-cgo), const SIOCSSPPPPARAMS ideal-int
+pkg syscall (openbsd-386-cgo), const SIOCSVNETID = 2149607846
+pkg syscall (openbsd-386-cgo), const SIOCSVNETID ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETRES = 89
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_GETTIME = 87
+pkg syscall (openbsd-386-cgo), const SYS_CLOCK_SETTIME = 88
+pkg syscall (openbsd-386-cgo), const SYS_FHSTATFS = 65
+pkg syscall (openbsd-386-cgo), const SYS_FSTAT = 53
+pkg syscall (openbsd-386-cgo), const SYS_FSTATAT = 42
+pkg syscall (openbsd-386-cgo), const SYS_FSTATFS = 64
+pkg syscall (openbsd-386-cgo), const SYS_FUTIMENS = 85
+pkg syscall (openbsd-386-cgo), const SYS_FUTIMES = 77
+pkg syscall (openbsd-386-cgo), const SYS_GETDENTS = 99
+pkg syscall (openbsd-386-cgo), const SYS_GETDENTS ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_GETFSSTAT = 62
+pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 70
+pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 19
+pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 67
+pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 72
+pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 40
+pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 91
+pkg syscall (openbsd-386-cgo), const SYS_PPOLL = 109
+pkg syscall (openbsd-386-cgo), const SYS_PPOLL ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_PSELECT = 110
+pkg syscall (openbsd-386-cgo), const SYS_PSELECT ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_SELECT = 71
+pkg syscall (openbsd-386-cgo), const SYS_SETITIMER = 69
+pkg syscall (openbsd-386-cgo), const SYS_SETTIMEOFDAY = 68
+pkg syscall (openbsd-386-cgo), const SYS_STAT = 38
+pkg syscall (openbsd-386-cgo), const SYS_STATFS = 63
+pkg syscall (openbsd-386-cgo), const SYS_UTIMENSAT = 84
+pkg syscall (openbsd-386-cgo), const SYS_UTIMES = 76
+pkg syscall (openbsd-386-cgo), const SYS_UTRACE = 209
+pkg syscall (openbsd-386-cgo), const SYS_UTRACE ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_WAIT4 = 11
+pkg syscall (openbsd-386-cgo), const SYS___THRSLEEP = 94
+pkg syscall (openbsd-386-cgo), const SizeofIfData = 212
+pkg syscall (openbsd-386-cgo), const SizeofIfMsghdr = 236
+pkg syscall (openbsd-386-cgo), const SizeofRtMetrics = 56
+pkg syscall (openbsd-386-cgo), const SizeofRtMsghdr = 96
+pkg syscall (openbsd-386-cgo), const TCP_NOPUSH = 16
+pkg syscall (openbsd-386-cgo), const TCP_NOPUSH ideal-int
+pkg syscall (openbsd-386-cgo), const TIOCGSID = 1074033763
+pkg syscall (openbsd-386-cgo), const TIOCGSID ideal-int
+pkg syscall (openbsd-386-cgo), const TIOCGTSTAMP = 1074558043
+pkg syscall (openbsd-386-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (openbsd-386-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (openbsd-386-cgo), type Dirent struct, Fileno uint64
+pkg syscall (openbsd-386-cgo), type Dirent struct, Off int64
+pkg syscall (openbsd-386-cgo), type Dirent struct, X__d_padding [4]uint8
+pkg syscall (openbsd-386-cgo), type FdSet struct, Bits [32]uint32
+pkg syscall (openbsd-386-cgo), type Kevent_t struct, Data int64
+pkg syscall (openbsd-386-cgo), type Mclpool struct, Grown int32
+pkg syscall (openbsd-386-cgo), type RtMetrics struct, Expire int64
+pkg syscall (openbsd-386-cgo), type RtMetrics struct, Pad uint32
+pkg syscall (openbsd-386-cgo), type Stat_t struct, Ino uint64
+pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_ctime uint64
+pkg syscall (openbsd-386-cgo), type Statfs_t struct, F_mntfromspec [90]int8
+pkg syscall (openbsd-386-cgo), type Statfs_t struct, Pad_cgo_0 [2]uint8
+pkg syscall (openbsd-386-cgo), type Termios struct
+pkg syscall (openbsd-386-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (openbsd-386-cgo), type Termios struct, Cflag uint32
+pkg syscall (openbsd-386-cgo), type Termios struct, Iflag uint32
+pkg syscall (openbsd-386-cgo), type Termios struct, Ispeed int32
+pkg syscall (openbsd-386-cgo), type Termios struct, Lflag uint32
+pkg syscall (openbsd-386-cgo), type Termios struct, Oflag uint32
+pkg syscall (openbsd-386-cgo), type Termios struct, Ospeed int32
+pkg syscall (openbsd-386-cgo), type Timespec struct, Sec int64
+pkg syscall (openbsd-386-cgo), type Timeval struct, Sec int64
+pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_INIT = 2
+pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_INIT ideal-int
+pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_RESP = 1
+pkg syscall (openbsd-amd64), const IPPROTO_DIVERT_RESP ideal-int
+pkg syscall (openbsd-amd64), const IPV6_RECVDSTPORT = 64
+pkg syscall (openbsd-amd64), const IPV6_RECVDSTPORT ideal-int
+pkg syscall (openbsd-amd64), const IP_DIVERTFL = 4130
+pkg syscall (openbsd-amd64), const IP_DIVERTFL ideal-int
+pkg syscall (openbsd-amd64), const MADV_DONTNEED = 4
+pkg syscall (openbsd-amd64), const MADV_DONTNEED ideal-int
+pkg syscall (openbsd-amd64), const MADV_FREE = 6
+pkg syscall (openbsd-amd64), const MADV_FREE ideal-int
+pkg syscall (openbsd-amd64), const MADV_NORMAL = 0
+pkg syscall (openbsd-amd64), const MADV_NORMAL ideal-int
+pkg syscall (openbsd-amd64), const MADV_RANDOM = 1
+pkg syscall (openbsd-amd64), const MADV_RANDOM ideal-int
+pkg syscall (openbsd-amd64), const MADV_SEQUENTIAL = 2
+pkg syscall (openbsd-amd64), const MADV_SEQUENTIAL ideal-int
+pkg syscall (openbsd-amd64), const MADV_SPACEAVAIL = 5
+pkg syscall (openbsd-amd64), const MADV_SPACEAVAIL ideal-int
+pkg syscall (openbsd-amd64), const MADV_WILLNEED = 3
+pkg syscall (openbsd-amd64), const MADV_WILLNEED ideal-int
+pkg syscall (openbsd-amd64), const MAP_ANON = 4096
+pkg syscall (openbsd-amd64), const MAP_ANON ideal-int
+pkg syscall (openbsd-amd64), const MAP_COPY = 4
+pkg syscall (openbsd-amd64), const MAP_COPY ideal-int
+pkg syscall (openbsd-amd64), const MAP_FILE = 0
+pkg syscall (openbsd-amd64), const MAP_FILE ideal-int
+pkg syscall (openbsd-amd64), const MAP_FIXED = 16
+pkg syscall (openbsd-amd64), const MAP_FIXED ideal-int
+pkg syscall (openbsd-amd64), const MAP_FLAGMASK = 8183
+pkg syscall (openbsd-amd64), const MAP_FLAGMASK ideal-int
+pkg syscall (openbsd-amd64), const MAP_HASSEMAPHORE = 512
+pkg syscall (openbsd-amd64), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (openbsd-amd64), const MAP_INHERIT = 128
+pkg syscall (openbsd-amd64), const MAP_INHERIT ideal-int
+pkg syscall (openbsd-amd64), const MAP_INHERIT_COPY = 1
+pkg syscall (openbsd-amd64), const MAP_INHERIT_COPY ideal-int
+pkg syscall (openbsd-amd64), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (openbsd-amd64), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (openbsd-amd64), const MAP_INHERIT_NONE = 2
+pkg syscall (openbsd-amd64), const MAP_INHERIT_NONE ideal-int
+pkg syscall (openbsd-amd64), const MAP_INHERIT_SHARE = 0
+pkg syscall (openbsd-amd64), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (openbsd-amd64), const MAP_NOEXTEND = 256
+pkg syscall (openbsd-amd64), const MAP_NOEXTEND ideal-int
+pkg syscall (openbsd-amd64), const MAP_NORESERVE = 64
+pkg syscall (openbsd-amd64), const MAP_NORESERVE ideal-int
+pkg syscall (openbsd-amd64), const MAP_PRIVATE = 2
+pkg syscall (openbsd-amd64), const MAP_PRIVATE ideal-int
+pkg syscall (openbsd-amd64), const MAP_RENAME = 32
+pkg syscall (openbsd-amd64), const MAP_RENAME ideal-int
+pkg syscall (openbsd-amd64), const MAP_SHARED = 1
+pkg syscall (openbsd-amd64), const MAP_SHARED ideal-int
+pkg syscall (openbsd-amd64), const MAP_TRYFIXED = 1024
+pkg syscall (openbsd-amd64), const MAP_TRYFIXED ideal-int
+pkg syscall (openbsd-amd64), const MCL_CURRENT = 1
+pkg syscall (openbsd-amd64), const MCL_CURRENT ideal-int
+pkg syscall (openbsd-amd64), const MCL_FUTURE = 2
+pkg syscall (openbsd-amd64), const MCL_FUTURE ideal-int
+pkg syscall (openbsd-amd64), const MS_ASYNC = 1
+pkg syscall (openbsd-amd64), const MS_ASYNC ideal-int
+pkg syscall (openbsd-amd64), const MS_INVALIDATE = 4
+pkg syscall (openbsd-amd64), const MS_INVALIDATE ideal-int
+pkg syscall (openbsd-amd64), const MS_SYNC = 2
+pkg syscall (openbsd-amd64), const MS_SYNC ideal-int
+pkg syscall (openbsd-amd64), const PROT_EXEC = 4
+pkg syscall (openbsd-amd64), const PROT_EXEC ideal-int
+pkg syscall (openbsd-amd64), const PROT_NONE = 0
+pkg syscall (openbsd-amd64), const PROT_NONE ideal-int
+pkg syscall (openbsd-amd64), const PROT_READ = 1
+pkg syscall (openbsd-amd64), const PROT_READ ideal-int
+pkg syscall (openbsd-amd64), const PROT_WRITE = 2
+pkg syscall (openbsd-amd64), const PROT_WRITE ideal-int
+pkg syscall (openbsd-amd64), const RTF_FMASK = 1112072
+pkg syscall (openbsd-amd64), const RTM_VERSION = 5
+pkg syscall (openbsd-amd64), const SIOCBRDGDADDR = 2166909255
+pkg syscall (openbsd-amd64), const SIOCBRDGSADDR = 3240651076
+pkg syscall (openbsd-amd64), const SIOCGETVLAN = 3223349648
+pkg syscall (openbsd-amd64), const SIOCGETVLAN ideal-int
+pkg syscall (openbsd-amd64), const SIOCGIFHARDMTU = 3223349669
+pkg syscall (openbsd-amd64), const SIOCGIFHARDMTU ideal-int
+pkg syscall (openbsd-amd64), const SIOCGLIFPHYTTL = 3223349673
+pkg syscall (openbsd-amd64), const SIOCGLIFPHYTTL ideal-int
+pkg syscall (openbsd-amd64), const SIOCGSPPPPARAMS = 3223349652
+pkg syscall (openbsd-amd64), const SIOCGSPPPPARAMS ideal-int
+pkg syscall (openbsd-amd64), const SIOCGVNETID = 3223349671
+pkg syscall (openbsd-amd64), const SIOCGVNETID ideal-int
+pkg syscall (openbsd-amd64), const SIOCSETVLAN = 2149607823
+pkg syscall (openbsd-amd64), const SIOCSETVLAN ideal-int
+pkg syscall (openbsd-amd64), const SIOCSLIFPHYTTL = 2149607848
+pkg syscall (openbsd-amd64), const SIOCSLIFPHYTTL ideal-int
+pkg syscall (openbsd-amd64), const SIOCSSPPPPARAMS = 2149607827
+pkg syscall (openbsd-amd64), const SIOCSSPPPPARAMS ideal-int
+pkg syscall (openbsd-amd64), const SIOCSVNETID = 2149607846
+pkg syscall (openbsd-amd64), const SIOCSVNETID ideal-int
+pkg syscall (openbsd-amd64), const SYS_CLOCK_GETRES = 89
+pkg syscall (openbsd-amd64), const SYS_CLOCK_GETTIME = 87
+pkg syscall (openbsd-amd64), const SYS_CLOCK_SETTIME = 88
+pkg syscall (openbsd-amd64), const SYS_FHSTATFS = 65
+pkg syscall (openbsd-amd64), const SYS_FSTAT = 53
+pkg syscall (openbsd-amd64), const SYS_FSTATAT = 42
+pkg syscall (openbsd-amd64), const SYS_FSTATFS = 64
+pkg syscall (openbsd-amd64), const SYS_FUTIMENS = 85
+pkg syscall (openbsd-amd64), const SYS_FUTIMES = 77
+pkg syscall (openbsd-amd64), const SYS_GETDENTS = 99
+pkg syscall (openbsd-amd64), const SYS_GETDENTS ideal-int
+pkg syscall (openbsd-amd64), const SYS_GETFSSTAT = 62
+pkg syscall (openbsd-amd64), const SYS_GETITIMER = 70
+pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 19
+pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 67
+pkg syscall (openbsd-amd64), const SYS_KEVENT = 72
+pkg syscall (openbsd-amd64), const SYS_LSTAT = 40
+pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 91
+pkg syscall (openbsd-amd64), const SYS_PPOLL = 109
+pkg syscall (openbsd-amd64), const SYS_PPOLL ideal-int
+pkg syscall (openbsd-amd64), const SYS_PSELECT = 110
+pkg syscall (openbsd-amd64), const SYS_PSELECT ideal-int
+pkg syscall (openbsd-amd64), const SYS_SELECT = 71
+pkg syscall (openbsd-amd64), const SYS_SETITIMER = 69
+pkg syscall (openbsd-amd64), const SYS_SETTIMEOFDAY = 68
+pkg syscall (openbsd-amd64), const SYS_STAT = 38
+pkg syscall (openbsd-amd64), const SYS_STATFS = 63
+pkg syscall (openbsd-amd64), const SYS_UTIMENSAT = 84
+pkg syscall (openbsd-amd64), const SYS_UTIMES = 76
+pkg syscall (openbsd-amd64), const SYS_UTRACE = 209
+pkg syscall (openbsd-amd64), const SYS_UTRACE ideal-int
+pkg syscall (openbsd-amd64), const SYS_WAIT4 = 11
+pkg syscall (openbsd-amd64), const SYS___THRSLEEP = 94
+pkg syscall (openbsd-amd64), const SizeofRtMetrics = 56
+pkg syscall (openbsd-amd64), const SizeofRtMsghdr = 96
+pkg syscall (openbsd-amd64), const TCP_NOPUSH = 16
+pkg syscall (openbsd-amd64), const TCP_NOPUSH ideal-int
+pkg syscall (openbsd-amd64), const TIOCGSID = 1074033763
+pkg syscall (openbsd-amd64), const TIOCGSID ideal-int
+pkg syscall (openbsd-amd64), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (openbsd-amd64), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (openbsd-amd64), type Dirent struct, Fileno uint64
+pkg syscall (openbsd-amd64), type Dirent struct, Off int64
+pkg syscall (openbsd-amd64), type Dirent struct, X__d_padding [4]uint8
+pkg syscall (openbsd-amd64), type FdSet struct, Bits [32]uint32
+pkg syscall (openbsd-amd64), type Kevent_t struct, Data int64
+pkg syscall (openbsd-amd64), type Kevent_t struct, Ident uint64
+pkg syscall (openbsd-amd64), type Mclpool struct, Grown int32
+pkg syscall (openbsd-amd64), type RtMetrics struct, Expire int64
+pkg syscall (openbsd-amd64), type RtMetrics struct, Pad uint32
+pkg syscall (openbsd-amd64), type Stat_t struct, Ino uint64
+pkg syscall (openbsd-amd64), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (openbsd-amd64), type Statfs_t struct, F_ctime uint64
+pkg syscall (openbsd-amd64), type Statfs_t struct, F_mntfromspec [90]int8
+pkg syscall (openbsd-amd64), type Statfs_t struct, Pad_cgo_1 [2]uint8
+pkg syscall (openbsd-amd64), type Termios struct
+pkg syscall (openbsd-amd64), type Termios struct, Cc [20]uint8
+pkg syscall (openbsd-amd64), type Termios struct, Cflag uint32
+pkg syscall (openbsd-amd64), type Termios struct, Iflag uint32
+pkg syscall (openbsd-amd64), type Termios struct, Ispeed int32
+pkg syscall (openbsd-amd64), type Termios struct, Lflag uint32
+pkg syscall (openbsd-amd64), type Termios struct, Oflag uint32
+pkg syscall (openbsd-amd64), type Termios struct, Ospeed int32
+pkg syscall (openbsd-amd64), type Timespec struct, Sec int64
+pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_INIT = 2
+pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_INIT ideal-int
+pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_RESP = 1
+pkg syscall (openbsd-amd64-cgo), const IPPROTO_DIVERT_RESP ideal-int
+pkg syscall (openbsd-amd64-cgo), const IPV6_RECVDSTPORT = 64
+pkg syscall (openbsd-amd64-cgo), const IPV6_RECVDSTPORT ideal-int
+pkg syscall (openbsd-amd64-cgo), const IP_DIVERTFL = 4130
+pkg syscall (openbsd-amd64-cgo), const IP_DIVERTFL ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_DONTNEED = 4
+pkg syscall (openbsd-amd64-cgo), const MADV_DONTNEED ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_FREE = 6
+pkg syscall (openbsd-amd64-cgo), const MADV_FREE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_NORMAL = 0
+pkg syscall (openbsd-amd64-cgo), const MADV_NORMAL ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_RANDOM = 1
+pkg syscall (openbsd-amd64-cgo), const MADV_RANDOM ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_SEQUENTIAL = 2
+pkg syscall (openbsd-amd64-cgo), const MADV_SEQUENTIAL ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_SPACEAVAIL = 5
+pkg syscall (openbsd-amd64-cgo), const MADV_SPACEAVAIL ideal-int
+pkg syscall (openbsd-amd64-cgo), const MADV_WILLNEED = 3
+pkg syscall (openbsd-amd64-cgo), const MADV_WILLNEED ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_ANON = 4096
+pkg syscall (openbsd-amd64-cgo), const MAP_ANON ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_COPY = 4
+pkg syscall (openbsd-amd64-cgo), const MAP_COPY ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_FILE = 0
+pkg syscall (openbsd-amd64-cgo), const MAP_FILE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_FIXED = 16
+pkg syscall (openbsd-amd64-cgo), const MAP_FIXED ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_FLAGMASK = 8183
+pkg syscall (openbsd-amd64-cgo), const MAP_FLAGMASK ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_HASSEMAPHORE = 512
+pkg syscall (openbsd-amd64-cgo), const MAP_HASSEMAPHORE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT = 128
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_COPY = 1
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_COPY ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY = 3
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_DONATE_COPY ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_NONE = 2
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_NONE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_SHARE = 0
+pkg syscall (openbsd-amd64-cgo), const MAP_INHERIT_SHARE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_NOEXTEND = 256
+pkg syscall (openbsd-amd64-cgo), const MAP_NOEXTEND ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_NORESERVE = 64
+pkg syscall (openbsd-amd64-cgo), const MAP_NORESERVE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_PRIVATE = 2
+pkg syscall (openbsd-amd64-cgo), const MAP_PRIVATE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_RENAME = 32
+pkg syscall (openbsd-amd64-cgo), const MAP_RENAME ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_SHARED = 1
+pkg syscall (openbsd-amd64-cgo), const MAP_SHARED ideal-int
+pkg syscall (openbsd-amd64-cgo), const MAP_TRYFIXED = 1024
+pkg syscall (openbsd-amd64-cgo), const MAP_TRYFIXED ideal-int
+pkg syscall (openbsd-amd64-cgo), const MCL_CURRENT = 1
+pkg syscall (openbsd-amd64-cgo), const MCL_CURRENT ideal-int
+pkg syscall (openbsd-amd64-cgo), const MCL_FUTURE = 2
+pkg syscall (openbsd-amd64-cgo), const MCL_FUTURE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MS_ASYNC = 1
+pkg syscall (openbsd-amd64-cgo), const MS_ASYNC ideal-int
+pkg syscall (openbsd-amd64-cgo), const MS_INVALIDATE = 4
+pkg syscall (openbsd-amd64-cgo), const MS_INVALIDATE ideal-int
+pkg syscall (openbsd-amd64-cgo), const MS_SYNC = 2
+pkg syscall (openbsd-amd64-cgo), const MS_SYNC ideal-int
+pkg syscall (openbsd-amd64-cgo), const PROT_EXEC = 4
+pkg syscall (openbsd-amd64-cgo), const PROT_EXEC ideal-int
+pkg syscall (openbsd-amd64-cgo), const PROT_NONE = 0
+pkg syscall (openbsd-amd64-cgo), const PROT_NONE ideal-int
+pkg syscall (openbsd-amd64-cgo), const PROT_READ = 1
+pkg syscall (openbsd-amd64-cgo), const PROT_READ ideal-int
+pkg syscall (openbsd-amd64-cgo), const PROT_WRITE = 2
+pkg syscall (openbsd-amd64-cgo), const PROT_WRITE ideal-int
+pkg syscall (openbsd-amd64-cgo), const RTF_FMASK = 1112072
+pkg syscall (openbsd-amd64-cgo), const RTM_VERSION = 5
+pkg syscall (openbsd-amd64-cgo), const SIOCBRDGDADDR = 2166909255
+pkg syscall (openbsd-amd64-cgo), const SIOCBRDGSADDR = 3240651076
+pkg syscall (openbsd-amd64-cgo), const SIOCGETVLAN = 3223349648
+pkg syscall (openbsd-amd64-cgo), const SIOCGETVLAN ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCGIFHARDMTU = 3223349669
+pkg syscall (openbsd-amd64-cgo), const SIOCGIFHARDMTU ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCGLIFPHYTTL = 3223349673
+pkg syscall (openbsd-amd64-cgo), const SIOCGLIFPHYTTL ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCGSPPPPARAMS = 3223349652
+pkg syscall (openbsd-amd64-cgo), const SIOCGSPPPPARAMS ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCGVNETID = 3223349671
+pkg syscall (openbsd-amd64-cgo), const SIOCGVNETID ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCSETVLAN = 2149607823
+pkg syscall (openbsd-amd64-cgo), const SIOCSETVLAN ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCSLIFPHYTTL = 2149607848
+pkg syscall (openbsd-amd64-cgo), const SIOCSLIFPHYTTL ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCSSPPPPARAMS = 2149607827
+pkg syscall (openbsd-amd64-cgo), const SIOCSSPPPPARAMS ideal-int
+pkg syscall (openbsd-amd64-cgo), const SIOCSVNETID = 2149607846
+pkg syscall (openbsd-amd64-cgo), const SIOCSVNETID ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETRES = 89
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_GETTIME = 87
+pkg syscall (openbsd-amd64-cgo), const SYS_CLOCK_SETTIME = 88
+pkg syscall (openbsd-amd64-cgo), const SYS_FHSTATFS = 65
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTAT = 53
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTATAT = 42
+pkg syscall (openbsd-amd64-cgo), const SYS_FSTATFS = 64
+pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMENS = 85
+pkg syscall (openbsd-amd64-cgo), const SYS_FUTIMES = 77
+pkg syscall (openbsd-amd64-cgo), const SYS_GETDENTS = 99
+pkg syscall (openbsd-amd64-cgo), const SYS_GETDENTS ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_GETFSSTAT = 62
+pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 70
+pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 19
+pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 67
+pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 72
+pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 40
+pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 91
+pkg syscall (openbsd-amd64-cgo), const SYS_PPOLL = 109
+pkg syscall (openbsd-amd64-cgo), const SYS_PPOLL ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_PSELECT = 110
+pkg syscall (openbsd-amd64-cgo), const SYS_PSELECT ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 71
+pkg syscall (openbsd-amd64-cgo), const SYS_SETITIMER = 69
+pkg syscall (openbsd-amd64-cgo), const SYS_SETTIMEOFDAY = 68
+pkg syscall (openbsd-amd64-cgo), const SYS_STAT = 38
+pkg syscall (openbsd-amd64-cgo), const SYS_STATFS = 63
+pkg syscall (openbsd-amd64-cgo), const SYS_UTIMENSAT = 84
+pkg syscall (openbsd-amd64-cgo), const SYS_UTIMES = 76
+pkg syscall (openbsd-amd64-cgo), const SYS_UTRACE = 209
+pkg syscall (openbsd-amd64-cgo), const SYS_UTRACE ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_WAIT4 = 11
+pkg syscall (openbsd-amd64-cgo), const SYS___THRSLEEP = 94
+pkg syscall (openbsd-amd64-cgo), const SizeofRtMetrics = 56
+pkg syscall (openbsd-amd64-cgo), const SizeofRtMsghdr = 96
+pkg syscall (openbsd-amd64-cgo), const TCP_NOPUSH = 16
+pkg syscall (openbsd-amd64-cgo), const TCP_NOPUSH ideal-int
+pkg syscall (openbsd-amd64-cgo), const TIOCGSID = 1074033763
+pkg syscall (openbsd-amd64-cgo), const TIOCGSID ideal-int
+pkg syscall (openbsd-amd64-cgo), func FcntlFlock(uintptr, int, *Flock_t) error
+pkg syscall (openbsd-amd64-cgo), func SendmsgN(int, []uint8, []uint8, Sockaddr, int) (int, error)
+pkg syscall (openbsd-amd64-cgo), type Dirent struct, Fileno uint64
+pkg syscall (openbsd-amd64-cgo), type Dirent struct, Off int64
+pkg syscall (openbsd-amd64-cgo), type Dirent struct, X__d_padding [4]uint8
+pkg syscall (openbsd-amd64-cgo), type FdSet struct, Bits [32]uint32
+pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Data int64
+pkg syscall (openbsd-amd64-cgo), type Kevent_t struct, Ident uint64
+pkg syscall (openbsd-amd64-cgo), type Mclpool struct, Grown int32
+pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Expire int64
+pkg syscall (openbsd-amd64-cgo), type RtMetrics struct, Pad uint32
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Ino uint64
+pkg syscall (openbsd-amd64-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_ctime uint64
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_mntfromspec [90]int8
+pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [2]uint8
+pkg syscall (openbsd-amd64-cgo), type Termios struct
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Cc [20]uint8
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Cflag uint32
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Iflag uint32
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Ispeed int32
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Lflag uint32
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Oflag uint32
+pkg syscall (openbsd-amd64-cgo), type Termios struct, Ospeed int32
+pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int64
+pkg syscall (windows-386), const ERROR_MORE_DATA = 234
+pkg syscall (windows-386), const ERROR_MORE_DATA Errno
+pkg syscall (windows-386), const ERROR_NETNAME_DELETED = 64
+pkg syscall (windows-386), const ERROR_NETNAME_DELETED Errno
+pkg syscall (windows-386), const IOC_VENDOR = 402653184
+pkg syscall (windows-386), const IOC_VENDOR ideal-int
+pkg syscall (windows-386), const SIO_KEEPALIVE_VALS = 2550136836
+pkg syscall (windows-386), const SIO_KEEPALIVE_VALS ideal-int
+pkg syscall (windows-386), const WSAECONNRESET = 10054
+pkg syscall (windows-386), const WSAECONNRESET Errno
+pkg syscall (windows-386), func NewCallbackCDecl(interface{}) uintptr
+pkg syscall (windows-386), type TCPKeepalive struct
+pkg syscall (windows-386), type TCPKeepalive struct, Interval uint32
+pkg syscall (windows-386), type TCPKeepalive struct, OnOff uint32
+pkg syscall (windows-386), type TCPKeepalive struct, Time uint32
+pkg syscall (windows-amd64), const ERROR_MORE_DATA = 234
+pkg syscall (windows-amd64), const ERROR_MORE_DATA Errno
+pkg syscall (windows-amd64), const ERROR_NETNAME_DELETED = 64
+pkg syscall (windows-amd64), const ERROR_NETNAME_DELETED Errno
+pkg syscall (windows-amd64), const IOC_VENDOR = 402653184
+pkg syscall (windows-amd64), const IOC_VENDOR ideal-int
+pkg syscall (windows-amd64), const SIO_KEEPALIVE_VALS = 2550136836
+pkg syscall (windows-amd64), const SIO_KEEPALIVE_VALS ideal-int
+pkg syscall (windows-amd64), const WSAECONNRESET = 10054
+pkg syscall (windows-amd64), const WSAECONNRESET Errno
+pkg syscall (windows-amd64), func NewCallbackCDecl(interface{}) uintptr
+pkg syscall (windows-amd64), type TCPKeepalive struct
+pkg syscall (windows-amd64), type TCPKeepalive struct, Interval uint32
+pkg syscall (windows-amd64), type TCPKeepalive struct, OnOff uint32
+pkg syscall (windows-amd64), type TCPKeepalive struct, Time uint32
+pkg testing, method (*B) RunParallel(func(*PB))
+pkg testing, method (*B) SetParallelism(int)
+pkg testing, method (*PB) Next() bool
+pkg testing, type PB struct
+pkg unicode, const Version = "6.3.0"
diff --git a/api/next.txt b/api/next.txt
index e69de29bb..5e49b3f94 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -0,0 +1,117 @@
+pkg debug/goobj, const SBSS = 21
+pkg debug/goobj, const SBSS SymKind
+pkg debug/goobj, const SCONST = 31
+pkg debug/goobj, const SCONST SymKind
+pkg debug/goobj, const SDATA = 19
+pkg debug/goobj, const SDATA SymKind
+pkg debug/goobj, const SDYNIMPORT = 32
+pkg debug/goobj, const SDYNIMPORT SymKind
+pkg debug/goobj, const SELFROSECT = 12
+pkg debug/goobj, const SELFROSECT SymKind
+pkg debug/goobj, const SELFRXSECT = 2
+pkg debug/goobj, const SELFRXSECT SymKind
+pkg debug/goobj, const SELFSECT = 14
+pkg debug/goobj, const SELFSECT SymKind
+pkg debug/goobj, const SFILE = 29
+pkg debug/goobj, const SFILE SymKind
+pkg debug/goobj, const SFILEPATH = 30
+pkg debug/goobj, const SFILEPATH SymKind
+pkg debug/goobj, const SFUNCTAB = 8
+pkg debug/goobj, const SFUNCTAB SymKind
+pkg debug/goobj, const SGOFUNC = 6
+pkg debug/goobj, const SGOFUNC SymKind
+pkg debug/goobj, const SGOSTRING = 5
+pkg debug/goobj, const SGOSTRING SymKind
+pkg debug/goobj, const SHOSTOBJ = 33
+pkg debug/goobj, const SHOSTOBJ SymKind
+pkg debug/goobj, const SINITARR = 18
+pkg debug/goobj, const SINITARR SymKind
+pkg debug/goobj, const SMACHO = 15
+pkg debug/goobj, const SMACHO SymKind
+pkg debug/goobj, const SMACHOGOT = 16
+pkg debug/goobj, const SMACHOGOT SymKind
+pkg debug/goobj, const SMACHOINDIRECTGOT = 28
+pkg debug/goobj, const SMACHOINDIRECTGOT SymKind
+pkg debug/goobj, const SMACHOINDIRECTPLT = 27
+pkg debug/goobj, const SMACHOINDIRECTPLT SymKind
+pkg debug/goobj, const SMACHOPLT = 13
+pkg debug/goobj, const SMACHOPLT SymKind
+pkg debug/goobj, const SMACHOSYMSTR = 25
+pkg debug/goobj, const SMACHOSYMSTR SymKind
+pkg debug/goobj, const SMACHOSYMTAB = 26
+pkg debug/goobj, const SMACHOSYMTAB SymKind
+pkg debug/goobj, const SNOPTRBSS = 22
+pkg debug/goobj, const SNOPTRBSS SymKind
+pkg debug/goobj, const SNOPTRDATA = 17
+pkg debug/goobj, const SNOPTRDATA SymKind
+pkg debug/goobj, const SPCLNTAB = 11
+pkg debug/goobj, const SPCLNTAB SymKind
+pkg debug/goobj, const SRODATA = 7
+pkg debug/goobj, const SRODATA SymKind
+pkg debug/goobj, const SSTRING = 4
+pkg debug/goobj, const SSTRING SymKind
+pkg debug/goobj, const SSYMTAB = 10
+pkg debug/goobj, const SSYMTAB SymKind
+pkg debug/goobj, const STEXT = 1
+pkg debug/goobj, const STEXT SymKind
+pkg debug/goobj, const STLSBSS = 23
+pkg debug/goobj, const STLSBSS SymKind
+pkg debug/goobj, const STYPE = 3
+pkg debug/goobj, const STYPE SymKind
+pkg debug/goobj, const STYPELINK = 9
+pkg debug/goobj, const STYPELINK SymKind
+pkg debug/goobj, const SWINDOWS = 20
+pkg debug/goobj, const SWINDOWS SymKind
+pkg debug/goobj, const SXREF = 24
+pkg debug/goobj, const SXREF SymKind
+pkg debug/goobj, func Parse(io.ReadSeeker, string) (*Package, error)
+pkg debug/goobj, method (Sym) String() string
+pkg debug/goobj, method (SymID) String() string
+pkg debug/goobj, method (SymKind) String() string
+pkg debug/goobj, type Data struct
+pkg debug/goobj, type Data struct, Offset int64
+pkg debug/goobj, type Data struct, Size int64
+pkg debug/goobj, type Func struct
+pkg debug/goobj, type Func struct, Args int
+pkg debug/goobj, type Func struct, File []string
+pkg debug/goobj, type Func struct, Frame int
+pkg debug/goobj, type Func struct, FuncData []FuncData
+pkg debug/goobj, type Func struct, Leaf bool
+pkg debug/goobj, type Func struct, NoSplit bool
+pkg debug/goobj, type Func struct, PCData []Data
+pkg debug/goobj, type Func struct, PCFile Data
+pkg debug/goobj, type Func struct, PCLine Data
+pkg debug/goobj, type Func struct, PCSP Data
+pkg debug/goobj, type Func struct, Var []Var
+pkg debug/goobj, type FuncData struct
+pkg debug/goobj, type FuncData struct, Offset int64
+pkg debug/goobj, type FuncData struct, Sym SymID
+pkg debug/goobj, type Package struct
+pkg debug/goobj, type Package struct, ImportPath string
+pkg debug/goobj, type Package struct, Imports []string
+pkg debug/goobj, type Package struct, MaxVersion int
+pkg debug/goobj, type Package struct, Syms []*Sym
+pkg debug/goobj, type Reloc struct
+pkg debug/goobj, type Reloc struct, Add int
+pkg debug/goobj, type Reloc struct, Offset int
+pkg debug/goobj, type Reloc struct, Size int
+pkg debug/goobj, type Reloc struct, Sym SymID
+pkg debug/goobj, type Reloc struct, Type int
+pkg debug/goobj, type Sym struct
+pkg debug/goobj, type Sym struct, Data Data
+pkg debug/goobj, type Sym struct, DupOK bool
+pkg debug/goobj, type Sym struct, Func *Func
+pkg debug/goobj, type Sym struct, Kind SymKind
+pkg debug/goobj, type Sym struct, Reloc []Reloc
+pkg debug/goobj, type Sym struct, Size int
+pkg debug/goobj, type Sym struct, Type SymID
+pkg debug/goobj, type Sym struct, embedded SymID
+pkg debug/goobj, type SymID struct
+pkg debug/goobj, type SymID struct, Name string
+pkg debug/goobj, type SymID struct, Version int
+pkg debug/goobj, type SymKind int
+pkg debug/goobj, type Var struct
+pkg debug/goobj, type Var struct, Kind int
+pkg debug/goobj, type Var struct, Name string
+pkg debug/goobj, type Var struct, Offset int
+pkg debug/goobj, type Var struct, Type SymID
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644
index 23262da94..000000000
--- a/doc/Makefile
+++ /dev/null
@@ -1,32 +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.
-
-RAWHTML=\
- articles/defer_panic_recover.rawhtml\
- articles/error_handling.rawhtml\
- articles/slices_usage_and_internals.rawhtml\
- articles/laws_of_reflection.rawhtml\
- articles/c_go_cgo.rawhtml\
- articles/concurrency_patterns.rawhtml\
- articles/godoc_documenting_go_code.rawhtml\
- articles/gobs_of_data.rawhtml\
- articles/json_and_go.rawhtml\
- articles/json_rpc_tale_of_interfaces.rawhtml\
- articles/image_draw.rawhtml\
- articles/image_package.rawhtml\
- effective_go.rawhtml\
- go1.rawhtml\
-
-all: $(RAWHTML)
-
-%.rawhtml: %.html
- godoc -url /doc/$< >$@
-
-clean:
- rm -f $(RAWHTML)
-
-compare:
- for i in $(RAWHTML); do \
- godoc -url /doc/$${i/.rawhtml/.html} | diff -u $$i -; \
- done
diff --git a/doc/articles/race_detector.html b/doc/articles/race_detector.html
new file mode 100644
index 000000000..282db8ba4
--- /dev/null
+++ b/doc/articles/race_detector.html
@@ -0,0 +1,388 @@
+<!--{
+ "Title": "Data Race Detector",
+ "Template": true
+}-->
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+Data races are among the most common and hardest to debug types of bugs in concurrent systems.
+A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write.
+See the <a href="/ref/mem/">The Go Memory Model</a> for details.
+</p>
+
+<p>
+Here is an example of a data race that can lead to crashes and memory corruption:
+</p>
+
+<pre>
+func main() {
+ c := make(chan bool)
+ m := make(map[string]string)
+ go func() {
+ m["1"] = "a" // First conflicting access.
+ c &lt;- true
+ }()
+ m["2"] = "b" // Second conflicting access.
+ &lt;-c
+ for k, v := range m {
+ fmt.Println(k, v)
+ }
+}
+</pre>
+
+<h2 id="Usage">Usage</h2>
+
+<p>
+To help diagnose such bugs, Go includes a built-in data race detector.
+To use it, add the <code>-race</code> flag to the go command:
+</p>
+
+<pre>
+$ go test -race mypkg // to test the package
+$ go run -race mysrc.go // to run the source file
+$ go build -race mycmd // to build the command
+$ go install -race mypkg // to install the package
+</pre>
+
+<h2 id="Report_Format">Report Format</h2>
+
+<p>
+When the race detector finds a data race in the program, it prints a report.
+The report contains stack traces for conflicting accesses, as well as stacks where the involved goroutines were created.
+Here is an example:
+</p>
+
+<pre>
+WARNING: DATA RACE
+Read by goroutine 185:
+ net.(*pollServer).AddFD()
+ src/pkg/net/fd_unix.go:89 +0x398
+ net.(*pollServer).WaitWrite()
+ src/pkg/net/fd_unix.go:247 +0x45
+ net.(*netFD).Write()
+ src/pkg/net/fd_unix.go:540 +0x4d4
+ net.(*conn).Write()
+ src/pkg/net/net.go:129 +0x101
+ net.func·060()
+ src/pkg/net/timeout_test.go:603 +0xaf
+
+Previous write by goroutine 184:
+ net.setWriteDeadline()
+ src/pkg/net/sockopt_posix.go:135 +0xdf
+ net.setDeadline()
+ src/pkg/net/sockopt_posix.go:144 +0x9c
+ net.(*conn).SetDeadline()
+ src/pkg/net/net.go:161 +0xe3
+ net.func·061()
+ src/pkg/net/timeout_test.go:616 +0x3ed
+
+Goroutine 185 (running) created at:
+ net.func·061()
+ src/pkg/net/timeout_test.go:609 +0x288
+
+Goroutine 184 (running) created at:
+ net.TestProlongTimeout()
+ src/pkg/net/timeout_test.go:618 +0x298
+ testing.tRunner()
+ src/pkg/testing/testing.go:301 +0xe8
+</pre>
+
+<h2 id="Options">Options</h2>
+
+<p>
+The <code>GORACE</code> environment variable sets race detector options.
+The format is:
+</p>
+
+<pre>
+GORACE="option1=val1 option2=val2"
+</pre>
+
+<p>
+The options are:
+</p>
+
+<ul>
+<li>
+<code>log_path</code> (default <code>stderr</code>): The race detector writes
+its report to a file named <code>log_path.<em>pid</em></code>.
+The special names <code>stdout</code>
+and <code>stderr</code> cause reports to be written to standard output and
+standard error, respectively.
+</li>
+
+<li>
+<code>exitcode</code> (default <code>66</code>): The exit status to use when
+exiting after a detected race.
+</li>
+
+<li>
+<code>strip_path_prefix</code> (default <code>""</code>): Strip this prefix
+from all reported file paths, to make reports more concise.
+</li>
+
+<li>
+<code>history_size</code> (default <code>1</code>): The per-goroutine memory
+access history is <code>32K * 2**history_size elements</code>.
+Increasing this value can avoid a "failed to restore the stack" error in reports, at the
+cost of increased memory usage.
+</li>
+
+<li>
+<code>halt_on_error</code> (default <code>0</code>): Controls whether the program
+exits after reporting first data race.
+</li>
+</ul>
+
+<p>
+Example:
+</p>
+
+<pre>
+$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race
+</pre>
+
+<h2 id="Excluding_Tests">Excluding Tests</h2>
+
+<p>
+When you build with <code>-race</code> flag, the <code>go</code> command defines additional
+<a href="/pkg/go/build/#hdr-Build_Constraints">build tag</a> <code>race</code>.
+You can use the tag to exclude some code and tests when running the race detector.
+Some examples:
+</p>
+
+<pre>
+// +build !race
+
+package foo
+
+// The test contains a data race. See issue 123.
+func TestFoo(t *testing.T) {
+ // ...
+}
+
+// The test fails under the race detector due to timeouts.
+func TestBar(t *testing.T) {
+ // ...
+}
+
+// The test takes too long under the race detector.
+func TestBaz(t *testing.T) {
+ // ...
+}
+</pre>
+
+<h2 id="How_To_Use">How To Use</h2>
+
+<p>
+To start, run your tests using the race detector (<code>go test -race</code>).
+The race detector only finds races that happen at runtime, so it can't find
+races in code paths that are not executed.
+If your tests have incomplete coverage,
+you may find more races by running a binary built with <code>-race</code> under a realistic
+workload.
+</p>
+
+<h2 id="Typical_Data_Races">Typical Data Races</h2>
+
+<p>
+Here are some typical data races. All of them can be detected with the race detector.
+</p>
+
+<h3 id="Race_on_loop_counter">Race on loop counter</h3>
+
+<pre>
+func main() {
+ var wg sync.WaitGroup
+ wg.Add(5)
+ for i := 0; i < 5; i++ {
+ go func() {
+ fmt.Println(i) // Not the 'i' you are looking for.
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+</pre>
+
+<p>
+The variable <code>i</code> in the function literal is the same variable used by the loop, so
+the read in the goroutine races with the loop increment.
+(This program typically prints 55555, not 01234.)
+The program can be fixed by making a copy of the variable:
+</p>
+
+<pre>
+func main() {
+ var wg sync.WaitGroup
+ wg.Add(5)
+ for i := 0; i < 5; i++ {
+ go func(j int) {
+ fmt.Println(j) // Good. Read local copy of the loop counter.
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+}
+</pre>
+
+<h3 id="Accidentally_shared_variable">Accidentally shared variable</h3>
+
+<pre>
+// ParallelWrite writes data to file1 and file2, returns the errors.
+func ParallelWrite(data []byte) chan error {
+ res := make(chan error, 2)
+ f1, err := os.Create("file1")
+ if err != nil {
+ res &lt;- err
+ } else {
+ go func() {
+ // This err is shared with the main goroutine,
+ // so the write races with the write below.
+ _, err = f1.Write(data)
+ res &lt;- err
+ f1.Close()
+ }()
+ }
+ f2, err := os.Create("file2") // The second conflicting write to err.
+ if err != nil {
+ res &lt;- err
+ } else {
+ go func() {
+ _, err = f2.Write(data)
+ res &lt;- err
+ f2.Close()
+ }()
+ }
+ return res
+}
+</pre>
+
+<p>
+The fix is to introduce new variables in the goroutines (note the use of <code>:=</code>):
+</p>
+
+<pre>
+ ...
+ _, err := f1.Write(data)
+ ...
+ _, err := f2.Write(data)
+ ...
+</pre>
+
+<h3 id="Unprotected_global_variable">Unprotected global variable</h3>
+
+<p>
+If the following code is called from several goroutines, it leads to races on the <code>service</code> map.
+Concurrent reads and writes of the same map are not safe:
+</p>
+
+<pre>
+var service map[string]net.Addr
+
+func RegisterService(name string, addr net.Addr) {
+ service[name] = addr
+}
+
+func LookupService(name string) net.Addr {
+ return service[name]
+}
+</pre>
+
+<p>
+To make the code safe, protect the accesses with a mutex:
+</p>
+
+<pre>
+var (
+ service map[string]net.Addr
+ serviceMu sync.Mutex
+)
+
+func RegisterService(name string, addr net.Addr) {
+ serviceMu.Lock()
+ defer serviceMu.Unlock()
+ service[name] = addr
+}
+
+func LookupService(name string) net.Addr {
+ serviceMu.Lock()
+ defer serviceMu.Unlock()
+ return service[name]
+}
+</pre>
+
+<h3 id="Primitive_unprotected_variable">Primitive unprotected variable</h3>
+
+<p>
+Data races can happen on variables of primitive types as well (<code>bool</code>, <code>int</code>, <code>int64</code>, etc.),
+as in this example:
+</p>
+
+<pre>
+type Watchdog struct{ last int64 }
+
+func (w *Watchdog) KeepAlive() {
+ w.last = time.Now().UnixNano() // First conflicting access.
+}
+
+func (w *Watchdog) Start() {
+ go func() {
+ for {
+ time.Sleep(time.Second)
+ // Second conflicting access.
+ if w.last < time.Now().Add(-10*time.Second).UnixNano() {
+ fmt.Println("No keepalives for 10 seconds. Dying.")
+ os.Exit(1)
+ }
+ }
+ }()
+}
+</pre>
+
+<p>
+Even such "innocent" data races can lead to hard-to-debug problems caused by
+non-atomicity of the memory accesses,
+interference with compiler optimizations,
+or reordering issues accessing processor memory .
+</p>
+
+<p>
+A typical fix for this race is to use a channel or a mutex.
+To preserve the lock-free behavior, one can also use the
+<a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package.
+</p>
+
+<pre>
+type Watchdog struct{ last int64 }
+
+func (w *Watchdog) KeepAlive() {
+ atomic.StoreInt64(&amp;w.last, time.Now().UnixNano())
+}
+
+func (w *Watchdog) Start() {
+ go func() {
+ for {
+ time.Sleep(time.Second)
+ if atomic.LoadInt64(&amp;w.last) < time.Now().Add(-10*time.Second).UnixNano() {
+ fmt.Println("No keepalives for 10 seconds. Dying.")
+ os.Exit(1)
+ }
+ }
+ }()
+}
+</pre>
+
+<h2 id="Supported_Systems">Supported Systems</h2>
+
+<p>
+The race detector runs on <code>darwin/amd64</code>, <code>linux/amd64</code>, and <code>windows/amd64</code>.
+</p>
+
+<h2 id="Runtime_Overheads">Runtime Overhead</h2>
+
+<p>
+The cost of race detection varies by program, but for a typical program, memory
+usage may increase by 5-10x and execution time by 2-20x.
+</p>
diff --git a/doc/articles/wiki/Makefile b/doc/articles/wiki/Makefile
deleted file mode 100644
index e40b1311e..000000000
--- a/doc/articles/wiki/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-all: index.html
-
-CLEANFILES:=get.bin final-test.bin a.out
-
-clean:
- rm -f $(CLEANFILES)
diff --git a/doc/articles/wiki/final.go b/doc/articles/wiki/final.go
index f15794d66..d84c1ffb2 100644
--- a/doc/articles/wiki/final.go
+++ b/doc/articles/wiki/final.go
@@ -5,12 +5,19 @@
package main
import (
+ "flag"
"html/template"
"io/ioutil"
+ "log"
+ "net"
"net/http"
"regexp"
)
+var (
+ addr = flag.Bool("addr", false, "find open address and print to final-port.txt")
+)
+
type Page struct {
Title string
Body []byte
@@ -81,8 +88,24 @@ func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.Handl
}
func main() {
+ flag.Parse()
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
+
+ if *addr {
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
+ s := &http.Server{}
+ s.Serve(l)
+ return
+ }
+
http.ListenAndServe(":8080", nil)
}
diff --git a/doc/articles/wiki/index.html b/doc/articles/wiki/index.html
index 7bf7213e8..b6b080df9 100644
--- a/doc/articles/wiki/index.html
+++ b/doc/articles/wiki/index.html
@@ -466,7 +466,7 @@ header to the HTTP response.
<p>
The function <code>saveHandler</code> will handle the submission of forms
located on the edit pages. After uncommenting the related line in
-<code>main</code>, let's implement the the handler:
+<code>main</code>, let's implement the handler:
</p>
{{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}}
diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash
index 54a632c30..2997f1680 100755
--- a/doc/articles/wiki/test.bash
+++ b/doc/articles/wiki/test.bash
@@ -7,10 +7,12 @@ set -e
wiki_pid=
cleanup() {
kill $wiki_pid
- rm -f test_*.out Test.txt final-test.bin final-test.go a.out get.bin
+ rm -f test_*.out Test.txt final.bin final-port.txt a.out get.bin
}
trap cleanup 0 INT
+rm -f get.bin final.bin a.out
+
# If called with -all, check that all code snippets compile.
if [ "$1" == "-all" ]; then
for fn in *.go; do
@@ -19,13 +21,25 @@ if [ "$1" == "-all" ]; then
fi
go build -o get.bin get.go
-addr=$(./get.bin -addr)
-sed s/:8080/$addr/ < final.go > final-test.go
-go build -o final-test.bin final-test.go
-(./final-test.bin) &
+go build -o final.bin final.go
+(./final.bin --addr) &
wiki_pid=$!
-./get.bin --wait_for_port=5s http://$addr/edit/Test > test_edit.out
+l=0
+while [ ! -f ./final-port.txt ]
+do
+ l=$(($l+1))
+ if [ "$l" -gt 5 ]
+ then
+ echo "port not available within 5 seconds"
+ exit 1
+ break
+ fi
+ sleep 1
+done
+
+addr=$(cat final-port.txt)
+./get.bin http://$addr/edit/Test > test_edit.out
diff -u test_edit.out test_edit.good
./get.bin -post=body=some%20content http://$addr/save/Test > test_save.out
diff -u test_save.out test_view.good # should be the same as viewing
diff --git a/doc/asm.html b/doc/asm.html
index b855b9ef7..d44cb799d 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -8,7 +8,11 @@
<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
+The document is not comprehensive.
+</p>
+
+<p>
+The assembler 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
@@ -70,6 +74,8 @@ The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
for use by the garbage collector; they are introduced by the compiler.
</p>
+<!-- Commenting out because the feature is gone but it's popular and may come back.
+
<p>
To see what gets put in the binary after linking, add the <code>-a</code> flag to the linker:
</p>
@@ -98,6 +104,7 @@ codeblk [0x2000,0x1d059) at offset 0x1000
...
</pre>
+-->
<h3 id="symbols">Symbols</h3>
@@ -194,7 +201,7 @@ TEXT runtime·profileloop(SB),NOSPLIT,$8
<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.)
+(It's not a 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>,
diff --git a/doc/codewalk/sharemem.xml b/doc/codewalk/sharemem.xml
index d443e176e..8b47f12b7 100644
--- a/doc/codewalk/sharemem.xml
+++ b/doc/codewalk/sharemem.xml
@@ -171,7 +171,7 @@ and/or writes to a shared map.
<step title="Conclusion" src="doc/codewalk/urlpoll.go">
In this codewalk we have explored a simple example of using Go's concurrency
-primitives to share memory through commmunication.
+primitives to share memory through communication.
<br/><br/>
This should provide a starting point from which to explore the ways in which
goroutines and channels can be used to write expressive and concise concurrent
diff --git a/doc/contrib.html b/doc/contrib.html
index 048a5d97f..6529c91d5 100644
--- a/doc/contrib.html
+++ b/doc/contrib.html
@@ -37,16 +37,13 @@ We encourage all Go users to subscribe to
A guide for updating your code to work with Go 1.
</p>
-<h4 id="go1.1notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
+<h4 id="release notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
<p>
-A list of significant changes in Go 1.1, with instructions for updating your
-code where necessary.
-</p>
-
-<h4 id="go1.2notes"><a href="/doc/go1.2">Go 1.2 Release Notes</a></h4>
-<p>
-A list of significant changes in Go 1.2, with instructions for updating your
-code where necessary.
+A list of significant changes in Go 1.1, with instructions for updating
+your code where necessary.
+Each point release includes a similar document appropriate for that
+release: <a href="/doc/go1.2">Go 1.2</a>, <a href="/doc/go1.3">Go 1.3</a>,
+and so on.
</p>
<h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3>
@@ -61,15 +58,22 @@ Go 1 matures.
<h3 id="source"><a href="https://code.google.com/p/go/source">Source Code</a></h3>
<p>Check out the Go source code.</p>
-<h3 id="golang-dev"><a href="http://groups.google.com/group/golang-dev">Developer Mailing List</a></h3>
-<p>The <a href="http://groups.google.com/group/golang-dev">golang-dev</a>
-mailing list is for discussing and reviewing code for the Go project.</p>
+<h3 id="golang-dev"><a href="https://groups.google.com/group/golang-dev">Developer</a> and
+<a href="https://groups.google.com/group/golang-codereviews">Code Review Mailing List</a></h3>
+<p>The <a href="https://groups.google.com/group/golang-dev">golang-dev</a>
+mailing list is for discussing code changes to the Go project.
+The <a href="https://groups.google.com/group/golang-codereviews">golang-codereviews</a>
+mailing list is for actual reviewing of the code changes (CLs).</p>
+
<p>For general discussion of Go programming, see <a
-href="http://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
+href="https://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
-<h3 id="golang-checkins"><a href="http://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
+<h3 id="golang-checkins"><a href="https://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
<p>A mailing list that receives a message summarizing each checkin to the Go repository.</p>
+<h3 id="golang-bugs"><a href="https://groups.google.com/group/golang-bugs">Bugs Mailing List</a></h3>
+<p>A mailing list that receives each update to the Go <a href="http://golang.org/issue">issue tracker</a>.</p>
+
<h3 id="build_status"><a href="http://build.golang.org/">Build Status</a></h3>
<p>View the status of Go builds across the supported operating
systems and architectures.</p>
@@ -77,13 +81,13 @@ systems and architectures.</p>
<h2 id="howto">How you can help</h2>
-<h3><a href="http://code.google.com/p/go/issues">Reporting issues</a></h3>
+<h3><a href="https://code.google.com/p/go/issues">Reporting issues</a></h3>
<p>
If you spot bugs, mistakes, or inconsistencies in the Go project's code or
documentation, please let us know by
-<a href="http://code.google.com/p/go/issues/entry">filing a ticket</a>
-on our <a href="http://code.google.com/p/go/issues">issue tracker</a>.
+<a href="https://code.google.com/p/go/issues/entry">filing a ticket</a>
+on our <a href="https://code.google.com/p/go/issues">issue tracker</a>.
(Of course, you should check it's not an existing issue before creating
a new one.)
</p>
@@ -102,8 +106,8 @@ To get started, read these <a href="/doc/contribute.html">contribution
guidelines</a> for information on design, testing, and our code review process.
</p>
<p>
-Check <a href="http://code.google.com/p/go/issues">the tracker</a> for
+Check <a href="https://code.google.com/p/go/issues">the tracker</a> for
open issues that interest you. Those labeled
-<a href="http://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
+<a href="https://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
are particularly in need of outside help.
</p>
diff --git a/doc/contribute.html b/doc/contribute.html
index 716a1849e..392734985 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -22,7 +22,7 @@ you're working on if you want it to become part of the main repository.
<p>
Before undertaking to write something new for the Go project, send
-mail to the <a href="http://groups.google.com/group/golang-nuts">mailing
+mail to the <a href="https://groups.google.com/group/golang-nuts">mailing
list</a> to discuss what you plan to do. This gives everyone a
chance to validate the design, helps prevent duplication of effort,
and ensures that the idea fits inside the goals for the language
@@ -45,11 +45,15 @@ tree to make sure the changes don't break other packages or programs:
</p>
<pre>
-cd $GOROOT/src
-./all.bash # On Windows, run all.bat
+$ cd go/src
+$ ./all.bash
</pre>
<p>
+(To build under Windows use <code>all.bat</code>.)
+</p>
+
+<p>
After running for a while, the command should print "<code>ALL TESTS PASSED</code>".
</p>
@@ -95,11 +99,11 @@ command.
<h3>Configure the extension</h3>
-<p>Edit <code>$GOROOT/.hg/hgrc</code> to add:</p>
+<p>Edit <code>.hg/hgrc</code> in the root of your Go checkout to add:</p>
<pre>
[extensions]
-codereview = $GOROOT/lib/codereview/codereview.py
+codereview = /path/to/go/lib/codereview/codereview.py
[ui]
username = Your Name &lt;you@server.dom&gt;
@@ -110,6 +114,16 @@ The <code>username</code> information will not be used unless
you are a committer (see below), but Mercurial complains if it is missing.
</p>
+<p>
+As the codereview extension is only enabled for your Go checkout, the remainder of this document assumes you
+are inside the go directory when issuing commands.
+</p>
+
+<p>To contribute to subrepositories, edit the <code>.hg/hgrc</code> for each
+subrepository in the same way. For example, add the codereview extension to
+<code>code.google.com/p/go.tools/.hg/hgrc</code>.
+</p>
+
<h3>Understanding the extension</h3>
<p>After adding the code review extension, you can run</p>
@@ -126,16 +140,10 @@ $ hg help change
</pre>
<p>
-As the codereview extension is only enabled for your checkout
-in <code>$GOROOT</code>, the remainder of this document assumes you
-are inside <code>$GOROOT</code> when issuing commands.
-</p>
-
-<p>
-Windows users may need to perform extra steps to get the code review
+Windows users may need to perform extra steps to get the code review
extension working. See the
-<a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview page</a>
-on the <a href="http://code.google.com/p/go-wiki/wiki">Go Wiki</a> for details.
+<a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview page</a>
+on the <a href="https://code.google.com/p/go-wiki/wiki">Go Wiki</a> for details.
</p>
<h3>Log in to the code review site.</h3>
@@ -146,7 +154,7 @@ The code review server uses a Google Account to authenticate.
<a href="https://www.google.com/accounts/Login?hl=en&amp;continue=http://www.google.com/">sign in at google.com</a>,
you can use it to sign in to the code review server.)
The email address you use on the Code Review site
-will be recorded in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+will be recorded in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file.
You can <a href="https://www.google.com/accounts/NewAccount">create a Google Account</a>
associated with any address where you receive email.
@@ -155,7 +163,6 @@ application-specific password and use that when prompted for a password.
</p>
<pre>
-$ cd $GOROOT
$ hg code-login
Email (login for uploading to codereview.appspot.com): rsc@golang.org
Password for rsc@golang.org:
@@ -165,7 +172,7 @@ Saving authentication cookies to /Users/rsc/.codereview_upload_cookies_coderevie
<h3>Configure your account settings.</h3>
-<p>Edit your <a href="http://codereview.appspot.com/settings">code review settings</a>.
+<p>Edit your <a href="https://codereview.appspot.com/settings">code review settings</a>.
Grab a nickname.
Many people prefer to set the Context option to
&ldquo;Whole file&rdquo; to see more context when reviewing changes.
@@ -240,7 +247,7 @@ These can be code review nicknames or arbitrary email addresses.
Unless explicitly told otherwise, such as in the discussion leading
up to sending in the change list, leave the reviewer field blank.
This means that the
-<a href="http://groups.google.com/group/golang-dev">golang-dev@googlegroups.com</a>
+<a href="https://groups.google.com/group/golang-codereviews">golang-codereviews@googlegroups.com</a>
mailing list will be used as the reviewer.
</p>
@@ -270,7 +277,7 @@ After editing, the template might now read:
# Lines beginning with # are ignored.
# Multi-line values should be indented.
-Reviewer: golang-dev@googlegroups.com
+Reviewer: golang-codereviews@googlegroups.com
CC: math-nuts@swtch.com
Description:
@@ -286,11 +293,11 @@ Files:
<p>
The special sentence &ldquo;Fixes issue 159.&rdquo; associates
-the change with issue 159 in the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
+the change with issue 159 in the <a href="https://code.google.com/p/go/issues/list">Go issue tracker</a>.
When this change is eventually submitted, the issue
tracker will automatically mark the issue as fixed.
(These conventions are described in detail by the
-<a href="http://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control">Google Project Hosting Issue Tracker documentation</a>.)
+<a href="https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control">Google Project Hosting Issue Tracker documentation</a>.)
</p>
<p>
@@ -302,7 +309,7 @@ which <code>hg change</code> will print, something like:
</p>
<pre>
-CL created: http://codereview.appspot.com/99999
+CL created: https://codereview.appspot.com/99999
</pre>
<h3>Adding or removing files from an existing change</h3>
@@ -448,7 +455,7 @@ lines blank and then run:
</p>
<pre>
-$ hg mail -r golang-dev@googlegroups.com --cc math-nuts@swtch.com 99999
+$ hg mail -r golang-codereviews@googlegroups.com --cc math-nuts@swtch.com 99999
</pre>
<p>to achieve the same effect.</p>
@@ -473,31 +480,33 @@ to send comments back.
<h3>Revise and upload</h3>
<p>
-You will probably revise your code in response to the reviewer comments. When
-you have done this, you can upload your change to the code review server
-without sending a notification by running <code>hg upload</code> using the change
-list number assigned during <code>hg change</code>
+When you have revised the code and are ready for another round of review,
+you can upload your change and send mail asking the reviewers to
+please take another look (<code>PTAL</code>). Use the change list number
+assigned during <code>hg change</code>
</p>
<pre>
-$ hg upload 99999
+$ hg mail 99999
</pre>
+
<p>
-When you have revised the code and are ready for another round of review, run
+Or to upload your change without sending a notification, run
</p>
<pre>
-$ hg mail 99999
+$ hg upload 99999
</pre>
-<p>again to upload the latest copy and send mail asking the reviewers to please take another look
-(<code>PTAL</code>).
+<p>
+You will probably revise your code in response to the reviewer comments.
You might also visit the code review web page and reply to the comments,
letting the reviewer know that you've addressed them or explain why you
haven't. When you're done replying, click &ldquo;Publish and Mail comments&rdquo;
to send the line-by-line replies and any other comments.
</p>
+
<p>
The reviewer can comment on the new copy, and the process repeats.
The reviewer approves the change by replying with a mail that says
@@ -597,11 +606,18 @@ $ hg submit 99999
local repository out of date; must sync before submit
</pre>
+<h3>More information</h3>
+
+<p>
+In addition to the information here, the Go community maintains a <a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview</a> wiki page.
+Feel free to contribute to this page as you learn the review process.
+</p>
+
<h2 id="copyright">Copyright</h2>
<p>Files in the Go repository don't list author names,
both to avoid clutter and to avoid having to keep the lists up to date.
-Instead, your name will appear in the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+Instead, your name will appear in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
</p>
@@ -616,13 +632,15 @@ In order for them to do that, you need to have completed one of the
contributor license agreements:
<ul>
<li>
-If you are the copyright holder, you will need to agree to
-the <a href="http://code.google.com/legal/individual-cla-v1.0.html">individual
+If you are the copyright holder, you will need to agree to the
+<a href="https://developers.google.com/open-source/cla/individual">individual
contributor license agreement</a>, which can be completed online.
</li>
<li>
If your organization is the copyright holder, the organization
-will need to agree to the <a href="http://code.google.com/legal/corporate-cla-v1.0.html">corporate contributor license agreement</a>.
+will need to agree to the
+<a href="https://developers.google.com/open-source/cla/corporate">corporate
+contributor license agreement</a>.
(If the copyright holder for your code has already completed the
agreement in connection with another Google open source project,
it does not need to be completed again.)
@@ -636,7 +654,7 @@ This rigmarole needs to be done only for your first submission.
<p>Code that you contribute should use the standard copyright header:</p>
<pre>
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
</pre>
diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html
index b893f931a..afaedf74c 100644
--- a/doc/debugging_with_gdb.html
+++ b/doc/debugging_with_gdb.html
@@ -9,6 +9,23 @@ Besides this overview you might want to consult the
<a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
</i></p>
+<p>
+GDB does not understand Go programs well.
+The stack management, threading, and runtime contain aspects that differ
+enough from the execution model GDB expects that they can confuse
+the debugger, even when the program is compiled with gccgo.
+As a consequence, although GDB can be useful in some situations, it is
+not a reliable debugger for Go programs, particularly heavily concurrent ones.
+Moreover, it is not a priority for the Go project to address these issues, which
+are difficult.
+In short, the instructions below should be taken only as a guide to how
+to use GDB when it works, not as a guarantee of success.
+</p>
+
+<p>
+In time, a more Go-centric debugging architecture may be required.
+</p>
+
<h2 id="Introduction">Introduction</h2>
<p>
@@ -19,8 +36,8 @@ use to inspect a live process or a core dump.
</p>
<p>
-Pass the <code>'-s'</code> flag to the linker to omit the debug information
-(for example, <code>go build -ldflags "-s" prog.go</code>).
+Pass the <code>'-w'</code> flag to the linker to omit the debug information
+(for example, <code>go build -ldflags "-w" prog.go</code>).
</p>
<p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 5511db71b..3a3d5bc13 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -13,12 +13,38 @@ hg pull
hg update <i>tag</i>
</pre>
+<h2 id="go1.3">go1.3 (released 2014/06/18)</h2>
+
+<p>
+Go 1.3 is a major release of Go.
+Read the <a href="/doc/go1.3">Go 1.3 Release Notes</a> for more information.
+</p>
+
+<h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
+
+<p>
+Go 1.2 is a major release of Go.
+Read the <a href="/doc/go1.2">Go 1.2 Release Notes</a> for more information.
+</p>
+
+<h3 id="go1.2.minor">Minor revisions</h3>
+
+<p>
+go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
+See the <a href="https://code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
+</p>
+
+<p>
+go1.2.2 (released 2014/05/05) includes a
+<a href="https://code.google.com/p/go/source/detail?r=bda3619e7a2c&repo=tools">security fix</a>
+that affects the tour binary included in the binary distributions (thanks to Guillaume T).
+</p>
+
<h2 id="go1.1">go1.1 (released 2013/05/13)</h2>
<p>
Go 1.1 is a major release of Go.
-Read the <a href="/doc/go1.1.html">Go 1.1 Release Notes</a> for
-more information.
+Read the <a href="/doc/go1.1">Go 1.1 Release Notes</a> for more information.
</p>
<h3 id="go1.1.minor">Minor revisions</h3>
@@ -363,12 +389,6 @@ variable to build and install your own code and external libraries outside of
the Go tree (and avoid writing Makefiles).
</p>
-<h3 id="go1.2.minor">Minor revisions</h3>
-
-<p>
-go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
-See the <a href="https://code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
-</p>
<h3 id="r58.minor">Minor revisions</h3>
diff --git a/doc/docs.html b/doc/docs.html
index 7aad8dadf..bb2d52dcb 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -97,6 +97,9 @@ one goroutine can be guaranteed to observe values produced by writes to the
same variable in a different goroutine.
</p>
+<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
+<p>A summary of the changes between Go releases.</p>
+
<h2 id="articles">Articles</h2>
@@ -143,7 +146,9 @@ Guided tours of Go programs.
<li><a href="/doc/gdb">Debugging Go Code with GDB</a></li>
<li><a href="/blog/godoc-documenting-go-code">Godoc: documenting Go code</a> - writing good documentation for <a href="/cmd/godoc/">godoc</a>.</li>
<li><a href="/blog/profiling-go-programs">Profiling Go Programs</a></li>
-<li><a href="/blog/race-detector">Data Race Detector</a> - testing Go programs for race conditions.</li>
+<li><a href="/doc/articles/race_detector.html">Data Race Detector</a> - a manual for the data race detector.</li>
+<li><a href="/blog/race-detector">Introducing the Go Race Detector</a> - an introduction to the race detector.
+<li><a href="/doc/asm">A Quick Guide to Go's Assembler</a> - an introduction to the assembler used by Go.
</ul>
<h4 id="articles_more">More</h4>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index f9199511a..25266d6ab 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -214,7 +214,7 @@ not be used.
One adjustment <code>godoc</code> does do is to display indented
text in a fixed-width font, suitable for program snippets.
The package comment for the
-<a href="http://golang.org/pkg/fmt/"><code>fmt</code> package</a> uses this to good effect.
+<a href="/pkg/fmt/"><code>fmt</code> package</a> uses this to good effect.
</p>
<p>
@@ -288,7 +288,7 @@ var (
</pre>
<p>
-Even for private names, grouping can also indicate relationships between items,
+Grouping can also indicate relationships between items,
such as the fact that a set of variables is protected by a mutex.
</p>
@@ -350,7 +350,7 @@ not <code>encoding_base64</code> and not <code>encodingBase64</code>.
</p>
<p>
-The importer of a package will use the name to refer to its contents.
+The importer of a package will use the name to refer to its contents,
so exported names in the package can use that fact
to avoid stutter.
(Don't use the <code>import .</code> notation, which can simplify
@@ -701,6 +701,7 @@ for _, value := range array {
<p>
The blank identifier has many uses, as described in <a href="#blank">a later section</a>.
+</p>
<p>
For strings, the <code>range</code> does more work for you, breaking out individual
@@ -709,7 +710,7 @@ Erroneous encodings consume one byte and produce the
replacement rune U+FFFD.
(The name (with associated builtin type) <code>rune</code> is Go terminology for a
single Unicode code point.
-See <a href="http://golang.org/ref/spec#Rune_literals">the language specification</a>
+See <a href="/ref/spec#Rune_literals">the language specification</a>
for details.)
The loop
</p>
@@ -849,7 +850,7 @@ func Compare(a, b []byte) int {
}
</pre>
-<h2 id="type_switch">Type switch</h2>
+<h3 id="type_switch">Type switch</h3>
<p>
A switch can also be used to discover the dynamic type of an interface
@@ -1385,8 +1386,9 @@ func (file *File) Read(buf []byte) (n int, err error)
</pre>
<p>
The method returns the number of bytes read and an error value, if
-any. To read into the first 32 bytes of a larger buffer
-<code>b</code>, <i>slice</i> (here used as a verb) the buffer.
+any.
+To read into the first 32 bytes of a larger buffer
+<code>buf</code>, <i>slice</i> (here used as a verb) the buffer.
</p>
<pre>
n, err := f.Read(buf[0:32])
@@ -1487,7 +1489,7 @@ If the slices might grow or shrink, they should be allocated independently
to avoid overwriting the next line; if not, it can be more efficient to construct
the object with a single allocation.
For reference, here are sketches of the two methods.
-First, a line a time:
+First, a line at a time:
</p>
<pre>
@@ -2054,10 +2056,22 @@ We pass the address of a <code>ByteSlice</code>
because only <code>*ByteSlice</code> satisfies <code>io.Writer</code>.
The rule about pointers vs. values for receivers is that value methods
can be invoked on pointers and values, but pointer methods can only be
-invoked on pointers. This is because pointer methods can modify the
-receiver; invoking them on a copy of the value would cause those
-modifications to be discarded.
+invoked on pointers.
</p>
+
+<p>
+This rule arises because pointer methods can modify the receiver; invoking
+them on a value would cause the method to receive a copy of the value, so
+any modifications would be discarded.
+The language therefore disallows this mistake.
+There is a handy exception, though. When the value is addressable, the
+language takes care of the common case of invoking a pointer method on a
+value by inserting the address operator automatically.
+In our example, the variable <code>b</code> is addressable, so we can call
+its <code>Write</code> method with just <code>b.Write</code>. The compiler
+will rewrite that to <code>(&amp;b).Write</code> for us.
+</p>
+
<p>
By the way, the idea of using <code>Write</code> on a slice of bytes
is central to the implementation of <code>bytes.Buffer</code>.
@@ -2173,6 +2187,7 @@ A one-case type switch would do, but so would a <em>type assertion</em>.
A type assertion takes an interface value and extracts from it a value of the specified explicit type.
The syntax borrows from the clause opening a type switch, but with an explicit
type rather than the <code>type</code> keyword:
+</p>
<pre>
value.(typeName)
@@ -2463,6 +2478,8 @@ It has uses beyond those we've seen already.
<p>
The use of a blank identifier in a <code>for</code> <code>range</code> loop is a
special case of a general situation: multiple assignment.
+</p>
+
<p>
If an assignment requires multiple values on the left side,
but one of the values will not be used by the program,
@@ -2937,26 +2954,19 @@ means waiting until some receiver has retrieved a value.
<p>
A buffered channel can be used like a semaphore, for instance to
limit throughput. In this example, incoming requests are passed
-to <code>handle</code>, which receives a value from the channel, processes
-the request, and then sends a value back to the channel
-to ready the "semaphore" for the next consumer.
+to <code>handle</code>, which sends a value into the channel, processes
+the request, and then receives a value from the channel
+to ready the &ldquo;semaphore&rdquo; for the next consumer.
The capacity of the channel buffer limits the number of
-simultaneous calls to <code>process</code>,
-so during initialization we prime the channel by filling it to capacity.
+simultaneous calls to <code>process</code>.
</p>
<pre>
var sem = make(chan int, MaxOutstanding)
func handle(r *Request) {
- &lt;-sem // Wait for active queue to drain.
- process(r) // May take a long time.
- sem &lt;- 1 // Done; enable next request to run.
-}
-
-func init() {
- for i := 0; i &lt; MaxOutstanding; i++ {
- sem &lt;- 1
- }
+ sem &lt;- 1 // Wait for active queue to drain.
+ process(r) // May take a long time.
+ &lt;-sem // Done; enable next request to run.
}
func Serve(queue chan *Request) {
@@ -2968,10 +2978,9 @@ func Serve(queue chan *Request) {
</pre>
<p>
-Because data synchronization occurs on a receive from a channel
-(that is, the send "happens before" the receive; see
-<a href="/ref/mem">The Go Memory Model</a>),
-acquisition of the semaphore must be on a channel receive, not a send.
+Once <code>MaxOutstanding</code> handlers are executing <code>process</code>,
+any more will block trying to send into the filled channel buffer,
+until one of the existing handlers finishes and receives from the buffer.
</p>
<p>
@@ -2988,10 +2997,10 @@ Here's an obvious solution, but beware it has a bug we'll fix subsequently:
<pre>
func Serve(queue chan *Request) {
for req := range queue {
- &lt;-sem
+ sem &lt;- 1
go func() {
process(req) // Buggy; see explanation below.
- sem &lt;- 1
+ &lt;-sem
}()
}
}</pre>
@@ -3009,10 +3018,10 @@ to the closure in the goroutine:
<pre>
func Serve(queue chan *Request) {
for req := range queue {
- &lt;-sem
+ sem &lt;- 1
go func(req *Request) {
process(req)
- sem &lt;- 1
+ &lt;-sem
}(req)
}
}</pre>
@@ -3027,11 +3036,11 @@ name, as in this example:
<pre>
func Serve(queue chan *Request) {
for req := range queue {
- &lt;-sem
req := req // Create new instance of req for the goroutine.
+ sem &lt;- 1
go func() {
process(req)
- sem &lt;- 1
+ &lt;-sem
}()
}
}</pre>
@@ -3278,9 +3287,18 @@ the garbage collector for bookkeeping.
<p>
Library routines must often return some sort of error indication to
-the caller. As mentioned earlier, Go's multivalue return makes it
+the caller.
+As mentioned earlier, Go's multivalue return makes it
easy to return a detailed error description alongside the normal
-return value. By convention, errors have type <code>error</code>,
+return value.
+It is good style to use this feature to provide detailed error information.
+For example, as we'll see, <code>os.Open</code> doesn't
+just return a <code>nil</code> pointer on failure, it also returns an
+error value that describes what went wrong.
+</p>
+
+<p>
+By convention, errors have type <code>error</code>,
a simple built-in interface.
</p>
<pre>
@@ -3292,7 +3310,12 @@ type error interface {
A library writer is free to implement this interface with a
richer model under the covers, making it possible not only
to see the error but also to provide some context.
-For example, <code>os.Open</code> returns an <code>os.PathError</code>.
+As mentioned, alongside the usual <code>*os.File</code>
+return value, <code>os.Open</code> also returns an
+error value.
+If the file is opened successfully, the error will be <code>nil</code>,
+but when there is a problem, it will hold an
+<code>os.PathError</code>:
</p>
<pre>
// PathError records an error and the operation and
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index eef5ac220..4c1a8c2f5 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -291,9 +291,9 @@ first one that it finds.
<ul>
<li><code><var>FILE</var>.gox</code>
-<li><code><var>FILE</var>.o</code>
<li><code>lib<var>FILE</var>.so</code>
<li><code>lib<var>FILE</var>.a</code>
+<li><code><var>FILE</var>.o</code>
</ul>
<p>
@@ -522,4 +522,4 @@ port is for x86. The goal is to extend the port to most of the
<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
architectures supported by <code>RTEMS</code></a>. For more information on the port,
as well as instructions on how to install it, please see this
-<a href="http://www.rtems.com/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
+<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
diff --git a/doc/go1.3.html b/doc/go1.3.html
new file mode 100644
index 000000000..ae5c02598
--- /dev/null
+++ b/doc/go1.3.html
@@ -0,0 +1,599 @@
+<!--{
+ "Title": "Go 1.3 Release Notes",
+ "Path": "/doc/go1.3",
+ "Template": true
+}-->
+
+<h2 id="introduction">Introduction to Go 1.3</h2>
+
+<p>
+The latest Go release, version 1.3, arrives six months after 1.2,
+and contains no language changes.
+It focuses primarily on implementation work, providing
+precise garbage collection,
+a major refactoring of the compiler tool chain that results in
+faster builds, especially for large projects,
+significant performance improvements across the board,
+and support for DragonFly BSD, Solaris, Plan 9 and Google's Native Client architecture (NaCl).
+It also has an important refinement to the memory model regarding synchronization.
+As always, Go 1.3 keeps the <a href="/doc/go1compat.html">promise
+of compatibility</a>,
+and almost everything
+will continue to compile and run without change when moved to 1.3.
+</p>
+
+<h2 id="os">Changes to the supported operating systems and architectures</h2>
+
+<h3 id="win2000">Removal of support for Windows 2000</h3>
+
+<p>
+Microsoft stopped supporting Windows 2000 in 2010.
+Since it has <a href="https://codereview.appspot.com/74790043">implementation difficulties</a>
+regarding exception handling (signals in Unix terminology),
+as of Go 1.3 it is not supported by Go either.
+</p>
+
+<h3 id="dragonfly">Support for DragonFly BSD</h3>
+
+<p>
+Go 1.3 now includes experimental support for DragonFly BSD on the <code>amd64</code> (64-bit x86) and <code>386</code> (32-bit x86) architectures.
+It uses DragonFly BSD 3.6 or above.
+</p>
+
+<h3 id="freebsd">Support for FreeBSD</h3>
+
+<p>
+It was not announced at the time, but since the release of Go 1.2, support for Go on FreeBSD
+requires FreeBSD 8 or above.
+</p>
+
+<p>
+As of Go 1.3, support for Go on FreeBSD requires that the kernel be compiled with the
+<code>COMPAT_FREEBSD32</code> flag configured.
+</p>
+
+<p>
+In concert with the switch to EABI syscalls for ARM platforms, Go 1.3 will run only on FreeBSD 10.
+The x86 platforms, 386 and amd64, are unaffected.
+</p>
+
+<h3 id="nacl">Support for Native Client</h3>
+
+<p>
+Support for the Native Client virtual machine architecture has returned to Go with the 1.3 release.
+It runs on the 32-bit Intel architectures (<code>GOARCH=386</code>) and also on 64-bit Intel, but using
+32-bit pointers (<code>GOARCH=amd64p32</code>).
+There is not yet support for Native Client on ARM.
+Note that this is Native Client (NaCl), not Portable Native Client (PNaCl).
+Details about Native Client are <a href="https://developers.google.com/native-client/dev/">here</a>;
+how to set up the Go version is described <a href="http://golang.org/wiki/NativeClient">here</a>.
+</p>
+
+<h3 id="netbsd">Support for NetBSD</h3>
+
+<p>
+As of Go 1.3, support for Go on NetBSD requires NetBSD 6.0 or above.
+</p>
+
+<h3 id="openbsd">Support for OpenBSD</h3>
+
+<p>
+As of Go 1.3, support for Go on OpenBSD requires OpenBSD 5.5 or above.
+</p>
+
+<h3 id="plan9">Support for Plan 9</h3>
+
+<p>
+Go 1.3 now includes experimental support for Plan 9 on the <code>386</code> (32-bit x86) architecture.
+It requires the <code>Tsemacquire</code> syscall, which has been in Plan 9 since June, 2012.
+</p>
+
+<h3 id="solaris">Support for Solaris</h3>
+
+<p>
+Go 1.3 now includes experimental support for Solaris on the <code>amd64</code> (64-bit x86) architecture.
+It requires illumos, Solaris 11 or above.
+</p>
+
+<h2 id="memory">Changes to the memory model</h2>
+
+<p>
+The Go 1.3 memory model <a href="https://codereview.appspot.com/75130045">adds a new rule</a>
+concerning sending and receiving on buffered channels,
+to make explicit that a buffered channel can be used as a simple
+semaphore, using a send into the
+channel to acquire and a receive from the channel to release.
+This is not a language change, just a clarification about an expected property of communication.
+</p>
+
+<h2 id="impl">Changes to the implementations and tools</h2>
+
+<h3 id="stacks">Stack</h3>
+
+<p>
+Go 1.3 has changed the implementation of goroutine stacks away from the old,
+"segmented" model to a contiguous model.
+When a goroutine needs more stack
+than is available, its stack is transferred to a larger single block of memory.
+The overhead of this transfer operation amortizes well and eliminates the old "hot spot"
+problem when a calculation repeatedly steps across a segment boundary.
+Details including performance numbers are in this
+<a href="http://golang.org/s/contigstacks">design document</a>.
+</p>
+
+<h3 id="garbage_collector">Changes to the garbage collector</h3>
+
+<p>
+For a while now, the garbage collector has been <em>precise</em> when examining
+values in the heap; the Go 1.3 release adds equivalent precision to values on the stack.
+This means that a non-pointer Go value such as an integer will never be mistaken for a
+pointer and prevent unused memory from being reclaimed.
+</p>
+
+<p>
+Starting with Go 1.3, the runtime assumes that values with pointer type
+contain pointers and other values do not.
+This assumption is fundamental to the precise behavior of both stack expansion
+and garbage collection.
+Programs that use <a href="/pkg/unsafe/">package unsafe</a>
+to store integers in pointer-typed values are illegal and will crash if the runtime detects the behavior.
+Programs that use <a href="/pkg/unsafe/">package unsafe</a> to store pointers
+in integer-typed values are also illegal but more difficult to diagnose during execution.
+Because the pointers are hidden from the runtime, a stack expansion or garbage collection
+may reclaim the memory they point at, creating
+<a href="http://en.wikipedia.org/wiki/Dangling_pointer">dangling pointers</a>.
+</p>
+
+<p>
+<em>Updating</em>: Code that uses <code>unsafe.Pointer</code> to convert
+an integer-typed value held in memory into a pointer is illegal and must be rewritten.
+Such code can be identified by <code>go vet</code>.
+</p>
+
+<h3 id="map">Map iteration</h3>
+
+<p>
+Iterations over small maps no longer happen in a consistent order.
+Go 1 defines that &ldquo;<a href="http://golang.org/ref/spec#For_statements">The iteration order over maps
+is not specified and is not guaranteed to be the same from one iteration to the next.</a>&rdquo;
+To keep code from depending on map iteration order,
+Go 1.0 started each map iteration at a random index in the map.
+A new map implementation introduced in Go 1.1 neglected to randomize
+iteration for maps with eight or fewer entries, although the iteration order
+can still vary from system to system.
+This has allowed people to write Go 1.1 and Go 1.2 programs that
+depend on small map iteration order and therefore only work reliably on certain systems.
+Go 1.3 reintroduces random iteration for small maps in order to flush out these bugs.
+</p>
+
+<p>
+<em>Updating</em>: If code assumes a fixed iteration order for small maps,
+it will break and must be rewritten not to make that assumption.
+Because only small maps are affected, the problem arises most often in tests.
+</p>
+
+<h3 id="liblink">The linker</h3>
+
+<p>
+As part of the general <a href="http://golang.org/s/go13linker">overhaul</a> to
+the Go linker, the compilers and linkers have been refactored.
+The linker is still a C program, but now the instruction selection phase that
+was part of the linker has been moved to the compiler through the creation of a new
+library called <code>liblink</code>.
+By doing instruction selection only once, when the package is first compiled,
+this can speed up compilation of large projects significantly.
+</p>
+
+<p>
+<em>Updating</em>: Although this is a major internal change, it should have no
+effect on programs.
+</p>
+
+<h3 id="gccgo">Status of gccgo</h3>
+
+<p>
+GCC release 4.9 will contain the Go 1.2 (not 1.3) version of gccgo.
+The release schedules for the GCC and Go projects do not coincide,
+which means that 1.3 will be available in the development branch but
+that the next GCC release, 4.10, will likely have the Go 1.4 version of gccgo.
+</p>
+
+<h3 id="gocmd">Changes to the go command</h3>
+
+<p>
+The <a href="/cmd/go/"><code>cmd/go</code></a> command has several new
+features.
+The <a href="/cmd/go/"><code>go run</code></a> and
+<a href="/cmd/go/"><code>go test</code></a> subcommands
+support a new <code>-exec</code> option to specify an alternate
+way to run the resulting binary.
+Its immediate purpose is to support NaCl.
+</p>
+
+<p>
+The test coverage support of the <a href="/cmd/go/"><code>go test</code></a>
+subcommand now automatically sets the coverage mode to <code>-atomic</code>
+when the race detector is enabled, to eliminate false reports about unsafe
+access to coverage counters.
+</p>
+
+<p>
+The <a href="/cmd/go/"><code>go test</code></a> subcommand
+now always builds the package, even if it has no test files.
+Previously, it would do nothing if no test files were present.
+</p>
+
+<p>
+The <a href="/cmd/go/"><code>go build</code></a> subcommand
+supports a new <code>-i</code> option to install dependencies
+of the specified target, but not the target itself.
+</p>
+
+<p>
+Cross compiling with <a href="/cmd/cgo/"><code>cgo</code></a> enabled
+is now supported.
+The CC_FOR_TARGET and CXX_FOR_TARGET environment
+variables are used when running all.bash to specify the cross compilers
+for C and C++ code, respectively.
+</p>
+
+<p>
+Finally, the go command now supports packages that import Objective-C
+files (suffixed <code>.m</code>) through cgo.
+</p>
+
+<h3 id="cgo">Changes to cgo</h3>
+
+<p>
+The <a href="/cmd/cgo/"><code>cmd/cgo</code></a> command,
+which processes <code>import "C"</code> declarations in Go packages,
+has corrected a serious bug that may cause some packages to stop compiling.
+Previously, all pointers to incomplete struct types translated to the Go type <code>*[0]byte</code>,
+with the effect that the Go compiler could not diagnose passing one kind of struct pointer
+to a function expecting another.
+Go 1.3 corrects this mistake by translating each different
+incomplete struct to a different named type.
+</p>
+
+<p>
+Given the C declaration <code>typedef struct S T</code> for an incomplete <code>struct S</code>,
+some Go code used this bug to refer to the types <code>C.struct_S</code> and <code>C.T</code> interchangeably.
+Cgo now explicitly allows this use, even for completed struct types.
+However, some Go code also used this bug to pass (for example) a <code>*C.FILE</code>
+from one package to another.
+This is not legal and no longer works: in general Go packages
+should avoid exposing C types and names in their APIs.
+</p>
+
+<p>
+<em>Updating</em>: Code confusing pointers to incomplete types or
+passing them across package boundaries will no longer compile
+and must be rewritten.
+If the conversion is correct and must be preserved,
+use an explicit conversion via <a href="/pkg/unsafe/#Pointer"><code>unsafe.Pointer</code></a>.
+</p>
+
+<h3 id="swig">SWIG 3.0 required for programs that use SWIG</h3>
+
+<p>
+For Go programs that use SWIG, SWIG version 3.0 is now required.
+The <a href="/cmd/go"><code>cmd/go</code></a> command will now link the
+SWIG generated object files directly into the binary, rather than
+building and linking with a shared library.
+</p>
+
+<h3 id="gc_flag">Command-line flag parsing</h3>
+
+<p>
+In the gc tool chain, the assemblers now use the
+same command-line flag parsing rules as the Go flag package, a departure
+from the traditional Unix flag parsing.
+This may affect scripts that invoke the tool directly.
+For example,
+<code>go tool 6a -SDfoo</code> must now be written
+<code>go tool 6a -S -D foo</code>.
+(The same change was made to the compilers and linkers in <a href="/doc/go1.1#gc_flag">Go 1.1</a>.)
+</p>
+
+<h3 id="godoc">Changes to godoc</h3>
+<p>
+When invoked with the <code>-analysis</code> flag,
+<a href="http://godoc.org/code.google.com/p/go.tools/cmd/godoc">godoc</a>
+now performs sophisticated <a href="/lib/godoc/analysis/help.html">static
+analysis</a> of the code it indexes.
+The results of analysis are presented in both the source view and the
+package documentation view, and include the call graph of each package
+and the relationships between
+definitions and references,
+types and their methods,
+interfaces and their implementations,
+send and receive operations on channels,
+functions and their callers, and
+call sites and their callees.
+</p>
+
+<h3 id="misc">Miscellany</h3>
+
+<p>
+The program <code>misc/benchcmp</code> that compares
+performance across benchmarking runs has been rewritten.
+Once a shell and awk script in the main repository, it is now a Go program in the <code>go.tools</code> repo.
+Documentation is <a href="http://godoc.org/code.google.com/p/go.tools/cmd/benchcmp">here</a>.
+</p>
+
+<p>
+For the few of us that build Go distributions, the tool <code>misc/dist</code> has been
+moved and renamed; it now lives in <code>misc/makerelease</code>, still in the main repository.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+The performance of Go binaries for this release has improved in many cases due to changes
+in the runtime and garbage collection, plus some changes to libraries.
+Significant instances include:
+</p>
+
+<ul>
+
+<li>
+The runtime handles defers more efficiently, reducing the memory footprint by about two kilobytes
+per goroutine that calls defer.
+</li>
+
+<li>
+The garbage collector has been sped up, using a concurrent sweep algorithm,
+better parallelization, and larger pages.
+The cumulative effect can be a 50-70% reduction in collector pause time.
+</li>
+
+<li>
+The race detector (see <a href="/doc/articles/race_detector.html">this guide</a>)
+is now about 40% faster.
+</li>
+
+<li>
+The regular expression package <a href="/pkg/regexp/"><code>regexp</code></a>
+is now significantly faster for certain simple expressions due to the implementation of
+a second, one-pass execution engine.
+The choice of which engine to use is automatic;
+the details are hidden from the user.
+</li>
+
+</ul>
+
+<p>
+Also, the runtime now includes in stack dumps how long a goroutine has been blocked,
+which can be useful information when debugging deadlocks or performance issues.
+</p>
+
+<h2 id="library">Changes to the standard library</h2>
+
+<h3 id="new_packages">New packages</h3>
+
+<p>
+A new package <a href="/pkg/debug/plan9obj/"><code>debug/plan9obj</code></a> was added to the standard library.
+It implements access to Plan 9 <a href="http://plan9.bell-labs.com/magic/man2html/6/a.out">a.out</a> object files.
+</p>
+
+<h3 id="major_library_changes">Major changes to the library</h3>
+
+<p>
+A previous bug in <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a>
+made it possible to skip verification in TLS inadvertently.
+In Go 1.3, the bug is fixed: one must specify either ServerName or
+InsecureSkipVerify, and if ServerName is specified it is enforced.
+This may break existing code that incorrectly depended on insecure
+behavior.
+</p>
+
+<p>
+There is an important new type added to the standard library: <a href="/pkg/sync/#Pool"><code>sync.Pool</code></a>.
+It provides an efficient mechanism for implementing certain types of caches whose memory
+can be reclaimed automatically by the system.
+</p>
+
+<p>
+The <a href="/pkg/testing/"><code>testing</code></a> package's benchmarking helper,
+<a href="/pkg/testing/#B"><code>B</code></a>, now has a
+<a href="/pkg/testing/#B.RunParallel"><code>RunParallel</code></a> method
+to make it easier to run benchmarks that exercise multiple CPUs.
+</p>
+
+<p>
+<em>Updating</em>: The crypto/tls fix may break existing code, but such
+code was erroneous and should be updated.
+</p>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+The following list summarizes a number of minor changes to the library, mostly additions.
+See the relevant package documentation for more information about each change.
+</p>
+
+<ul>
+
+<li> In the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package,
+a new <a href="/pkg/crypto/tls/#DialWithDialer"><code>DialWithDialer</code></a>
+function lets one establish a TLS connection using an existing dialer, making it easier
+to control dial options such as timeouts.
+The package also now reports the TLS version used by the connection in the
+<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+struct.
+</li>
+
+<li> The <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+function of the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
+now supports parsing (and elsewhere, serialization) of PKCS #10 certificate
+signature requests.
+</li>
+
+<li>
+The formatted print functions of the <code>fmt</code> package now define <code>%F</code>
+as a synonym for <code>%f</code> when printing floating-point values.
+</li>
+
+<li>
+The <a href="/pkg/math/big/"><code>math/big</code></a> package's
+<a href="/pkg/math/big/#Int"><code>Int</code></a> and
+<a href="/pkg/math/big/#Rat"><code>Rat</code></a> types
+now implement
+<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a> and
+<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>.
+</li>
+
+<li>
+The complex power function, <a href="/pkg/math/cmplx/#Pow"><code>Pow</code></a>,
+now specifies the behavior when the first argument is zero.
+It was undefined before.
+The details are in the <a href="/pkg/math/cmplx/#Pow">documentation for the function</a>.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now exposes the
+properties of a TLS connection used to make a client request in the new
+<a href="/pkg/net/http/#Response"><code>Response.TLS</code></a> field.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+allows setting an optional server error logger
+with <a href="/pkg/net/http/#Server"><code>Server.ErrorLog</code></a>.
+The default is still that all errors go to stderr.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+supports disabling HTTP keep-alive connections on the server
+with <a href="/pkg/net/http/#Server.SetKeepAlivesEnabled"><code>Server.SetKeepAlivesEnabled</code></a>.
+The default continues to be that the server does keep-alive (reuses
+connections for multiple requests) by default.
+Only resource-constrained servers or those in the process of graceful
+shutdown will want to disable them.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package adds an optional
+<a href="/pkg/net/http/#Transport"><code>Transport.TLSHandshakeTimeout</code></a>
+setting to cap the amount of time HTTP client requests will wait for
+TLS handshakes to complete.
+It's now also set by default
+on <a href="/pkg/net/http#DefaultTransport"><code>DefaultTransport</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's
+<a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport</code></a>,
+used by the HTTP client code, now
+enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
+keep-alives</a> by default.
+Other <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+values with a nil <code>Dial</code> field continue to function the same
+as before: no TCP keep-alives are used.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package
+now enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
+keep-alives</a> for incoming server requests when
+<a href="/pkg/net/http/#ListenAndServe"><code>ListenAndServe</code></a>
+or
+<a href="/pkg/net/http/#ListenAndServeTLS"><code>ListenAndServeTLS</code></a>
+are used.
+When a server is started otherwise, TCP keep-alives are not enabled.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+provides an
+optional <a href="/pkg/net/http/#Server"><code>Server.ConnState</code></a>
+callback to hook various phases of a server connection's lifecycle
+(see <a href="/pkg/net/http/#ConnState"><code>ConnState</code></a>).
+This can be used to implement rate limiting or graceful shutdown.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's HTTP
+client now has an
+optional <a href="/pkg/net/http/#Client"><code>Client.Timeout</code></a>
+field to specify an end-to-end timeout on requests made using the
+client.
+</li>
+
+<li> In the <a href="/pkg/net/"><code>net</code></a> package,
+the <a href="/pkg/net/#Dialer"><code>Dialer</code></a> struct now
+has a <code>KeepAlive</code> option to specify a keep-alive period for the connection.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+now closes <a href="/pkg/net/http/#Request"><code>Request.Body</code></a>
+consistently, even on error.
+</li>
+
+<li>
+The <a href="/pkg/os/exec/"><code>os/exec</code></a> package now implements
+what the documentation has always said with regard to relative paths for the binary.
+In particular, it only calls <a href="/pkg/os/exec/#LookPath"><code>LookPath</code></a>
+when the binary's file name contains no path separators.
+</li>
+
+<li>
+The <a href="/pkg/reflect/#Value.SetMapIndex"><code>SetMapIndex</code></a>
+function in the <a href="/pkg/reflect/"><code>reflect</code></a> package
+no longer panics when deleting from a <code>nil</code> map.
+</li>
+
+<li>
+If the main goroutine calls
+<a href="/pkg/runtime/#Goexit"><code>runtime.Goexit</code></a>
+and all other goroutines finish execution, the program now always crashes,
+reporting a detected deadlock.
+Earlier versions of Go handled this situation inconsistently: most instances
+were reported as deadlocks, but some trivial cases exited cleanly instead.
+</li>
+
+<li>
+The runtime/debug package now has a new function
+<a href="/pkg/runtime/debug/#WriteHeapDump"><code>debug.WriteHeapDump</code></a>
+that writes out a description of the heap.
+</li>
+
+<li>
+The <a href="/pkg/strconv/#CanBackquote"><code>CanBackquote</code></a>
+function in the <a href="/pkg/strconv/"><code>strconv</code></a> package
+now considers the <code>DEL</code> character, <code>U+007F</code>, to be
+non-printing.
+</li>
+
+<li>
+The <a href="/pkg/syscall/"><code>syscall</code></a> package now provides
+<a href="/pkg/syscall/#SendmsgN"><code>SendmsgN</code></a>
+as an alternate version of
+<a href="/pkg/syscall/#Sendmsg"><code>Sendmsg</code></a>
+that returns the number of bytes written.
+</li>
+
+<li>
+On Windows, the <a href="/pkg/syscall/"><code>syscall</code></a> package now
+supports the cdecl calling convention through the addition of a new function
+<a href="/pkg/syscall/#NewCallbackCDecl"><code>NewCallbackCDecl</code></a>
+alongside the existing function
+<a href="/pkg/syscall/#NewCallback"><code>NewCallback</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/testing/"><code>testing</code></a> package now
+diagnoses tests that call <code>panic(nil)</code>, which are almost always erroneous.
+Also, tests now write profiles (if invoked with profiling flags) even on failure.
+</li>
+
+<li>
+The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
+support throughout the system has been upgraded from
+Unicode 6.2.0 to <a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3.0</a>.
+</li>
+
+</ul>
diff --git a/doc/go1.html b/doc/go1.html
index 3bbe5d316..a664b6555 100644
--- a/doc/go1.html
+++ b/doc/go1.html
@@ -2035,4 +2035,4 @@ They are available for many combinations of architecture and operating system
Installation details are described on the
<a href="/doc/install">Getting Started</a> page, while
the distributions themselves are listed on the
-<a href="http://code.google.com/p/go/downloads/list">downloads page</a>.
+<a href="/dl/">downloads page</a>.
diff --git a/doc/go_faq.html b/doc/go_faq.html
index f65dff796..b1945dda8 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -426,18 +426,20 @@ When a coroutine blocks, such as by calling a blocking system call,
the run-time automatically moves other coroutines on the same operating
system thread to a different, runnable thread so they won't be blocked.
The programmer sees none of this, which is the point.
-The result, which we call goroutines, can be very cheap: unless they spend a lot of time
-in long-running system calls, they cost little more than the memory
-for the stack, which is just a few kilobytes.
+The result, which we call goroutines, can be very cheap: they have little
+overhead beyond the memory for the stack, which is just a few kilobytes.
</p>
<p>
-To make the stacks small, Go's run-time uses segmented stacks. A newly
+To make the stacks small, Go's run-time uses resizable, bounded stacks. A newly
minted goroutine is given a few kilobytes, which is almost always enough.
-When it isn't, the run-time allocates (and frees) extension segments automatically.
-The overhead averages about three cheap instructions per function call.
+When it isn't, the run-time grows (and shrinks) the memory for storing
+the stack automatically, allowing many goroutines to live in a modest
+amount of memory.
+The CPU overhead averages about three cheap instructions per function call.
It is practical to create hundreds of thousands of goroutines in the same
-address space. If goroutines were just threads, system resources would
+address space.
+If goroutines were just threads, system resources would
run out at a much smaller number.
</p>
@@ -446,7 +448,7 @@ Why are map operations not defined to be atomic?</h3>
<p>
After long discussion it was decided that the typical use of maps did not require
-safe access from multiple threads, and in those cases where it did, the map was
+safe access from multiple goroutines, and in those cases where it did, the map was
probably part of some larger data structure or computation that was already
synchronized. Therefore requiring that all map operations grab a mutex would slow
down most programs and add safety to few. This was not an easy decision,
@@ -938,9 +940,9 @@ How are libraries documented?</h3>
There is a program, <code>godoc</code>, written in Go, that extracts
package documentation from the source code. It can be used on the
command line or on the web. An instance is running at
-<a href="http://golang.org/pkg/">http://golang.org/pkg/</a>.
+<a href="/pkg/">http://golang.org/pkg/</a>.
In fact, <code>godoc</code> implements the full site at
-<a href="http://golang.org/">http://golang.org/</a>.
+<a href="/">http://golang.org/</a>.
</p>
<h3 id="Is_there_a_Go_programming_style_guide">
@@ -957,6 +959,14 @@ compendium of do's and don'ts that allows interpretation.
All the Go code in the repository has been run through <code>gofmt</code>.
</p>
+<p>
+The document titled
+<a href="http://golang.org/s/comments">Go Code Review Comments</a>
+is a collection of very short essays about details of Go idiom that are often
+missed by programmers.
+It is a handy reference for people doing code reviews for Go projects.
+</p>
+
<h3 id="How_do_I_submit_patches_to_the_Go_libraries">
How do I submit patches to the Go libraries?</h3>
@@ -1427,7 +1437,7 @@ each closure shares that single variable. When the closure runs, it prints the
value of <code>v</code> at the time <code>fmt.Println</code> is executed,
but <code>v</code> may have been modified since the goroutine was launched.
To help detect this and other problems before they happen, run
-<a href="http://golang.org/cmd/go/#hdr-Run_go_tool_vet_on_packages"><code>go vet</code></a>.
+<a href="/cmd/go/#hdr-Run_go_tool_vet_on_packages"><code>go vet</code></a>.
</p>
<p>
@@ -1606,9 +1616,10 @@ it now. <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
<code>Gc</code> uses a custom library to keep the footprint under
control; it is
compiled with a version of the Plan 9 C compiler that supports
-segmented stacks for goroutines.
-The <code>gccgo</code> compiler implements segmented
-stacks on Linux only, supported by recent modifications to the gold linker.
+resizable stacks for goroutines.
+The <code>gccgo</code> compiler implements these on Linux only,
+using a technique called segmented stacks,
+supported by recent modifications to the gold linker.
</p>
<h3 id="Why_is_my_trivial_program_such_a_large_binary">
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 3e769daec..2ea1ded7a 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Memory Model",
- "Subtitle": "Version of March 6, 2012",
+ "Subtitle": "Version of May 31, 2014",
"Path": "/ref/mem"
}-->
@@ -274,6 +274,41 @@ then the program would not be guaranteed to print
crash, or do something else.)
</p>
+<p class="rule">
+The <i>k</i>th receive on a channel with capacity <i>C</i> happens before the <i>k</i>+<i>C</i>th send from that channel completes.
+</p>
+
+<p>
+This rule generalizes the previous rule to buffered channels.
+It allows a counting semaphore to be modeled by a buffered channel:
+the number of items in the channel corresponds to the number of active uses,
+the capacity of the channel corresponds to the maximum number of simultaneous uses,
+sending an item acquires the semaphore, and receiving an item releases
+the semaphore.
+This is a common idiom for limiting concurrency.
+</p>
+
+<p>
+This program starts a goroutine for every entry in the work list, but the
+goroutines coordinate using the <code>limit</code> channel to ensure
+that at most three are running work functions at a time.
+</p>
+
+<pre>
+var limit = make(chan int, 3)
+
+func main() {
+ for _, w := range work {
+ go func() {
+ limit <- 1
+ w()
+ <-limit
+ }()
+ }
+ select{}
+}
+</pre>
+
<h3>Locks</h3>
<p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
index bc9ec682a..baa0ecf40 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of Nov 13, 2013",
+ "Subtitle": "Version of May 28, 2014",
"Path": "/ref/spec"
}-->
@@ -23,7 +23,7 @@ TODO
<p>
This is a reference manual for the Go programming language. For
-more information and other documents, see <a href="http://golang.org/">http://golang.org</a>.
+more information and other documents, see <a href="/">http://golang.org</a>.
</p>
<p>
@@ -120,7 +120,7 @@ unicode_digit = /* a Unicode code point classified as "Decimal Digit" */ .
</pre>
<p>
-In <a href="http://www.unicode.org/versions/Unicode6.2.0/">The Unicode Standard 6.2</a>,
+In <a href="http://www.unicode.org/versions/Unicode6.3.0/">The Unicode Standard 6.3</a>,
Section 4.5 "General Category"
defines a set of character categories. Go treats
those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters,
@@ -471,7 +471,7 @@ string composed of the uninterpreted (implicitly UTF-8-encoded) characters
between the quotes;
in particular, backslashes have no special meaning and the string may
contain newlines.
-Carriage returns inside raw string literals
+Carriage return characters ('\r') inside raw string literals
are discarded from the raw string value.
</p>
<p>
@@ -674,7 +674,8 @@ types, the dynamic type is always the static type.
<p>
Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
-is a predeclared type or a type literal, the corresponding underlying
+is one of the predeclared boolean, numeric, or string types, or a type literal,
+the corresponding underlying
type is <code>T</code> itself. Otherwise, <code>T</code>'s underlying type
is the underlying type of the type to which <code>T</code> refers in its
<a href="#Type_declarations">type declaration</a>.
@@ -695,19 +696,19 @@ and <code>T4</code> is <code>[]T1</code>.
<h3 id="Method_sets">Method sets</h3>
<p>
-A type may have a <i>method set</i> associated with it
-(§<a href="#Interface_types">Interface types</a>, §<a href="#Method_declarations">Method declarations</a>).
+A type may have a <i>method set</i> associated with it.
The method set of an <a href="#Interface_types">interface type</a> is its interface.
-The method set of any other type <code>T</code>
-consists of all methods with receiver type <code>T</code>.
-The method set of the corresponding pointer type <code>*T</code>
-is the set of all methods with receiver <code>*T</code> or <code>T</code>
+The method set of any other type <code>T</code> consists of all
+<a href="#Method_declarations">methods</a> declared with receiver type <code>T</code>.
+The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
+is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
(that is, it also contains the method set of <code>T</code>).
Further rules apply to structs containing anonymous fields, as described
in the section on <a href="#Struct_types">struct types</a>.
Any other type has an empty method set.
In a method set, each method must have a
-<a href="#Uniqueness_of_identifiers">unique</a> <a href="#MethodName">method name</a>.
+<a href="#Uniqueness_of_identifiers">unique</a>
+non-<a href="#Blank_identifier">blank</a> <a href="#MethodName">method name</a>.
</p>
<p>
@@ -817,8 +818,8 @@ ElementType = Type .
</pre>
<p>
-The length is part of the array's type; it must evaluate to a non-
-negative <a href="#Constants">constant</a> representable by a value
+The length is part of the array's type; it must evaluate to a
+non-negative <a href="#Constants">constant</a> representable by a value
of type <code>int</code>.
The length of array <code>a</code> can be discovered
using the built-in function <a href="#Length_and_capacity"><code>len</code></a>.
@@ -1009,7 +1010,7 @@ A field declaration may be followed by an optional string literal <i>tag</i>,
which becomes an attribute for all the fields in the corresponding
field declaration. The tags are made
visible through a <a href="/pkg/reflect/#StructTag">reflection interface</a>
-and take part in <a href="Type_identity">type identity</a> for structs
+and take part in <a href="#Type_identity">type identity</a> for structs
but are otherwise ignored.
</p>
@@ -1108,7 +1109,8 @@ InterfaceTypeName = TypeName .
<p>
As with all method sets, in an interface type, each method must have a
-<a href="#Uniqueness_of_identifiers">unique</a> name.
+<a href="#Uniqueness_of_identifiers">unique</a>
+non-<a href="#Blank_identifier">blank</a> name.
</p>
<pre>
@@ -1277,20 +1279,23 @@ may be added.
<h3 id="Channel_types">Channel types</h3>
<p>
-A channel provides a mechanism for two concurrently executing functions
-to synchronize execution and communicate by passing a value of a
-specified element type.
+A channel provides a mechanism for
+<a href="#Go_statements">concurrently executing functions</a>
+to communicate by
+<a href="#Send_statements">sending</a> and
+<a href="#Receive_operator">receiving</a>
+values of a specified element type.
The value of an uninitialized channel is <code>nil</code>.
</p>
<pre class="ebnf">
-ChannelType = ( "chan" [ "&lt;-" ] | "&lt;-" "chan" ) ElementType .
+ChannelType = ( "chan" | "chan" "&lt;-" | "&lt;-" "chan" ) ElementType .
</pre>
<p>
-The <code>&lt;-</code> operator specifies the channel <i>direction</i>,
+The optional <code>&lt;-</code> operator specifies the channel <i>direction</i>,
<i>send</i> or <i>receive</i>. If no direction is given, the channel is
-<i>bi-directional</i>.
+<i>bidirectional</i>.
A channel may be constrained only to send or only to receive by
<a href="#Conversions">conversion</a> or <a href="#Assignments">assignment</a>.
</p>
@@ -1317,7 +1322,7 @@ chan (&lt;-chan int)
A new, initialized channel
value can be made using the built-in function
<a href="#Making_slices_maps_and_channels"><code>make</code></a>,
-which takes the channel type and an optional capacity as arguments:
+which takes the channel type and an optional <i>capacity</i> as arguments:
</p>
<pre>
@@ -1325,21 +1330,35 @@ make(chan int, 100)
</pre>
<p>
-The capacity, in number of elements, sets the size of the buffer in the channel. If the
-capacity is greater than zero, the channel is asynchronous: communication operations
-succeed without blocking if the buffer is not full (sends) or not empty (receives),
-and elements are received in the order they are sent.
-If the capacity is zero or absent, the communication succeeds only when both a sender and
-receiver are ready.
+The capacity, in number of elements, sets the size of the buffer in the channel.
+If the capacity is zero or absent, the channel is unbuffered and communication
+succeeds only when both a sender and receiver are ready. Otherwise, the channel
+is buffered and communication succeeds without blocking if the buffer
+is not full (sends) or not empty (receives).
A <code>nil</code> channel is never ready for communication.
</p>
<p>
A channel may be closed with the built-in function
-<a href="#Close"><code>close</code></a>; the
-multi-valued assignment form of the
+<a href="#Close"><code>close</code></a>.
+The multi-valued assignment form of the
<a href="#Receive_operator">receive operator</a>
-tests whether a channel has been closed.
+reports whether a received value was sent before
+the channel was closed.
+</p>
+
+<p>
+A single channel may be used in
+<a href="#Send_statements">send statements</a>,
+<a href="#Receive_operator">receive operations</a>,
+and calls to the built-in functions
+<a href="#Length_and_capacity"><code>cap</code></a> and
+<a href="#Length_and_capacity"><code>len</code></a>
+by any number of goroutines without further synchronization.
+Channels act as first-in-first-out queues.
+For example, if one goroutine sends values on a channel
+and a second goroutine receives them, the values are
+received in the order sent.
</p>
<h2 id="Properties_of_types_and_values">Properties of types and values</h2>
@@ -1515,6 +1534,9 @@ no identifier may be declared in both the file and package block.
<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.
+In the package block, the identifier <code>init</code> may only be used for
+<a href="#Package_initialization"><code>init</code> function</a> declarations,
+and like the blank identifier it does not introduce a new binding.
</p>
<pre class="ebnf">
@@ -1770,9 +1792,9 @@ last non-empty expression list.
<p>
A type declaration binds an identifier, the <i>type name</i>, to a new type
-that has the same <a href="#Types">underlying type</a> as
-an existing type. The new type is <a href="#Type_identity">different</a> from
-the existing type.
+that has the same <a href="#Types">underlying type</a> as an existing type,
+and operations defined for the existing type are also defined for the new type.
+The new type is <a href="#Type_identity">different</a> from the existing type.
</p>
<pre class="ebnf">
@@ -2267,8 +2289,6 @@ Similarly, elements that are addresses of composite literals may elide
the <code>&amp;T</code> when the element type is <code>*T</code>.
</p>
-
-
<pre>
[...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
@@ -2278,13 +2298,13 @@ the <code>&amp;T</code> when the element type is <code>*T</code>.
<p>
A parsing ambiguity arises when a composite literal using the
-TypeName form of the LiteralType appears between the
-<a href="#Keywords">keyword</a> and the opening brace of the block of an
-"if", "for", or "switch" statement, because the braces surrounding
-the expressions in the literal are confused with those introducing
-the block of statements. To resolve the ambiguity in this rare case,
-the composite literal must appear within
-parentheses.
+TypeName form of the LiteralType appears as an operand between the
+<a href="#Keywords">keyword</a> and the opening brace of the block
+of an "if", "for", or "switch" statement, and the composite literal
+is not enclosed in parentheses, square brackets, or curly braces.
+In this rare case, the opening brace of the literal is erroneously parsed
+as the one introducing the block of statements. To resolve the ambiguity,
+the composite literal must appear within parentheses.
</p>
<pre>
@@ -2692,7 +2712,7 @@ For arrays or strings, the indices are <i>in range</i> if
otherwise they are <i>out of range</i>.
For slices, the upper index bound is the slice capacity <code>cap(a)</code> rather than the length.
A <a href="#Constants">constant</a> index must be non-negative and representable by a value of type
-<code>int</code>.
+<code>int</code>; for arrays or constant strings, constant indices must also be in range.
If both indices are constant, they must satisfy <code>low &lt;= high</code>.
If the indices are out of range at run time, a <a href="#Run_time_panics">run-time panic</a> occurs.
</p>
@@ -2752,7 +2772,7 @@ If the sliced operand is an array, it must be <a href="#Address_operators">addre
The indices are <i>in range</i> if <code>0 &lt;= low &lt;= high &lt;= max &lt;= cap(a)</code>,
otherwise they are <i>out of range</i>.
A <a href="#Constants">constant</a> index must be non-negative and representable by a value of type
-<code>int</code>.
+<code>int</code>; for arrays, constant indices must also be in range.
If multiple indices are constant, the constants that are present must be in range relative to each
other.
If the indices are out of range at run time, a <a href="#Run_time_panics">run-time panic</a> occurs.
@@ -2916,27 +2936,32 @@ There is no distinct method type and there are no method literals.
<h3 id="Passing_arguments_to_..._parameters">Passing arguments to <code>...</code> parameters</h3>
<p>
-If <code>f</code> is variadic with final parameter type <code>...T</code>,
-then within the function the argument is equivalent to a parameter of type
-<code>[]T</code>. At each call of <code>f</code>, the argument
-passed to the final parameter is
-a new slice of type <code>[]T</code> whose successive elements are
-the actual arguments, which all must be <a href="#Assignability">assignable</a>
-to the type <code>T</code>. The length of the slice is therefore the number of
-arguments bound to the final parameter and may differ for each call site.
+If <code>f</code> is <a href="#Function_types">variadic</a> with a final
+parameter <code>p</code> of type <code>...T</code>, then within <code>f</code>
+the type of <code>p</code> is equivalent to type <code>[]T</code>.
+If <code>f</code> is invoked with no actual arguments for <code>p</code>,
+the value passed to <code>p</code> is <code>nil</code>.
+Otherwise, the value passed is a new slice
+of type <code>[]T</code> with a new underlying array whose successive elements
+are the actual arguments, which all must be <a href="#Assignability">assignable</a>
+to <code>T</code>. The length and capacity of the slice is therefore
+the number of arguments bound to <code>p</code> and may differ for each
+call site.
</p>
<p>
-Given the function and call
+Given the function and calls
</p>
<pre>
func Greeting(prefix string, who ...string)
+Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
</pre>
<p>
within <code>Greeting</code>, <code>who</code> will have the value
-<code>[]string{"Joe", "Anna", "Eileen"}</code>
+<code>nil</code> in the first call, and
+<code>[]string{"Joe", "Anna", "Eileen"}</code> in the second.
</p>
<p>
@@ -3385,7 +3410,8 @@ and the type of the receive operation is the element type of the channel.
The expression blocks until a value is available.
Receiving from a <code>nil</code> channel blocks forever.
A receive operation on a <a href="#Close">closed</a> channel can always proceed
-immediately, yielding the element type's <a href="#The_zero_value">zero value</a>.
+immediately, yielding the element type's <a href="#The_zero_value">zero value</a>
+after any previously sent values have been received.
</p>
<pre>
@@ -3929,7 +3955,7 @@ an untyped complex constant.
<pre>
const ic = complex(0, c) // ic == 3.75i (untyped complex constant)
-const iΘ = complex(0, Θ) // iΘ == 1.5i (type complex128)
+const iΘ = complex(0, Θ) // iΘ == 1i (type complex128)
</pre>
<p>
@@ -3992,8 +4018,11 @@ precision.
<h3 id="Order_of_evaluation">Order of evaluation</h3>
<p>
-When evaluating the <a href="#Operands">operands</a> of an expression,
-<a href="#Assignments">assignment</a>, or
+At package level, <a href="#Package_initialization">initialization dependencies</a>
+determine the evaluation order of individual initialization expressions in
+<a href="#Variable_declarations">variable declarations</a>.
+Otherwise, when evaluating the <a href="#Operands">operands</a> of an
+expression, assignment, or
<a href="#Return_statements">return statement</a>,
all function calls, method calls, and
communication operations are evaluated in lexical left-to-right
@@ -4001,7 +4030,7 @@ order.
</p>
<p>
-For example, in the assignment
+For example, in the (function-local) assignment
</p>
<pre>
y[f()], ok = g(h(), i()+x[j()], &lt;-c), k()
@@ -4018,12 +4047,34 @@ of <code>y</code> is not specified.
<pre>
a := 1
f := func() int { a++; return a }
-x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
-m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
-m2 := map[int]int{a: f()} // m2 may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
+x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
+m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
+n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
</pre>
<p>
+At package level, initialization dependencies override the left-to-right rule
+for individual initialization expressions, but not for operands within each
+expression:
+</p>
+
+<pre>
+var a, b, c = f() + v(), g(), sqr(u()) + v()
+
+func f() int { return c }
+func g() int { return a }
+func sqr(x int) int { return x*x }
+
+// functions u and v are independent of all other variables and functions
+</pre>
+
+<p>
+The function calls happen in the order
+<code>u()</code>, <code>sqr()</code>, <code>v()</code>,
+<code>f()</code>, <code>v()</code>, and <code>g()</code>.
+</p>
+
+<p>
Floating-point operations within a single expression are evaluated according to
the associativity of the operators. Explicit parentheses affect the evaluation
by overriding the default associativity.
@@ -4209,22 +4260,8 @@ A send on a closed channel proceeds by causing a <a href="#Run_time_panics">run-
A send on a <code>nil</code> channel blocks forever.
</p>
-<p>
-Channels act as first-in-first-out queues.
-For example, if a single goroutine sends on a channel values
-that are received by a single goroutine, the values are received in the order sent.
-</p>
-
-<p>
-A single channel may be used for send and receive
-operations and calls to the built-in functions
-<a href="#Length_and_capacity"><code>cap</code></a> and
-<a href="#Length_and_capacity"><code>len</code></a>
-by any number of goroutines without further synchronization.
-</p>
-
<pre>
-ch &lt;- 3
+ch &lt;- 3 // send value 3 to channel ch
</pre>
@@ -4459,8 +4496,8 @@ If no case matches and there is a "default" case,
its statements are executed.
There can be at most one default case and it may appear anywhere in the
"switch" statement.
-A missing switch expression is equivalent to
-the expression <code>true</code>.
+A missing switch expression is equivalent to the boolean value
+<code>true</code>.
</p>
<pre class="ebnf">
@@ -4625,7 +4662,8 @@ Condition = Expression .
In its simplest form, a "for" statement specifies the repeated execution of
a block as long as a boolean condition evaluates to true.
The condition is evaluated before each iteration.
-If the condition is absent, it is equivalent to <code>true</code>.
+If the condition is absent, it is equivalent to the boolean value
+<code>true</code>.
</p>
<pre>
@@ -4662,7 +4700,8 @@ only if the block was executed).
Any element of the ForClause may be empty but the
<a href="#Semicolons">semicolons</a> are
required unless there is only a condition.
-If the condition is absent, it is equivalent to <code>true</code>.
+If the condition is absent, it is equivalent to the boolean value
+<code>true</code>.
</p>
<pre>
@@ -4844,8 +4883,12 @@ go func(ch chan&lt;- bool) { for { sleep(10); ch &lt;- true; }} (c)
<h3 id="Select_statements">Select statements</h3>
<p>
-A "select" statement chooses which of a set of possible communications
-will proceed. It looks similar to a "switch" statement but with the
+A "select" statement chooses which of a set of possible
+<a href="#Send_statements">send</a> or
+<a href="#Receive_operator">receive</a>
+operations will proceed.
+It looks similar to a
+<a href="#Switch_statements">"switch"</a> statement but with the
cases all referring to communication operations.
</p>
@@ -4858,41 +4901,63 @@ RecvExpr = Expression .
</pre>
<p>
-RecvExpr must be a <a href="#Receive_operator">receive operation</a>.
-For all the cases in the "select"
-statement, the channel expressions are evaluated in top-to-bottom order, along with
-any expressions that appear on the right hand side of send statements.
-A channel may be <code>nil</code>,
-which is equivalent to that case not
-being present in the select statement
-except, if a send, its expression is still evaluated.
-If any of the resulting operations can proceed, one of those is
-chosen and the corresponding communication and statements are
-evaluated. Otherwise, if there is a default case, that executes;
-if there is no default case, the statement blocks until one of the communications can
-complete. There can be at most one default case and it may appear anywhere in the
-"select" statement.
-If there are no cases with non-<code>nil</code> channels,
-the statement blocks forever.
-Even if the statement blocks,
-the channel and send expressions are evaluated only once,
-upon entering the select statement.
+A case with a RecvStmt may assign the result of a RecvExpr to one or
+two variables, which may be declared using a
+<a href="#Short_variable_declarations">short variable declaration</a>.
+The RecvExpr must be a (possibly parenthesized) receive operation.
+There can be at most one default case and it may appear anywhere
+in the list of cases.
</p>
+
<p>
-Since all the channels and send expressions are evaluated, any side
-effects in that evaluation will occur for all the communications
-in the "select" statement.
+Execution of a "select" statement proceeds in several steps:
</p>
+
+<ol>
+<li>
+For all the cases in the statement, the channel operands of receive operations
+and the channel and right-hand-side expressions of send statements are
+evaluated exactly once, in source order, upon entering the "select" statement.
+The result is a set of channels to receive from or send to,
+and the corresponding values to send.
+Any side effects in that evaluation will occur irrespective of which (if any)
+communication operation is selected to proceed.
+Expressions on the left-hand side of a RecvStmt with a short variable declaration
+or assignment are not yet evaluated.
+</li>
+
+<li>
+If one or more of the communications can proceed,
+a single one that can proceed is chosen via a uniform pseudo-random selection.
+Otherwise, if there is a default case, that case is chosen.
+If there is no default case, the "select" statement blocks until
+at least one of the communications can proceed.
+</li>
+
+<li>
+Unless the selected case is the default case, the respective communication
+operation is executed.
+</li>
+
+<li>
+If the selected case is a RecvStmt with a short variable declaration or
+an assignment, the left-hand side expressions are evaluated and the
+received value (or values) are assigned.
+</li>
+
+<li>
+The statement list of the selected case is executed.
+</li>
+</ol>
+
<p>
-If multiple cases can proceed, a uniform pseudo-random choice is made to decide
-which single communication will execute.
-<p>
-The receive case may declare one or two new variables using a
-<a href="#Short_variable_declarations">short variable declaration</a>.
+Since communication on <code>nil</code> channels can never proceed,
+a select with only <code>nil</code> channels and no default case blocks forever.
</p>
<pre>
-var c, c1, c2, c3 chan int
+var a []int
+var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = &lt;-c1:
@@ -4905,6 +4970,10 @@ case i3, ok := (&lt;-c3): // same as: i3, ok := &lt;-c3
} else {
print("c3 is closed\n")
}
+case a[f()] = &lt;-c4:
+ // same as:
+ // case t := &lt;-c4
+ // a[f()] = t
default:
print("no communication\n")
}
@@ -5002,6 +5071,21 @@ function. A "return" statement that specifies results sets the result parameters
any deferred functions are executed.
</p>
+<p>
+Implementation restriction: A compiler may disallow an empty expression list
+in a "return" statement if a different entity (constant, type, or variable)
+with the same name as a result parameter is in
+<a href="#Declarations_and_scope">scope</a> at the place of the return.
+</p>
+
+<pre>
+func f(n int) (res int, err error) {
+ if _, err := f(n-1); err != nil {
+ return // invalid return statement: err is shadowed
+ }
+ return
+}
+</pre>
<h3 id="Break_statements">Break statements</h3>
@@ -5009,7 +5093,8 @@ any deferred functions are executed.
A "break" statement terminates execution of the innermost
<a href="#For_statements">"for"</a>,
<a href="#Switch_statements">"switch"</a>, or
-<a href="#Select_statements">"select"</a> statement.
+<a href="#Select_statements">"select"</a> statement
+within the same function.
</p>
<pre class="ebnf">
@@ -5043,6 +5128,7 @@ OuterLoop:
<p>
A "continue" statement begins the next iteration of the
innermost <a href="#For_statements">"for" loop</a> at its post statement.
+The "for" loop must be within the same function.
</p>
<pre class="ebnf">
@@ -5070,7 +5156,8 @@ RowLoop:
<h3 id="Goto_statements">Goto statements</h3>
<p>
-A "goto" statement transfers control to the statement with the corresponding label.
+A "goto" statement transfers control to the statement with the corresponding label
+within the same function.
</p>
<pre class="ebnf">
@@ -5263,7 +5350,7 @@ At any time the following relationship holds:
<p>
The length of a <code>nil</code> slice, map or channel is 0.
-The capacity of a <code>nil</code> slice and channel is 0.
+The capacity of a <code>nil</code> slice or channel is 0.
</p>
<p>
@@ -5271,12 +5358,22 @@ The expression <code>len(s)</code> is <a href="#Constants">constant</a> if
<code>s</code> is a string constant. The expressions <code>len(s)</code> and
<code>cap(s)</code> are constants if the type of <code>s</code> is an array
or pointer to an array and the expression <code>s</code> does not contain
-<a href="#Receive_operator">channel receives</a> or
+<a href="#Receive_operator">channel receives</a> or (non-constant)
<a href="#Calls">function calls</a>; in this case <code>s</code> is not evaluated.
Otherwise, invocations of <code>len</code> and <code>cap</code> are not
constant and <code>s</code> is evaluated.
</p>
+<pre>
+const (
+ c1 = imag(2i) // imag(2i) = 2.0 is a constant
+ c2 = len([10]float64{2}) // [10]float64{2} contains no function calls
+ c3 = len([10]float64{c1}) // [10]float64{c1} contains no function calls
+ c4 = len([10]float64{imag(2i)}) // imag(2i) is a constant and no function call is issued
+ c5 = len([10]float64{imag(z)}) // invalid: imag(x) is a (non-constant) function call
+)
+var z complex128
+</pre>
<h3 id="Allocation">Allocation</h3>
@@ -5327,8 +5424,8 @@ make(T, n, m) slice slice of type T with length n and capacity m
make(T) map map of type T
make(T, n) map map of type T with initial space for n elements
-make(T) channel synchronous channel of type T
-make(T, n) channel asynchronous channel of type T, buffer size n
+make(T) channel unbuffered channel of type T
+make(T, n) channel buffered channel of type T, buffer size n
</pre>
@@ -5669,7 +5766,7 @@ If the PackageName is omitted, it defaults to the identifier specified in the
If an explicit period (<code>.</code>) appears instead of a name, all the
package's exported identifiers declared in that package's
<a href="#Blocks">package block</a> will be declared in the importing source
-file's file block and can be accessed without a qualifier.
+file's file block and must be accessed without a qualifier.
</p>
<p>
@@ -5681,7 +5778,7 @@ package and may be relative to a repository of installed packages.
<p>
Implementation restriction: A compiler may restrict ImportPaths to
non-empty strings using only characters belonging to
-<a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode's</a>
+<a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode's</a>
L, M, N, P, and S general categories (the Graphic characters without
spaces) and may also exclude the characters
<code>!"#$%&amp;'()*,:;&lt;=&gt;?[\]^`{|}</code>
@@ -5693,7 +5790,7 @@ Assume we have compiled a package containing the package clause
<code>package math</code>, which exports function <code>Sin</code>, and
installed the compiled package in the file identified by
<code>"lib/math"</code>.
-This table illustrates how <code>Sin</code> may be accessed in files
+This table illustrates how <code>Sin</code> is accessed in files
that import the package after the
various types of import declaration.
</p>
@@ -5817,62 +5914,126 @@ The same would also be true after
var t T
</pre>
-<h3 id="Program_execution">Program execution</h3>
+<h3 id="Package_initialization">Package initialization</h3>
<p>
-A package with no imports is initialized by assigning initial values to
-all its package-level variables
-and then calling any
-package-level function with the name and signature of
-</p>
-<pre>
-func init()
-</pre>
-<p>
-defined in its source.
-A package-scope or file-scope identifier
-with name <code>init</code> may only be
-declared to be a function with this signature.
-Multiple such functions may be defined, even
-within a single source file; they execute
-in unspecified order.
-</p>
-<p>
-Within a package, package-level variables are initialized,
-and constant values are determined, according to
-order of reference: if the initializer of <code>A</code>
-depends on <code>B</code>, <code>A</code>
-will be set after <code>B</code>.
-Dependency analysis does not depend on the actual values
-of the items being initialized, only on their appearance
-in the source.
-<code>A</code>
-depends on <code>B</code> if the value of <code>A</code>
-contains a mention of <code>B</code>, contains a value
-whose initializer
-mentions <code>B</code>, or mentions a function that
-mentions <code>B</code>, recursively.
-It is an error if such dependencies form a cycle.
-If two items are not interdependent, they will be initialized
-in the order they appear in the source, possibly in multiple files,
-as presented to the compiler.
-Since the dependency analysis is done per package, it can produce
-unspecified results if <code>A</code>'s initializer calls a function defined
-in another package that refers to <code>B</code>.
+Within a package, package-level variables are initialized according
+to their <i>dependencies</i>: if a variable <code>x</code> depends on
+a variable <code>y</code>, <code>x</code> will be initialized after
+<code>y</code>.
+</p>
+
+<p>
+Dependency analysis does not rely on the actual values of the
+variables, only on lexical <i>references</i> to them in the source,
+analyzed transitively. For instance, a variable <code>x</code>'s
+<a href="#Variable_declarations">initialization expression</a>
+may refer to a function whose body refers to variable <code>y</code>;
+if so, <code>x</code> depends on <code>y</code>.
+Specifically:
+</p>
+
+<ul>
+<li>
+A reference to a variable or function is an identifier denoting that
+variable or function.
+</li>
+
+<li>
+A reference to a method <code>m</code> is a
+<a href="#Method_values">method value</a> or
+<a href="#Method_expressions">method expression</a> of the form
+<code>t.m</code>, where the (static) type of <code>t</code> is
+not an interface type, and the method <code>m</code> is in the
+<a href="#Method_sets">method set</a> of <code>t</code>.
+It is immaterial whether the resulting function value
+<code>t.m</code> is invoked.
+</li>
+
+<li>
+A variable, function, or method <code>x</code> depends on a variable
+<code>y</code> if <code>x</code>'s initialization expression or body
+(for functions and methods) contains a reference to <code>y</code>
+or to a function or method that depends on <code>y</code>.
+</li>
+</ul>
+
+<p>
+Dependency analysis is performed per package; only references referring
+to variables, functions, and methods declared in the current package
+are considered.
+It is an error if variable dependencies form a cycle
+(but dependency cycles containing no variables are permitted).
+If two variables are independent of each other,
+they are initialized in the order they are declared
+in the source, possibly in multiple files, as presented to the compiler.
+</p>
+
+<p>
+For example, given the declarations
+</p>
+
+<pre>
+var (
+ a = c + b
+ b = f()
+ c = f()
+ d = 3
+)
+
+func f() int {
+ d++
+ return d
+}
+</pre>
+
+<p>
+the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
+Since <code>b</code> and <code>c</code> are independent of each other, they are
+initialized in declaration order (<code>b</code> before <code>c</code>).
+</p>
+
+<p>
+Variables may also be initialized using functions named <code>init</code>
+declared in the package block, with no arguments and no result parameters.
</p>
+
+<pre>
+func init() { … }
+</pre>
+
<p>
-An <code>init</code> function cannot be referred to from anywhere
-in a program. In particular, <code>init</code> cannot be called explicitly,
-nor can a pointer to <code>init</code> be assigned to a function variable.
+Multiple such functions may be defined, even within a single
+source file. The <code>init</code> identifier is not
+<a href="#Declarations_and_scope">declared</a> and thus
+<code>init</code> functions cannot be referred to from anywhere
+in a program.
</p>
+
<p>
+A package with no imports is initialized by assigning initial values
+to all its package-level variables followed by calling all <code>init</code>
+functions in the order they appear in the source, possibly in multiple files,
+as presented to the compiler.
If a package has imports, the imported packages are initialized
before initializing the package itself. If multiple packages import
-a package <code>P</code>, <code>P</code> will be initialized only once.
+a package, the imported package will be initialized only once.
+The importing of packages, by construction, guarantees that there
+can be no cyclic initialization dependencies.
</p>
+
<p>
-The importing of packages, by construction, guarantees that there can
-be no cyclic dependencies in initialization.
+Package initialization&mdash;variable initialization and the invocation of
+<code>init</code> functions&mdash;happens in a single goroutine,
+sequentially, one package at a time.
+An <code>init</code> function may launch other goroutines, which can run
+concurrently with the initialization code. However, initialization
+always sequences
+the <code>init</code> functions: it will not invoke the next one
+until the previous one has returned.
</p>
+
+
+<h3 id="Program_execution">Program execution</h3>
<p>
A complete program is created by linking a single, unimported package
called the <i>main package</i> with all the packages it imports, transitively.
@@ -5889,22 +6050,10 @@ func main() { … }
<p>
Program execution begins by initializing the main package and then
invoking the function <code>main</code>.
-When the function <code>main</code> returns, the program exits.
+When that function invocation returns, the program exits.
It does not wait for other (non-<code>main</code>) goroutines to complete.
</p>
-<p>
-Package initialization&mdash;variable initialization and the invocation of
-<code>init</code> functions&mdash;happens in a single goroutine,
-sequentially, one package at a time.
-An <code>init</code> function may launch other goroutines, which can run
-concurrently with the initialization code. However, initialization
-always sequences
-the <code>init</code> functions: it will not start the next
-<code>init</code> until
-the previous one has returned.
-</p>
-
<h2 id="Errors">Errors</h2>
<p>
diff --git a/doc/gopher/README b/doc/gopher/README
new file mode 100644
index 000000000..936a24c66
--- /dev/null
+++ b/doc/gopher/README
@@ -0,0 +1,3 @@
+The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
+The design is licensed under the Creative Commons 3.0 Attributions license.
+Read this article for more details: http://blog.golang.org/gopher
diff --git a/doc/help.html b/doc/help.html
index 3de520640..ad92c5695 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -39,7 +39,7 @@ Go IRC channel.</p>
<h3 id="twitter"><a href="http://twitter.com/golang">@golang at Twitter</a></h3>
<p>The Go project's official Twitter account.</p>
-<p>Tweeting your about problem with the <code>#golang</code> hashtag usually
+<p>Tweeting about your problem with the <code>#golang</code> hashtag usually
generates some helpful responses.</p>
<h3 id="go_user_groups"><a href="/wiki/GoUserGroups">Go User Groups</a></h3>
diff --git a/doc/install-source.html b/doc/install-source.html
index b99360c71..6f6a15afd 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -69,8 +69,8 @@ goroutines, such as stacks that grow and shrink on demand.
</p>
<p>
-The compilers can target the FreeBSD, Linux, NetBSD, OpenBSD, OS X (Darwin), Plan 9,
-and Windows operating systems.
+The compilers can target the DragonFly BSD, FreeBSD, Linux, NetBSD, OpenBSD,
+OS X (Darwin), Plan 9, Solaris and Windows operating systems.
The full set of supported combinations is listed in the discussion of
<a href="#environment">environment variables</a> below.
</p>
@@ -95,7 +95,7 @@ have an <code>hg</code> command.)
<p>
If you do not have a working Mercurial installation,
follow the instructions on the
-<a href="http://mercurial.selenic.com/downloads/">Mercurial downloads</a> page.
+<a href="http://mercurial.selenic.com/downloads">Mercurial downloads</a> page.
</p>
<p>
@@ -176,6 +176,10 @@ architecture, and root directory used during the install.
<p>
For more information about ways to control the build, see the discussion of
<a href="#environment">environment variables</a> below.
+<code>all.bash</code> (or <code>all.bat</code>) runs important tests for Go,
+which can take more time than simply building Go. If you do not want to run
+the test suite use <code>make.bash</code> (or <code>make.bat</code>)
+instead.
</p>
</div>
@@ -354,9 +358,9 @@ These default to the values of <code>$GOHOSTOS</code> and
<p>
Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.6 and above), <code>freebsd</code>,
+<code>darwin</code> (Mac OS X 10.6 and above), <code>dragonfly</code>, <code>freebsd</code>,
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
-<code>plan9</code>, and <code>windows</code>.
+<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
Choices for <code>$GOARCH</code> are
<code>amd64</code> (64-bit x86, the most mature port),
<code>386</code> (32-bit x86), and <code>arm</code> (32-bit ARM).
@@ -372,6 +376,12 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
<td></td><td><code>darwin</code></td> <td><code>amd64</code></td>
</tr>
<tr>
+<td></td><td><code>dragonfly</code></td> <td><code>386</code></td>
+</tr>
+<tr>
+<td></td><td><code>dragonfly</code></td> <td><code>amd64</code></td>
+</tr>
+<tr>
<td></td><td><code>freebsd</code></td> <td><code>386</code></td>
</tr>
<tr>
@@ -411,6 +421,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
<td></td><td><code>plan9</code></td> <td><code>amd64</code></td>
</tr>
<tr>
+<td></td><td><code>solaris</code></td> <td><code>amd64</code></td>
+</tr>
+<tr>
<td></td><td><code>windows</code></td> <td><code>386</code></td>
</tr>
<tr>
@@ -444,7 +457,7 @@ installs all commands there.
</p>
<li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
-if built natively, <code>387</code> if not)
+if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
<p>
This controls the code generated by 8g to use either the 387 floating-point unit
(set to <code>387</code>) or SSE2 instructions (set to <code>sse2</code>) for
diff --git a/doc/install.html b/doc/install.html
index af4c8f3d1..7282ae947 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -6,15 +6,15 @@
<h2 id="download">Download the Go distribution</h2>
<p>
-<a href="http://code.google.com/p/go/downloads" id="start" class="download" target="_blank">
+<a href="/dl/" id="start" class="download" target="_blank">
<span class="big">Download Go</span>
<span class="desc">Click here to visit the downloads page</span>
</a>
</p>
<p>
-<a href="http://code.google.com/p/go/downloads" target="_blank">Official binary
-distributions</a> are available for the FreeBSD, Linux, Mac OS X (Snow Leopard
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2" target="_blank">Official binary
+distributions</a> are available for the FreeBSD (release 8 and above), Linux, Mac OS X (Snow Leopard
and above), and Windows operating systems and the 32-bit (<code>386</code>) and
64-bit (<code>amd64</code>) x86 processor architectures.
</p>
@@ -39,15 +39,15 @@ proceeding. If your OS or architecture is not on the list, it's possible that
<table class="codetable" frame="border" summary="requirements">
<tr>
-<th align="middle">Operating system</th>
-<th align="middle">Architectures</th>
-<th align="middle">Notes</th>
+<th align="center">Operating system</th>
+<th align="center">Architectures</th>
+<th align="center">Notes</th>
</tr>
<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>FreeBSD 8 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 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup></td></tr>
-<tr><td>Windows 2000 or later</td> <td>amd64, 386</td> <td>use mingw gcc<sup>&#8224;</sup>; cygwin or msys is not needed</td></tr>
+<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>&#8224;</sup>. No need for cgywin or msys.</td></tr>
</table>
<p>
@@ -70,18 +70,19 @@ first <a href="#uninstall">remove the existing version</a>.
<h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
<p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-FreeBSD+OR+OpSys-Linux+OR+OpSys-OSX+Type-Archive">Download the archive</a>
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the archive</a>
and extract it into <code>/usr/local</code>, creating a Go tree in
<code>/usr/local/go</code>. For example:
</p>
<pre>
-tar -C /usr/local -xzf go1.2.1.linux-amd64.tar.gz
+tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
</pre>
<p>
-The name of the archive may differ, depending on the version of Go you are
-installing and your system's operating system and processor architecture.
+Choose the archive file appropriate for your installation.
+For instance, if you are installing Go version 1.2.1 for 64-bit x86 on Linux,
+the archive you want is called <code>go1.2.1.linux-amd64.tar.gz</code>.
</p>
<p>
@@ -126,7 +127,7 @@ location.
<h3 id="osx">Mac OS X package installer</h3>
<p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-OSX+Type-Installer">Download the package file</a>,
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the package file</a>,
open it, and follow the prompts to install the Go tools.
The package installs the Go distribution to <code>/usr/local/go</code>.
</p>
@@ -149,7 +150,7 @@ MSI installer that configures your installation automatically.
<h4 id="windows_msi">MSI installer</h4>
<p>
-Open the <a href="http://code.google.com/p/go/downloads/list?q=OpSys-Windows+Type%3DInstaller">MSI file</a>
+Open the <a href="https://code.google.com/p/go/wiki/Downloads?tm=2">MSI file</a>
and follow the prompts to install the Go tools.
By default, the installer puts the Go distribution in <code>c:\Go</code>.
</p>
@@ -163,7 +164,7 @@ command prompts for the change to take effect.
<h4 id="windows_zip">Zip archive</h4>
<p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-Windows+Type%3DArchive">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
</p>
<p>
@@ -227,7 +228,7 @@ You just need to do a little more setup.
</p>
<p>
-<a href="/doc/code.html" class="download" id="start">
+<a href="/doc/code.html" class="download" id="writing">
<span class="big">How to Write Go Code</span>
<span class="desc">Learn how to set up and use the Go tools</span>
</a>
diff --git a/doc/root.html b/doc/root.html
index 48280ac35..43637933a 100644
--- a/doc/root.html
+++ b/doc/root.html
@@ -140,7 +140,6 @@ window.initFuncs.push(function() {
var videos = [
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
- {h: 233, s: "//player.vimeo.com/video/53221560"}, // Grows with grace
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
];
var v = videos[Math.floor(Math.random()*videos.length)];
diff --git a/include/bio.h b/include/bio.h
index 5506c7c32..f61409b8a 100644
--- a/include/bio.h
+++ b/include/bio.h
@@ -33,8 +33,6 @@ extern "C" {
AUTOLIB(bio)
#endif
-#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
-
typedef struct Biobuf Biobuf;
enum
@@ -75,7 +73,7 @@ struct Biobuf
* next few bytes in little-endian order.
*/
#define BGETC(bp)\
- ((bp)->icount?(bp)->ebuf[(bp)->icount++]:Bgetc((bp)))
+ ((bp)->icount?(int)((bp)->ebuf[(bp)->icount++]):Bgetc((bp)))
#define BGETLE2(bp)\
((bp)->icount<=-2?((bp)->icount+=2,((bp)->ebuf[(bp)->icount-2])|((bp)->ebuf[(bp)->icount-1]<<8)):Bgetle2((bp)))
#define BGETLE4(bp)\
diff --git a/include/bootexec.h b/include/bootexec.h
deleted file mode 100644
index 49721ea33..000000000
--- a/include/bootexec.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Inferno libmach/bootexec.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/bootexec.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-struct coffsect
-{
- char name[8];
- uint32 phys;
- uint32 virt;
- uint32 size;
- uint32 fptr;
- uint32 fptrreloc;
- uint32 fptrlineno;
- uint32 nrelocnlineno;
- uint32 flags;
-};
-
-/*
- * proprietary exec headers, needed to bootstrap various machines
- */
-struct mipsexec
-{
- short mmagic; /* (0x160) mips magic number */
- short nscns; /* (unused) number of sections */
- int32 timdat; /* (unused) time & date stamp */
- int32 symptr; /* offset to symbol table */
- int32 nsyms; /* size of symbol table */
- short opthdr; /* (0x38) sizeof(optional hdr) */
- short pcszs; /* flags */
- short amagic; /* see above */
- short vstamp; /* version stamp */
- int32 tsize; /* text size in bytes */
- int32 dsize; /* initialized data */
- int32 bsize; /* uninitialized data */
- int32 mentry; /* entry pt. */
- int32 text_start; /* base of text used for this file */
- int32 data_start; /* base of data used for this file */
- int32 bss_start; /* base of bss used for this file */
- int32 gprmask; /* general purpose register mask */
-union{
- int32 cprmask[4]; /* co-processor register masks */
- int32 pcsize;
-};
- int32 gp_value; /* the gp value used for this object */
-};
-
-struct mips4kexec
-{
- struct mipsexec h;
- struct coffsect itexts;
- struct coffsect idatas;
- struct coffsect ibsss;
-};
-
-struct sparcexec
-{
- short sjunk; /* dynamic bit and version number */
- short smagic; /* 0407 */
- uint32 stext;
- uint32 sdata;
- uint32 sbss;
- uint32 ssyms;
- uint32 sentry;
- uint32 strsize;
- uint32 sdrsize;
-};
-
-struct nextexec
-{
-/* UNUSED
- struct nexthdr{
- uint32 nmagic;
- uint32 ncputype;
- uint32 ncpusubtype;
- uint32 nfiletype;
- uint32 ncmds;
- uint32 nsizeofcmds;
- uint32 nflags;
- };
-
- struct nextcmd{
- uint32 cmd;
- uint32 cmdsize;
- uchar segname[16];
- uint32 vmaddr;
- uint32 vmsize;
- uint32 fileoff;
- uint32 filesize;
- uint32 maxprot;
- uint32 initprot;
- uint32 nsects;
- uint32 flags;
- }textc;
- struct nextsect{
- char sectname[16];
- char segname[16];
- uint32 addr;
- uint32 size;
- uint32 offset;
- uint32 align;
- uint32 reloff;
- uint32 nreloc;
- uint32 flags;
- uint32 reserved1;
- uint32 reserved2;
- }texts;
- struct nextcmd datac;
- struct nextsect datas;
- struct nextsect bsss;
- struct nextsym{
- uint32 cmd;
- uint32 cmdsize;
- uint32 symoff;
- uint32 nsyms;
- uint32 spoff;
- uint32 pcoff;
- }symc;
-*/
-};
-
-struct i386exec
-{
-/* UNUSED
- struct i386coff{
- uint32 isectmagic;
- uint32 itime;
- uint32 isyms;
- uint32 insyms;
- uint32 iflags;
- };
- struct i386hdr{
- uint32 imagic;
- uint32 itextsize;
- uint32 idatasize;
- uint32 ibsssize;
- uint32 ientry;
- uint32 itextstart;
- uint32 idatastart;
- };
- struct coffsect itexts;
- struct coffsect idatas;
- struct coffsect ibsss;
- struct coffsect icomments;
-*/
-};
diff --git a/include/link.h b/include/link.h
new file mode 100644
index 000000000..248497888
--- /dev/null
+++ b/include/link.h
@@ -0,0 +1,616 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+typedef struct Addr Addr;
+typedef struct Prog Prog;
+typedef struct LSym LSym;
+typedef struct Reloc Reloc;
+typedef struct Auto Auto;
+typedef struct Hist Hist;
+typedef struct Link Link;
+typedef struct Plist Plist;
+typedef struct LinkArch LinkArch;
+typedef struct Library Library;
+
+typedef struct Pcln Pcln;
+typedef struct Pcdata Pcdata;
+typedef struct Pciter Pciter;
+
+// prevent incompatible type signatures between liblink and 8l on Plan 9
+#pragma incomplete struct Node
+
+struct Addr
+{
+ vlong offset;
+
+ union
+ {
+ char sval[8];
+ float64 dval;
+ Prog* branch; // for 5g, 6g, 8g
+ } u;
+
+ LSym* sym;
+ LSym* gotype;
+ short type;
+ uint8 index;
+ int8 scale;
+ int8 reg; // for 5l
+ int8 name; // for 5l
+ int8 class; // for 5l
+ uint8 etype; // for 5g, 6g, 8g
+ int32 offset2; // for 5l, 8l
+ struct Node* node; // for 5g, 6g, 8g
+ int64 width; // for 5g, 6g, 8g
+};
+
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ uchar done;
+ int32 type;
+ int64 add;
+ int64 xadd;
+ LSym* sym;
+ LSym* xsym;
+};
+
+struct Prog
+{
+ vlong pc;
+ int32 lineno;
+ Prog* link;
+ short as;
+ uchar reg; // arm only
+ uchar scond; // arm only
+ Addr from;
+ Addr to;
+
+ // for 5g, 6g, 8g internal use
+ void* opt;
+
+ // for 5l, 6l, 8l internal use
+ Prog* forwd;
+ Prog* pcond;
+ Prog* comefrom; // 6l, 8l
+ Prog* pcrel; // 5l
+ int32 spadj;
+ uchar mark;
+ uchar back; // 6l, 8l
+ char ft; /* 6l, 8l oclass cache */
+ char tt; // 6l, 8l
+ uchar optab; // 5l
+ uchar isize; // 6l, 8l
+
+ char width; /* fake for DATA */
+ char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
+};
+
+// prevent incompatible type signatures between liblink and 8l on Plan 9
+#pragma incomplete struct Section
+
+struct LSym
+{
+ char* name;
+ char* extname; // name used in external object files
+ short type;
+ short version;
+ uchar dupok;
+ uchar external;
+ uchar nosplit;
+ uchar reachable;
+ uchar cgoexport;
+ uchar special;
+ uchar stkcheck;
+ uchar hide;
+ uchar leaf; // arm only
+ uchar fnptr; // arm only
+ uchar seenglobl;
+ uchar onlist; // on the textp or datap lists
+ int16 symid; // for writing .5/.6/.8 files
+ int32 dynid;
+ int32 sig;
+ int32 plt;
+ int32 got;
+ int32 align; // if non-zero, required alignment in bytes
+ int32 elfsym;
+ int32 args; // size of stack frame incoming arguments area
+ int32 locals; // size of stack frame locals area (arm only?)
+ vlong value;
+ vlong size;
+ LSym* hash; // in hash table
+ LSym* allsym; // in all symbol list
+ LSym* next; // in text or data list
+ LSym* sub; // in SSUB list
+ LSym* outer; // container of sub
+ LSym* gotype;
+ LSym* reachparent;
+ LSym* queue;
+ char* file;
+ char* dynimplib;
+ char* dynimpvers;
+ struct Section* sect;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+ Prog* etext;
+ Pcln* pcln;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
+};
+
+// LSym.type
+enum
+{
+ Sxxx,
+
+ /* order here is order in output file */
+ /* readonly, executable */
+ STEXT,
+ SELFRXSECT,
+
+ /* readonly, non-executable */
+ STYPE,
+ SSTRING,
+ SGOSTRING,
+ SGOFUNC,
+ SRODATA,
+ SFUNCTAB,
+ STYPELINK,
+ SSYMTAB, // TODO: move to unmapped section
+ SPCLNTAB,
+ SELFROSECT,
+
+ /* writable, non-executable */
+ SMACHOPLT,
+ SELFSECT,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SNOPTRDATA,
+ SINITARR,
+ SDATA,
+ SWINDOWS,
+ SBSS,
+ SNOPTRBSS,
+ STLSBSS,
+
+ /* not mapped */
+ SXREF,
+ SMACHOSYMSTR,
+ SMACHOSYMTAB,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
+ SFILE,
+ SFILEPATH,
+ SCONST,
+ SDYNIMPORT,
+ SHOSTOBJ,
+
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
+ SMASK = SSUB - 1,
+ SHIDDEN = 1<<9, // hidden or local symbol
+};
+
+// Reloc.type
+enum
+{
+ R_ADDR = 1,
+ R_SIZE,
+ R_CALL, // relocation for direct PC-relative call
+ R_CALLARM, // relocation for ARM direct call
+ R_CALLIND, // marker for indirect call (no actual relocating necessary)
+ R_CONST,
+ R_PCREL,
+ R_TLS,
+ R_TLS_LE, // TLS local exec offset from TLS segment register
+ R_TLS_IE, // TLS initial exec offset from TLS base pointer
+ R_GOTOFF,
+ R_PLT0,
+ R_PLT1,
+ R_PLT2,
+ R_USEFIELD,
+};
+
+// Auto.type
+enum
+{
+ A_AUTO = 1,
+ A_PARAM,
+};
+
+struct Auto
+{
+ LSym* asym;
+ Auto* link;
+ int32 aoffset;
+ int16 type;
+ LSym* gotype;
+};
+
+enum
+{
+ LINKHASH = 100003,
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ int32 line;
+ int32 offset;
+};
+
+struct Plist
+{
+ LSym* name;
+ Prog* firstpc;
+ int recur;
+ Plist* link;
+};
+
+struct Library
+{
+ char *objref; // object where we found the reference
+ char *srcref; // src file where we found the reference
+ char *file; // object file
+ char *pkg; // import path
+};
+
+struct Pcdata
+{
+ uchar *p;
+ int n;
+ int m;
+};
+
+struct Pcln
+{
+ Pcdata pcsp;
+ Pcdata pcfile;
+ Pcdata pcline;
+ Pcdata *pcdata;
+ int npcdata;
+ LSym **funcdata;
+ int64 *funcdataoff;
+ int nfuncdata;
+
+ LSym **file;
+ int nfile;
+ int mfile;
+
+ LSym *lastfile;
+ int lastindex;
+};
+
+// Pcdata iterator.
+// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
+struct Pciter
+{
+ Pcdata d;
+ uchar *p;
+ uint32 pc;
+ uint32 nextpc;
+ uint32 pcscale;
+ int32 value;
+ int start;
+ int done;
+};
+
+void pciterinit(Link*, Pciter*, Pcdata*);
+void pciternext(Pciter*);
+
+// symbol version, incremented each time a file is loaded.
+// version==1 is reserved for savehist.
+enum
+{
+ HistVersion = 1,
+};
+
+// Link holds the context for writing object code from a compiler
+// to be linker input or for reading that input into the linker.
+struct Link
+{
+ int32 thechar; // '5' (arm), '6' (amd64), etc.
+ char* thestring; // full name of architecture ("arm", "amd64", ..)
+ int32 goarm; // for arm only, GOARM setting
+ int headtype;
+
+ LinkArch* arch;
+ int32 (*ignore)(char*); // do not emit names satisfying this function
+ int32 debugasm; // -S flag in compiler
+ int32 debugline; // -L flag in compiler
+ int32 debughist; // -O flag in linker
+ int32 debugread; // -W flag in linker
+ int32 debugvlog; // -v flag in linker
+ int32 debugstack; // -K flag in linker
+ int32 debugzerostack; // -Z flag in linker
+ int32 debugdivmod; // -M flag in 5l
+ int32 debugfloat; // -F flag in 5l
+ int32 debugpcln; // -O flag in linker
+ int32 flag_shared; // -shared flag in linker
+ int32 iself;
+ Biobuf* bso; // for -v flag
+ char* pathname;
+ int32 windows;
+ char* trimpath;
+ char* goroot;
+ char* goroot_final;
+
+ // hash table of all symbols
+ LSym* hash[LINKHASH];
+ LSym* allsym;
+ int32 nsymbol;
+
+ // file-line history
+ Hist* hist;
+ Hist* ehist;
+
+ // all programs
+ Plist* plist;
+ Plist* plast;
+
+ // code generation
+ LSym* sym_div;
+ LSym* sym_divu;
+ LSym* sym_mod;
+ LSym* sym_modu;
+ LSym* symmorestack[20];
+ LSym* gmsym;
+ LSym* plan9tos;
+ Prog* curp;
+ Prog* printp;
+ Prog* blitrl;
+ Prog* elitrl;
+ int rexflag;
+ int rep; // for nacl
+ int repn; // for nacl
+ int lock; // for nacl
+ int asmode;
+ uchar* andptr;
+ uchar and[100];
+ int32 instoffset;
+ int32 autosize;
+ int32 armsize;
+
+ // for reading input files (during linker)
+ vlong pc;
+ char** libdir;
+ int32 nlibdir;
+ int32 maxlibdir;
+ Library* library;
+ int libraryp;
+ int nlibrary;
+ int tlsoffset;
+ void (*diag)(char*, ...);
+ int mode;
+ Auto* curauto;
+ Auto* curhist;
+ LSym* cursym;
+ int version;
+ LSym* textp;
+ LSym* etextp;
+ int32 histdepth;
+ int32 nhistfile;
+ LSym* filesyms;
+};
+
+// LinkArch is the definition of a single architecture.
+struct LinkArch
+{
+ char* name; // "arm", "amd64", and so on
+ int thechar; // '5', '6', and so on
+
+ void (*addstacksplit)(Link*, LSym*);
+ void (*assemble)(Link*, LSym*);
+ int (*datasize)(Prog*);
+ void (*follow)(Link*, LSym*);
+ int (*iscall)(Prog*);
+ int (*isdata)(Prog*);
+ Prog* (*prg)(void);
+ void (*progedit)(Link*, Prog*);
+ void (*settextflag)(Prog*, int);
+ int (*symtype)(Addr*);
+ int (*textflag)(Prog*);
+
+ int minlc;
+ int ptrsize;
+ int regsize;
+
+ // TODO: Give these the same values on all systems.
+ int D_ADDR;
+ int D_AUTO;
+ int D_BRANCH;
+ int D_CONST;
+ int D_EXTERN;
+ int D_FCONST;
+ int D_NONE;
+ int D_PARAM;
+ int D_SCONST;
+ int D_STATIC;
+
+ int ACALL;
+ int ADATA;
+ int AEND;
+ int AFUNCDATA;
+ int AGLOBL;
+ int AJMP;
+ int ANOP;
+ int APCDATA;
+ int ARET;
+ int ATEXT;
+ int ATYPE;
+ int AUSEFIELD;
+};
+
+/* executable header types */
+enum {
+ Hunknown = 0,
+ Hdarwin,
+ Hdragonfly,
+ Helf,
+ Hfreebsd,
+ Hlinux,
+ Hnacl,
+ Hnetbsd,
+ Hopenbsd,
+ Hplan9,
+ Hsolaris,
+ Hwindows,
+};
+
+enum
+{
+ LinkAuto = 0,
+ LinkInternal,
+ LinkExternal,
+};
+
+extern uchar fnuxi8[8];
+extern uchar fnuxi4[4];
+extern uchar inuxi1[1];
+extern uchar inuxi2[2];
+extern uchar inuxi4[4];
+extern uchar inuxi8[8];
+
+// asm5.c
+void span5(Link *ctxt, LSym *s);
+int chipfloat5(Link *ctxt, float64 e);
+int chipzero5(Link *ctxt, float64 e);
+
+// asm6.c
+void span6(Link *ctxt, LSym *s);
+
+// asm8.c
+void span8(Link *ctxt, LSym *s);
+
+// data.c
+vlong addaddr(Link *ctxt, LSym *s, LSym *t);
+vlong addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add);
+vlong addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add);
+vlong addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add);
+Reloc* addrel(LSym *s);
+vlong addsize(Link *ctxt, LSym *s, LSym *t);
+vlong adduint16(Link *ctxt, LSym *s, uint16 v);
+vlong adduint32(Link *ctxt, LSym *s, uint32 v);
+vlong adduint64(Link *ctxt, LSym *s, uint64 v);
+vlong adduint8(Link *ctxt, LSym *s, uint8 v);
+vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid);
+void mangle(char *file);
+void savedata(Link *ctxt, LSym *s, Prog *p, char *pn);
+vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
+vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
+vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v);
+vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 v);
+vlong setuint64(Link *ctxt, LSym *s, vlong r, uint64 v);
+vlong setuint8(Link *ctxt, LSym *s, vlong r, uint8 v);
+vlong setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid);
+void symgrow(Link *ctxt, LSym *s, vlong siz);
+
+// go.c
+void double2ieee(uint64 *ieee, double native);
+void* emallocz(long n);
+void* erealloc(void *p, long n);
+char* estrdup(char *p);
+char* expandpkg(char *t0, char *pkg);
+
+// ld.c
+void addhist(Link *ctxt, int32 line, int type);
+void addlib(Link *ctxt, char *src, char *obj, char *path);
+void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg);
+void collapsefrog(Link *ctxt, LSym *s);
+void copyhistfrog(Link *ctxt, char *buf, int nbuf);
+int find1(int32 l, int c);
+void linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l);
+void histtoauto(Link *ctxt);
+void mkfwd(LSym*);
+void nuxiinit(void);
+void savehist(Link *ctxt, int32 line, int32 off);
+Prog* copyp(Link*, Prog*);
+Prog* appendp(Link*, Prog*);
+vlong atolwhex(char*);
+
+// list[568].c
+void listinit5(void);
+void listinit6(void);
+void listinit8(void);
+
+// obj.c
+int linklinefmt(Link *ctxt, Fmt *fp);
+void linklinehist(Link *ctxt, int lineno, char *f, int offset);
+Plist* linknewplist(Link *ctxt);
+void linkprfile(Link *ctxt, int32 l);
+
+// objfile.c
+void ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path);
+void writeobj(Link *ctxt, Biobuf *b);
+
+// pass.c
+Prog* brchain(Link *ctxt, Prog *p);
+Prog* brloop(Link *ctxt, Prog *p);
+void linkpatch(Link *ctxt, LSym *sym);
+
+// pcln.c
+void linkpcln(Link*, LSym*);
+
+// sym.c
+LSym* linklookup(Link *ctxt, char *name, int v);
+Link* linknew(LinkArch*);
+LSym* linknewsym(Link *ctxt, char *symb, int v);
+LSym* linkrlookup(Link *ctxt, char *name, int v);
+int linksymfmt(Fmt *f);
+int headtype(char*);
+char* headstr(int);
+
+extern char* anames5[];
+extern char* anames6[];
+extern char* anames8[];
+
+extern LinkArch link386;
+extern LinkArch linkamd64;
+extern LinkArch linkamd64p32;
+extern LinkArch linkarm;
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Addr*
+#pragma varargck type "lD" Addr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "R" int
+
+// TODO(ality): remove this workaround.
+// It's here because Pconv in liblink/list?.c references %L.
+#pragma varargck type "L" int32
diff --git a/include/mach.h b/include/mach.h
deleted file mode 100644
index cf7151cfd..000000000
--- a/include/mach.h
+++ /dev/null
@@ -1,411 +0,0 @@
-// Inferno libmach/a.out.h and libmach/mach.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/a.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/mach.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * Architecture-dependent application data
- */
-
-typedef struct Exec Exec;
-struct Exec
-{
- int32 magic; /* magic number */
- int32 text; /* size of text segment */
- int32 data; /* size of initialized data */
- int32 bss; /* size of uninitialized data */
- int32 syms; /* size of symbol table */
- int32 entry; /* entry point */
- int32 spsz; /* size of pc/sp offset table */
- int32 pcsz; /* size of pc/line number table */
-};
-
-#define HDR_MAGIC 0x00008000 /* header expansion */
-
-#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
-#define A_MAGIC _MAGIC(0, 8) /* 68020 */
-#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
-#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
-#define K_MAGIC _MAGIC(0, 13) /* sparc */
-#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
-#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
-#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
-#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
-#define E_MAGIC _MAGIC(0, 20) /* arm */
-#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
-#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
-#define L_MAGIC _MAGIC(0, 23) /* dec alpha */
-#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
-#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
-#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
-#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
-
-#define MIN_MAGIC 8
-#define MAX_MAGIC 27 /* <= 90 */
-
-#define DYN_MAGIC 0x80000000 /* dlm */
-
-typedef struct Sym Sym;
-struct Sym
-{
- vlong value;
- uint sig;
- char type;
- char *name;
- vlong gotype;
- int sequence; // order in file
-};
-
-
-/*
- * Supported architectures:
- * mips,
- * 68020,
- * i386,
- * amd64,
- * sparc,
- * sparc64,
- * mips2 (R4000)
- * arm
- * powerpc,
- * powerpc64
- * alpha
- */
-enum
-{
- MMIPS, /* machine types */
- MSPARC,
- M68020,
- MI386,
- MI960, /* retired */
- M3210, /* retired */
- MMIPS2,
- NMIPS2,
- M29000, /* retired */
- MARM,
- MPOWER,
- MALPHA,
- NMIPS,
- MSPARC64,
- MAMD64,
- MPOWER64,
- /* types of executables */
- FNONE = 0, /* unidentified */
- FMIPS, /* v.out */
- FMIPSB, /* mips bootable */
- FSPARC, /* k.out */
- FSPARCB, /* Sparc bootable */
- F68020, /* 2.out */
- F68020B, /* 68020 bootable */
- FNEXTB, /* Next bootable */
- FI386, /* 8.out */
- FI386B, /* I386 bootable */
- FI960, /* retired */
- FI960B, /* retired */
- F3210, /* retired */
- FMIPS2BE, /* 4.out */
- F29000, /* retired */
- FARM, /* 5.out */
- FARMB, /* ARM bootable */
- FPOWER, /* q.out */
- FPOWERB, /* power pc bootable */
- FMIPS2LE, /* 0.out */
- FALPHA, /* 7.out */
- FALPHAB, /* DEC Alpha bootable */
- FMIPSLE, /* 3k little endian */
- FSPARC64, /* u.out */
- FAMD64, /* 6.out */
- FAMD64B, /* 6.out bootable */
- FPOWER64, /* 9.out */
- FPOWER64B, /* 9.out bootable */
- FWINPE, /* windows PE executable */
-
- ANONE = 0, /* dissembler types */
- AMIPS,
- AMIPSCO, /* native mips */
- ASPARC,
- ASUNSPARC, /* native sun */
- A68020,
- AI386,
- AI8086, /* oh god */
- AI960, /* retired */
- A29000, /* retired */
- AARM,
- APOWER,
- AALPHA,
- ASPARC64,
- AAMD64,
- APOWER64,
- /* object file types */
- Obj68020 = 0, /* .2 */
- ObjSparc, /* .k */
- ObjMips, /* .v */
- Obj386, /* .8 */
- Obj960, /* retired */
- Obj3210, /* retired */
- ObjMips2, /* .4 */
- Obj29000, /* retired */
- ObjArm, /* .5 */
- ObjPower, /* .q */
- ObjMips2le, /* .0 */
- ObjAlpha, /* .7 */
- ObjSparc64, /* .u */
- ObjAmd64, /* .6 */
- ObjSpim, /* .0 */
- ObjPower64, /* .9 */
- Maxobjtype,
-
- CNONE = 0, /* symbol table classes */
- CAUTO,
- CPARAM,
- CSTAB,
- CTEXT,
- CDATA,
- CANY, /* to look for any class */
-};
-
-typedef struct Map Map;
-typedef struct Symbol Symbol;
-typedef struct Reglist Reglist;
-typedef struct Mach Mach;
-typedef struct Machdata Machdata;
-typedef struct Seg Seg;
-
-typedef int Maprw(Map *m, Seg *s, uvlong addr, void *v, uint n, int isread);
-
-struct Seg {
- char *name; /* the segment name */
- int fd; /* file descriptor */
- int inuse; /* in use - not in use */
- int cache; /* should cache reads? */
- uvlong b; /* base */
- uvlong e; /* end */
- vlong f; /* offset within file */
- Maprw *rw; /* read/write fn for seg */
-};
-
-/*
- * Structure to map a segment to data
- */
-struct Map {
- int pid;
- int tid;
- int nsegs; /* number of segments */
- Seg seg[1]; /* actually n of these */
-};
-
-/*
- * Internal structure describing a symbol table entry
- */
-struct Symbol {
- void *handle; /* used internally - owning func */
- struct {
- char *name;
- vlong value; /* address or stack offset */
- char type; /* as in a.out.h */
- char class; /* as above */
- int index; /* in findlocal, globalsym, textsym */
- };
-};
-
-/*
- * machine register description
- */
-struct Reglist {
- char *rname; /* register name */
- short roffs; /* offset in u-block */
- char rflags; /* INTEGER/FLOAT, WRITABLE */
- char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
-};
-
-enum { /* bits in rflags field */
- RINT = (0<<0),
- RFLT = (1<<0),
- RRDONLY = (1<<1),
-};
-
-/*
- * Machine-dependent data is stored in two structures:
- * Mach - miscellaneous general parameters
- * Machdata - jump vector of service functions used by debuggers
- *
- * Mach is defined in ?.c and set in executable.c
- *
- * Machdata is defined in ?db.c
- * and set in the debugger startup.
- */
-struct Mach{
- char *name;
- int mtype; /* machine type code */
- Reglist *reglist; /* register set */
- int32 regsize; /* sizeof registers in bytes */
- int32 fpregsize; /* sizeof fp registers in bytes */
- char *pc; /* pc name */
- char *sp; /* sp name */
- char *link; /* link register name */
- char *sbreg; /* static base register name */
- uvlong sb; /* static base register value */
- int pgsize; /* page size */
- uvlong kbase; /* kernel base address */
- uvlong ktmask; /* ktzero = kbase & ~ktmask */
- uvlong utop; /* user stack top */
- int pcquant; /* quantization of pc */
- int szaddr; /* sizeof(void*) */
- int szreg; /* sizeof(register) */
- int szfloat; /* sizeof(float) */
- int szdouble; /* sizeof(double) */
-};
-
-extern Mach *mach; /* Current machine */
-
-typedef uvlong (*Rgetter)(Map*, char*);
-typedef void (*Tracer)(Map*, uvlong, uvlong, Symbol*);
-
-struct Machdata { /* Machine-dependent debugger support */
- uchar bpinst[4]; /* break point instr. */
- short bpsize; /* size of break point instr. */
-
- ushort (*swab)(ushort); /* ushort to local byte order */
- uint32 (*swal)(uint32); /* uint32 to local byte order */
- uvlong (*swav)(uvlong); /* uvlong to local byte order */
- int (*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */
- uvlong (*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */
- char* (*excep)(Map*, Rgetter); /* last exception */
- uint32 (*bpfix)(uvlong); /* breakpoint fixup */
- int (*sftos)(char*, int, void*); /* single precision float */
- int (*dftos)(char*, int, void*); /* double precision float */
- int (*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */
- int (*das)(Map*, uvlong, char, char*, int); /* symbolic disassembly */
- int (*hexinst)(Map*, uvlong, char*, int); /* hex disassembly */
- int (*instsize)(Map*, uvlong); /* instruction size */
-};
-
-/*
- * Common a.out header describing all architectures
- */
-typedef struct Fhdr
-{
- char *name; /* identifier of executable */
- uchar type; /* file type - see codes above */
- uchar hdrsz; /* header size */
- uchar _magic; /* _MAGIC() magic */
- uchar spare;
- int32 magic; /* magic number */
- uvlong txtaddr; /* text address */
- vlong txtoff; /* start of text in file */
- uvlong dataddr; /* start of data segment */
- vlong datoff; /* offset to data seg in file */
- vlong symoff; /* offset of symbol table in file */
- uvlong entry; /* entry point */
- vlong sppcoff; /* offset of sp-pc table in file */
- vlong lnpcoff; /* offset of line number-pc table in file */
- int32 txtsz; /* text size */
- int32 datsz; /* size of data seg */
- int32 bsssz; /* size of bss */
- int32 symsz; /* size of symbol table */
- int32 sppcsz; /* size of sp-pc table */
- int32 lnpcsz; /* size of line number-pc table */
-} Fhdr;
-
-extern int asstype; /* dissembler type - machdata.c */
-extern Machdata *machdata; /* jump vector - machdata.c */
-
-int beieee80ftos(char*, int, void*);
-int beieeesftos(char*, int, void*);
-int beieeedftos(char*, int, void*);
-ushort beswab(ushort);
-uint32 beswal(uint32);
-uvlong beswav(uvlong);
-uvlong ciscframe(Map*, uvlong, uvlong, uvlong, uvlong);
-int cisctrace(Map*, uvlong, uvlong, uvlong, Tracer);
-int crackhdr(int fd, Fhdr*);
-uvlong file2pc(char*, int32);
-int fileelem(Sym**, uchar *, char*, int);
-int32 fileline(char*, int, uvlong);
-int filesym(int, char*, int);
-int findlocal(Symbol*, char*, Symbol*);
-int findseg(Map*, char*);
-int findsym(uvlong, int, Symbol *);
-int fnbound(uvlong, uvlong*);
-int fpformat(Map*, Reglist*, char*, int, int);
-int get1(Map*, uvlong, uchar*, int);
-int get2(Map*, uvlong, ushort*);
-int get4(Map*, uvlong, uint32*);
-int get8(Map*, uvlong, uvlong*);
-int geta(Map*, uvlong, uvlong*);
-int getauto(Symbol*, int, int, Symbol*);
-Sym* getsym(int);
-int globalsym(Symbol *, int);
-char* _hexify(char*, uint32, int);
-int ieeesftos(char*, int, uint32);
-int ieeedftos(char*, int, uint32, uint32);
-int isar(Biobuf*);
-int leieee80ftos(char*, int, void*);
-int leieeesftos(char*, int, void*);
-int leieeedftos(char*, int, void*);
-ushort leswab(ushort);
-uint32 leswal(uint32);
-uvlong leswav(uvlong);
-uvlong line2addr(int32, uvlong, uvlong);
-Map* loadmap(Map*, int, Fhdr*);
-int localaddr(Map*, char*, char*, uvlong*, Rgetter);
-int localsym(Symbol*, int);
-int lookup(char*, char*, Symbol*);
-void machbytype(int);
-int machbyname(char*);
-int nextar(Biobuf*, int, char*);
-Map* newmap(Map*, int);
-void objtraverse(void(*)(Sym*, void*), void*);
-int objtype(Biobuf*, char**);
-uvlong pc2sp(uvlong);
-int32 pc2line(uvlong);
-int put1(Map*, uvlong, uchar*, int);
-int put2(Map*, uvlong, ushort);
-int put4(Map*, uvlong, uint32);
-int put8(Map*, uvlong, uvlong);
-int puta(Map*, uvlong, uvlong);
-int readar(Biobuf*, int, vlong, int);
-int readobj(Biobuf*, int);
-uvlong riscframe(Map*, uvlong, uvlong, uvlong, uvlong);
-int risctrace(Map*, uvlong, uvlong, uvlong, Tracer);
-int setmap(Map*, int, uvlong, uvlong, vlong, char*, Maprw *rw);
-Sym* symbase(int32*);
-int syminit(int, Fhdr*);
-int symoff(char*, int, uvlong, int);
-void textseg(uvlong, Fhdr*);
-int textsym(Symbol*, int);
-void unusemap(Map*, int);
-
-Map* attachproc(int pid, Fhdr *fp);
-int ctlproc(int pid, char *msg);
-void detachproc(Map *m);
-int procnotes(int pid, char ***pnotes);
-char* proctextfile(int pid);
-int procthreadpids(int pid, int *tid, int ntid);
-char* procstatus(int);
-
-Maprw fdrw;
diff --git a/include/plan9/386/u.h b/include/plan9/386/u.h
index 4736b8efb..1c4076b5e 100644
--- a/include/plan9/386/u.h
+++ b/include/plan9/386/u.h
@@ -13,3 +13,5 @@ typedef uint uint32;
typedef vlong int64;
typedef uvlong uint64;
typedef int intptr;
+typedef float float32;
+typedef double float64;
diff --git a/include/plan9/amd64/u.h b/include/plan9/amd64/u.h
index 090b2fa5c..c2d499938 100644
--- a/include/plan9/amd64/u.h
+++ b/include/plan9/amd64/u.h
@@ -13,3 +13,5 @@ typedef uint uint32;
typedef vlong int64;
typedef uvlong uint64;
typedef vlong intptr;
+typedef float float32;
+typedef double float64;
diff --git a/include/plan9/bio.h b/include/plan9/bio.h
new file mode 100644
index 000000000..13d5e0ef2
--- /dev/null
+++ b/include/plan9/bio.h
@@ -0,0 +1,8 @@
+// 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 "../bio.h"
+
+#define fmtcharstod charstod
+#define lseek seek
diff --git a/include/plan9/ureg_amd64.h b/include/plan9/errno.h
index 8aaa83f52..1ed572ace 100644
--- a/include/plan9/ureg_amd64.h
+++ b/include/plan9/errno.h
@@ -1,5 +1,7 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "/amd64/include/ureg.h"
+int errno;
+
+#define ERANGE 1001
diff --git a/include/plan9/fmt.h b/include/plan9/fmt.h
new file mode 100644
index 000000000..b4a4fe791
--- /dev/null
+++ b/include/plan9/fmt.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../fmt.h"
+
+#pragma varargck argpos fmtprint 2
+#pragma varargck argpos fprint 2
+#pragma varargck argpos print 1
+#pragma varargck argpos runeseprint 3
+#pragma varargck argpos runesmprint 1
+#pragma varargck argpos runesnprint 3
+#pragma varargck argpos runesprint 2
+#pragma varargck argpos seprint 3
+#pragma varargck argpos smprint 1
+#pragma varargck argpos snprint 3
+#pragma varargck argpos sprint 2
+
+#pragma varargck type "lld" vlong
+#pragma varargck type "llo" vlong
+#pragma varargck type "llx" vlong
+#pragma varargck type "llb" vlong
+#pragma varargck type "lld" uvlong
+#pragma varargck type "llo" uvlong
+#pragma varargck type "llx" uvlong
+#pragma varargck type "llb" uvlong
+#pragma varargck type "ld" long
+#pragma varargck type "lo" long
+#pragma varargck type "lx" long
+#pragma varargck type "lb" long
+#pragma varargck type "ld" ulong
+#pragma varargck type "lo" ulong
+#pragma varargck type "lx" ulong
+#pragma varargck type "lb" ulong
+#pragma varargck type "d" int
+#pragma varargck type "o" int
+#pragma varargck type "x" int
+#pragma varargck type "c" int
+#pragma varargck type "C" int
+#pragma varargck type "b" int
+#pragma varargck type "d" uint
+#pragma varargck type "x" uint
+#pragma varargck type "c" uint
+#pragma varargck type "C" uint
+#pragma varargck type "b" uint
+#pragma varargck type "f" double
+#pragma varargck type "e" double
+#pragma varargck type "g" double
+#pragma varargck type "s" char*
+#pragma varargck type "q" char*
+#pragma varargck type "S" Rune*
+#pragma varargck type "Q" Rune*
+#pragma varargck type "r" void
+#pragma varargck type "%" void
+#pragma varargck type "n" int*
+#pragma varargck type "p" uintptr
+#pragma varargck type "p" void*
+#pragma varargck flag ','
+#pragma varargck flag ' '
+#pragma varargck flag 'h'
+#pragma varargck type "<" void*
+#pragma varargck type "[" void*
+#pragma varargck type "H" void*
+#pragma varargck type "lH" void*
diff --git a/include/plan9/libc.h b/include/plan9/libc.h
index 798e47095..773edeee3 100644
--- a/include/plan9/libc.h
+++ b/include/plan9/libc.h
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "/sys/include/libc.h"
#include "/sys/include/ctype.h"
+#include "fmt.h"
+#include "utf.h"
+#include "libc_plan9.h"
char* getgoos(void);
char* getgoarch(void);
@@ -26,3 +28,6 @@ void flagprint(int);
// The libraries use size_t to avoid -Wconversion warnings from GCC
// when calling standard library functions like memcpy.
typedef unsigned long size_t;
+
+// math.h
+#define HUGE_VAL 1.79769313486231e+308
diff --git a/include/plan9/mach.h b/include/plan9/link.h
index 636f44fe8..f65971efc 100644
--- a/include/plan9/mach.h
+++ b/include/plan9/link.h
@@ -1,5 +1,5 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 "../mach.h"
+#include "../link.h"
diff --git a/include/plan9/mklibc.rc b/include/plan9/mklibc.rc
new file mode 100755
index 000000000..449e15fdf
--- /dev/null
+++ b/include/plan9/mklibc.rc
@@ -0,0 +1,8 @@
+#!/bin/rc
+
+pattern='/umuldiv/d
+ /rune routines/,/^\/\*/d
+ /print routines/,/^\/\*/d
+ /error string for/,/^\/\*/d'
+
+sed -e $pattern /sys/include/libc.h | awk '/^enum/ && !n++, /^};/ {next}1'
diff --git a/include/plan9/stdarg.h b/include/plan9/stdarg.h
new file mode 100644
index 000000000..b562a3a6e
--- /dev/null
+++ b/include/plan9/stdarg.h
@@ -0,0 +1,3 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
diff --git a/include/plan9/ureg_x86.h b/include/plan9/utf.h
index 7d73a4865..03c26d69d 100644
--- a/include/plan9/ureg_x86.h
+++ b/include/plan9/utf.h
@@ -1,5 +1,5 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "/386/include/ureg.h"
+#include "../utf.h"
diff --git a/include/u.h b/include/u.h
index 44bfcd63b..6b2d50cc1 100644
--- a/include/u.h
+++ b/include/u.h
@@ -188,6 +188,8 @@ typedef u32int uint32;
typedef s64int int64;
typedef u64int uint64;
+typedef float float32;
+typedef double float64;
#undef _NEEDUCHAR
#undef _NEEDUSHORT
diff --git a/include/ureg_amd64.h b/include/ureg_amd64.h
deleted file mode 100644
index 2c39f17ce..000000000
--- a/include/ureg_amd64.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Inferno utils/libmach/ureg6.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg6.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-struct Ureg {
- u64int ax;
- u64int bx;
- u64int cx;
- u64int dx;
- u64int si;
- u64int di;
- u64int bp;
- u64int r8;
- u64int r9;
- u64int r10;
- u64int r11;
- u64int r12;
- u64int r13;
- u64int r14;
- u64int r15;
-
- u16int ds;
- u16int es;
- u16int fs;
- u16int gs;
-
- u64int type;
- u64int error; /* error code (or zero) */
- u64int ip; /* pc */
- u64int cs; /* old context */
- u64int flags; /* old flags */
- u64int sp; /* sp */
- u64int ss; /* old stack segment */
-};
diff --git a/include/ureg_arm.h b/include/ureg_arm.h
deleted file mode 100644
index c740b0302..000000000
--- a/include/ureg_arm.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Inferno utils/libmach/ureg5.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg5.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-struct Ureg {
- uint r0;
- uint r1;
- uint r2;
- uint r3;
- uint r4;
- uint r5;
- uint r6;
- uint r7;
- uint r8;
- uint r9;
- uint r10;
- uint r11;
- uint r12;
- uint r13;
- uint r14;
- uint link;
- uint type;
- uint psr;
- uint pc;
-};
diff --git a/include/ureg_x86.h b/include/ureg_x86.h
deleted file mode 100644
index c20fe4e4c..000000000
--- a/include/ureg_x86.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Inferno utils/libmach/ureg8.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg8.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-struct Ureg
-{
- uint32 di; /* general registers */
- uint32 si; /* ... */
- uint32 bp; /* ... */
- uint32 nsp;
- uint32 bx; /* ... */
- uint32 dx; /* ... */
- uint32 cx; /* ... */
- uint32 ax; /* ... */
- uint32 gs; /* data segments */
- uint32 fs; /* ... */
- uint32 es; /* ... */
- uint32 ds; /* ... */
- uint32 trap; /* trap type */
- uint32 ecode; /* error code (or zero) */
- uint32 pc; /* pc */
- uint32 cs; /* old context */
- uint32 flags; /* old flags */
- union {
- uint32 usp;
- uint32 sp;
- };
- uint32 ss; /* old stack segment */
-};
diff --git a/lib/time/update.bash b/lib/time/update.bash
index f24ef8204..8e1662afd 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -6,11 +6,9 @@
# This script rebuilds the time zone files using files
# downloaded from the ICANN/IANA distribution.
-# NOTE: As of Oct, 2013, the C files will not build on Macs but will build on Linux.
-
# Versions to use.
-CODE=2013g
-DATA=2013g
+CODE=2014d
+DATA=2014d
set -e
rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index c9181153f..e0d3afe07 100644
--- a/lib/time/zoneinfo.zip
+++ b/lib/time/zoneinfo.zip
Binary files differ
diff --git a/misc/bash/go b/misc/bash/go
index f5d79e41a..50f4f720b 100644
--- a/misc/bash/go
+++ b/misc/bash/go
@@ -20,10 +20,9 @@ _go()
local cmd="${COMP_WORDS[1]}"
- local cmds="build clean doc fix fmt get
+ local cmds="build clean env fix fmt get
install list run test tool version vet"
- local addhelp="gopath importpath remote
- testflag testfunc"
+ local addhelp="c gopath importpath packages testflag testfunc"
local other="help"
if [ "$COMP_CWORD" == 1 ]; then
@@ -88,9 +87,6 @@ _go()
COMPREPLY=(`_go_importpath "$cur"`)
fi
;;
- 'doc')
- COMPREPLY=(`_go_importpath "$cur"`)
- ;;
'fix')
COMPREPLY=(`_go_importpath "$cur"`)
;;
@@ -188,15 +184,9 @@ _go()
'dist') # TODO: Implement something.
#_go_tool_dist
;;
- 'ebnflint') # TODO: Implement something.
- #_go_tool_ebnflint
- ;;
'fix') # TODO: Implement something.
#_go_tool_fix
;;
- 'gotype') # TODO: Implement something.
- #_go_tool_gotype
- ;;
'nm') # TODO: Implement something.
#_go_tool_nm
;;
@@ -206,9 +196,6 @@ _go()
'pprof') # TODO: Implement something.
#_go_tool_pprof
;;
- 'prof') # TODO: Implement something.
- #_go_tool_prof
- ;;
'vet') # TODO: Implement something.
#_go_tool_vet
;;
diff --git a/misc/benchcmp b/misc/benchcmp
index 3180f57ea..28a37392d 100755
--- a/misc/benchcmp
+++ b/misc/benchcmp
@@ -1,124 +1,5 @@
-#!/bin/sh
-# Copyright 2011 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
+#!/bin/bash
-case "$1" in
--*)
- echo 'usage: benchcmp old.txt new.txt' >&2
- echo >&2
- echo 'Each input file should be from:' >&2
- echo ' go test -test.run=NONE -test.bench=. > [old,new].txt' >&2
- echo >&2
- echo 'Benchcmp compares the first and last for each benchmark.' >&2
- echo >&2
- echo 'If -test.benchmem=true is added to the "go test" command' >&2
- echo 'benchcmp will also compare memory allocations.' >&2
- exit 2
-esac
-
-awk '
-BEGIN {
- n = 0
-}
-
-$1 ~ /Benchmark/ && $4 == "ns/op" {
- if(old[$1]) {
- if(!saw[$1]++) {
- name[n++] = $1
- if(length($1) > len)
- len = length($1)
- }
- new[$1] = $3
- if($6 == "MB/s")
- newmb[$1] = $5
-
- # allocs/op might be at $8 or $10 depending on if
- # SetBytes was used or not.
- # B/op might be at $6 or $8, it should be immediately
- # followed by allocs/op
- if($8 == "allocs/op") {
- newbytes[$1] = $5
- newalloc[$1] = $7
- }
- if($10 == "allocs/op") {
- newbytes[$1] = $7
- newalloc[$1] = $9
- }
- } else {
- old[$1] = $3
- if($6 == "MB/s")
- oldmb[$1] = $5
- if($8 == "allocs/op") {
- oldbytes[$1] = $5
- oldalloc[$1] = $7
- }
- if($10 == "allocs/op") {
- oldbytes[$1] = $7
- oldalloc[$1] = $9
- }
- }
-}
-
-END {
- if(n == 0) {
- print "benchcmp: no repeated benchmarks" >"/dev/stderr"
- exit 1
- }
-
- printf("%-*s %12s %12s %7s\n", len, "benchmark", "old ns/op", "new ns/op", "delta")
-
- # print ns/op
- for(i=0; i<n; i++) {
- what = name[i]
- printf("%-*s %12d %12d %6s%%\n", len, what, old[what], new[what],
- sprintf("%+.2f", 100*new[what]/old[what]-100))
- }
-
- # print mb/s
- anymb = 0
- for(i=0; i<n; i++) {
- what = name[i]
- if(!(what in newmb))
- continue
- if(anymb++ == 0)
- printf("\n%-*s %12s %12s %7s\n", len, "benchmark", "old MB/s", "new MB/s", "speedup")
- printf("%-*s %12s %12s %6sx\n", len, what,
- sprintf("%.2f", oldmb[what]),
- sprintf("%.2f", newmb[what]),
- sprintf("%.2f", newmb[what]/oldmb[what]))
- }
-
- # print allocs
- anyalloc = 0
- for(i=0; i<n; i++) {
- what = name[i]
- if(!(what in newalloc))
- continue
- if(anyalloc++ == 0)
- printf("\n%-*s %12s %12s %7s\n", len, "benchmark", "old allocs", "new allocs", "delta")
- if(oldalloc[what] == 0)
- delta="n/a"
- else
- delta=sprintf("%.2f", 100*newalloc[what]/oldalloc[what]-100)
- printf("%-*s %12d %12d %6s%%\n", len, what,
- oldalloc[what], newalloc[what], delta)
- }
-
- # print alloc bytes
- anybytes = 0
- for(i=0; i<n; i++) {
- what = name[i]
- if(!(what in newbytes))
- continue
- if(anybytes++ == 0)
- printf("\n%-*s %12s %12s %7s\n", len, "benchmark", "old bytes", "new bytes", "delta")
- if(oldbytes[what] == 0)
- delta="n/a"
- else
- delta=sprintf("%.2f", 100*newbytes[what]/oldbytes[what]-100)
- printf("%-*s %12d %12d %6s%%\n", len, what,
- oldbytes[what], newbytes[what], delta)
- }
-}
-' "$@"
+echo 'misc/benchcmp has moved:' >&2
+echo ' go get -u code.google.com/p/go.tools/cmd/benchcmp' >&2
+exit 2
diff --git a/misc/cgo/errors/err3.go b/misc/cgo/errors/err3.go
new file mode 100644
index 000000000..3680a4a4c
--- /dev/null
+++ b/misc/cgo/errors/err3.go
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+typedef struct foo foo_t;
+typedef struct bar bar_t;
+
+foo_t *foop;
+*/
+import "C"
+
+func main() {
+ x := (*C.bar_t)(nil)
+ C.foop = x // ERROR HERE
+}
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index 697ae2fed..f0f60c844 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -26,6 +26,7 @@ check() {
check err1.go
check err2.go
+check err3.go
rm -rf errs _obj
exit 0
diff --git a/misc/cgo/nocgo/nocgo.go b/misc/cgo/nocgo/nocgo.go
new file mode 100644
index 000000000..00ae5e9c8
--- /dev/null
+++ b/misc/cgo/nocgo/nocgo.go
@@ -0,0 +1,22 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that -static works when not using cgo. This test is in
+// misc/cgo to take advantage of the testing framework support for
+// when -static is expected to work.
+
+package nocgo
+
+func NoCgo() int {
+ c := make(chan int)
+
+ // The test is run with external linking, which means that
+ // goroutines will be created via the runtime/cgo package.
+ // Make sure that works.
+ go func() {
+ c <- 42
+ }()
+
+ return <-c
+}
diff --git a/misc/cgo/nocgo/nocgo_test.go b/misc/cgo/nocgo/nocgo_test.go
new file mode 100644
index 000000000..45d247cf9
--- /dev/null
+++ b/misc/cgo/nocgo/nocgo_test.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package nocgo
+
+import "testing"
+
+func TestNop(t *testing.T) {
+ i := NoCgo()
+ if i != 42 {
+ t.Errorf("got %d, want %d", i, 42)
+ }
+}
diff --git a/misc/cgo/test/backdoor/backdoor.go b/misc/cgo/test/backdoor/backdoor.go
index efe4f01f4..7398772bd 100644
--- a/misc/cgo/test/backdoor/backdoor.go
+++ b/misc/cgo/test/backdoor/backdoor.go
@@ -5,3 +5,4 @@
package backdoor
func LockedOSThread() bool // in runtime.c
+func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr)
diff --git a/misc/cgo/test/backdoor/backdoor_gccgo.go b/misc/cgo/test/backdoor/backdoor_gccgo.go
new file mode 100644
index 000000000..514f76ec5
--- /dev/null
+++ b/misc/cgo/test/backdoor/backdoor_gccgo.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is the gccgo version of the stub in runtime.c.
+
+// +build gccgo
+
+package backdoor
+
+func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) {}
diff --git a/misc/cgo/test/backdoor/runtime.c b/misc/cgo/test/backdoor/runtime.c
index 194a9c8e4..7e6b44872 100644
--- a/misc/cgo/test/backdoor/runtime.c
+++ b/misc/cgo/test/backdoor/runtime.c
@@ -23,3 +23,10 @@ void
b = runtime·lockedOSThread();
FLUSH(&b);
}
+
+// This is what a cgo-compiled stub declaration looks like.
+void
+·Issue7695(struct{void *y[8*sizeof(void*)];}p)
+{
+ USED(p);
+}
diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 056d67c96..0a405c7a3 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -7,3 +7,4 @@ package cgotest
import "testing"
func TestSetgid(t *testing.T) { testSetgid(t) }
+func Test6997(t *testing.T) { test6997(t) }
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index b7c6d2876..eb237725a 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -43,12 +43,15 @@ func TestCflags(t *testing.T) { testCflags(t) }
func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) }
+func Test6833(t *testing.T) { test6833(t) }
func Test3250(t *testing.T) { test3250(t) }
func TestCallbackStack(t *testing.T) { testCallbackStack(t) }
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 Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) }
+func Test7560(t *testing.T) { test7560(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/issue6833.go b/misc/cgo/test/issue6833.go
new file mode 100644
index 000000000..e12d53422
--- /dev/null
+++ b/misc/cgo/test/issue6833.go
@@ -0,0 +1,27 @@
+// 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 cgotest
+
+/*
+extern unsigned long long issue6833Func(unsigned int, unsigned long long);
+*/
+import "C"
+
+import "testing"
+
+//export GoIssue6833Func
+func GoIssue6833Func(aui uint, aui64 uint64) uint64 {
+ return aui64 + uint64(aui)
+}
+
+func test6833(t *testing.T) {
+ ui := 7
+ ull := uint64(0x4000300020001000)
+ v := uint64(C.issue6833Func(C.uint(ui), C.ulonglong(ull)))
+ exp := uint64(ui) + ull
+ if v != exp {
+ t.Errorf("issue6833Func() returns %x, expected %x", v, exp)
+ }
+}
diff --git a/misc/cgo/test/issue6833_c.c b/misc/cgo/test/issue6833_c.c
new file mode 100644
index 000000000..a77b425b5
--- /dev/null
+++ b/misc/cgo/test/issue6833_c.c
@@ -0,0 +1,10 @@
+// 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 "_cgo_export.h"
+
+unsigned long long
+issue6833Func(unsigned int aui, unsigned long long aull) {
+ return GoIssue6833Func(aui, aull);
+}
diff --git a/misc/cgo/test/issue6997_linux.c b/misc/cgo/test/issue6997_linux.c
new file mode 100644
index 000000000..897cdd081
--- /dev/null
+++ b/misc/cgo/test/issue6997_linux.c
@@ -0,0 +1,26 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static pthread_t thread;
+
+static void* threadfunc(void* dummy) {
+ while(1) {
+ sleep(1);
+ }
+}
+
+int StartThread() {
+ return pthread_create(&thread, NULL, &threadfunc, NULL);
+}
+
+int CancelThread() {
+ void *r;
+ pthread_cancel(thread);
+ pthread_join(thread, &r);
+ return (r == PTHREAD_CANCELED);
+}
diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go
new file mode 100644
index 000000000..871bd517a
--- /dev/null
+++ b/misc/cgo/test/issue6997_linux.go
@@ -0,0 +1,40 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that pthread_cancel works as expected
+// (NPTL uses SIGRTMIN to implement thread cancellation)
+// See http://golang.org/issue/6997
+package cgotest
+
+/*
+#cgo CFLAGS: -pthread
+#cgo LDFLAGS: -pthread
+extern int StartThread();
+extern int CancelThread();
+*/
+import "C"
+
+import "testing"
+import "time"
+
+func test6997(t *testing.T) {
+ r := C.StartThread()
+ if r != 0 {
+ t.Error("pthread_create failed")
+ }
+ c := make(chan C.int)
+ go func() {
+ time.Sleep(500 * time.Millisecond)
+ c <- C.CancelThread()
+ }()
+
+ select {
+ case r = <-c:
+ if r == 0 {
+ t.Error("pthread finished but wasn't cancelled??")
+ }
+ case <-time.After(5 * time.Second):
+ t.Error("hung in pthread_cancel/pthread_join")
+ }
+}
diff --git a/misc/cgo/test/issue7234_test.go b/misc/cgo/test/issue7234_test.go
new file mode 100644
index 000000000..713dade4c
--- /dev/null
+++ b/misc/cgo/test/issue7234_test.go
@@ -0,0 +1,21 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+import "testing"
+
+// This test actually doesn't have anything to do with cgo. It is a
+// test of http://golang.org/issue/7234, a compiler/linker bug in
+// handling string constants when using -linkmode=external. The test
+// is in this directory because we routinely test -linkmode=external
+// here.
+
+var v7234 = [...]string{"runtime/cgo"}
+
+func TestIssue7234(t *testing.T) {
+ if v7234[0] != "runtime/cgo" {
+ t.Errorf("bad string constant %q", v7234[0])
+ }
+}
diff --git a/misc/cgo/test/issue7560.go b/misc/cgo/test/issue7560.go
new file mode 100644
index 000000000..4bea6e357
--- /dev/null
+++ b/misc/cgo/test/issue7560.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+#include <stdint.h>
+
+typedef struct {
+ char x;
+ long y;
+} __attribute__((__packed__)) misaligned;
+
+int
+offset7560(void)
+{
+ return (uintptr_t)&((misaligned*)0)->y;
+}
+*/
+import "C"
+
+import (
+ "reflect"
+ "testing"
+)
+
+func test7560(t *testing.T) {
+ // some mingw don't implement __packed__ correctly.
+ if C.offset7560() != 1 {
+ t.Skip("C compiler did not pack struct")
+ }
+
+ // C.misaligned should have x but then a padding field to get to the end of the struct.
+ // There should not be a field named 'y'.
+ var v C.misaligned
+ rt := reflect.TypeOf(&v).Elem()
+ if rt.NumField() != 2 || rt.Field(0).Name != "x" || rt.Field(1).Name != "_" {
+ t.Errorf("unexpected fields in C.misaligned:\n")
+ for i := 0; i < rt.NumField(); i++ {
+ t.Logf("%+v\n", rt.Field(i))
+ }
+ }
+}
diff --git a/misc/cgo/test/issue7665.go b/misc/cgo/test/issue7665.go
new file mode 100644
index 000000000..4f36dce75
--- /dev/null
+++ b/misc/cgo/test/issue7665.go
@@ -0,0 +1,25 @@
+// 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 cgotest
+
+import (
+ "testing"
+ "unsafe"
+)
+
+// extern void f7665(void);
+import "C"
+
+//export f7665
+func f7665() {}
+
+var bad7665 unsafe.Pointer = C.f7665
+var good7665 uintptr = uintptr(C.f7665)
+
+func test7665(t *testing.T) {
+ if bad7665 == nil || bad7665 != unsafe.Pointer(good7665) {
+ t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665)
+ }
+}
diff --git a/misc/cgo/test/issue7695_test.go b/misc/cgo/test/issue7695_test.go
new file mode 100644
index 000000000..4bd6f8e73
--- /dev/null
+++ b/misc/cgo/test/issue7695_test.go
@@ -0,0 +1,27 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Demo of deferred C function with untrue prototype
+// breaking stack copying. See golang.org/issue/7695.
+
+package cgotest
+
+import (
+ "testing"
+
+ "./backdoor"
+)
+
+func TestIssue7695(t *testing.T) {
+ defer backdoor.Issue7695(1, 0, 2, 0, 0, 3, 0, 4)
+ recurse(100)
+}
+
+func recurse(n int) {
+ var x [128]int
+ n += x[0]
+ if n > 0 {
+ recurse(n - 1)
+ }
+}
diff --git a/misc/cgo/test/issue7786.go b/misc/cgo/test/issue7786.go
new file mode 100644
index 000000000..b92763789
--- /dev/null
+++ b/misc/cgo/test/issue7786.go
@@ -0,0 +1,51 @@
+// 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.
+
+// Issue 7786. No runtime test, just make sure that typedef and struct/union/class are interchangeable at compile time.
+
+package cgotest
+
+// struct test7786;
+// typedef struct test7786 typedef_test7786;
+// void f7786(struct test7786 *ctx) {}
+// void g7786(typedef_test7786 *ctx) {}
+//
+// typedef struct body7786 typedef_body7786;
+// struct body7786 { int x; };
+// void b7786(struct body7786 *ctx) {}
+// void c7786(typedef_body7786 *ctx) {}
+//
+// typedef union union7786 typedef_union7786;
+// void u7786(union union7786 *ctx) {}
+// void v7786(typedef_union7786 *ctx) {}
+import "C"
+
+func f() {
+ var x1 *C.typedef_test7786
+ var x2 *C.struct_test7786
+ x1 = x2
+ x2 = x1
+ C.f7786(x1)
+ C.f7786(x2)
+ C.g7786(x1)
+ C.g7786(x2)
+
+ var b1 *C.typedef_body7786
+ var b2 *C.struct_body7786
+ b1 = b2
+ b2 = b1
+ C.b7786(b1)
+ C.b7786(b2)
+ C.c7786(b1)
+ C.c7786(b2)
+
+ var u1 *C.typedef_union7786
+ var u2 *C.union_union7786
+ u1 = u2
+ u2 = u1
+ C.u7786(u1)
+ C.u7786(u2)
+ C.v7786(u1)
+ C.v7786(u2)
+}
diff --git a/misc/cgo/test/issue8148.go b/misc/cgo/test/issue8148.go
new file mode 100644
index 000000000..8e4190848
--- /dev/null
+++ b/misc/cgo/test/issue8148.go
@@ -0,0 +1,31 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8148. A typedef of an unnamed struct didn't work when used
+// with an exported Go function. No runtime test; just make sure it
+// compiles.
+
+package cgotest
+
+/*
+typedef struct { int i; } T;
+
+int issue8148Callback(T*);
+
+static int get() {
+ T t;
+ t.i = 42;
+ return issue8148Callback(&t);
+}
+*/
+import "C"
+
+//export issue8148Callback
+func issue8148Callback(t *C.T) C.int {
+ return t.i
+}
+
+func Issue8148() int {
+ return int(C.get())
+}
diff --git a/misc/cgo/test/issue8331.h b/misc/cgo/test/issue8331.h
new file mode 100644
index 000000000..936ae9d5c
--- /dev/null
+++ b/misc/cgo/test/issue8331.h
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef struct {
+ int i;
+} issue8331;
diff --git a/misc/cgo/test/issue8331a.go b/misc/cgo/test/issue8331a.go
new file mode 100644
index 000000000..7fa55be43
--- /dev/null
+++ b/misc/cgo/test/issue8331a.go
@@ -0,0 +1,15 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8331. A typedef of an unnamed struct is the same struct when
+// #include'd twice. No runtime test; just make sure it compiles.
+
+package cgotest
+
+// #include "issue8331.h"
+import "C"
+
+func issue8331a() C.issue8331 {
+ return issue8331Var
+}
diff --git a/misc/cgo/test/issue8331b.go b/misc/cgo/test/issue8331b.go
new file mode 100644
index 000000000..d52aed63e
--- /dev/null
+++ b/misc/cgo/test/issue8331b.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8331. A typedef of an unnamed struct is the same struct when
+// #include'd twice. No runtime test; just make sure it compiles.
+
+package cgotest
+
+// #include "issue8331.h"
+import "C"
+
+var issue8331Var C.issue8331
diff --git a/misc/cgo/testcdefs/test.bash b/misc/cgo/testcdefs/test.bash
index 1a14ad35c..01621a49a 100755
--- a/misc/cgo/testcdefs/test.bash
+++ b/misc/cgo/testcdefs/test.bash
@@ -12,5 +12,5 @@ done
go build . && ./testcdefs
EXIT=$?
-rm -rf _obj main *.h
+rm -rf _obj testcdefs *.h
exit $EXIT
diff --git a/misc/cgo/testso/cgoso_c.c b/misc/cgo/testso/cgoso_c.c
index 27155c27f..7a38022b5 100644
--- a/misc/cgo/testso/cgoso_c.c
+++ b/misc/cgo/testso/cgoso_c.c
@@ -19,6 +19,11 @@ extern void goCallback(void);
void setCallback(void *f) { (void)f; }
#endif
+// OpenBSD and older Darwin lack TLS support
+#if !defined(__OpenBSD__) && !defined(__APPLE__)
+__thread int tlsvar = 12345;
+#endif
+
void sofunc(void)
{
goCallback();
diff --git a/misc/cgo/testso/cgoso_unix.go b/misc/cgo/testso/cgoso_unix.go
new file mode 100644
index 000000000..7d5444cd1
--- /dev/null
+++ b/misc/cgo/testso/cgoso_unix.go
@@ -0,0 +1,20 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd linux netbsd
+
+package cgosotest
+
+/*
+extern int __thread tlsvar;
+int *getTLS() { return &tlsvar; }
+*/
+import "C"
+
+func init() {
+ if v := *C.getTLS(); v != 12345 {
+ println("got", v)
+ panic("BAD TLS value")
+ }
+}
diff --git a/misc/cgo/testtls/tls.go b/misc/cgo/testtls/tls.go
index a9546a61c..8e9ee7003 100644
--- a/misc/cgo/testtls/tls.go
+++ b/misc/cgo/testtls/tls.go
@@ -15,14 +15,16 @@ import (
)
func testTLS(t *testing.T) {
- var keyVal C.int = 1234
-
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- C.setTLS(C.int(keyVal))
- storedVal := C.getTLS()
- if storedVal != keyVal {
- t.Fatalf("stored %d want %d", storedVal, keyVal)
+ if val := C.getTLS(); val != 0 {
+ t.Fatalf("at start, C.getTLS() = %#x, want 0", val)
+ }
+
+ const keyVal = 0x1234
+ C.setTLS(keyVal)
+ if val := C.getTLS(); val != keyVal {
+ t.Fatalf("at end, C.getTLS() = %#x, want %#x", val, keyVal)
}
}
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index 75b28ac73..6333ff966 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -7,6 +7,7 @@
(require 'cl)
(require 'etags)
(require 'ffap)
+(require 'find-file)
(require 'ring)
(require 'url)
@@ -61,6 +62,7 @@
;; 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.
@@ -167,6 +169,13 @@ from https://github.com/bradfitz/goimports."
:type 'string
:group 'go)
+(defcustom go-other-file-alist
+ '(("_test\\.go\\'" (".go"))
+ ("\\.go\\'" ("_test.go")))
+ "See the documentation of `ff-other-file-alist' for details."
+ :type '(repeat (list regexp (choice (repeat string) function)))
+ :group 'go)
+
(defface go-coverage-untracked
'((t (:foreground "#505050")))
"Coverage color of untracked code."
@@ -249,22 +258,23 @@ For mode=set, all covered lines will have this weight."
"Syntax table for Go mode.")
(defun go--build-font-lock-keywords ()
- ;; we cannot use 'symbols in regexp-opt because emacs <24 doesn't
- ;; understand that
+ ;; we cannot use 'symbols in regexp-opt because GNU Emacs <24
+ ;; doesn't understand that
(append
`((,(go--regexp-enclose-in-symbol (regexp-opt go-mode-keywords t)) . font-lock-keyword-face)
- (,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
+ (,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
(,(go--regexp-enclose-in-symbol (regexp-opt go-constants t)) . font-lock-constant-face)
(,go-func-regexp 1 font-lock-function-name-face)) ;; function (not method) name
(if go-fontify-function-calls
`((,(concat "\\(" go-identifier-regexp "\\)[[:space:]]*(") 1 font-lock-function-name-face) ;; function call/method name
(,(concat "[^[:word:][:multibyte:]](\\(" go-identifier-regexp "\\))[[:space:]]*(") 1 font-lock-function-name-face)) ;; bracketed function call
- `((,go-func-meth-regexp 1 font-lock-function-name-face))) ;; method name
+ `((,go-func-meth-regexp 2 font-lock-function-name-face))) ;; method name
`(
- (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
- (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
+ ("\\(`[^`]*`\\)" 1 font-lock-multiline) ;; raw string literal, needed for font-lock-syntactic-keywords
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
(,(concat "[^[:word:][:multibyte:]]\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" go-type-name-regexp) 2 font-lock-type-face) ;; Arrays/slices
(,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face)
(,(concat (go--regexp-enclose-in-symbol "map") "\\[[^]]+\\]" go-type-name-regexp) 1 font-lock-type-face) ;; map value type
@@ -281,6 +291,14 @@ For mode=set, all covered lines will have this weight."
(,(concat "^[[:space:]]*\\(" go-label-regexp "\\)[[:space:]]*:\\(\\S.\\|$\\)") 1 font-lock-constant-face) ;; Labels and compound literal fields
(,(concat (go--regexp-enclose-in-symbol "\\(goto\\|break\\|continue\\)") "[[:space:]]*\\(" go-label-regexp "\\)") 2 font-lock-constant-face)))) ;; labels in goto/break/continue
+(defconst go--font-lock-syntactic-keywords
+ ;; Override syntax property of raw string literal contents, so that
+ ;; backslashes have no special meaning in ``. Used in Emacs 23 or older.
+ '((go--match-raw-string-literal
+ (1 (7 . ?`))
+ (2 (15 . nil)) ;; 15 = "generic string"
+ (3 (7 . ?`)))))
+
(defvar go-mode-map
(let ((m (make-sparse-keymap)))
(define-key m "}" #'go-mode-insert-and-indent)
@@ -349,6 +367,18 @@ STOP-AT-STRING is not true, over strings."
(- (point-max)
(point-min))))
+(defun go--match-raw-string-literal (end)
+ "Search for a raw string literal. Set point to the end of the
+occurence found on success. Returns nil on failure."
+ (when (search-forward "`" end t)
+ (goto-char (match-beginning 0))
+ (if (go-in-string-or-comment-p)
+ (progn (goto-char (match-end 0))
+ (go--match-raw-string-literal end))
+ (when (looking-at "\\(`\\)\\([^`]*\\)\\(`\\)")
+ (goto-char (match-end 0))
+ t))))
+
(defun go-previous-line-has-dangling-op-p ()
"Returns non-nil if the current line is a continuation line."
(let* ((cur-line (line-number-at-pos))
@@ -450,8 +480,9 @@ current line will be returned."
(goto-char (- (point-max) pos))))))
(defun go-beginning-of-defun (&optional count)
- (unless count (setq count 1))
- (let ((first t) failure)
+ (setq count (or count 1))
+ (let ((first t)
+ failure)
(dotimes (i (abs count))
(while (and (not failure)
(or first (go-in-string-or-comment-p)))
@@ -513,7 +544,7 @@ The following extra functions are defined:
If you want to automatically run `gofmt' before saving a file,
add the following hook to your emacs configuration:
-\(add-hook 'before-save-hook 'gofmt-before-save)
+\(add-hook 'before-save-hook #'gofmt-before-save)
If you want to use `godef-jump' instead of etags (or similar),
consider binding godef-jump to `M-.', which is the default key
@@ -532,7 +563,8 @@ If you're looking for even more integration with Go, namely
on-the-fly syntax checking, auto-completion and snippets, it is
recommended that you look at goflymake
\(https://github.com/dougm/goflymake), gocode
-\(https://github.com/nsf/gocode) and yasnippet-go
+\(https://github.com/nsf/gocode), go-eldoc
+\(github.com/syohex/emacs-go-eldoc) and yasnippet-go
\(https://github.com/dominikh/yasnippet-go)"
;; Font lock
@@ -553,11 +585,16 @@ recommended that you look at goflymake
(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 'font-lock-syntactic-keywords)
+ go--font-lock-syntactic-keywords)
+ (set (make-local-variable 'font-lock-multiline) t))
(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)
+ ;; ff-find-other-file
+ (setq ff-other-file-alist 'go-other-file-alist)
(setq imenu-generic-expression
'(("type" "^type *\\([^ \t\n\r\f]*\\)" 1)
@@ -992,7 +1029,7 @@ description at POINT."
"-f"
(file-truename (buffer-file-name (go--coverage-origin-buffer)))
"-o"
- (number-to-string (go--position-bytes (point))))
+ (number-to-string (go--position-bytes point)))
(with-current-buffer outbuf
(split-string (buffer-substring-no-properties (point-min) (point-max)) "\n")))))
@@ -1108,7 +1145,7 @@ divisor for FILE-NAME."
(start-line start-column end-line end-column num count)
(mapcar #'string-to-number rest)
- (when (and (string= (file-name-nondirectory file) file-name))
+ (when (string= (file-name-nondirectory file) file-name)
(if (> count max-count)
(setq max-count count))
(push (make-go--covered :start-line start-line
diff --git a/misc/goplay/Makefile b/misc/goplay/Makefile
deleted file mode 100644
index a6db75ac3..000000000
--- a/misc/goplay/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-goplay: goplay.go
- go build goplay.go
diff --git a/misc/goplay/README b/misc/goplay/README
deleted file mode 100644
index e8a1d290f..000000000
--- a/misc/goplay/README
+++ /dev/null
@@ -1 +0,0 @@
-See doc.go.
diff --git a/misc/goplay/doc.go b/misc/goplay/doc.go
deleted file mode 100644
index 61e74a000..000000000
--- a/misc/goplay/doc.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Goplay is a web interface for experimenting with Go code.
-// It is similar to the Go Playground: http://golang.org/doc/play/
-//
-// To use goplay:
-// $ cd $GOROOT/misc/goplay
-// $ go run goplay.go
-// and load http://localhost:3999/ in a web browser.
-//
-// You should see a Hello World program, which you can compile and run by
-// pressing shift-enter. There is also a "compile-on-keypress" feature that can
-// be enabled by checking a checkbox.
-//
-// WARNING! CUIDADO! ACHTUNG! ATTENZIONE!
-// A note on security: anyone with access to the goplay web interface can run
-// arbitrary code on your computer. Goplay is not a sandbox, and has no other
-// security mechanisms. Do not deploy it in untrusted environments.
-// By default, goplay listens only on localhost. This can be overridden with
-// the -http parameter. Do so at your own risk.
-package main
diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go
deleted file mode 100644
index 9cb7d7bfb..000000000
--- a/misc/goplay/goplay.go
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "flag"
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "strconv"
- "text/template"
-)
-
-var (
- httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
- htmlOutput = flag.Bool("html", false, "render program output as HTML")
-)
-
-var (
- // a source of numbers, for naming temporary files
- uniq = make(chan int)
-)
-
-func main() {
- flag.Parse()
-
- // source of unique numbers
- go func() {
- for i := 0; ; i++ {
- uniq <- i
- }
- }()
-
- http.HandleFunc("/", FrontPage)
- http.HandleFunc("/compile", Compile)
- log.Fatal(http.ListenAndServe(*httpListen, nil))
-}
-
-// FrontPage is an HTTP handler that renders the goplay interface.
-// If a filename is supplied in the path component of the URI,
-// its contents will be put in the interface's text area.
-// Otherwise, the default "hello, world" program is displayed.
-func FrontPage(w http.ResponseWriter, req *http.Request) {
- data, err := ioutil.ReadFile(req.URL.Path[1:])
- if err != nil {
- data = helloWorld
- }
- frontPage.Execute(w, data)
-}
-
-// Compile is an HTTP handler that reads Go source code from the request,
-// runs the program (returning any errors),
-// and sends the program's output as the HTTP response.
-func Compile(w http.ResponseWriter, req *http.Request) {
- out, err := compile(req)
- if err != nil {
- error_(w, out, err)
- return
- }
-
- // write the output of x as the http response
- if *htmlOutput {
- w.Write(out)
- } else {
- output.Execute(w, out)
- }
-}
-
-var (
- commentRe = regexp.MustCompile(`(?m)^#.*\n`)
- tmpdir string
-)
-
-func init() {
- // find real temporary directory (for rewriting filename in output)
- var err error
- tmpdir, err = filepath.EvalSymlinks(os.TempDir())
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func compile(req *http.Request) (out []byte, err error) {
- // x is the base name for .go, .6, executable files
- x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
- src := x + ".go"
-
- // rewrite filename in error output
- defer func() {
- if err != nil {
- // drop messages from the go tool like '# _/compile0'
- out = commentRe.ReplaceAll(out, nil)
- }
- out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
- }()
-
- // write body to x.go
- body := new(bytes.Buffer)
- if _, err = body.ReadFrom(req.Body); err != nil {
- return
- }
- defer os.Remove(src)
- if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil {
- return
- }
-
- // go run x.go
- dir, file := filepath.Split(src)
- out, err = run(dir, "go", "run", file)
- if err != nil {
- return
- }
- return out, nil
-}
-
-// error writes compile, link, or runtime errors to the HTTP connection.
-// The JavaScript interface uses the 404 status code to identify the error.
-func error_(w http.ResponseWriter, out []byte, err error) {
- w.WriteHeader(404)
- if out != nil {
- output.Execute(w, out)
- } else {
- output.Execute(w, err.Error())
- }
-}
-
-// run executes the specified command and returns its output and an error.
-func run(dir string, args ...string) ([]byte, error) {
- var buf bytes.Buffer
- cmd := exec.Command(args[0], args[1:]...)
- cmd.Dir = dir
- cmd.Stdout = &buf
- cmd.Stderr = cmd.Stdout
- err := cmd.Run()
- return buf.Bytes(), err
-}
-
-var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
-var output = template.Must(template.New("output").Parse(outputText)) // HTML template
-
-var outputText = `<pre>{{printf "%s" . |html}}</pre>`
-
-var frontPageText = `<!doctype html>
-<html>
-<head>
-<style>
-pre, textarea {
- font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
- font-size: 100%;
-}
-.hints {
- font-size: 0.8em;
- text-align: right;
-}
-#edit, #output, #errors { width: 100%; text-align: left; }
-#edit { height: 500px; }
-#output { color: #00c; }
-#errors { color: #c00; }
-</style>
-<script>
-
-function insertTabs(n) {
- // find the selection start and end
- var cont = document.getElementById("edit");
- var start = cont.selectionStart;
- var end = cont.selectionEnd;
- // split the textarea content into two, and insert n tabs
- var v = cont.value;
- var u = v.substr(0, start);
- for (var i=0; i<n; i++) {
- u += "\t";
- }
- u += v.substr(end);
- // set revised content
- cont.value = u;
- // reset caret position after inserted tabs
- cont.selectionStart = start+n;
- cont.selectionEnd = start+n;
-}
-
-function autoindent(el) {
- var curpos = el.selectionStart;
- var tabs = 0;
- while (curpos > 0) {
- curpos--;
- if (el.value[curpos] == "\t") {
- tabs++;
- } else if (tabs > 0 || el.value[curpos] == "\n") {
- break;
- }
- }
- setTimeout(function() {
- insertTabs(tabs);
- }, 1);
-}
-
-function preventDefault(e) {
- if (e.preventDefault) {
- e.preventDefault();
- } else {
- e.cancelBubble = true;
- }
-}
-
-function keyHandler(event) {
- var e = window.event || event;
- if (e.keyCode == 9) { // tab
- insertTabs(1);
- preventDefault(e);
- return false;
- }
- if (e.keyCode == 13) { // enter
- if (e.shiftKey) { // +shift
- compile(e.target);
- preventDefault(e);
- return false;
- } else {
- autoindent(e.target);
- }
- }
- return true;
-}
-
-var xmlreq;
-
-function autocompile() {
- if(!document.getElementById("autocompile").checked) {
- return;
- }
- compile();
-}
-
-function compile() {
- var prog = document.getElementById("edit").value;
- var req = new XMLHttpRequest();
- xmlreq = req;
- req.onreadystatechange = compileUpdate;
- req.open("POST", "/compile", true);
- req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
- req.send(prog);
-}
-
-function compileUpdate() {
- var req = xmlreq;
- if(!req || req.readyState != 4) {
- return;
- }
- if(req.status == 200) {
- document.getElementById("output").innerHTML = req.responseText;
- document.getElementById("errors").innerHTML = "";
- } else {
- document.getElementById("errors").innerHTML = req.responseText;
- document.getElementById("output").innerHTML = "";
- }
-}
-</script>
-</head>
-<body>
-<table width="100%"><tr><td width="60%" valign="top">
-<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{printf "%s" . |html}}</textarea>
-<div class="hints">
-(Shift-Enter to compile and run.)&nbsp;&nbsp;&nbsp;&nbsp;
-<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
-</div>
-<td width="3%">
-<td width="27%" align="right" valign="top">
-<div id="output"></div>
-</table>
-<div id="errors"></div>
-</body>
-</html>
-`
-
-var helloWorld = []byte(`package main
-
-import "fmt"
-
-func main() {
- fmt.Println("hello, world")
-}
-`)
diff --git a/misc/dist/darwin/Distribution b/misc/makerelease/darwin/Distribution
index 8b764b69f..8b764b69f 100644
--- a/misc/dist/darwin/Distribution
+++ b/misc/makerelease/darwin/Distribution
diff --git a/misc/dist/darwin/Resources/bg.png b/misc/makerelease/darwin/Resources/bg.png
index c3d8ea93a..c3d8ea93a 100644
--- a/misc/dist/darwin/Resources/bg.png
+++ b/misc/makerelease/darwin/Resources/bg.png
Binary files differ
diff --git a/misc/dist/darwin/etc/paths.d/go b/misc/makerelease/darwin/etc/paths.d/go
index 532e5f936..532e5f936 100644
--- a/misc/dist/darwin/etc/paths.d/go
+++ b/misc/makerelease/darwin/etc/paths.d/go
diff --git a/misc/dist/darwin/scripts/postinstall b/misc/makerelease/darwin/scripts/postinstall
index 13f5bff9b..13f5bff9b 100755
--- a/misc/dist/darwin/scripts/postinstall
+++ b/misc/makerelease/darwin/scripts/postinstall
diff --git a/misc/dist/darwin/scripts/preinstall b/misc/makerelease/darwin/scripts/preinstall
index 4cdaaa4bc..4cdaaa4bc 100755
--- a/misc/dist/darwin/scripts/preinstall
+++ b/misc/makerelease/darwin/scripts/preinstall
diff --git a/misc/dist/bindist.go b/misc/makerelease/makerelease.go
index 223d2dc17..2496a865a 100644
--- a/misc/dist/bindist.go
+++ b/misc/makerelease/makerelease.go
@@ -12,14 +12,15 @@ import (
"bufio"
"bytes"
"compress/gzip"
- "encoding/base64"
+ "crypto/sha1"
+ "encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
- "mime/multipart"
"net/http"
+ "net/url"
"os"
"os/exec"
"path"
@@ -27,29 +28,36 @@ import (
"regexp"
"runtime"
"strings"
+
+ "code.google.com/p/goauth2/oauth"
+ "code.google.com/p/google-api-go-client/storage/v1beta2"
)
var (
tag = flag.String("tag", "release", "mercurial tag to check out")
toolTag = flag.String("tool", defaultToolTag, "go.tools tag to check out")
+ tourTag = flag.String("tour", defaultTourTag, "go-tour tag to check out")
repo = flag.String("repo", "https://code.google.com/p/go", "repo URL")
verbose = flag.Bool("v", false, "verbose output")
- upload = flag.Bool("upload", true, "upload resulting files to Google Code")
- wxsFile = flag.String("wxs", "", "path to custom installer.wxs")
+ upload = flag.Bool("upload", false, "upload resulting files to Google Code")
addLabel = flag.String("label", "", "additional label to apply to file when uploading")
includeRace = flag.Bool("race", true, "build race detector packages")
versionOverride = flag.String("version", "", "override version name")
staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)")
+ tokenCache = flag.String("token", defaultCacheFile, "Authentication token cache file")
+ storageBucket = flag.String("bucket", "golang", "Cloud Storage Bucket")
+ uploadURL = flag.String("upload_url", defaultUploadURL, "Upload URL")
- username, password string // for Google Code upload
+ defaultCacheFile = filepath.Join(os.Getenv("HOME"), ".makerelease-request-token")
+ defaultUploadURL = "http://golang.org/dl/upload"
)
const (
- uploadURL = "https://go.googlecode.com/files"
blogPath = "code.google.com/p/go.blog"
toolPath = "code.google.com/p/go.tools"
tourPath = "code.google.com/p/go-tour"
defaultToolTag = "release-branch.go1.2"
+ defaultTourTag = "release-branch.go1.2"
)
// Import paths for tool commands.
@@ -90,7 +98,6 @@ var tourPackages = []string{
var tourContent = []string{
"content",
- "js",
"solutions",
"static",
"template",
@@ -117,8 +124,13 @@ var staticLinkAvailable = []string{
"netbsd",
}
-var fileRe = regexp.MustCompile(
- `^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]))?)\.`)
+var fileRe = regexp.MustCompile(`^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]+))?)\.(tar\.gz|zip|pkg|msi)$`)
+
+// OAuth2-authenticated HTTP client used to make calls to Cloud Storage.
+var oauthClient *http.Client
+
+// Builder key as specified in ~/.gobuildkey
+var builderKey string
func main() {
flag.Usage = func() {
@@ -136,7 +148,10 @@ func main() {
if *upload {
if err := readCredentials(); err != nil {
- log.Println("readCredentials:", err)
+ log.Fatalln("readCredentials:", err)
+ }
+ if err := setupOAuthClient(); err != nil {
+ log.Fatalln("setupOAuthClient:", err)
}
}
for _, targ := range flag.Args() {
@@ -156,7 +171,7 @@ func main() {
continue
}
if err := b.Upload(version, targ); err != nil {
- log.Printf("%s: %v", targ, err)
+ log.Printf("uploading %s: %v", targ, err)
}
continue
}
@@ -206,7 +221,7 @@ type Build struct {
}
func (b *Build) Do() error {
- work, err := ioutil.TempDir("", "bindist")
+ work, err := ioutil.TempDir("", "makerelease")
if err != nil {
return err
}
@@ -268,15 +283,7 @@ func (b *Build) Do() error {
if err != nil {
return err
}
- err = b.tools()
- if err != nil {
- return err
- }
- err = b.blog()
- if err != nil {
- return err
- }
- err = b.tour()
+ err = b.extras()
}
if err != nil {
return err
@@ -350,9 +357,11 @@ func (b *Build) Do() error {
err = makeTar(targ, work)
targs = append(targs, targ)
+ makerelease := filepath.Join(runtime.GOROOT(), "misc/makerelease")
+
// build pkg
// arrange work so it's laid out as the dest filesystem
- etc := filepath.Join(b.root, "misc/dist/darwin/etc")
+ etc := filepath.Join(makerelease, "darwin/etc")
_, err = b.run(work, "cp", "-r", etc, ".")
if err != nil {
return err
@@ -372,11 +381,10 @@ func (b *Build) Do() error {
return err
}
defer os.RemoveAll(pkgdest)
- dist := filepath.Join(runtime.GOROOT(), "misc/dist")
_, err = b.run("", "pkgbuild",
"--identifier", "com.googlecode.go",
"--version", version,
- "--scripts", filepath.Join(dist, "darwin/scripts"),
+ "--scripts", filepath.Join(makerelease, "darwin/scripts"),
"--root", work,
filepath.Join(pkgdest, "com.googlecode.go.pkg"))
if err != nil {
@@ -384,8 +392,8 @@ func (b *Build) Do() error {
}
targ = base + ".pkg"
_, err = b.run("", "productbuild",
- "--distribution", filepath.Join(dist, "darwin/Distribution"),
- "--resources", filepath.Join(dist, "darwin/Resources"),
+ "--distribution", filepath.Join(makerelease, "darwin/Distribution"),
+ "--resources", filepath.Join(makerelease, "darwin/Resources"),
"--package-path", pkgdest,
targ)
if err != nil {
@@ -405,11 +413,8 @@ func (b *Build) Do() error {
targs = append(targs, targ)
// Create MSI installer.
- win := filepath.Join(b.root, "misc/dist/windows")
+ win := filepath.Join(runtime.GOROOT(), "misc/makerelease/windows")
installer := filepath.Join(win, "installer.wxs")
- if *wxsFile != "" {
- installer = *wxsFile
- }
appfiles := filepath.Join(work, "AppFiles.wxs")
msi := filepath.Join(work, "installer.msi")
// Gather files.
@@ -454,33 +459,51 @@ func (b *Build) Do() error {
for _, targ := range targs {
err = b.Upload(version, targ)
if err != nil {
- return err
+ return fmt.Errorf("uploading %s: %v", targ, err)
}
}
}
return err
}
-func (b *Build) tools() error {
+// extras fetches the go.tools, go.blog, and go-tour repositories,
+// builds them and copies the resulting binaries and static assets
+// to the new GOROOT.
+func (b *Build) extras() error {
defer b.cleanGopath()
- // Fetch the tool packages (without building/installing).
- args := append([]string{"get", "-d"}, toolPaths...)
- _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...)
- if err != nil {
+ if err := b.tools(); err != nil {
+ return err
+ }
+ if err := b.blog(); err != nil {
return err
}
+ return b.tour()
+}
- // Update the repo to the revision specified by -tool.
- repoPath := filepath.Join(b.gopath, "src", filepath.FromSlash(toolPath))
- _, err = b.run(repoPath, "hg", "update", *toolTag)
+func (b *Build) get(repoPath, revision string) error {
+ // Fetch the packages (without building/installing).
+ _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"),
+ "get", "-d", repoPath+"/...")
if err != nil {
return err
}
+ // Update the repo to the specified revision.
+ p := filepath.Join(b.gopath, "src", filepath.FromSlash(repoPath))
+ _, err = b.run(p, "hg", "update", revision)
+ return err
+}
+
+func (b *Build) tools() error {
+ // Fetch the go.tools repository.
+ if err := b.get(toolPath, *toolTag); err != nil {
+ return err
+ }
+
// Install tools.
- args = append([]string{"install"}, toolPaths...)
- _, err = b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...)
+ args := append([]string{"install"}, toolPaths...)
+ _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...)
if err != nil {
return err
}
@@ -509,8 +532,6 @@ func (b *Build) tools() error {
}
func (b *Build) blog() error {
- defer b.cleanGopath()
-
// Fetch the blog repository.
_, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", "-d", blogPath+"/blog")
if err != nil {
@@ -524,10 +545,14 @@ func (b *Build) blog() error {
}
func (b *Build) tour() error {
- defer b.cleanGopath()
+ // Fetch the go-tour repository.
+ if err := b.get(tourPath, *tourTag); err != nil {
+ return err
+ }
- // go get the gotour package.
- _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", tourPath+"/gotour")
+ // Build tour binary.
+ _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"),
+ "install", tourPath+"/gotour")
if err != nil {
return err
}
@@ -632,121 +657,95 @@ func (b *Build) env() []string {
}
func (b *Build) Upload(version string, filename string) error {
- // Prepare upload metadata.
- var labels []string
- os_, arch := b.OS, b.Arch
- switch b.Arch {
- case "386":
- arch = "x86 32-bit"
- case "amd64":
- arch = "x86 64-bit"
- }
- if arch != "" {
- labels = append(labels, "Arch-"+b.Arch)
- }
- var opsys, ftype string // labels
- switch b.OS {
- case "linux":
- os_ = "Linux"
- opsys = "Linux"
- case "freebsd":
- os_ = "FreeBSD"
- opsys = "FreeBSD"
- case "darwin":
- os_ = "Mac OS X"
- opsys = "OSX"
- case "netbsd":
- os_ = "NetBSD"
- opsys = "NetBSD"
- case "windows":
- os_ = "Windows"
- opsys = "Windows"
- }
- summary := fmt.Sprintf("%s %s (%s)", version, os_, arch)
- switch {
- case strings.HasSuffix(filename, ".msi"):
- ftype = "Installer"
- summary += " MSI installer"
- case strings.HasSuffix(filename, ".pkg"):
- ftype = "Installer"
- summary += " PKG installer"
- case strings.HasSuffix(filename, ".zip"):
- ftype = "Archive"
- summary += " ZIP archive"
- case strings.HasSuffix(filename, ".tar.gz"):
- ftype = "Archive"
- summary += " tarball"
- }
- if b.Source {
- ftype = "Source"
- summary = fmt.Sprintf("%s (source only)", version)
- }
- if opsys != "" {
- labels = append(labels, "OpSys-"+opsys)
- }
- if ftype != "" {
- labels = append(labels, "Type-"+ftype)
- }
- if b.Label != "" {
- labels = append(labels, b.Label)
- }
- if *addLabel != "" {
- labels = append(labels, *addLabel)
- }
- // Put "Go" prefix on summary when it doesn't already begin with "go".
- if !strings.HasPrefix(strings.ToLower(summary), "go") {
- summary = "Go " + summary
- }
-
- // Open file to upload.
- f, err := os.Open(filename)
+ file, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
- defer f.Close()
- // Prepare multipart payload.
- body := new(bytes.Buffer)
- w := multipart.NewWriter(body)
- if err := w.WriteField("summary", summary); err != nil {
- return err
- }
- for _, l := range labels {
- if err := w.WriteField("label", l); err != nil {
- return err
- }
- }
- fw, err := w.CreateFormFile("filename", filename)
+ svc, err := storage.New(oauthClient)
if err != nil {
return err
}
- if _, err = io.Copy(fw, f); err != nil {
- return err
+ obj := &storage.Object{
+ Acl: []*storage.ObjectAccessControl{{Entity: "allUsers", Role: "READER"}},
+ Name: filename,
}
- if err := w.Close(); err != nil {
+ _, err = svc.Objects.Insert(*storageBucket, obj).Media(bytes.NewReader(file)).Do()
+ if err != nil {
return err
}
- // Send the file to Google Code.
- req, err := http.NewRequest("POST", uploadURL, body)
+ sum := fmt.Sprintf("%x", sha1.Sum(file))
+ kind := "unknown"
+ switch {
+ case b.Source:
+ kind = "source"
+ case strings.HasSuffix(filename, ".tar.gz"), strings.HasSuffix(filename, ".zip"):
+ kind = "archive"
+ case strings.HasSuffix(filename, ".msi"), strings.HasSuffix(filename, ".pkg"):
+ kind = "installer"
+ }
+ req, err := json.Marshal(File{
+ Filename: filename,
+ Version: version,
+ OS: b.OS,
+ Arch: b.Arch,
+ Checksum: sum,
+ Kind: kind,
+ })
if err != nil {
return err
}
- token := fmt.Sprintf("%s:%s", username, password)
- token = base64.StdEncoding.EncodeToString([]byte(token))
- req.Header.Set("Authorization", "Basic "+token)
- req.Header.Set("Content-type", w.FormDataContentType())
-
- resp, err := http.DefaultTransport.RoundTrip(req)
+ u := fmt.Sprintf("%s?%s", *uploadURL, url.Values{"key": []string{builderKey}}.Encode())
+ resp, err := http.Post(u, "application/json", bytes.NewReader(req))
if err != nil {
return err
}
- if resp.StatusCode/100 != 2 {
- fmt.Fprintln(os.Stderr, "upload failed")
- defer resp.Body.Close()
- io.Copy(os.Stderr, resp.Body)
- return fmt.Errorf("upload: %s", resp.Status)
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("upload status: %v", resp.Status)
+ }
+
+ return nil
+}
+
+type File struct {
+ Filename string
+ OS string
+ Arch string
+ Version string
+ Checksum string `datastore:",noindex"`
+ Kind string // "archive", "installer", "source"
+}
+
+func setupOAuthClient() error {
+ config := &oauth.Config{
+ ClientId: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
+ ClientSecret: "8YLFgOhXIELWbO",
+ Scope: storage.DevstorageRead_writeScope,
+ AuthURL: "https://accounts.google.com/o/oauth2/auth",
+ TokenURL: "https://accounts.google.com/o/oauth2/token",
+ TokenCache: oauth.CacheFile(*tokenCache),
+ RedirectURL: "oob",
+ }
+ transport := &oauth.Transport{Config: config}
+ if token, err := config.TokenCache.Token(); err != nil {
+ url := transport.Config.AuthCodeURL("")
+ fmt.Println("Visit the following URL, obtain an authentication" +
+ "code, and enter it below.")
+ fmt.Println(url)
+ fmt.Print("Enter authentication code: ")
+ code := ""
+ if _, err := fmt.Scan(&code); err != nil {
+ return err
+ }
+ if _, err := transport.Exchange(code); err != nil {
+ return err
+ }
+ } else {
+ transport.Token = token
}
+ oauthClient = transport.Client()
return nil
}
@@ -776,21 +775,11 @@ func readCredentials() error {
return err
}
defer f.Close()
- r := bufio.NewReader(f)
- for i := 0; i < 3; i++ {
- b, _, err := r.ReadLine()
- if err != nil {
- return err
- }
- b = bytes.TrimSpace(b)
- switch i {
- case 1:
- username = string(b)
- case 2:
- password = string(b)
- }
+ s := bufio.NewScanner(f)
+ if s.Scan() {
+ builderKey = s.Text()
}
- return nil
+ return s.Err()
}
func cp(dst, src string) error {
diff --git a/misc/dist/windows/LICENSE.rtf b/misc/makerelease/windows/LICENSE.rtf
index b2b0be62c..b2b0be62c 100644
--- a/misc/dist/windows/LICENSE.rtf
+++ b/misc/makerelease/windows/LICENSE.rtf
Binary files differ
diff --git a/misc/dist/windows/README.txt b/misc/makerelease/windows/README.txt
index 0cf828b24..0cf828b24 100644
--- a/misc/dist/windows/README.txt
+++ b/misc/makerelease/windows/README.txt
diff --git a/misc/dist/windows/images/Banner.jpg b/misc/makerelease/windows/images/Banner.jpg
index ce65f63af..ce65f63af 100644
--- a/misc/dist/windows/images/Banner.jpg
+++ b/misc/makerelease/windows/images/Banner.jpg
Binary files differ
diff --git a/misc/dist/windows/images/Dialog.jpg b/misc/makerelease/windows/images/Dialog.jpg
index 1f0ec0a31..1f0ec0a31 100644
--- a/misc/dist/windows/images/Dialog.jpg
+++ b/misc/makerelease/windows/images/Dialog.jpg
Binary files differ
diff --git a/misc/dist/windows/images/DialogLeft.jpg b/misc/makerelease/windows/images/DialogLeft.jpg
index 73bab89b4..73bab89b4 100644
--- a/misc/dist/windows/images/DialogLeft.jpg
+++ b/misc/makerelease/windows/images/DialogLeft.jpg
Binary files differ
diff --git a/misc/dist/windows/images/gopher.ico b/misc/makerelease/windows/images/gopher.ico
index 2e861ebe0..2e861ebe0 100644
--- a/misc/dist/windows/images/gopher.ico
+++ b/misc/makerelease/windows/images/gopher.ico
Binary files differ
diff --git a/misc/dist/windows/installer.wxs b/misc/makerelease/windows/installer.wxs
index b170b98dc..b170b98dc 100644
--- a/misc/dist/windows/installer.wxs
+++ b/misc/makerelease/windows/installer.wxs
diff --git a/misc/nacl/README b/misc/nacl/README
new file mode 100644
index 000000000..9cc2bda60
--- /dev/null
+++ b/misc/nacl/README
@@ -0,0 +1,63 @@
+Native Client
+=============
+
+This document outlines the basics of building and developing the Go runtime and programs in the Native Client (NaCl) environment.
+
+Go 1.3 supports two architectures
+
+ * nacl/386 which is standard 386.
+ * nacl/amd64p32 which is a 64 bit architecture, where the address space is limited to a 4gb window.
+
+For background it is recommended that you read http://golang.org/s/go13nacl.
+
+Prerequisites
+-------------
+
+Native Client programs are executed inside a sandbox, the NaCl runtime. This runtime must be installed before you can use NaCl programs.
+
+The NaCl distribution comes with an installer which ensures you have access to the latest version of the runtime. The version tracks the Chrome numbering scheme.
+
+# Download NaCl
+
+Download nacl_sdk.zip file from https://developers.google.com/native-client/dev/sdk/download, and unpack it. I chose /opt/nacl_sdk
+
+# Update
+
+The zip file contains a small skeleton that can be used to download the correct sdk. These are released every 6-8 weeks, in line with Chrome releases.
+
+ % cd /opt/nacl_sdk
+ % ./naclsdk update
+
+At this time pepper_33 is the stable version. If naclsdk downloads a later version, please adjust accordingly.
+
+The cmd/go helper scripts expect that the runtime loaders, sel_ldr_x86_{32,64} are in your path. I find it easiest to make a symlink from the NaCl distribution to my $GOPATH/bin directory.
+
+ % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
+ % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
+
+Support scripts
+---------------
+
+Symlink the two scripts in this directory into your $PATH, just as you did with NaCl sdk above.
+
+ % ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec
+ % ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec
+
+Building and testing
+--------------------
+
+Building for NaCl is similar to cross compiling for other platforms. However, as it is not possible to ever build in a `native` NaCl environment, the cmd/go tool has been enhanced to allow the full build, all.bash, to be executed, rather than just the compile stage, make.bash.
+
+The cmd/go tool knows that if GOOS is set to `nacl` it should not try to execute any binaries itself. Instead it passes their execution to a support script which sets up a Native Client environment and invokes the NaCl sandbox.
+
+The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can find it.
+
+In short, if the support scripts are in place, the cmd/go tool can be used as per normal.
+
+# Build and test Go for NaCl
+
+NaCl does not permit direct file system access. Instead, package syscall provides a simulated file system served by in-memory data. The script nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an in-memory file system containing files needed for tests, and then it runs the tests.
+
+ % cd go/src
+ % env GOARCH=amd64p32 ./nacltest.bash
+
diff --git a/misc/nacl/go_nacl_386_exec b/misc/nacl/go_nacl_386_exec
new file mode 100755
index 000000000..9cff63556
--- /dev/null
+++ b/misc/nacl/go_nacl_386_exec
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+eval $(go env)
+
+export NACLENV_GOARCH=$GOARCH
+export NACLENV_GOOS=$GOOS
+export NACLENV_GOROOT=/go
+export NACLENV_NACLPWD=$(pwd | sed "s;$GOROOT;/go;")
+
+exec sel_ldr_x86_32 -l /dev/null -S -e "$@"
diff --git a/misc/nacl/go_nacl_amd64p32_exec b/misc/nacl/go_nacl_amd64p32_exec
new file mode 100755
index 000000000..0a5ed651f
--- /dev/null
+++ b/misc/nacl/go_nacl_amd64p32_exec
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+eval $(go env)
+
+export NACLENV_GOARCH=$GOARCH
+export NACLENV_GOOS=$GOOS
+export NACLENV_GOROOT=/go
+export NACLENV_NACLPWD=$(pwd | sed "s;$GOROOT;/go;")
+
+exec sel_ldr_x86_64 -l /dev/null -S -e "$@"
diff --git a/misc/nacl/mkzip.go b/misc/nacl/mkzip.go
new file mode 100644
index 000000000..7b2de7d47
--- /dev/null
+++ b/misc/nacl/mkzip.go
@@ -0,0 +1,220 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Mkzip creates a zip file from a 'proto' file describing the contents.
+//
+// The proto file is inspired by the Plan 9 mkfs prototype file format.
+// It describes a file tree, one directory per line, with leading tab
+// indentation marking the tree structure. Each line contains a leading
+// name field giving the name of the file to copy into the zip file,
+// and then a sequence of optional key=value attributes to control
+// the copy. The only known attribute is src=foo, meaning copy the
+// actual data for the file (or directory) from an alternate location.
+package main
+
+import (
+ "archive/zip"
+ "bufio"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: mkzip [-r root] src.proto out.zip\n")
+ os.Exit(2)
+}
+
+func sysfatal(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "mkzip: %s\n", fmt.Sprintf(format, args...))
+ os.Exit(2)
+}
+
+var (
+ root = flag.String("r", ".", "interpret source paths relative to this directory")
+ gopackage = flag.String("p", "", "write Go source file in this package")
+)
+
+type stack struct {
+ name string
+ src string
+ depth int
+}
+
+func main() {
+ log.SetFlags(0)
+ flag.Usage = usage
+ flag.Parse()
+
+ args := flag.Args()
+ if len(args) != 2 {
+ usage()
+ }
+
+ rf, err := os.Open(args[0])
+ if err != nil {
+ sysfatal("%v", err)
+ }
+ r := bufio.NewScanner(rf)
+
+ zf, err := os.Create(args[1])
+ if err != nil {
+ sysfatal("%v", err)
+ }
+
+ var w io.Writer = zf
+ if *gopackage != "" {
+ fmt.Fprintf(zf, "package %s\n\nfunc init() {\n\tunzip(\"", *gopackage)
+ gw := &goWriter{b: bufio.NewWriter(w)}
+ defer func() {
+ if err := gw.Close(); err != nil {
+ sysfatal("finishing Go output: %v", err)
+ }
+ }()
+ w = gw
+ }
+ z := zip.NewWriter(w)
+
+ lineno := 0
+
+ addfile := func(info os.FileInfo, dst string, src string) {
+ zh, err := zip.FileInfoHeader(info)
+ if err != nil {
+ sysfatal("%s:%d: %s: %v", args[0], lineno, src, err)
+ }
+ zh.Name = dst
+ zh.Method = zip.Deflate
+ if info.IsDir() && !strings.HasSuffix(dst, "/") {
+ zh.Name += "/"
+ }
+ w, err := z.CreateHeader(zh)
+ if err != nil {
+ sysfatal("%s:%d: %s: %v", args[0], lineno, src, err)
+ }
+ if info.IsDir() {
+ return
+ }
+ r, err := os.Open(src)
+ if err != nil {
+ sysfatal("%s:%d: %s: %v", args[0], lineno, src, err)
+ }
+ defer r.Close()
+ if _, err := io.Copy(w, r); err != nil {
+ sysfatal("%s:%d: %s: %v", args[0], lineno, src, err)
+ }
+ }
+
+ var stk []stack
+
+ for r.Scan() {
+ line := r.Text()
+ lineno++
+ s := strings.TrimLeft(line, "\t")
+ prefix, line := line[:len(line)-len(s)], s
+ if i := strings.Index(line, "#"); i >= 0 {
+ line = line[:i]
+ }
+ f := strings.Fields(line)
+ if len(f) == 0 {
+ continue
+ }
+ if strings.HasPrefix(line, " ") {
+ sysfatal("%s:%d: must use tabs for indentation", args[0], lineno)
+ }
+ depth := len(prefix)
+ for len(stk) > 0 && depth <= stk[len(stk)-1].depth {
+ stk = stk[:len(stk)-1]
+ }
+ parent := ""
+ psrc := *root
+ if len(stk) > 0 {
+ parent = stk[len(stk)-1].name
+ psrc = stk[len(stk)-1].src
+ }
+ if strings.Contains(f[0], "/") {
+ sysfatal("%s:%d: destination name cannot contain slash", args[0], lineno)
+ }
+ name := path.Join(parent, f[0])
+ src := filepath.Join(psrc, f[0])
+ for _, attr := range f[1:] {
+ i := strings.Index(attr, "=")
+ if i < 0 {
+ sysfatal("%s:%d: malformed attribute %q", args[0], lineno, attr)
+ }
+ key, val := attr[:i], attr[i+1:]
+ switch key {
+ case "src":
+ src = val
+ default:
+ sysfatal("%s:%d: unknown attribute %q", args[0], lineno, attr)
+ }
+ }
+
+ stk = append(stk, stack{name: name, src: src, depth: depth})
+
+ if f[0] == "*" || f[0] == "+" {
+ if f[0] == "*" {
+ dir, err := ioutil.ReadDir(psrc)
+ if err != nil {
+ sysfatal("%s:%d: %v", args[0], lineno, err)
+ }
+ for _, d := range dir {
+ addfile(d, path.Join(parent, d.Name()), filepath.Join(psrc, d.Name()))
+ }
+ } else {
+ err := filepath.Walk(psrc, func(src string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if src == psrc {
+ return nil
+ }
+ if psrc == "." {
+ psrc = ""
+ }
+ name := path.Join(parent, filepath.ToSlash(src[len(psrc):]))
+ addfile(info, name, src)
+ return nil
+ })
+ if err != nil {
+ sysfatal("%s:%d: %v", args[0], lineno, err)
+ }
+ }
+ continue
+ }
+
+ fi, err := os.Stat(src)
+ if err != nil {
+ sysfatal("%s:%d: %v", args[0], lineno, err)
+ }
+ addfile(fi, name, src)
+ }
+
+ if err := z.Close(); err != nil {
+ sysfatal("finishing zip file: %v", err)
+ }
+}
+
+type goWriter struct {
+ b *bufio.Writer
+}
+
+func (w *goWriter) Write(b []byte) (int, error) {
+ for _, c := range b {
+ fmt.Fprintf(w.b, "\\x%02x", c)
+ }
+ return len(b), nil
+}
+
+func (w *goWriter) Close() error {
+ fmt.Fprintf(w.b, "\")\n}\n")
+ w.b.Flush()
+ return nil
+}
diff --git a/misc/nacl/testdata/bin/placeholder b/misc/nacl/testdata/bin/placeholder
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/misc/nacl/testdata/bin/placeholder
diff --git a/misc/nacl/testdata/empty b/misc/nacl/testdata/empty
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/misc/nacl/testdata/empty
diff --git a/misc/nacl/testdata/group b/misc/nacl/testdata/group
new file mode 100644
index 000000000..eb7f9a307
--- /dev/null
+++ b/misc/nacl/testdata/group
@@ -0,0 +1,8 @@
+nobody:*:-2:
+nogroup:*:-1:
+wheel:*:0:root
+daemon:*:1:root
+kmem:*:2:root
+sys:*:3:root
+tty:*:4:root
+operator:*:5:root
diff --git a/misc/nacl/testdata/hosts b/misc/nacl/testdata/hosts
new file mode 100644
index 000000000..75721cd5a
--- /dev/null
+++ b/misc/nacl/testdata/hosts
@@ -0,0 +1 @@
+127.0.0.1 localhost
diff --git a/misc/nacl/testdata/mime.types b/misc/nacl/testdata/mime.types
new file mode 100644
index 000000000..2c41bd2c0
--- /dev/null
+++ b/misc/nacl/testdata/mime.types
@@ -0,0 +1,1596 @@
+# This file maps Internet media types to unique file extension(s).
+# Although created for httpd, this file is used by many software systems
+# and has been placed in the public domain for unlimited redisribution.
+#
+# The table below contains both registered and (common) unregistered types.
+# A type that has no unique extension can be ignored -- they are listed
+# here to guide configurations toward known types and to make it easier to
+# identify "new" types. File extensions are also commonly used to indicate
+# content languages and encodings, so choose them carefully.
+#
+# Internet media types should be registered as described in RFC 4288.
+# The registry is at <http://www.iana.org/assignments/media-types/>.
+#
+# MIME type (lowercased) Extensions
+# ============================================ ==========
+# application/1d-interleaved-parityfec
+# application/3gpp-ims+xml
+# application/activemessage
+application/andrew-inset ez
+# application/applefile
+application/applixware aw
+application/atom+xml atom
+application/atomcat+xml atomcat
+# application/atomicmail
+application/atomsvc+xml atomsvc
+# application/auth-policy+xml
+# application/batch-smtp
+# application/beep+xml
+# application/calendar+xml
+# application/cals-1840
+# application/ccmp+xml
+application/ccxml+xml ccxml
+application/cdmi-capability cdmia
+application/cdmi-container cdmic
+application/cdmi-domain cdmid
+application/cdmi-object cdmio
+application/cdmi-queue cdmiq
+# application/cea-2018+xml
+# application/cellml+xml
+# application/cfw
+# application/cnrp+xml
+# application/commonground
+# application/conference-info+xml
+# application/cpl+xml
+# application/csta+xml
+# application/cstadata+xml
+application/cu-seeme cu
+# application/cybercash
+application/davmount+xml davmount
+# application/dca-rft
+# application/dec-dx
+# application/dialog-info+xml
+# application/dicom
+# application/dns
+application/docbook+xml dbk
+# application/dskpp+xml
+application/dssc+der dssc
+application/dssc+xml xdssc
+# application/dvcs
+application/ecmascript ecma
+# application/edi-consent
+# application/edi-x12
+# application/edifact
+application/emma+xml emma
+# application/epp+xml
+application/epub+zip epub
+# application/eshop
+# application/example
+application/exi exi
+# application/fastinfoset
+# application/fastsoap
+# application/fits
+application/font-tdpfr pfr
+# application/framework-attributes+xml
+application/gml+xml gml
+application/gpx+xml gpx
+application/gxf gxf
+# application/h224
+# application/held+xml
+# application/http
+application/hyperstudio stk
+# application/ibe-key-request+xml
+# application/ibe-pkg-reply+xml
+# application/ibe-pp-data
+# application/iges
+# application/im-iscomposing+xml
+# application/index
+# application/index.cmd
+# application/index.obj
+# application/index.response
+# application/index.vnd
+application/inkml+xml ink inkml
+# application/iotp
+application/ipfix ipfix
+# application/ipp
+# application/isup
+application/java-archive jar
+application/java-serialized-object ser
+application/java-vm class
+application/javascript js
+application/json json
+application/jsonml+json jsonml
+# application/kpml-request+xml
+# application/kpml-response+xml
+application/lost+xml lostxml
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+# application/macwriteii
+application/mads+xml mads
+application/marc mrc
+application/marcxml+xml mrcx
+application/mathematica ma nb mb
+# application/mathml-content+xml
+# application/mathml-presentation+xml
+application/mathml+xml mathml
+# application/mbms-associated-procedure-description+xml
+# application/mbms-deregister+xml
+# application/mbms-envelope+xml
+# application/mbms-msk+xml
+# application/mbms-msk-response+xml
+# application/mbms-protection-description+xml
+# application/mbms-reception-report+xml
+# application/mbms-register+xml
+# application/mbms-register-response+xml
+# application/mbms-user-service-description+xml
+application/mbox mbox
+# application/media_control+xml
+application/mediaservercontrol+xml mscml
+application/metalink+xml metalink
+application/metalink4+xml meta4
+application/mets+xml mets
+# application/mikey
+application/mods+xml mods
+# application/moss-keys
+# application/moss-signature
+# application/mosskey-data
+# application/mosskey-request
+application/mp21 m21 mp21
+application/mp4 mp4s
+# application/mpeg4-generic
+# application/mpeg4-iod
+# application/mpeg4-iod-xmt
+# application/msc-ivr+xml
+# application/msc-mixer+xml
+application/msword doc dot
+application/mxf mxf
+# application/nasdata
+# application/news-checkgroups
+# application/news-groupinfo
+# application/news-transmission
+# application/nss
+# application/ocsp-request
+# application/ocsp-response
+application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy mobipocket-ebook
+application/oda oda
+application/oebps-package+xml opf
+application/ogg ogx
+application/omdoc+xml omdoc
+application/onenote onetoc onetoc2 onetmp onepkg
+application/oxps oxps
+# application/parityfec
+application/patch-ops-error+xml xer
+application/pdf pdf
+application/pgp-encrypted pgp
+# application/pgp-keys
+application/pgp-signature asc sig
+application/pics-rules prf
+# application/pidf+xml
+# application/pidf-diff+xml
+application/pkcs10 p10
+application/pkcs7-mime p7m p7c
+application/pkcs7-signature p7s
+application/pkcs8 p8
+application/pkix-attr-cert ac
+application/pkix-cert cer
+application/pkix-crl crl
+application/pkix-pkipath pkipath
+application/pkixcmp pki
+application/pls+xml pls
+# application/poc-settings+xml
+application/postscript ai eps ps
+# application/prs.alvestrand.titrax-sheet
+application/prs.cww cww
+# application/prs.nprend
+# application/prs.plucker
+# application/prs.rdf-xml-crypt
+# application/prs.xsf+xml
+application/pskc+xml pskcxml
+# application/qsig
+application/rdf+xml rdf
+application/reginfo+xml rif
+application/relax-ng-compact-syntax rnc
+# application/remote-printing
+application/resource-lists+xml rl
+application/resource-lists-diff+xml rld
+# application/riscos
+# application/rlmi+xml
+application/rls-services+xml rs
+application/rpki-ghostbusters gbr
+application/rpki-manifest mft
+application/rpki-roa roa
+# application/rpki-updown
+application/rsd+xml rsd
+application/rss+xml rss
+application/rtf rtf
+# application/rtx
+# application/samlassertion+xml
+# application/samlmetadata+xml
+application/sbml+xml sbml
+application/scvp-cv-request scq
+application/scvp-cv-response scs
+application/scvp-vp-request spq
+application/scvp-vp-response spp
+application/sdp sdp
+# application/set-payment
+application/set-payment-initiation setpay
+# application/set-registration
+application/set-registration-initiation setreg
+# application/sgml
+# application/sgml-open-catalog
+application/shf+xml shf
+# application/sieve
+# application/simple-filter+xml
+# application/simple-message-summary
+# application/simplesymbolcontainer
+# application/slate
+# application/smil
+application/smil+xml smi smil
+# application/soap+fastinfoset
+# application/soap+xml
+application/sparql-query rq
+application/sparql-results+xml srx
+# application/spirits-event+xml
+application/srgs gram
+application/srgs+xml grxml
+application/sru+xml sru
+application/ssdl+xml ssdl
+application/ssml+xml ssml
+# application/tamp-apex-update
+# application/tamp-apex-update-confirm
+# application/tamp-community-update
+# application/tamp-community-update-confirm
+# application/tamp-error
+# application/tamp-sequence-adjust
+# application/tamp-sequence-adjust-confirm
+# application/tamp-status-query
+# application/tamp-status-response
+# application/tamp-update
+# application/tamp-update-confirm
+application/tei+xml tei teicorpus
+application/thraud+xml tfi
+# application/timestamp-query
+# application/timestamp-reply
+application/timestamped-data tsd
+# application/tve-trigger
+# application/ulpfec
+# application/vcard+xml
+# application/vemmi
+# application/vividence.scriptfile
+# application/vnd.3gpp.bsf+xml
+application/vnd.3gpp.pic-bw-large plb
+application/vnd.3gpp.pic-bw-small psb
+application/vnd.3gpp.pic-bw-var pvb
+# application/vnd.3gpp.sms
+# application/vnd.3gpp2.bcmcsinfo+xml
+# application/vnd.3gpp2.sms
+application/vnd.3gpp2.tcap tcap
+application/vnd.3m.post-it-notes pwn
+application/vnd.accpac.simply.aso aso
+application/vnd.accpac.simply.imp imp
+application/vnd.acucobol acu
+application/vnd.acucorp atc acutc
+application/vnd.adobe.air-application-installer-package+zip air
+application/vnd.adobe.formscentral.fcdt fcdt
+application/vnd.adobe.fxp fxp fxpl
+# application/vnd.adobe.partial-upload
+application/vnd.adobe.xdp+xml xdp
+application/vnd.adobe.xfdf xfdf
+# application/vnd.aether.imp
+# application/vnd.ah-barcode
+application/vnd.ahead.space ahead
+application/vnd.airzip.filesecure.azf azf
+application/vnd.airzip.filesecure.azs azs
+application/vnd.amazon.ebook azw
+application/vnd.americandynamics.acc acc
+application/vnd.amiga.ami ami
+# application/vnd.amundsen.maze+xml
+application/vnd.android.package-archive apk
+application/vnd.anser-web-certificate-issue-initiation cii
+application/vnd.anser-web-funds-transfer-initiation fti
+application/vnd.antix.game-component atx
+application/vnd.apple.installer+xml mpkg
+application/vnd.apple.mpegurl m3u8
+# application/vnd.arastra.swi
+application/vnd.aristanetworks.swi swi
+application/vnd.astraea-software.iota iota
+application/vnd.audiograph aep
+# application/vnd.autopackage
+# application/vnd.avistar+xml
+application/vnd.blueice.multipass mpm
+# application/vnd.bluetooth.ep.oob
+application/vnd.bmi bmi
+application/vnd.businessobjects rep
+# application/vnd.cab-jscript
+# application/vnd.canon-cpdl
+# application/vnd.canon-lips
+# application/vnd.cendio.thinlinc.clientconf
+application/vnd.chemdraw+xml cdxml
+application/vnd.chipnuts.karaoke-mmd mmd
+application/vnd.cinderella cdy
+# application/vnd.cirpack.isdn-ext
+application/vnd.claymore cla
+application/vnd.cloanto.rp9 rp9
+application/vnd.clonk.c4group c4g c4d c4f c4p c4u
+application/vnd.cluetrust.cartomobile-config c11amc
+application/vnd.cluetrust.cartomobile-config-pkg c11amz
+# application/vnd.collection+json
+# application/vnd.commerce-battelle
+application/vnd.commonspace csp
+application/vnd.contact.cmsg cdbcmsg
+application/vnd.cosmocaller cmc
+application/vnd.crick.clicker clkx
+application/vnd.crick.clicker.keyboard clkk
+application/vnd.crick.clicker.palette clkp
+application/vnd.crick.clicker.template clkt
+application/vnd.crick.clicker.wordbank clkw
+application/vnd.criticaltools.wbs+xml wbs
+application/vnd.ctc-posml pml
+# application/vnd.ctct.ws+xml
+# application/vnd.cups-pdf
+# application/vnd.cups-postscript
+application/vnd.cups-ppd ppd
+# application/vnd.cups-raster
+# application/vnd.cups-raw
+# application/vnd.curl
+application/vnd.curl.car car
+application/vnd.curl.pcurl pcurl
+# application/vnd.cybank
+application/vnd.dart dart
+application/vnd.data-vision.rdz rdz
+application/vnd.dece.data uvf uvvf uvd uvvd
+application/vnd.dece.ttml+xml uvt uvvt
+application/vnd.dece.unspecified uvx uvvx
+application/vnd.dece.zip uvz uvvz
+application/vnd.denovo.fcselayout-link fe_launch
+# application/vnd.dir-bi.plate-dl-nosuffix
+application/vnd.dna dna
+application/vnd.dolby.mlp mlp
+# application/vnd.dolby.mobile.1
+# application/vnd.dolby.mobile.2
+application/vnd.dpgraph dpg
+application/vnd.dreamfactory dfac
+application/vnd.ds-keypoint kpxx
+application/vnd.dvb.ait ait
+# application/vnd.dvb.dvbj
+# application/vnd.dvb.esgcontainer
+# application/vnd.dvb.ipdcdftnotifaccess
+# application/vnd.dvb.ipdcesgaccess
+# application/vnd.dvb.ipdcesgaccess2
+# application/vnd.dvb.ipdcesgpdd
+# application/vnd.dvb.ipdcroaming
+# application/vnd.dvb.iptv.alfec-base
+# application/vnd.dvb.iptv.alfec-enhancement
+# application/vnd.dvb.notif-aggregate-root+xml
+# application/vnd.dvb.notif-container+xml
+# application/vnd.dvb.notif-generic+xml
+# application/vnd.dvb.notif-ia-msglist+xml
+# application/vnd.dvb.notif-ia-registration-request+xml
+# application/vnd.dvb.notif-ia-registration-response+xml
+# application/vnd.dvb.notif-init+xml
+# application/vnd.dvb.pfr
+application/vnd.dvb.service svc
+# application/vnd.dxr
+application/vnd.dynageo geo
+# application/vnd.easykaraoke.cdgdownload
+# application/vnd.ecdis-update
+application/vnd.ecowin.chart mag
+# application/vnd.ecowin.filerequest
+# application/vnd.ecowin.fileupdate
+# application/vnd.ecowin.series
+# application/vnd.ecowin.seriesrequest
+# application/vnd.ecowin.seriesupdate
+# application/vnd.emclient.accessrequest+xml
+application/vnd.enliven nml
+# application/vnd.eprints.data+xml
+application/vnd.epson.esf esf
+application/vnd.epson.msf msf
+application/vnd.epson.quickanime qam
+application/vnd.epson.salt slt
+application/vnd.epson.ssf ssf
+# application/vnd.ericsson.quickcall
+application/vnd.eszigno3+xml es3 et3
+# application/vnd.etsi.aoc+xml
+# application/vnd.etsi.cug+xml
+# application/vnd.etsi.iptvcommand+xml
+# application/vnd.etsi.iptvdiscovery+xml
+# application/vnd.etsi.iptvprofile+xml
+# application/vnd.etsi.iptvsad-bc+xml
+# application/vnd.etsi.iptvsad-cod+xml
+# application/vnd.etsi.iptvsad-npvr+xml
+# application/vnd.etsi.iptvservice+xml
+# application/vnd.etsi.iptvsync+xml
+# application/vnd.etsi.iptvueprofile+xml
+# application/vnd.etsi.mcid+xml
+# application/vnd.etsi.overload-control-policy-dataset+xml
+# application/vnd.etsi.sci+xml
+# application/vnd.etsi.simservs+xml
+# application/vnd.etsi.tsl+xml
+# application/vnd.etsi.tsl.der
+# application/vnd.eudora.data
+application/vnd.ezpix-album ez2
+application/vnd.ezpix-package ez3
+# application/vnd.f-secure.mobile
+application/vnd.fdf fdf
+application/vnd.fdsn.mseed mseed
+application/vnd.fdsn.seed seed dataless
+# application/vnd.ffsns
+# application/vnd.fints
+application/vnd.flographit gph
+application/vnd.fluxtime.clip ftc
+# application/vnd.font-fontforge-sfd
+application/vnd.framemaker fm frame maker book
+application/vnd.frogans.fnc fnc
+application/vnd.frogans.ltf ltf
+application/vnd.fsc.weblaunch fsc
+application/vnd.fujitsu.oasys oas
+application/vnd.fujitsu.oasys2 oa2
+application/vnd.fujitsu.oasys3 oa3
+application/vnd.fujitsu.oasysgp fg5
+application/vnd.fujitsu.oasysprs bh2
+# application/vnd.fujixerox.art-ex
+# application/vnd.fujixerox.art4
+# application/vnd.fujixerox.hbpl
+application/vnd.fujixerox.ddd ddd
+application/vnd.fujixerox.docuworks xdw
+application/vnd.fujixerox.docuworks.binder xbd
+# application/vnd.fut-misnet
+application/vnd.fuzzysheet fzs
+application/vnd.genomatix.tuxedo txd
+# application/vnd.geocube+xml
+application/vnd.geogebra.file ggb
+application/vnd.geogebra.tool ggt
+application/vnd.geometry-explorer gex gre
+application/vnd.geonext gxt
+application/vnd.geoplan g2w
+application/vnd.geospace g3w
+# application/vnd.globalplatform.card-content-mgt
+# application/vnd.globalplatform.card-content-mgt-response
+application/vnd.gmx gmx
+application/vnd.google-earth.kml+xml kml
+application/vnd.google-earth.kmz kmz
+application/vnd.grafeq gqf gqs
+# application/vnd.gridmp
+application/vnd.groove-account gac
+application/vnd.groove-help ghf
+application/vnd.groove-identity-message gim
+application/vnd.groove-injector grv
+application/vnd.groove-tool-message gtm
+application/vnd.groove-tool-template tpl
+application/vnd.groove-vcard vcg
+# application/vnd.hal+json
+application/vnd.hal+xml hal
+application/vnd.handheld-entertainment+xml zmm
+application/vnd.hbci hbci
+# application/vnd.hcl-bireports
+application/vnd.hhe.lesson-player les
+application/vnd.hp-hpgl hpgl
+application/vnd.hp-hpid hpid
+application/vnd.hp-hps hps
+application/vnd.hp-jlyt jlt
+application/vnd.hp-pcl pcl
+application/vnd.hp-pclxl pclxl
+# application/vnd.httphone
+application/vnd.hydrostatix.sof-data sfd-hdstx
+# application/vnd.hzn-3d-crossword
+# application/vnd.ibm.afplinedata
+# application/vnd.ibm.electronic-media
+application/vnd.ibm.minipay mpy
+application/vnd.ibm.modcap afp listafp list3820
+application/vnd.ibm.rights-management irm
+application/vnd.ibm.secure-container sc
+application/vnd.iccprofile icc icm
+application/vnd.igloader igl
+application/vnd.immervision-ivp ivp
+application/vnd.immervision-ivu ivu
+# application/vnd.informedcontrol.rms+xml
+# application/vnd.informix-visionary
+# application/vnd.infotech.project
+# application/vnd.infotech.project+xml
+# application/vnd.innopath.wamp.notification
+application/vnd.insors.igm igm
+application/vnd.intercon.formnet xpw xpx
+application/vnd.intergeo i2g
+# application/vnd.intertrust.digibox
+# application/vnd.intertrust.nncp
+application/vnd.intu.qbo qbo
+application/vnd.intu.qfx qfx
+# application/vnd.iptc.g2.conceptitem+xml
+# application/vnd.iptc.g2.knowledgeitem+xml
+# application/vnd.iptc.g2.newsitem+xml
+# application/vnd.iptc.g2.newsmessage+xml
+# application/vnd.iptc.g2.packageitem+xml
+# application/vnd.iptc.g2.planningitem+xml
+application/vnd.ipunplugged.rcprofile rcprofile
+application/vnd.irepository.package+xml irp
+application/vnd.is-xpr xpr
+application/vnd.isac.fcs fcs
+application/vnd.jam jam
+# application/vnd.japannet-directory-service
+# application/vnd.japannet-jpnstore-wakeup
+# application/vnd.japannet-payment-wakeup
+# application/vnd.japannet-registration
+# application/vnd.japannet-registration-wakeup
+# application/vnd.japannet-setstore-wakeup
+# application/vnd.japannet-verification
+# application/vnd.japannet-verification-wakeup
+application/vnd.jcp.javame.midlet-rms rms
+application/vnd.jisp jisp
+application/vnd.joost.joda-archive joda
+application/vnd.kahootz ktz ktr
+application/vnd.kde.karbon karbon
+application/vnd.kde.kchart chrt
+application/vnd.kde.kformula kfo
+application/vnd.kde.kivio flw
+application/vnd.kde.kontour kon
+application/vnd.kde.kpresenter kpr kpt
+application/vnd.kde.kspread ksp
+application/vnd.kde.kword kwd kwt
+application/vnd.kenameaapp htke
+application/vnd.kidspiration kia
+application/vnd.kinar kne knp
+application/vnd.koan skp skd skt skm
+application/vnd.kodak-descriptor sse
+application/vnd.las.las+xml lasxml
+# application/vnd.liberty-request+xml
+application/vnd.llamagraphics.life-balance.desktop lbd
+application/vnd.llamagraphics.life-balance.exchange+xml lbe
+application/vnd.lotus-1-2-3 123
+application/vnd.lotus-approach apr
+application/vnd.lotus-freelance pre
+application/vnd.lotus-notes nsf
+application/vnd.lotus-organizer org
+application/vnd.lotus-screencam scm
+application/vnd.lotus-wordpro lwp
+application/vnd.macports.portpkg portpkg
+# application/vnd.marlin.drm.actiontoken+xml
+# application/vnd.marlin.drm.conftoken+xml
+# application/vnd.marlin.drm.license+xml
+# application/vnd.marlin.drm.mdcf
+application/vnd.mcd mcd
+application/vnd.medcalcdata mc1
+application/vnd.mediastation.cdkey cdkey
+# application/vnd.meridian-slingshot
+application/vnd.mfer mwf
+application/vnd.mfmp mfm
+application/vnd.micrografx.flo flo
+application/vnd.micrografx.igx igx
+application/vnd.mif mif
+# application/vnd.minisoft-hp3000-save
+# application/vnd.mitsubishi.misty-guard.trustweb
+application/vnd.mobius.daf daf
+application/vnd.mobius.dis dis
+application/vnd.mobius.mbk mbk
+application/vnd.mobius.mqy mqy
+application/vnd.mobius.msl msl
+application/vnd.mobius.plc plc
+application/vnd.mobius.txf txf
+application/vnd.mophun.application mpn
+application/vnd.mophun.certificate mpc
+# application/vnd.motorola.flexsuite
+# application/vnd.motorola.flexsuite.adsi
+# application/vnd.motorola.flexsuite.fis
+# application/vnd.motorola.flexsuite.gotap
+# application/vnd.motorola.flexsuite.kmr
+# application/vnd.motorola.flexsuite.ttc
+# application/vnd.motorola.flexsuite.wem
+# application/vnd.motorola.iprm
+application/vnd.mozilla.xul+xml xul
+application/vnd.ms-artgalry cil
+# application/vnd.ms-asf
+application/vnd.ms-cab-compressed cab
+# application/vnd.ms-color.iccprofile
+application/vnd.ms-excel xls xlm xla xlc xlt xlw
+application/vnd.ms-excel.addin.macroenabled.12 xlam
+application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb
+application/vnd.ms-excel.sheet.macroenabled.12 xlsm
+application/vnd.ms-excel.template.macroenabled.12 xltm
+application/vnd.ms-fontobject eot
+application/vnd.ms-htmlhelp chm
+application/vnd.ms-ims ims
+application/vnd.ms-lrm lrm
+# application/vnd.ms-office.activex+xml
+application/vnd.ms-officetheme thmx
+# application/vnd.ms-opentype
+# application/vnd.ms-package.obfuscated-opentype
+application/vnd.ms-pki.seccat cat
+application/vnd.ms-pki.stl stl
+# application/vnd.ms-playready.initiator+xml
+application/vnd.ms-powerpoint ppt pps pot
+application/vnd.ms-powerpoint.addin.macroenabled.12 ppam
+application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm
+application/vnd.ms-powerpoint.slide.macroenabled.12 sldm
+application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm
+application/vnd.ms-powerpoint.template.macroenabled.12 potm
+# application/vnd.ms-printing.printticket+xml
+application/vnd.ms-project mpp mpt
+# application/vnd.ms-tnef
+# application/vnd.ms-wmdrm.lic-chlg-req
+# application/vnd.ms-wmdrm.lic-resp
+# application/vnd.ms-wmdrm.meter-chlg-req
+# application/vnd.ms-wmdrm.meter-resp
+application/vnd.ms-word.document.macroenabled.12 docm
+application/vnd.ms-word.template.macroenabled.12 dotm
+application/vnd.ms-works wps wks wcm wdb
+application/vnd.ms-wpl wpl
+application/vnd.ms-xpsdocument xps
+application/vnd.mseq mseq
+# application/vnd.msign
+# application/vnd.multiad.creator
+# application/vnd.multiad.creator.cif
+# application/vnd.music-niff
+application/vnd.musician mus
+application/vnd.muvee.style msty
+application/vnd.mynfc taglet
+# application/vnd.ncd.control
+# application/vnd.ncd.reference
+# application/vnd.nervana
+# application/vnd.netfpx
+application/vnd.neurolanguage.nlu nlu
+application/vnd.nitf ntf nitf
+application/vnd.noblenet-directory nnd
+application/vnd.noblenet-sealer nns
+application/vnd.noblenet-web nnw
+# application/vnd.nokia.catalogs
+# application/vnd.nokia.conml+wbxml
+# application/vnd.nokia.conml+xml
+# application/vnd.nokia.isds-radio-presets
+# application/vnd.nokia.iptv.config+xml
+# application/vnd.nokia.landmark+wbxml
+# application/vnd.nokia.landmark+xml
+# application/vnd.nokia.landmarkcollection+xml
+# application/vnd.nokia.n-gage.ac+xml
+application/vnd.nokia.n-gage.data ngdat
+application/vnd.nokia.n-gage.symbian.install n-gage
+# application/vnd.nokia.ncd
+# application/vnd.nokia.pcd+wbxml
+# application/vnd.nokia.pcd+xml
+application/vnd.nokia.radio-preset rpst
+application/vnd.nokia.radio-presets rpss
+application/vnd.novadigm.edm edm
+application/vnd.novadigm.edx edx
+application/vnd.novadigm.ext ext
+# application/vnd.ntt-local.file-transfer
+# application/vnd.ntt-local.sip-ta_remote
+# application/vnd.ntt-local.sip-ta_tcp_stream
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.database odb
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template odft
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-master odm
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-web oth
+# application/vnd.obn
+# application/vnd.oftn.l10n+json
+# application/vnd.oipf.contentaccessdownload+xml
+# application/vnd.oipf.contentaccessstreaming+xml
+# application/vnd.oipf.cspg-hexbinary
+# application/vnd.oipf.dae.svg+xml
+# application/vnd.oipf.dae.xhtml+xml
+# application/vnd.oipf.mippvcontrolmessage+xml
+# application/vnd.oipf.pae.gem
+# application/vnd.oipf.spdiscovery+xml
+# application/vnd.oipf.spdlist+xml
+# application/vnd.oipf.ueprofile+xml
+# application/vnd.oipf.userprofile+xml
+application/vnd.olpc-sugar xo
+# application/vnd.oma-scws-config
+# application/vnd.oma-scws-http-request
+# application/vnd.oma-scws-http-response
+# application/vnd.oma.bcast.associated-procedure-parameter+xml
+# application/vnd.oma.bcast.drm-trigger+xml
+# application/vnd.oma.bcast.imd+xml
+# application/vnd.oma.bcast.ltkm
+# application/vnd.oma.bcast.notification+xml
+# application/vnd.oma.bcast.provisioningtrigger
+# application/vnd.oma.bcast.sgboot
+# application/vnd.oma.bcast.sgdd+xml
+# application/vnd.oma.bcast.sgdu
+# application/vnd.oma.bcast.simple-symbol-container
+# application/vnd.oma.bcast.smartcard-trigger+xml
+# application/vnd.oma.bcast.sprov+xml
+# application/vnd.oma.bcast.stkm
+# application/vnd.oma.cab-address-book+xml
+# application/vnd.oma.cab-feature-handler+xml
+# application/vnd.oma.cab-pcc+xml
+# application/vnd.oma.cab-user-prefs+xml
+# application/vnd.oma.dcd
+# application/vnd.oma.dcdc
+application/vnd.oma.dd2+xml dd2
+# application/vnd.oma.drm.risd+xml
+# application/vnd.oma.group-usage-list+xml
+# application/vnd.oma.pal+xml
+# application/vnd.oma.poc.detailed-progress-report+xml
+# application/vnd.oma.poc.final-report+xml
+# application/vnd.oma.poc.groups+xml
+# application/vnd.oma.poc.invocation-descriptor+xml
+# application/vnd.oma.poc.optimized-progress-report+xml
+# application/vnd.oma.push
+# application/vnd.oma.scidm.messages+xml
+# application/vnd.oma.xcap-directory+xml
+# application/vnd.omads-email+xml
+# application/vnd.omads-file+xml
+# application/vnd.omads-folder+xml
+# application/vnd.omaloc-supl-init
+application/vnd.openofficeorg.extension oxt
+# application/vnd.openxmlformats-officedocument.custom-properties+xml
+# application/vnd.openxmlformats-officedocument.customxmlproperties+xml
+# application/vnd.openxmlformats-officedocument.drawing+xml
+# application/vnd.openxmlformats-officedocument.drawingml.chart+xml
+# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml
+# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml
+# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml
+# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml
+# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml
+# application/vnd.openxmlformats-officedocument.extended-properties+xml
+# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml
+# application/vnd.openxmlformats-officedocument.presentationml.comments+xml
+# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml
+# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml
+# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml
+application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
+# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml
+# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml
+application/vnd.openxmlformats-officedocument.presentationml.slide sldx
+# application/vnd.openxmlformats-officedocument.presentationml.slide+xml
+# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml
+# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml
+application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
+# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml
+# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml
+# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml
+# application/vnd.openxmlformats-officedocument.presentationml.tags+xml
+application/vnd.openxmlformats-officedocument.presentationml.template potx
+# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml
+# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml
+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
+# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml
+application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
+# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml
+# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml
+# application/vnd.openxmlformats-officedocument.theme+xml
+# application/vnd.openxmlformats-officedocument.themeoverride+xml
+# application/vnd.openxmlformats-officedocument.vmldrawing
+# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml
+application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
+# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml
+application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
+# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml
+# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml
+# application/vnd.openxmlformats-package.core-properties+xml
+# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml
+# application/vnd.openxmlformats-package.relationships+xml
+# application/vnd.quobject-quoxdocument
+# application/vnd.osa.netdeploy
+application/vnd.osgeo.mapguide.package mgp
+# application/vnd.osgi.bundle
+application/vnd.osgi.dp dp
+application/vnd.osgi.subsystem esa
+# application/vnd.otps.ct-kip+xml
+application/vnd.palm pdb pqa oprc
+# application/vnd.paos.xml
+application/vnd.pawaafile paw
+application/vnd.pg.format str
+application/vnd.pg.osasli ei6
+# application/vnd.piaccess.application-licence
+application/vnd.picsel efif
+application/vnd.pmi.widget wg
+# application/vnd.poc.group-advertisement+xml
+application/vnd.pocketlearn plf
+application/vnd.powerbuilder6 pbd
+# application/vnd.powerbuilder6-s
+# application/vnd.powerbuilder7
+# application/vnd.powerbuilder7-s
+# application/vnd.powerbuilder75
+# application/vnd.powerbuilder75-s
+# application/vnd.preminet
+application/vnd.previewsystems.box box
+application/vnd.proteus.magazine mgz
+application/vnd.publishare-delta-tree qps
+application/vnd.pvi.ptid1 ptid
+# application/vnd.pwg-multiplexed
+# application/vnd.pwg-xhtml-print+xml
+# application/vnd.qualcomm.brew-app-res
+application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
+# application/vnd.radisys.moml+xml
+# application/vnd.radisys.msml+xml
+# application/vnd.radisys.msml-audit+xml
+# application/vnd.radisys.msml-audit-conf+xml
+# application/vnd.radisys.msml-audit-conn+xml
+# application/vnd.radisys.msml-audit-dialog+xml
+# application/vnd.radisys.msml-audit-stream+xml
+# application/vnd.radisys.msml-conf+xml
+# application/vnd.radisys.msml-dialog+xml
+# application/vnd.radisys.msml-dialog-base+xml
+# application/vnd.radisys.msml-dialog-fax-detect+xml
+# application/vnd.radisys.msml-dialog-fax-sendrecv+xml
+# application/vnd.radisys.msml-dialog-group+xml
+# application/vnd.radisys.msml-dialog-speech+xml
+# application/vnd.radisys.msml-dialog-transform+xml
+# application/vnd.rainstor.data
+# application/vnd.rapid
+application/vnd.realvnc.bed bed
+application/vnd.recordare.musicxml mxl
+application/vnd.recordare.musicxml+xml musicxml
+# application/vnd.renlearn.rlprint
+application/vnd.rig.cryptonote cryptonote
+application/vnd.rim.cod cod
+application/vnd.rn-realmedia rm
+application/vnd.rn-realmedia-vbr rmvb
+application/vnd.route66.link66+xml link66
+# application/vnd.rs-274x
+# application/vnd.ruckus.download
+# application/vnd.s3sms
+application/vnd.sailingtracker.track st
+# application/vnd.sbm.cid
+# application/vnd.sbm.mid2
+# application/vnd.scribus
+# application/vnd.sealed.3df
+# application/vnd.sealed.csf
+# application/vnd.sealed.doc
+# application/vnd.sealed.eml
+# application/vnd.sealed.mht
+# application/vnd.sealed.net
+# application/vnd.sealed.ppt
+# application/vnd.sealed.tiff
+# application/vnd.sealed.xls
+# application/vnd.sealedmedia.softseal.html
+# application/vnd.sealedmedia.softseal.pdf
+application/vnd.seemail see
+application/vnd.sema sema
+application/vnd.semd semd
+application/vnd.semf semf
+application/vnd.shana.informed.formdata ifm
+application/vnd.shana.informed.formtemplate itp
+application/vnd.shana.informed.interchange iif
+application/vnd.shana.informed.package ipk
+application/vnd.simtech-mindmapper twd twds
+application/vnd.smaf mmf
+# application/vnd.smart.notebook
+application/vnd.smart.teacher teacher
+# application/vnd.software602.filler.form+xml
+# application/vnd.software602.filler.form-xml-zip
+application/vnd.solent.sdkm+xml sdkm sdkd
+application/vnd.spotfire.dxp dxp
+application/vnd.spotfire.sfs sfs
+# application/vnd.sss-cod
+# application/vnd.sss-dtf
+# application/vnd.sss-ntf
+application/vnd.stardivision.calc sdc
+application/vnd.stardivision.draw sda
+application/vnd.stardivision.impress sdd
+application/vnd.stardivision.math smf
+application/vnd.stardivision.writer sdw vor
+application/vnd.stardivision.writer-global sgl
+application/vnd.stepmania.package smzip
+application/vnd.stepmania.stepchart sm
+# application/vnd.street-stream
+application/vnd.sun.xml.calc sxc
+application/vnd.sun.xml.calc.template stc
+application/vnd.sun.xml.draw sxd
+application/vnd.sun.xml.draw.template std
+application/vnd.sun.xml.impress sxi
+application/vnd.sun.xml.impress.template sti
+application/vnd.sun.xml.math sxm
+application/vnd.sun.xml.writer sxw
+application/vnd.sun.xml.writer.global sxg
+application/vnd.sun.xml.writer.template stw
+# application/vnd.sun.wadl+xml
+application/vnd.sus-calendar sus susp
+application/vnd.svd svd
+# application/vnd.swiftview-ics
+application/vnd.symbian.install sis sisx
+application/vnd.syncml+xml xsm
+application/vnd.syncml.dm+wbxml bdm
+application/vnd.syncml.dm+xml xdm
+# application/vnd.syncml.dm.notification
+# application/vnd.syncml.ds.notification
+application/vnd.tao.intent-module-archive tao
+application/vnd.tcpdump.pcap pcap cap dmp
+application/vnd.tmobile-livetv tmo
+application/vnd.trid.tpt tpt
+application/vnd.triscape.mxs mxs
+application/vnd.trueapp tra
+# application/vnd.truedoc
+# application/vnd.ubisoft.webplayer
+application/vnd.ufdl ufd ufdl
+application/vnd.uiq.theme utz
+application/vnd.umajin umj
+application/vnd.unity unityweb
+application/vnd.uoml+xml uoml
+# application/vnd.uplanet.alert
+# application/vnd.uplanet.alert-wbxml
+# application/vnd.uplanet.bearer-choice
+# application/vnd.uplanet.bearer-choice-wbxml
+# application/vnd.uplanet.cacheop
+# application/vnd.uplanet.cacheop-wbxml
+# application/vnd.uplanet.channel
+# application/vnd.uplanet.channel-wbxml
+# application/vnd.uplanet.list
+# application/vnd.uplanet.list-wbxml
+# application/vnd.uplanet.listcmd
+# application/vnd.uplanet.listcmd-wbxml
+# application/vnd.uplanet.signal
+application/vnd.vcx vcx
+# application/vnd.vd-study
+# application/vnd.vectorworks
+# application/vnd.verimatrix.vcas
+# application/vnd.vidsoft.vidconference
+application/vnd.visio vsd vst vss vsw
+application/vnd.visionary vis
+# application/vnd.vividence.scriptfile
+application/vnd.vsf vsf
+# application/vnd.wap.sic
+# application/vnd.wap.slc
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/vnd.webturbo wtb
+# application/vnd.wfa.wsc
+# application/vnd.wmc
+# application/vnd.wmf.bootstrap
+# application/vnd.wolfram.mathematica
+# application/vnd.wolfram.mathematica.package
+application/vnd.wolfram.player nbp
+application/vnd.wordperfect wpd
+application/vnd.wqd wqd
+# application/vnd.wrq-hp3000-labelled
+application/vnd.wt.stf stf
+# application/vnd.wv.csp+wbxml
+# application/vnd.wv.csp+xml
+# application/vnd.wv.ssp+xml
+application/vnd.xara xar
+application/vnd.xfdl xfdl
+# application/vnd.xfdl.webform
+# application/vnd.xmi+xml
+# application/vnd.xmpie.cpkg
+# application/vnd.xmpie.dpkg
+# application/vnd.xmpie.plan
+# application/vnd.xmpie.ppkg
+# application/vnd.xmpie.xlim
+application/vnd.yamaha.hv-dic hvd
+application/vnd.yamaha.hv-script hvs
+application/vnd.yamaha.hv-voice hvp
+application/vnd.yamaha.openscoreformat osf
+application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg
+# application/vnd.yamaha.remote-setup
+application/vnd.yamaha.smaf-audio saf
+application/vnd.yamaha.smaf-phrase spf
+# application/vnd.yamaha.through-ngn
+# application/vnd.yamaha.tunnel-udpencap
+application/vnd.yellowriver-custom-menu cmp
+application/vnd.zul zir zirz
+application/vnd.zzazz.deck+xml zaz
+application/voicexml+xml vxml
+# application/vq-rtcpxr
+# application/watcherinfo+xml
+# application/whoispp-query
+# application/whoispp-response
+application/widget wgt
+application/winhlp hlp
+# application/wita
+# application/wordperfect5.1
+application/wsdl+xml wsdl
+application/wspolicy+xml wspolicy
+application/x-7z-compressed 7z
+application/x-abiword abw
+application/x-ace-compressed ace
+# application/x-amf
+application/x-apple-diskimage dmg
+application/x-authorware-bin aab x32 u32 vox
+application/x-authorware-map aam
+application/x-authorware-seg aas
+application/x-bcpio bcpio
+application/x-bittorrent torrent
+application/x-blorb blb blorb
+application/x-bzip bz
+application/x-bzip2 bz2 boz
+application/x-cbr cbr cba cbt cbz cb7
+application/x-cdlink vcd
+application/x-cfs-compressed cfs
+application/x-chat chat
+application/x-chess-pgn pgn
+application/x-conference nsc
+# application/x-compress
+application/x-cpio cpio
+application/x-csh csh
+application/x-debian-package deb udeb
+application/x-dgc-compressed dgc
+application/x-director dir dcr dxr cst cct cxt w3d fgd swa
+application/x-doom wad
+application/x-dtbncx+xml ncx
+application/x-dtbook+xml dtb
+application/x-dtbresource+xml res
+application/x-dvi dvi
+application/x-envoy evy
+application/x-eva eva
+application/x-font-bdf bdf
+# application/x-font-dos
+# application/x-font-framemaker
+application/x-font-ghostscript gsf
+# application/x-font-libgrx
+application/x-font-linux-psf psf
+application/x-font-otf otf
+application/x-font-pcf pcf
+application/x-font-snf snf
+# application/x-font-speedo
+# application/x-font-sunos-news
+application/x-font-ttf ttf ttc
+application/x-font-type1 pfa pfb pfm afm
+application/x-font-woff woff
+# application/x-font-vfont
+application/x-freearc arc
+application/x-futuresplash spl
+application/x-gca-compressed gca
+application/x-glulx ulx
+application/x-gnumeric gnumeric
+application/x-gramps-xml gramps
+application/x-gtar gtar
+# application/x-gzip
+application/x-hdf hdf
+application/x-install-instructions install
+application/x-iso9660-image iso
+application/x-java-jnlp-file jnlp
+application/x-latex latex
+application/x-lzh-compressed lzh lha
+application/x-mie mie
+application/x-mobipocket-ebook prc mobi
+application/x-mpegurl m3u8
+application/x-ms-application application
+application/x-ms-shortcut lnk
+application/x-ms-wmd wmd
+application/x-ms-wmz wmz
+application/x-ms-xbap xbap
+application/x-msaccess mdb
+application/x-msbinder obd
+application/x-mscardfile crd
+application/x-msclip clp
+application/x-msdownload exe dll com bat msi
+application/x-msmediaview mvb m13 m14
+application/x-msmetafile wmf wmz emf emz
+application/x-msmoney mny
+application/x-mspublisher pub
+application/x-msschedule scd
+application/x-msterminal trm
+application/x-mswrite wri
+application/x-netcdf nc cdf
+application/x-nzb nzb
+application/x-pkcs12 p12 pfx
+application/x-pkcs7-certificates p7b spc
+application/x-pkcs7-certreqresp p7r
+application/x-rar-compressed rar
+application/x-research-info-systems ris
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-silverlight-app xap
+application/x-sql sql
+application/x-stuffit sit
+application/x-stuffitx sitx
+application/x-subrip srt
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-t3vm-image t3
+application/x-tads gam
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-tex-tfm tfm
+application/x-texinfo texinfo texi
+application/x-tgif obj
+application/x-ustar ustar
+application/x-wais-source src
+application/x-x509-ca-cert der crt
+application/x-xfig fig
+application/x-xliff+xml xlf
+application/x-xpinstall xpi
+application/x-xz xz
+application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8
+# application/x400-bp
+application/xaml+xml xaml
+# application/xcap-att+xml
+# application/xcap-caps+xml
+application/xcap-diff+xml xdf
+# application/xcap-el+xml
+# application/xcap-error+xml
+# application/xcap-ns+xml
+# application/xcon-conference-info-diff+xml
+# application/xcon-conference-info+xml
+application/xenc+xml xenc
+application/xhtml+xml xhtml xht
+# application/xhtml-voice+xml
+application/xml xml xsl
+application/xml-dtd dtd
+# application/xml-external-parsed-entity
+# application/xmpp+xml
+application/xop+xml xop
+application/xproc+xml xpl
+application/xslt+xml xslt
+application/xspf+xml xspf
+application/xv+xml mxml xhvml xvml xvm
+application/yang yang
+application/yin+xml yin
+application/zip zip
+# audio/1d-interleaved-parityfec
+# audio/32kadpcm
+# audio/3gpp
+# audio/3gpp2
+# audio/ac3
+audio/adpcm adp
+# audio/amr
+# audio/amr-wb
+# audio/amr-wb+
+# audio/asc
+# audio/atrac-advanced-lossless
+# audio/atrac-x
+# audio/atrac3
+audio/basic au snd
+# audio/bv16
+# audio/bv32
+# audio/clearmode
+# audio/cn
+# audio/dat12
+# audio/dls
+# audio/dsr-es201108
+# audio/dsr-es202050
+# audio/dsr-es202211
+# audio/dsr-es202212
+# audio/dv
+# audio/dvi4
+# audio/eac3
+# audio/evrc
+# audio/evrc-qcp
+# audio/evrc0
+# audio/evrc1
+# audio/evrcb
+# audio/evrcb0
+# audio/evrcb1
+# audio/evrcwb
+# audio/evrcwb0
+# audio/evrcwb1
+# audio/example
+# audio/fwdred
+# audio/g719
+# audio/g722
+# audio/g7221
+# audio/g723
+# audio/g726-16
+# audio/g726-24
+# audio/g726-32
+# audio/g726-40
+# audio/g728
+# audio/g729
+# audio/g7291
+# audio/g729d
+# audio/g729e
+# audio/gsm
+# audio/gsm-efr
+# audio/gsm-hr-08
+# audio/ilbc
+# audio/ip-mr_v2.5
+# audio/isac
+# audio/l16
+# audio/l20
+# audio/l24
+# audio/l8
+# audio/lpc
+audio/midi mid midi kar rmi
+# audio/mobile-xmf
+audio/mp4 mp4a
+# audio/mp4a-latm
+audio/mp4a-latm m4a m4p
+# audio/mpa
+# audio/mpa-robust
+audio/mpeg mpga mp2 mp2a mp3 m2a m3a
+# audio/mpeg4-generic
+# audio/musepack
+audio/ogg oga ogg spx
+# audio/opus
+# audio/parityfec
+# audio/pcma
+# audio/pcma-wb
+# audio/pcmu-wb
+# audio/pcmu
+# audio/prs.sid
+# audio/qcelp
+# audio/red
+# audio/rtp-enc-aescm128
+# audio/rtp-midi
+# audio/rtx
+audio/s3m s3m
+audio/silk sil
+# audio/smv
+# audio/smv0
+# audio/smv-qcp
+# audio/sp-midi
+# audio/speex
+# audio/t140c
+# audio/t38
+# audio/telephone-event
+# audio/tone
+# audio/uemclip
+# audio/ulpfec
+# audio/vdvi
+# audio/vmr-wb
+# audio/vnd.3gpp.iufp
+# audio/vnd.4sb
+# audio/vnd.audiokoz
+# audio/vnd.celp
+# audio/vnd.cisco.nse
+# audio/vnd.cmles.radio-events
+# audio/vnd.cns.anp1
+# audio/vnd.cns.inf1
+audio/vnd.dece.audio uva uvva
+audio/vnd.digital-winds eol
+# audio/vnd.dlna.adts
+# audio/vnd.dolby.heaac.1
+# audio/vnd.dolby.heaac.2
+# audio/vnd.dolby.mlp
+# audio/vnd.dolby.mps
+# audio/vnd.dolby.pl2
+# audio/vnd.dolby.pl2x
+# audio/vnd.dolby.pl2z
+# audio/vnd.dolby.pulse.1
+audio/vnd.dra dra
+audio/vnd.dts dts
+audio/vnd.dts.hd dtshd
+# audio/vnd.dvb.file
+# audio/vnd.everad.plj
+# audio/vnd.hns.audio
+audio/vnd.lucent.voice lvp
+audio/vnd.ms-playready.media.pya pya
+# audio/vnd.nokia.mobile-xmf
+# audio/vnd.nortel.vbk
+audio/vnd.nuera.ecelp4800 ecelp4800
+audio/vnd.nuera.ecelp7470 ecelp7470
+audio/vnd.nuera.ecelp9600 ecelp9600
+# audio/vnd.octel.sbc
+# audio/vnd.qcelp
+# audio/vnd.rhetorex.32kadpcm
+audio/vnd.rip rip
+# audio/vnd.sealedmedia.softseal.mpeg
+# audio/vnd.vmx.cvsd
+# audio/vorbis
+# audio/vorbis-config
+audio/webm weba
+audio/x-aac aac
+audio/x-aiff aif aiff aifc
+audio/x-caf caf
+audio/x-flac flac
+audio/x-matroska mka
+audio/x-mpegurl m3u
+audio/x-ms-wax wax
+audio/x-ms-wma wma
+audio/x-pn-realaudio ram ra
+audio/x-pn-realaudio-plugin rmp
+# audio/x-tta
+audio/x-wav wav
+audio/xm xm
+chemical/x-cdx cdx
+chemical/x-cif cif
+chemical/x-cmdf cmdf
+chemical/x-cml cml
+chemical/x-csml csml
+# chemical/x-pdb
+chemical/x-xyz xyz
+image/bmp bmp
+image/cgm cgm
+# image/example
+# image/fits
+image/g3fax g3
+image/gif gif
+image/ief ief
+# image/jp2
+image/jp2 jp2
+image/jpeg jpeg jpg jpe
+# image/jpm
+# image/jpx
+image/ktx ktx
+# image/naplps
+image/pict pict pic pct
+image/png png
+image/prs.btif btif
+# image/prs.pti
+image/sgi sgi
+image/svg+xml svg svgz
+# image/t38
+image/tiff tiff tif
+# image/tiff-fx
+image/vnd.adobe.photoshop psd
+# image/vnd.cns.inf2
+image/vnd.dece.graphic uvi uvvi uvg uvvg
+image/vnd.dvb.subtitle sub
+image/vnd.djvu djvu djv
+image/vnd.dwg dwg
+image/vnd.dxf dxf
+image/vnd.fastbidsheet fbs
+image/vnd.fpx fpx
+image/vnd.fst fst
+image/vnd.fujixerox.edmics-mmr mmr
+image/vnd.fujixerox.edmics-rlc rlc
+# image/vnd.globalgraphics.pgb
+# image/vnd.microsoft.icon
+# image/vnd.mix
+image/vnd.ms-modi mdi
+image/vnd.ms-photo wdp
+image/vnd.net-fpx npx
+# image/vnd.radiance
+# image/vnd.sealed.png
+# image/vnd.sealedmedia.softseal.gif
+# image/vnd.sealedmedia.softseal.jpg
+# image/vnd.svf
+image/vnd.wap.wbmp wbmp
+image/vnd.xiff xif
+image/webp webp
+image/x-3ds 3ds
+image/x-cmu-raster ras
+image/x-cmx cmx
+image/x-freehand fh fhc fh4 fh5 fh7
+image/x-icon ico
+image/x-macpaint pntg pnt mac
+image/x-mrsid-image sid
+image/x-pcx pcx
+image/x-pict pic pct
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-quicktime qtif qti
+image/x-rgb rgb
+image/x-tga tga
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+# message/cpim
+# message/delivery-status
+# message/disposition-notification
+# message/example
+# message/external-body
+# message/feedback-report
+# message/global
+# message/global-delivery-status
+# message/global-disposition-notification
+# message/global-headers
+# message/http
+# message/imdn+xml
+# message/news
+# message/partial
+message/rfc822 eml mime
+# message/s-http
+# message/sip
+# message/sipfrag
+# message/tracking-status
+# message/vnd.si.simp
+# model/example
+model/iges igs iges
+model/mesh msh mesh silo
+model/vnd.collada+xml dae
+model/vnd.dwf dwf
+# model/vnd.flatland.3dml
+model/vnd.gdl gdl
+# model/vnd.gs-gdl
+# model/vnd.gs.gdl
+model/vnd.gtw gtw
+# model/vnd.moml+xml
+model/vnd.mts mts
+# model/vnd.parasolid.transmit.binary
+# model/vnd.parasolid.transmit.text
+model/vnd.vtu vtu
+model/vrml wrl vrml
+model/x3d+binary x3db x3dbz
+model/x3d+vrml x3dv x3dvz
+model/x3d+xml x3d x3dz
+# multipart/alternative
+# multipart/appledouble
+# multipart/byteranges
+# multipart/digest
+# multipart/encrypted
+# multipart/example
+# multipart/form-data
+# multipart/header-set
+# multipart/mixed
+# multipart/parallel
+# multipart/related
+# multipart/report
+# multipart/signed
+# multipart/voice-message
+text/cache-manifest manifest
+# text/1d-interleaved-parityfec
+text/cache-manifest appcache
+text/calendar ics ifb
+text/css css
+text/csv csv
+# text/directory
+# text/dns
+# text/ecmascript
+# text/enriched
+# text/example
+# text/fwdred
+text/html html htm
+# text/javascript
+text/n3 n3
+# text/parityfec
+text/plain txt text conf def list log in
+# text/prs.fallenstein.rst
+text/prs.lines.tag dsc
+# text/vnd.radisys.msml-basic-layout
+# text/red
+# text/rfc822-headers
+text/richtext rtx
+# text/rtf
+# text/rtp-enc-aescm128
+# text/rtx
+text/sgml sgml sgm
+# text/t140
+text/tab-separated-values tsv
+text/troff t tr roff man me ms
+text/turtle ttl
+# text/ulpfec
+text/uri-list uri uris urls
+text/vcard vcard
+# text/vnd.abc
+text/vnd.curl curl
+text/vnd.curl.dcurl dcurl
+text/vnd.curl.scurl scurl
+text/vnd.curl.mcurl mcurl
+# text/vnd.dmclientscript
+text/vnd.dvb.subtitle sub
+# text/vnd.esmertec.theme-descriptor
+text/vnd.fly fly
+text/vnd.fmi.flexstor flx
+text/vnd.graphviz gv
+text/vnd.in3d.3dml 3dml
+text/vnd.in3d.spot spot
+# text/vnd.iptc.newsml
+# text/vnd.iptc.nitf
+# text/vnd.latex-z
+# text/vnd.motorola.reflex
+# text/vnd.ms-mediapackage
+# text/vnd.net2phone.commcenter.command
+# text/vnd.si.uricatalogue
+text/vnd.sun.j2me.app-descriptor jad
+# text/vnd.trolltech.linguist
+# text/vnd.wap.si
+# text/vnd.wap.sl
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/x-asm s asm
+text/x-c c cc cxx cpp h hh dic
+text/x-fortran f for f77 f90
+text/x-java-source java
+text/x-opml opml
+text/x-pascal p pas
+text/x-nfo nfo
+text/x-setext etx
+text/x-sfv sfv
+text/x-uuencode uu
+text/x-vcalendar vcs
+text/x-vcard vcf
+# text/xml
+# text/xml-external-parsed-entity
+# video/1d-interleaved-parityfec
+video/3gpp 3gp
+# video/3gpp-tt
+video/3gpp2 3g2
+# video/bmpeg
+# video/bt656
+# video/celb
+# video/dv
+# video/example
+video/h261 h261
+video/h263 h263
+# video/h263-1998
+# video/h263-2000
+video/h264 h264
+# video/h264-rcdo
+# video/h264-svc
+video/jpeg jpgv
+# video/jpeg2000
+video/jpm jpm jpgm
+video/mj2 mj2 mjp2
+# video/mp1s
+# video/mp2p
+# video/mp4v-es
+video/mp2t ts
+video/mp4 mp4 mp4v mpg4 m4v
+video/mpeg mpeg mpg mpe m1v m2v
+# video/mpeg4-generic
+# video/mpv
+# video/nv
+video/ogg ogv
+# video/parityfec
+# video/pointer
+video/quicktime qt mov
+# video/raw
+# video/rtp-enc-aescm128
+# video/rtx
+# video/smpte292m
+# video/ulpfec
+# video/vc1
+# video/vnd.cctv
+video/vnd.dece.hd uvh uvvh
+video/vnd.dece.mobile uvm uvvm
+# video/vnd.dece.mp4
+video/vnd.dece.pd uvp uvvp
+video/vnd.dece.sd uvs uvvs
+video/vnd.dece.video uvv uvvv
+# video/vnd.directv.mpeg
+# video/vnd.directv.mpeg-tts
+# video/vnd.dlna.mpeg-tts
+video/vnd.dvb.file dvb
+video/vnd.fvt fvt
+# video/vnd.hns.video
+# video/vnd.iptvforum.1dparityfec-1010
+# video/vnd.iptvforum.1dparityfec-2005
+# video/vnd.iptvforum.2dparityfec-1010
+# video/vnd.iptvforum.2dparityfec-2005
+# video/vnd.iptvforum.ttsavc
+# video/vnd.iptvforum.ttsmpeg2
+# video/vnd.motorola.video
+# video/vnd.motorola.videop
+video/vnd.mpegurl mxu m4u
+video/vnd.ms-playready.media.pyv pyv
+# video/vnd.nokia.interleaved-multimedia
+# video/vnd.nokia.videovoip
+# video/vnd.objectvideo
+# video/vnd.sealed.mpeg1
+# video/vnd.sealed.mpeg4
+# video/vnd.sealed.swf
+# video/vnd.sealedmedia.softseal.mov
+video/vnd.uvvu.mp4 uvu uvvu
+video/vnd.vivo viv
+video/x-dv dv dif
+video/webm webm
+video/x-f4v f4v
+video/x-fli fli
+video/x-flv flv
+video/x-m4v m4v
+video/x-matroska mkv mk3d mks
+video/x-mng mng
+video/x-ms-asf asf asx
+video/x-ms-vob vob
+video/x-ms-wm wm
+video/x-ms-wmv wmv
+video/x-ms-wmx wmx
+video/x-ms-wvx wvx
+video/x-msvideo avi
+video/x-sgi-movie movie
+video/x-smv smv
+x-conference/x-cooltalk ice
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
new file mode 100644
index 000000000..2701ff463
--- /dev/null
+++ b/misc/nacl/testzip.proto
@@ -0,0 +1,113 @@
+etc src=/etc
+ mime.types src=../misc/nacl/testdata/mime.types
+ resolv.conf src=../misc/nacl/testdata/empty
+ group src=../misc/nacl/testdata/group
+ passwd src=../misc/nacl/testdata/empty
+ hosts src=../misc/nacl/testdata/hosts
+ services
+usr src=../misc/nacl/testdata
+ bin
+go src=..
+ src
+ cmd
+ gofmt
+ testdata
+ +
+ pkg
+ archive
+ tar
+ testdata
+ +
+ zip
+ testdata
+ +
+ compress
+ bzip2
+ testdata
+ +
+ flate
+ gzip
+ testdata
+ +
+ lzw
+ testdata
+ +
+ zlib
+ crypto
+ rsa
+ testdata
+ +
+ tls
+ testdata
+ +
+ debug
+ dwarf
+ testdata
+ +
+ elf
+ testdata
+ +
+ macho
+ testdata
+ +
+ pe
+ testdata
+ +
+ plan9obj
+ testdata
+ +
+ go
+ build
+ +
+ doc
+ testdata
+ +
+ format
+ +
+ parser
+ +
+ printer
+ +
+ image
+ testdata
+ +
+ draw
+ gif
+ jpeg
+ png
+ testdata
+ +
+ io
+ +
+ mime
+ testdata
+ +
+ multipart
+ testdata
+ +
+ net
+ http
+ +
+ testdata
+ +
+ os
+ +
+ path
+ filepath
+ +
+ regexp
+ testdata
+ +
+ strconv
+ testdata
+ +
+ text
+ template
+ testdata
+ +
+ lib
+ time
+ zoneinfo.zip
+
+ test
+ +
diff --git a/misc/notepadplus/functionList.xml b/misc/notepadplus/functionList.xml
index ca949f018..7c605db4f 100644
--- a/misc/notepadplus/functionList.xml
+++ b/misc/notepadplus/functionList.xml
@@ -1,8 +1,15 @@
<!-- <NotepadPlus> -->
<!-- <functionList> -->
<!-- <associationMap> -->
+
+ <!--
+ if npp version == 6.4:
<association ext=".go" id="go"/>
+ if npp version >= 6.5:
+ <association userDefinedLangName="go" id="go"/>
+ -->
+
<!-- </associationMap> -->
<!-- <parsers> -->
<parser id="go" displayName="Go" commentExpr="((/\*.*?\*)/|(//.*?$))">
diff --git a/misc/pprof b/misc/pprof
index 1fc8d3621..ad3f1ebe1 100755
--- a/misc/pprof
+++ b/misc/pprof
@@ -730,6 +730,13 @@ sub RunWeb {
return;
}
+ if (`uname` =~ /CYGWIN/) {
+ # Windows(cygwin): open will use standard preference for SVG files.
+ my $winname = `cygpath -wa $fname`;
+ system("explorer.exe", $winname);
+ return;
+ }
+
# Some kind of Unix; try generic symlinks, then specific browsers.
# (Stop once we find one.)
# Works best if the browser is already running.
@@ -2645,6 +2652,7 @@ sub RemoveUninterestingFrames {
'makechan',
'makemap',
'mal',
+ 'profilealloc',
'runtime.new',
'makeslice1',
'runtime.malloc',
@@ -4608,6 +4616,7 @@ sub ConfigureObjTools {
# in the same directory as pprof.
$obj_tool_map{"nm_pdb"} = "nm-pdb";
$obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
+ $obj_tool_map{"objdump"} = "false"; # no objdump
}
if ($file_type =~ /Mach-O/) {
diff --git a/misc/vim/autoload/go/complete.vim b/misc/vim/autoload/go/complete.vim
index 8dd43de4a..a4fa6b668 100644
--- a/misc/vim/autoload/go/complete.vim
+++ b/misc/vim/autoload/go/complete.vim
@@ -58,7 +58,7 @@ function! go#complete#Package(ArgLead, CmdLine, CursorPos)
if executable('go')
let goroot = substitute(system('go env GOROOT'), '\n', '', 'g')
if v:shell_error
- echomsg '\'go env GOROOT\' failed'
+ echomsg '''go env GOROOT'' failed'
endif
else
let goroot = $GOROOT
diff --git a/misc/vim/ftplugin/go.vim b/misc/vim/ftplugin/go.vim
index 8066733cf..532fb1723 100644
--- a/misc/vim/ftplugin/go.vim
+++ b/misc/vim/ftplugin/go.vim
@@ -9,9 +9,11 @@ if exists("b:did_ftplugin")
endif
let b:did_ftplugin = 1
+setlocal formatoptions-=t
+
setlocal comments=s1:/*,mb:*,ex:*/,://
setlocal commentstring=//\ %s
-let b:undo_ftplugin = "setl com< cms<"
+let b:undo_ftplugin = "setl fo< com< cms<"
" vim:ts=4:sw=4:et
diff --git a/misc/vim/ftplugin/go/fmt.vim b/misc/vim/ftplugin/go/fmt.vim
index 5f7976f5f..359545bd4 100644
--- a/misc/vim/ftplugin/go/fmt.vim
+++ b/misc/vim/ftplugin/go/fmt.vim
@@ -57,7 +57,7 @@ function! s:GoFormat()
endif
undo
if !empty(errors)
- call setloclist(0, errors, 'r')
+ call setqflist(errors, 'r')
endif
echohl Error | echomsg "Gofmt returned error" | echohl None
endif
diff --git a/misc/vim/indent/go.vim b/misc/vim/indent/go.vim
index faf4d79e2..e3d6e8416 100644
--- a/misc/vim/indent/go.vim
+++ b/misc/vim/indent/go.vim
@@ -24,6 +24,18 @@ if exists("*GoIndent")
finish
endif
+" The shiftwidth() function is relatively new.
+" Don't require it to exist.
+if exists('*shiftwidth')
+ func s:sw()
+ return shiftwidth()
+ endfunc
+else
+ func s:sw()
+ return &shiftwidth
+ endfunc
+endif
+
function! GoIndent(lnum)
let prevlnum = prevnonblank(a:lnum-1)
if prevlnum == 0
@@ -40,17 +52,17 @@ function! GoIndent(lnum)
if prevl =~ '[({]\s*$'
" previous line opened a block
- let ind += &sw
+ let ind += s:sw()
endif
if prevl =~# '^\s*\(case .*\|default\):$'
" previous line is part of a switch statement
- let ind += &sw
+ let ind += s:sw()
endif
" TODO: handle if the previous line is a label.
if thisl =~ '^\s*[)}]'
" this line closed a block
- let ind -= &sw
+ let ind -= s:sw()
endif
" Colons are tricky.
@@ -58,7 +70,7 @@ function! GoIndent(lnum)
" We ignore trying to deal with jump labels because (a) they're rare, and
" (b) they're hard to disambiguate from a composite literal key.
if thisl =~# '^\s*\(case .*\|default\):$'
- let ind -= &sw
+ let ind -= s:sw()
endif
return ind
diff --git a/misc/vim/readme.txt b/misc/vim/readme.txt
index b8469f927..9a9e22870 100644
--- a/misc/vim/readme.txt
+++ b/misc/vim/readme.txt
@@ -5,9 +5,11 @@ To use all the Vim plugins, add these lines to your $HOME/.vimrc.
" Some Linux distributions set filetype in /etc/vimrc.
" Clear filetype flags before changing runtimepath to force Vim to reload them.
- filetype off
- filetype plugin indent off
- set runtimepath+=$GOROOT/misc/vim
+ if exists("g:did_load_filetypes")
+ filetype off
+ filetype plugin indent off
+ endif
+ set runtimepath+=$GOROOT/misc/vim " replace $GOROOT with the output of: go env GOROOT
filetype plugin indent on
syntax on
diff --git a/misc/zsh/go b/misc/zsh/go
index 18bcaaff2..066cf4065 100644
--- a/misc/zsh/go
+++ b/misc/zsh/go
@@ -19,7 +19,6 @@ __go_tool_complete() {
commands+=(
'build[compile packages and dependencies]'
'clean[remove object files]'
- 'doc[run godoc on package sources]'
'env[print Go environment information]'
'fix[run go tool fix on packages]'
'fmt[run gofmt on package sources]'
@@ -92,6 +91,7 @@ __go_tool_complete() {
"-short[use short mode]" \
"-parallel[number of parallel tests]:number" \
"-cpu[values of GOMAXPROCS to use]:number list" \
+ "-cover[enable coverage analysis]" \
"-run[run tests and examples matching regexp]:regexp" \
"-bench[run benchmarks matching regexp]:regexp" \
"-benchmem[print memory allocation stats]" \
@@ -106,9 +106,10 @@ __go_tool_complete() {
;;
help)
_values "${commands[@]}" \
+ 'c[how to call C code]' \
+ 'importpath[description of import path]' \
'gopath[GOPATH environment variable]' \
'packages[description of package lists]' \
- 'remote[remote import path syntax]' \
'testflag[description of testing flags]' \
'testfunc[description of testing functions]'
;;
diff --git a/src/all.bash b/src/all.bash
index 488ca4679..5d994d3d0 100755
--- a/src/all.bash
+++ b/src/all.bash
@@ -9,7 +9,7 @@ if [ ! -f make.bash ]; then
exit 1
fi
OLDPATH="$PATH"
-. ./make.bash --no-banner
+. ./make.bash "$@" --no-banner
bash run.bash --no-rebuild
PATH="$OLDPATH"
$GOTOOLDIR/dist banner # print build info
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index 8b39d610f..bb60fe7de 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -29,6 +29,7 @@
// THE SOFTWARE.
#include <bio.h>
+#include <link.h>
#include "../5l/5.out.h"
#ifndef EXTERN
@@ -43,9 +44,7 @@
#define ungetc ccungetc
typedef struct Sym Sym;
-typedef struct Gen Gen;
typedef struct Io Io;
-typedef struct Hist Hist;
#define MAXALIGN 7
#define FPCHIP 1
@@ -88,33 +87,6 @@ struct Io
};
#define I ((Io*)0)
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- Sym* sym;
- int32 offset;
- int32 offset2;
- short type;
- short reg;
- short name;
- double dval;
- char sval[8];
-};
-
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
enum
{
CLAST,
@@ -125,13 +97,11 @@ enum
Always = 14,
};
-EXTERN char debug[256];
+EXTERN int debug[256];
EXTERN Sym* hash[NHASH];
EXTERN char** Dlist;
EXTERN int nDlist;
-EXTERN Hist* ehist;
EXTERN int newflag;
-EXTERN Hist* hist;
EXTERN char* hunk;
EXTERN char** include;
EXTERN Io* iofree;
@@ -142,10 +112,9 @@ EXTERN int nerrors;
EXTERN int32 nhunk;
EXTERN int ninclude;
EXTERN int32 nsymb;
-EXTERN Gen nullgen;
+EXTERN Addr nullgen;
EXTERN char* outfile;
EXTERN int pass;
-EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
EXTERN int32 stmtline;
@@ -155,6 +124,8 @@ EXTERN int thechar;
EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
+EXTERN Link* ctxt;
+EXTERN Biobuf bstdout;
void* alloc(int32);
void* allocn(void*, int32, int32);
@@ -174,11 +145,8 @@ int escchar(int);
void cinit(void);
void pinit(char*);
void cclean(void);
-int isreg(Gen*);
-void outcode(int, int, Gen*, int, Gen*);
-void zname(char*, int, int);
-void zaddr(Gen*, int);
-void ieeedtod(Ieee*, double);
+int isreg(Addr*);
+void outcode(int, int, Addr*, int, Addr*);
int filbuf(void);
Sym* getsym(void);
void domacro(void);
@@ -190,7 +158,6 @@ void maclin(void);
void macprag(void);
void macif(int);
void macend(void);
-void outhist(void);
void dodefine(char*);
void prfile(int32);
void linehist(char*, int);
@@ -199,3 +166,4 @@ void yyerror(char*, ...);
int yyparse(void);
void setinclude(char*);
int assemble(char*);
+void listinit(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index c506ff9d5..56d0c563d 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -41,7 +41,7 @@
int32 lval;
double dval;
char sval[8];
- Gen gen;
+ Addr addr;
}
%left '|'
%left '^'
@@ -62,8 +62,8 @@
%token <sym> LNAME LLAB LVAR
%type <lval> con expr oexpr pointer offset sreg spreg creg
%type <lval> rcon cond reglist
-%type <gen> gen rel reg regreg freg shift fcon frcon
-%type <gen> imm ximm name oreg ireg nireg ioreg imsr
+%type <addr> gen rel reg regreg freg shift fcon frcon
+%type <addr> imm ximm name oreg ireg nireg ioreg imsr
%%
prog:
| prog
@@ -175,7 +175,7 @@ inst:
*/
| LTYPE8 cond ioreg ',' '[' reglist ']'
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
@@ -184,7 +184,7 @@ inst:
}
| LTYPE8 cond '[' reglist ']' ',' ioreg
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
@@ -279,7 +279,7 @@ inst:
*/
| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
@@ -294,7 +294,7 @@ inst:
(($11 & 15) << 0) | /* Crm */
(($12 & 7) << 5) | /* coprocessor information */
(1<<4); /* must be set */
- outcode(AWORD, Always, &nullgen, NREG, &g);
+ outcode(AMRC, Always, &nullgen, NREG, &g);
}
/*
* MULL r1,r2,(hi,lo)
@@ -336,7 +336,7 @@ inst:
{
if($2.type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
- if($4.type != D_EXTERN && $4.type != D_STATIC)
+ if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
yyerror("value for FUNCDATA must be symbol reference");
outcode($1, Always, &$2, NREG, &$4);
}
@@ -377,14 +377,12 @@ rel:
if(pass == 2)
yyerror("undefined label: %s", $1->name);
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $1->value + $2;
}
@@ -408,7 +406,7 @@ ximm: '$' con
{
$$ = nullgen;
$$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
+ memcpy($$.u.sval, $2, sizeof($$.u.sval));
}
| fcon
@@ -417,13 +415,13 @@ fcon:
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = $2;
+ $$.u.dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = -$3;
+ $$.u.dval = -$3;
}
reglist:
@@ -635,7 +633,7 @@ name:
$$ = nullgen;
$$.type = D_OREG;
$$.name = $3;
- $$.sym = S;
+ $$.sym = nil;
$$.offset = $1;
}
| LNAME offset '(' pointer ')'
@@ -643,7 +641,7 @@ name:
$$ = nullgen;
$$.type = D_OREG;
$$.name = $4;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 0);
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
@@ -651,7 +649,7 @@ name:
$$ = nullgen;
$$.type = D_OREG;
$$.name = D_STATIC;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 1);
$$.offset = $4;
}
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index c1b54e50b..571fdf7f2 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -51,60 +51,76 @@ systemtype(int sys)
#endif
}
+int
+Lconv(Fmt *fp)
+{
+ return linklinefmt(ctxt, fp);
+}
+
+void
+dodef(char *p)
+{
+ if(nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+}
+
+void
+usage(void)
+{
+ print("usage: %ca [options] file.c...\n", thechar);
+ flagprint(1);
+ errorexit();
+}
+
void
main(int argc, char *argv[])
{
char *p;
- int c;
thechar = '5';
thestring = "arm";
+ ctxt = linknew(&linkarm);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+ listinit5();
+ fmtinstall('L', Lconv);
+
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
cinit();
outfile = 0;
setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- case 't':
- thechar = 't';
- thestring = "thumb";
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
+
+ flagfn1("D", "name[=value]: add #define", dodef);
+ flagfn1("I", "dir: add dir to include path", setinclude);
+ flagcount("S", "print assembly and machine code", &debug['S']);
+ flagcount("m", "debug preprocessor macros", &debug['m']);
+ flagstr("o", "file: set output file", &outfile);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
+
+ flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
+
+ if(argc < 1)
+ usage();
if(argc > 1){
print("can't assemble multiple files\n");
errorexit();
}
+
if(assemble(argv[0]))
errorexit();
+ Bflush(&bstdout);
exits(0);
}
@@ -143,30 +159,22 @@ assemble(char *file)
errorexit();
}
Binit(&obuf, of, OWRITE);
-
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+ Bprint(&obuf, "!\n");
+
+ for(pass = 1; pass <= 2; pass++) {
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
cclean();
- return nerrors;
+ if(nerrors)
+ return nerrors;
}
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
+ writeobj(ctxt, &obuf);
+ Bflush(&obuf);
+ return 0;
}
struct
@@ -426,15 +434,9 @@ cinit(void)
Sym *s;
int i;
- nullgen.sym = S;
- nullgen.offset = 0;
nullgen.type = D_NONE;
nullgen.name = D_NONE;
nullgen.reg = NREG;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
nerrors = 0;
iostack = I;
@@ -448,13 +450,6 @@ cinit(void)
s->type = itab[i].type;
s->value = itab[i].value;
}
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
}
void
@@ -466,7 +461,7 @@ syminit(Sym *s)
}
int
-isreg(Gen *g)
+isreg(Addr *g)
{
USED(g);
@@ -476,81 +471,7 @@ isreg(Gen *g)
void
cclean(void)
{
-
outcode(AEND, Always, &nullgen, NREG, &nullgen);
- Bflush(&obuf);
-}
-
-void
-zname(char *n, int t, int s)
-{
-
- BPUTC(&obuf, ANAME);
- BPUTC(&obuf, t); /* type */
- BPUTC(&obuf, s); /* sym */
- while(*n) {
- BPUTC(&obuf, *n);
- n++;
- }
- BPUTC(&obuf, 0);
-}
-
-void
-zaddr(Gen *a, int s)
-{
- int32 l;
- int i;
- char *n;
- Ieee e;
-
- BPUTC(&obuf, a->type);
- BPUTC(&obuf, a->reg);
- BPUTC(&obuf, s);
- BPUTC(&obuf, a->name);
- BPUTC(&obuf, 0);
- switch(a->type) {
- default:
- print("unknown type %d\n", a->type);
- exits("arg");
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
-
- case D_REGREG:
- case D_REGREG2:
- BPUTC(&obuf, a->offset);
- break;
-
- case D_CONST2:
- l = a->offset2;
- BPUTLE4(&obuf, l);
- // fall through
- case D_OREG:
- case D_CONST:
- case D_BRANCH:
- case D_SHIFT:
- l = a->offset;
- BPUTLE4(&obuf, l);
- break;
-
- case D_SCONST:
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(&obuf, *n);
- n++;
- }
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->dval);
- BPUTLE4(&obuf, e.l);
- BPUTLE4(&obuf, e.h);
- break;
- }
}
static int bcode[] =
@@ -573,11 +494,13 @@ static int bcode[] =
ANOP,
};
+static Prog *lastpc;
+
void
-outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
+outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
{
- int sf, st, t;
- Sym *s;
+ Prog *p;
+ Plist *pl;
/* hack to make B.NE etc. work: turn it into the corresponding conditional */
if(a == AB){
@@ -587,154 +510,28 @@ outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
if(pass == 1)
goto out;
-jackpot:
- sf = 0;
- s = g1->sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g1->name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- BPUTC(&obuf, a);
- BPUTC(&obuf, scond);
- BPUTC(&obuf, reg);
- BPUTLE4(&obuf, stmtline);
- zaddr(g1, sf);
- zaddr(g2, st);
+
+ p = malloc(sizeof *p);
+ memset(p, 0, sizeof *p);
+ p->as = a;
+ p->lineno = stmtline;
+ p->scond = scond;
+ p->from = *g1;
+ p->reg = reg;
+ p->to = *g2;
+ p->pc = pc;
+
+ if(lastpc == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastpc->link = p;
+ lastpc = p;
out:
if(a != AGLOBL && a != ADATA)
pc++;
}
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- g = nullgen;
- c = '/';
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTC(&obuf, ANAME);
- BPUTC(&obuf, D_FILE); /* type */
- BPUTC(&obuf, 1); /* sym */
- BPUTC(&obuf, '<');
- Bwrite(&obuf, p, n);
- BPUTC(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- BPUTC(&obuf, AHISTORY);
- BPUTC(&obuf, Always);
- BPUTC(&obuf, 0);
- BPUTLE4(&obuf, h->line);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
#include "../cc/lexbody"
#include "../cc/macbody"
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
index dd102a09a..0bc8c34e1 100644
--- a/src/cmd/5a/y.tab.c
+++ b/src/cmd/5a/y.tab.c
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.7.12-4996"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
/* Pull parsers. */
#define YYPULL 1
-/* Using locations. */
-#define YYLSP_NEEDED 0
/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
+/* Line 371 of yacc.c */
#line 31 "a.y"
#include <u.h>
@@ -74,14 +71,16 @@
#include "a.h"
#include "../../pkg/runtime/funcdata.h"
+/* Line 371 of yacc.c */
+#line 76 "y.tab.c"
-/* Line 268 of yacc.c */
-#line 80 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
@@ -91,11 +90,17 @@
# define YYERROR_VERBOSE 0
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
#endif
-
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -205,36 +210,49 @@
-
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
-
-/* Line 293 of yacc.c */
+/* Line 387 of yacc.c */
#line 39 "a.y"
Sym *sym;
int32 lval;
double dval;
char sval[8];
- Gen gen;
+ Addr addr;
-
-/* Line 293 of yacc.c */
-#line 226 "y.tab.c"
+/* Line 387 of yacc.c */
+#line 228 "y.tab.c"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
+extern YYSTYPE yylval;
-/* Copy the second part of user declarations. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_Y_TAB_H_INCLUDED */
+/* Copy the second part of user declarations. */
-/* Line 343 of yacc.c */
-#line 238 "y.tab.c"
+/* Line 390 of yacc.c */
+#line 256 "y.tab.c"
#ifdef short
# undef short
@@ -287,24 +305,33 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
+
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
@@ -340,6 +367,7 @@ YYID (yyi)
# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# endif
@@ -431,20 +459,20 @@ union yyalloc
#endif
#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO. The source and destination do
+/* Copy COUNT objects from SRC to DST. The source and destination do
not overlap. */
# ifndef YYCOPY
# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
while (YYID (0))
# endif
# endif
@@ -594,19 +622,19 @@ static const yytype_uint16 yyrline[] =
141, 148, 155, 162, 169, 176, 185, 197, 201, 205,
212, 219, 225, 231, 240, 247, 254, 261, 265, 269,
273, 280, 302, 310, 319, 326, 335, 346, 352, 355,
- 359, 364, 365, 368, 374, 383, 391, 397, 402, 407,
- 413, 416, 422, 430, 434, 443, 449, 450, 451, 452,
- 457, 463, 469, 475, 476, 479, 480, 488, 497, 498,
- 507, 508, 514, 517, 518, 519, 521, 529, 537, 546,
- 552, 558, 564, 572, 578, 586, 587, 591, 599, 600,
- 606, 607, 615, 616, 619, 625, 633, 641, 649, 659,
- 662, 666, 672, 673, 674, 677, 678, 682, 686, 690,
- 694, 700, 703, 709, 710, 714, 718, 722, 726, 730,
- 734, 738, 742, 746
+ 359, 364, 365, 368, 374, 382, 389, 395, 400, 405,
+ 411, 414, 420, 428, 432, 441, 447, 448, 449, 450,
+ 455, 461, 467, 473, 474, 477, 478, 486, 495, 496,
+ 505, 506, 512, 515, 516, 517, 519, 527, 535, 544,
+ 550, 556, 562, 570, 576, 584, 585, 589, 597, 598,
+ 604, 605, 613, 614, 617, 623, 631, 639, 647, 657,
+ 660, 664, 670, 671, 672, 675, 676, 680, 684, 688,
+ 692, 698, 701, 707, 708, 712, 716, 720, 724, 728,
+ 732, 736, 740, 744
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 0
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -623,7 +651,7 @@ static const char *const yytname[] =
"$@1", "line", "$@2", "$@3", "inst", "cond", "comma", "rel", "ximm",
"fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg", "imsr",
"imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg",
- "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", 0
+ "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", YY_NULL
};
#endif
@@ -850,10 +878,10 @@ static const yytype_int16 yytable[] =
202, 203, 204, 198, 199, 200, 201, 202, 203, 204
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-128))
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-128)))
-#define yytable_value_is_error(yytable_value) \
+#define yytable_value_is_error(Yytable_value) \
YYID (0)
static const yytype_int16 yycheck[] =
@@ -988,62 +1016,35 @@ static const yytype_uint8 yystos[] =
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-
+/* Error token number */
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
/* This macro is provided for backward compatibility. */
-
#ifndef YY_LOCATION_PRINT
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
@@ -1093,6 +1094,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -1101,11 +1104,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# else
YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -1344,12 +1343,11 @@ static int
yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
yytype_int16 *yyssp, int yytoken)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
- const char *yyformat = 0;
+ const char *yyformat = YY_NULL;
/* Arguments of yyformat. */
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
/* Number of reported tokens (one for the "unexpected", one per
@@ -1409,11 +1407,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
break;
}
yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
}
}
}
@@ -1433,10 +1433,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
# undef YYCASE_
}
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
if (*yymsg_alloc < yysize)
{
@@ -1492,36 +1494,26 @@ yydestruct (yymsg, yytype, yyvaluep)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- switch (yytype)
- {
-
- default:
- break;
- }
+ YYUSE (yytype);
}
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
/* The lookahead symbol. */
int yychar;
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
/* Number of syntax errors so far. */
int yynerrs;
@@ -1561,7 +1553,7 @@ yyparse ()
`yyss': related to states.
`yyvs': related to semantic values.
- Refer to the stacks thru separate pointers, to allow yyoverflow
+ Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* The state stack. */
@@ -1579,7 +1571,7 @@ yyparse ()
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1597,9 +1589,8 @@ yyparse ()
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1608,14 +1599,6 @@ yyparse ()
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1756,7 +1739,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1793,8 +1778,7 @@ yyreduce:
switch (yyn)
{
case 3:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 70 "a.y"
{
stmtline = lineno;
@@ -1802,8 +1786,7 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 77 "a.y"
{
if((yyvsp[(1) - (2)].sym)->value != pc)
@@ -1813,8 +1796,7 @@ yyreduce:
break;
case 7:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 84 "a.y"
{
(yyvsp[(1) - (2)].sym)->type = LLAB;
@@ -1823,8 +1805,7 @@ yyreduce:
break;
case 9:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 90 "a.y"
{
(yyvsp[(1) - (4)].sym)->type = LVAR;
@@ -1833,8 +1814,7 @@ yyreduce:
break;
case 10:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 95 "a.y"
{
if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
@@ -1844,162 +1824,145 @@ yyreduce:
break;
case 14:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 109 "a.y"
{
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen));
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
}
break;
case 15:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 113 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen);
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
}
break;
case 16:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 117 "a.y"
{
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
case 17:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 124 "a.y"
{
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
case 18:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 131 "a.y"
{
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
case 19:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 138 "a.y"
{
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
case 20:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 142 "a.y"
{
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
case 21:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 149 "a.y"
{
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
case 22:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 156 "a.y"
{
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
case 23:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 163 "a.y"
{
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
}
break;
case 24:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 170 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen);
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
}
break;
case 25:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 177 "a.y"
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
g.offset = (yyvsp[(6) - (7)].lval);
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), NREG, &g);
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), NREG, &g);
}
break;
case 26:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 186 "a.y"
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
g.offset = (yyvsp[(4) - (7)].lval);
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].gen));
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].addr));
}
break;
case 27:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 198 "a.y"
{
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].gen), (yyvsp[(3) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen));
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
}
break;
case 28:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 202 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].gen), (yyvsp[(3) - (6)].gen).reg, &(yyvsp[(3) - (6)].gen));
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr));
}
break;
case 29:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 206 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].gen), (yyvsp[(6) - (6)].gen).reg, &(yyvsp[(6) - (6)].gen));
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
}
break;
case 30:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 213 "a.y"
{
outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
@@ -2007,107 +1970,96 @@ yyreduce:
break;
case 31:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 220 "a.y"
{
- (yyvsp[(4) - (4)].gen).type = D_CONST2;
- (yyvsp[(4) - (4)].gen).offset2 = ArgsSizeUnknown;
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), 0, &(yyvsp[(4) - (4)].gen));
+ (yyvsp[(4) - (4)].addr).type = D_CONST2;
+ (yyvsp[(4) - (4)].addr).offset2 = ArgsSizeUnknown;
+ outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
}
break;
case 32:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 226 "a.y"
{
- (yyvsp[(6) - (6)].gen).type = D_CONST2;
- (yyvsp[(6) - (6)].gen).offset2 = ArgsSizeUnknown;
- outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen));
+ (yyvsp[(6) - (6)].addr).type = D_CONST2;
+ (yyvsp[(6) - (6)].addr).offset2 = ArgsSizeUnknown;
+ outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
}
break;
case 33:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 232 "a.y"
{
- (yyvsp[(6) - (8)].gen).type = D_CONST2;
- (yyvsp[(6) - (8)].gen).offset2 = (yyvsp[(8) - (8)].lval);
- outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].gen), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].gen));
+ (yyvsp[(6) - (8)].addr).type = D_CONST2;
+ (yyvsp[(6) - (8)].addr).offset2 = (yyvsp[(8) - (8)].lval);
+ outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr));
}
break;
case 34:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 241 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen));
+ outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
}
break;
case 35:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 248 "a.y"
{
- outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].gen), NREG, &nullgen);
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen);
}
break;
case 36:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 255 "a.y"
{
- outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
}
break;
case 37:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 262 "a.y"
{
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
case 38:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 266 "a.y"
{
- outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
}
break;
case 39:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 270 "a.y"
{
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen));
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
}
break;
case 40:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 274 "a.y"
{
- outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].gen).reg, &nullgen);
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
}
break;
case 41:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 281 "a.y"
{
- Gen g;
+ Addr g;
g = nullgen;
g.type = D_CONST;
@@ -2122,66 +2074,60 @@ yyreduce:
(((yyvsp[(11) - (12)].lval) & 15) << 0) | /* Crm */
(((yyvsp[(12) - (12)].lval) & 7) << 5) | /* coprocessor information */
(1<<4); /* must be set */
- outcode(AWORD, Always, &nullgen, NREG, &g);
+ outcode(AMRC, Always, &nullgen, NREG, &g);
}
break;
case 42:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 303 "a.y"
{
- outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen));
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
}
break;
case 43:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 311 "a.y"
{
- (yyvsp[(7) - (9)].gen).type = D_REGREG2;
- (yyvsp[(7) - (9)].gen).offset = (yyvsp[(9) - (9)].lval);
- outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].gen), (yyvsp[(5) - (9)].gen).reg, &(yyvsp[(7) - (9)].gen));
+ (yyvsp[(7) - (9)].addr).type = D_REGREG2;
+ (yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval);
+ outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr));
}
break;
case 44:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 320 "a.y"
{
- outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].gen), NREG, &nullgen);
+ outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
}
break;
case 45:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 327 "a.y"
{
- if((yyvsp[(2) - (4)].gen).type != D_CONST || (yyvsp[(4) - (4)].gen).type != D_CONST)
+ if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), NREG, &(yyvsp[(4) - (4)].gen));
+ outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
}
break;
case 46:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 336 "a.y"
{
- if((yyvsp[(2) - (4)].gen).type != D_CONST)
+ if((yyvsp[(2) - (4)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(4) - (4)].gen).type != D_EXTERN && (yyvsp[(4) - (4)].gen).type != D_STATIC)
+ if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG)
yyerror("value for FUNCDATA must be symbol reference");
- outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), NREG, &(yyvsp[(4) - (4)].gen));
+ outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
}
break;
case 47:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 347 "a.y"
{
outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
@@ -2189,8 +2135,7 @@ yyreduce:
break;
case 48:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 352 "a.y"
{
(yyval.lval) = Always;
@@ -2198,8 +2143,7 @@ yyreduce:
break;
case 49:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 356 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
@@ -2207,8 +2151,7 @@ yyreduce:
break;
case 50:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 360 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
@@ -2216,119 +2159,106 @@ yyreduce:
break;
case 53:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 369 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
}
break;
case 54:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 375 "a.y"
{
- (yyval.gen) = nullgen;
+ (yyval.addr) = nullgen;
if(pass == 2)
yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 55:
-
-/* Line 1806 of yacc.c */
-#line 384 "a.y"
+/* Line 1787 of yacc.c */
+#line 383 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
case 56:
-
-/* Line 1806 of yacc.c */
-#line 392 "a.y"
+/* Line 1787 of yacc.c */
+#line 390 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST;
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 57:
-
-/* Line 1806 of yacc.c */
-#line 398 "a.y"
+/* Line 1787 of yacc.c */
+#line 396 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
- (yyval.gen).type = D_CONST;
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
+ (yyval.addr).type = D_CONST;
}
break;
case 58:
-
-/* Line 1806 of yacc.c */
-#line 403 "a.y"
+/* Line 1787 of yacc.c */
+#line 401 "a.y"
{
- (yyval.gen) = (yyvsp[(4) - (4)].gen);
- (yyval.gen).type = D_OCONST;
+ (yyval.addr) = (yyvsp[(4) - (4)].addr);
+ (yyval.addr).type = D_OCONST;
}
break;
case 59:
-
-/* Line 1806 of yacc.c */
-#line 408 "a.y"
+/* Line 1787 of yacc.c */
+#line 406 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SCONST;
- memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SCONST;
+ memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
}
break;
case 61:
-
-/* Line 1806 of yacc.c */
-#line 417 "a.y"
+/* Line 1787 of yacc.c */
+#line 415 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
}
break;
case 62:
-
-/* Line 1806 of yacc.c */
-#line 423 "a.y"
+/* Line 1787 of yacc.c */
+#line 421 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
}
break;
case 63:
-
-/* Line 1806 of yacc.c */
-#line 431 "a.y"
+/* Line 1787 of yacc.c */
+#line 429 "a.y"
{
(yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
}
break;
case 64:
-
-/* Line 1806 of yacc.c */
-#line 435 "a.y"
+/* Line 1787 of yacc.c */
+#line 433 "a.y"
{
int i;
(yyval.lval)=0;
@@ -2340,185 +2270,168 @@ yyreduce:
break;
case 65:
-
-/* Line 1806 of yacc.c */
-#line 444 "a.y"
+/* Line 1787 of yacc.c */
+#line 442 "a.y"
{
(yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
}
break;
case 69:
-
-/* Line 1806 of yacc.c */
-#line 453 "a.y"
+/* Line 1787 of yacc.c */
+#line 451 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (4)].gen);
- (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr) = (yyvsp[(1) - (4)].addr);
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
}
break;
case 70:
-
-/* Line 1806 of yacc.c */
-#line 458 "a.y"
+/* Line 1787 of yacc.c */
+#line 456 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_PSR;
- (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_PSR;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
}
break;
case 71:
-
-/* Line 1806 of yacc.c */
-#line 464 "a.y"
+/* Line 1787 of yacc.c */
+#line 462 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FPCR;
- (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FPCR;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
}
break;
case 72:
-
-/* Line 1806 of yacc.c */
-#line 470 "a.y"
+/* Line 1787 of yacc.c */
+#line 468 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
}
break;
case 76:
-
-/* Line 1806 of yacc.c */
-#line 481 "a.y"
+/* Line 1787 of yacc.c */
+#line 479 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (1)].gen);
- if((yyvsp[(1) - (1)].gen).name != D_EXTERN && (yyvsp[(1) - (1)].gen).name != D_STATIC) {
+ (yyval.addr) = (yyvsp[(1) - (1)].addr);
+ if((yyvsp[(1) - (1)].addr).name != D_EXTERN && (yyvsp[(1) - (1)].addr).name != D_STATIC) {
}
}
break;
case 77:
-
-/* Line 1806 of yacc.c */
-#line 489 "a.y"
+/* Line 1787 of yacc.c */
+#line 487 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).reg = (yyvsp[(2) - (3)].lval);
- (yyval.gen).offset = 0;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(2) - (3)].lval);
+ (yyval.addr).offset = 0;
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 499 "a.y"
+/* Line 1787 of yacc.c */
+#line 497 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 81:
-
-/* Line 1806 of yacc.c */
-#line 509 "a.y"
+/* Line 1787 of yacc.c */
+#line 507 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (4)].gen);
- (yyval.gen).type = D_OREG;
- (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr) = (yyvsp[(1) - (4)].addr);
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
}
break;
case 86:
-
-/* Line 1806 of yacc.c */
-#line 522 "a.y"
+/* Line 1787 of yacc.c */
+#line 520 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST;
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 87:
-
-/* Line 1806 of yacc.c */
-#line 530 "a.y"
+/* Line 1787 of yacc.c */
+#line 528 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_REG;
- (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
}
break;
case 88:
-
-/* Line 1806 of yacc.c */
-#line 538 "a.y"
+/* Line 1787 of yacc.c */
+#line 536 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_REGREG;
- (yyval.gen).reg = (yyvsp[(2) - (5)].lval);
- (yyval.gen).offset = (yyvsp[(4) - (5)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_REGREG;
+ (yyval.addr).reg = (yyvsp[(2) - (5)].lval);
+ (yyval.addr).offset = (yyvsp[(4) - (5)].lval);
}
break;
case 89:
-
-/* Line 1806 of yacc.c */
-#line 547 "a.y"
+/* Line 1787 of yacc.c */
+#line 545 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SHIFT;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SHIFT;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5);
}
break;
case 90:
-
-/* Line 1806 of yacc.c */
-#line 553 "a.y"
+/* Line 1787 of yacc.c */
+#line 551 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SHIFT;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SHIFT;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5);
}
break;
case 91:
-
-/* Line 1806 of yacc.c */
-#line 559 "a.y"
+/* Line 1787 of yacc.c */
+#line 557 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SHIFT;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SHIFT;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5);
}
break;
case 92:
-
-/* Line 1806 of yacc.c */
-#line 565 "a.y"
+/* Line 1787 of yacc.c */
+#line 563 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SHIFT;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SHIFT;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5);
}
break;
case 93:
-
-/* Line 1806 of yacc.c */
-#line 573 "a.y"
+/* Line 1787 of yacc.c */
+#line 571 "a.y"
{
if((yyval.lval) < 0 || (yyval.lval) >= 16)
print("register value out of range\n");
@@ -2527,9 +2440,8 @@ yyreduce:
break;
case 94:
-
-/* Line 1806 of yacc.c */
-#line 579 "a.y"
+/* Line 1787 of yacc.c */
+#line 577 "a.y"
{
if((yyval.lval) < 0 || (yyval.lval) >= 32)
print("shift value out of range\n");
@@ -2538,18 +2450,16 @@ yyreduce:
break;
case 96:
-
-/* Line 1806 of yacc.c */
-#line 588 "a.y"
+/* Line 1787 of yacc.c */
+#line 586 "a.y"
{
(yyval.lval) = REGPC;
}
break;
case 97:
-
-/* Line 1806 of yacc.c */
-#line 592 "a.y"
+/* Line 1787 of yacc.c */
+#line 590 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range\n");
@@ -2558,18 +2468,16 @@ yyreduce:
break;
case 99:
-
-/* Line 1806 of yacc.c */
-#line 601 "a.y"
+/* Line 1787 of yacc.c */
+#line 599 "a.y"
{
(yyval.lval) = REGSP;
}
break;
case 101:
-
-/* Line 1806 of yacc.c */
-#line 608 "a.y"
+/* Line 1787 of yacc.c */
+#line 606 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range\n");
@@ -2578,250 +2486,224 @@ yyreduce:
break;
case 104:
-
-/* Line 1806 of yacc.c */
-#line 620 "a.y"
+/* Line 1787 of yacc.c */
+#line 618 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FREG;
- (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(1) - (1)].lval);
}
break;
case 105:
-
-/* Line 1806 of yacc.c */
-#line 626 "a.y"
+/* Line 1787 of yacc.c */
+#line 624 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FREG;
- (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FREG;
+ (yyval.addr).reg = (yyvsp[(3) - (4)].lval);
}
break;
case 106:
-
-/* Line 1806 of yacc.c */
-#line 634 "a.y"
+/* Line 1787 of yacc.c */
+#line 632 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).name = (yyvsp[(3) - (4)].lval);
- (yyval.gen).sym = S;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = (yyvsp[(3) - (4)].lval);
+ (yyval.addr).sym = nil;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 107:
-
-/* Line 1806 of yacc.c */
-#line 642 "a.y"
+/* Line 1787 of yacc.c */
+#line 640 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).name = (yyvsp[(4) - (5)].lval);
- (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = (yyvsp[(4) - (5)].lval);
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
+ (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
}
break;
case 108:
-
-/* Line 1806 of yacc.c */
-#line 650 "a.y"
+/* Line 1787 of yacc.c */
+#line 648 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_OREG;
- (yyval.gen).name = D_STATIC;
- (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
- (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_OREG;
+ (yyval.addr).name = D_STATIC;
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
+ (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
}
break;
case 109:
-
-/* Line 1806 of yacc.c */
-#line 659 "a.y"
+/* Line 1787 of yacc.c */
+#line 657 "a.y"
{
(yyval.lval) = 0;
}
break;
case 110:
-
-/* Line 1806 of yacc.c */
-#line 663 "a.y"
+/* Line 1787 of yacc.c */
+#line 661 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 111:
-
-/* Line 1806 of yacc.c */
-#line 667 "a.y"
+/* Line 1787 of yacc.c */
+#line 665 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 116:
-
-/* Line 1806 of yacc.c */
-#line 679 "a.y"
+/* Line 1787 of yacc.c */
+#line 677 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
case 117:
-
-/* Line 1806 of yacc.c */
-#line 683 "a.y"
+/* Line 1787 of yacc.c */
+#line 681 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 118:
-
-/* Line 1806 of yacc.c */
-#line 687 "a.y"
+/* Line 1787 of yacc.c */
+#line 685 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 119:
-
-/* Line 1806 of yacc.c */
-#line 691 "a.y"
+/* Line 1787 of yacc.c */
+#line 689 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
case 120:
-
-/* Line 1806 of yacc.c */
-#line 695 "a.y"
+/* Line 1787 of yacc.c */
+#line 693 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
case 121:
-
-/* Line 1806 of yacc.c */
-#line 700 "a.y"
+/* Line 1787 of yacc.c */
+#line 698 "a.y"
{
(yyval.lval) = 0;
}
break;
case 122:
-
-/* Line 1806 of yacc.c */
-#line 704 "a.y"
+/* Line 1787 of yacc.c */
+#line 702 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 124:
-
-/* Line 1806 of yacc.c */
-#line 711 "a.y"
+/* Line 1787 of yacc.c */
+#line 709 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
case 125:
-
-/* Line 1806 of yacc.c */
-#line 715 "a.y"
+/* Line 1787 of yacc.c */
+#line 713 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
case 126:
-
-/* Line 1806 of yacc.c */
-#line 719 "a.y"
+/* Line 1787 of yacc.c */
+#line 717 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
case 127:
-
-/* Line 1806 of yacc.c */
-#line 723 "a.y"
+/* Line 1787 of yacc.c */
+#line 721 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
case 128:
-
-/* Line 1806 of yacc.c */
-#line 727 "a.y"
+/* Line 1787 of yacc.c */
+#line 725 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
case 129:
-
-/* Line 1806 of yacc.c */
-#line 731 "a.y"
+/* Line 1787 of yacc.c */
+#line 729 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
case 130:
-
-/* Line 1806 of yacc.c */
-#line 735 "a.y"
+/* Line 1787 of yacc.c */
+#line 733 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
case 131:
-
-/* Line 1806 of yacc.c */
-#line 739 "a.y"
+/* Line 1787 of yacc.c */
+#line 737 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
case 132:
-
-/* Line 1806 of yacc.c */
-#line 743 "a.y"
+/* Line 1787 of yacc.c */
+#line 741 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
case 133:
-
-/* Line 1806 of yacc.c */
-#line 747 "a.y"
+/* Line 1787 of yacc.c */
+#line 745 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
break;
-
-/* Line 1806 of yacc.c */
-#line 2825 "y.tab.c"
+/* Line 1787 of yacc.c */
+#line 2707 "y.tab.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -2984,7 +2866,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -3008,7 +2892,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -3050,4 +2934,3 @@ yyreturn:
}
-
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
index 92230a2a5..f11fb85c6 100644
--- a/src/cmd/5a/y.tab.h
+++ b/src/cmd/5a/y.tab.h
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison interface for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,6 +30,15 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
+#ifndef YY_YY_Y_TAB_H_INCLUDED
+# define YY_YY_Y_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -139,24 +148,21 @@
-
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
-
-/* Line 2068 of yacc.c */
+/* Line 2053 of yacc.c */
#line 39 "a.y"
Sym *sym;
int32 lval;
double dval;
char sval[8];
- Gen gen;
+ Addr addr;
-
-/* Line 2068 of yacc.c */
-#line 160 "y.tab.h"
+/* Line 2053 of yacc.c */
+#line 166 "y.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -165,4 +171,18 @@ typedef union YYSTYPE
extern YYSTYPE yylval;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+#endif /* !YY_YY_Y_TAB_H_INCLUDED */
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
index 084da7e6a..40d3a2b07 100644
--- a/src/cmd/5c/gc.h
+++ b/src/cmd/5c/gc.h
@@ -46,46 +46,19 @@
#define SZ_DOUBLE 8
#define FNX 100
-typedef struct Adr Adr;
-typedef struct Prog Prog;
typedef struct Case Case;
typedef struct C1 C1;
typedef struct Multab Multab;
typedef struct Hintab Hintab;
-typedef struct Var Var;
typedef struct Reg Reg;
typedef struct Rgn Rgn;
#define R0ISZERO 0
-struct Adr
-{
- int32 offset;
- int32 offset2;
- double dval;
- char sval[NSNAME];
- Ieee ieee;
-
- Sym* sym;
- char type;
- uchar reg;
- char name;
- char etype;
-};
-#define A ((Adr*)0)
+#define A ((Addr*)0)
#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- char as;
- uchar reg;
- uchar scond;
-};
#define P ((Prog*)0)
struct Case
@@ -116,14 +89,6 @@ struct Hintab
char hint[10];
};
-struct Var
-{
- int32 offset;
- Sym* sym;
- char name;
- char etype;
-};
-
struct Reg
{
int32 pc;
@@ -174,7 +139,6 @@ EXTERN Node fconstnode;
EXTERN int32 continpc;
EXTERN int32 curarg;
EXTERN int32 cursafe;
-EXTERN Prog* firstp;
EXTERN int32 isbigendian;
EXTERN Prog* lastp;
EXTERN int32 maxargsafe;
@@ -230,7 +194,6 @@ EXTERN Reg* firstr;
EXTERN Reg* lastr;
EXTERN Reg zreg;
EXTERN Reg* freer;
-EXTERN Var var[NVAR];
EXTERN int32* idom;
EXTERN Reg** rpo2r;
EXTERN int32 maxnr;
@@ -285,7 +248,7 @@ void regaalloc(Node*, Node*);
void regind(Node*, Node*);
void gprep(Node*, Node*);
void raddr(Node*, Prog*);
-void naddr(Node*, Adr*);
+void naddr(Node*, Addr*);
void gmovm(Node*, Node*, int);
void gmove(Node*, Node*);
void gmover(Node*, Node*);
@@ -314,19 +277,11 @@ int mulcon(Node*, Node*);
Multab* mulcon0(int32);
void nullwarn(Node*, Node*);
void outcode(void);
-void ieeedtod(Ieee*, double);
/*
* list
*/
void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Nconv(Fmt*);
-int Bconv(Fmt*);
-int Rconv(Fmt*);
/*
* reg.c
@@ -335,7 +290,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Adr*, int);
+Bits mkvar(Addr*, int);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
@@ -343,7 +298,7 @@ uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
-void addreg(Adr*, int);
+void addreg(Addr*, int);
/*
* peep.c
@@ -352,21 +307,21 @@ void peep(void);
void excise(Reg*);
Reg* uniqp(Reg*);
Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int regzer(Adr*);
-int anyvar(Adr*);
+int regtyp(Addr*);
+int regzer(Addr*);
+int anyvar(Addr*);
int subprop(Reg*);
int copyprop(Reg*);
int shiftprop(Reg*);
-void constprop(Adr*, Adr*, Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
+void constprop(Addr*, Addr*, Reg*);
+int copy1(Addr*, Addr*, Reg*, int);
+int copyu(Prog*, Addr*, Addr*);
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copyau1(Prog*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
+int copyas(Addr*, Addr*);
+int copyau(Addr*, Addr*);
+int copyau1(Prog*, Addr*);
+int copysub(Addr*, Addr*, Addr*, int);
+int copysub1(Prog*, Addr*, Addr*, int);
int32 RtoB(int);
int32 FtoB(int);
@@ -377,11 +332,3 @@ void predicate(void);
int isbranch(Prog *);
int predicable(Prog *p);
int modifiescpsr(Prog *p);
-
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "N" Adr*
-#pragma varargck type "R" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "S" char*
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
index 30b88400f..98da424de 100644
--- a/src/cmd/5c/list.c
+++ b/src/cmd/5c/list.c
@@ -35,306 +35,5 @@
void
listinit(void)
{
-
- fmtinstall('A', Aconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('N', Nconv);
- fmtinstall('B', Bconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%d", var[i].offset);
- s = ss;
- } else
- s = var[i].sym->name;
- if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
- break;
- strcat(str, s);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return fmtstrcpy(fp, str);
-}
-
-char *extra [] = {
- ".EQ", ".NE", ".CS", ".CC",
- ".MI", ".PL", ".VS", ".VC",
- ".HI", ".LS", ".GE", ".LT",
- ".GT", ".LE", "", ".NV",
-};
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ], sc[20];
- Prog *p;
- int a, s;
-
- p = va_arg(fp->args, Prog*);
- a = p->as;
- s = p->scond;
- strcpy(sc, extra[s & C_SCOND]);
- if(s & C_SBIT)
- strcat(sc, ".S");
- if(s & C_PBIT)
- strcat(sc, ".P");
- if(s & C_WBIT)
- strcat(sc, ".W");
- if(s & C_UBIT) /* ambiguous with FBIT */
- strcat(sc, ".U");
- if(a == AMOVM) {
- if(p->from.type == D_CONST)
- sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to);
- else
- if(p->to.type == D_CONST)
- sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to);
- else
- sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
- } else
- if(a == ADATA)
- sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
- else
- if(p->as == ATEXT)
- sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
- else
- if(p->reg == NREG)
- sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to);
- else
- if(p->from.type != D_FREG)
- sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
- else
- sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames[a];
- return fmtstrcpy(fp, s);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- const char *op;
- int v;
-
- a = va_arg(fp->args, Adr*);
- switch(a->type) {
-
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%N(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg != NREG)
- sprint(str, "$%N(R%d)", a, a->reg);
- else
- sprint(str, "$%N", a);
- break;
-
- case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
- if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
- break;
-
- case D_OREG:
- if(a->reg != NREG)
- sprint(str, "%N(R%d)", a, a->reg);
- else
- sprint(str, "%N", a);
- break;
-
- case D_REG:
- sprint(str, "R%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_FREG:
- sprint(str, "F%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_PSR:
- sprint(str, "PSR");
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(PSR)(REG)", a);
- break;
-
- case D_BRANCH:
- sprint(str, "%d(PC)", a->offset-pc);
- break;
-
- case D_FCONST:
- sprint(str, "$%.17e", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- int i, v;
-
- a = va_arg(fp->args, Adr*);
- sprint(str, "GOK-reglist");
- switch(a->type) {
- case D_CONST:
- case D_CONST2:
- if(a->reg != NREG)
- break;
- if(a->sym != S)
- break;
- v = a->offset;
- strcpy(str, "");
- for(i=0; i<NREG; i++) {
- if(v & (1<<i)) {
- if(str[0] == 0)
- strcat(str, "[R");
- else
- strcat(str, ",R");
- sprint(strchr(str, 0), "%d", i);
- }
- }
- strcat(str, "]");
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<NSNAME; i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9' ||
- c == ' ' || c == '%') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- case '\r':
- *p++ = 'r';
- continue;
- case '\f':
- *p++ = 'f';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
-int
-Nconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- Sym *s;
-
- a = va_arg(fp->args, Adr*);
- s = a->sym;
- if(s == S) {
- sprint(str, "%d", a->offset);
- goto out;
- }
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- sprint(str, "%d", a->offset);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%d(SB)", s->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%d(SB)", s->name, a->offset);
- break;
-
- case D_AUTO:
- sprint(str, "%s-%d(SP)", s->name, -a->offset);
- break;
-
- case D_PARAM:
- sprint(str, "%s+%d(FP)", s->name, a->offset);
- break;
- }
-out:
- return fmtstrcpy(fp, str);
+ listinit5();
}
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
index 22328c18c..143400a63 100644
--- a/src/cmd/5c/peep.c
+++ b/src/cmd/5c/peep.c
@@ -31,7 +31,7 @@
#include "gc.h"
-int xtramodes(Reg*, Adr*);
+int xtramodes(Reg*, Addr*);
void
peep(void)
@@ -281,7 +281,7 @@ uniqs(Reg *r)
}
int
-regtyp(Adr *a)
+regtyp(Addr *a)
{
if(a->type == D_REG)
@@ -309,7 +309,7 @@ int
subprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
int t;
@@ -427,7 +427,7 @@ int
copyprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
p = r0->prog;
@@ -441,7 +441,7 @@ copyprop(Reg *r0)
}
int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
{
int t;
Prog *p;
@@ -525,7 +525,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f)
* The v1->v2 should be eliminated by copy propagation.
*/
void
-constprop(Adr *c1, Adr *v1, Reg *r)
+constprop(Addr *c1, Addr *v1, Reg *r)
{
Prog *p;
@@ -574,7 +574,7 @@ shiftprop(Reg *r)
Reg *r1;
Prog *p, *p1, *p2;
int n, o;
- Adr a;
+ Addr a;
p = r->prog;
if(p->to.type != D_REG)
@@ -710,7 +710,7 @@ shiftprop(Reg *r)
}
Reg*
-findpre(Reg *r, Adr *v)
+findpre(Reg *r, Addr *v)
{
Reg *r1;
@@ -730,7 +730,7 @@ findpre(Reg *r, Adr *v)
}
Reg*
-findinc(Reg *r, Reg *r2, Adr *v)
+findinc(Reg *r, Reg *r2, Addr *v)
{
Reg *r1;
Prog *p;
@@ -758,7 +758,7 @@ findinc(Reg *r, Reg *r2, Adr *v)
int
nochange(Reg *r, Reg *r2, Prog *p)
{
- Adr a[3];
+ Addr a[3];
int i, n;
if(r == r2)
@@ -788,7 +788,7 @@ nochange(Reg *r, Reg *r2, Prog *p)
}
int
-findu1(Reg *r, Adr *v)
+findu1(Reg *r, Addr *v)
{
for(; r != R; r = r->s1) {
if(r->active)
@@ -810,7 +810,7 @@ findu1(Reg *r, Adr *v)
}
int
-finduse(Reg *r, Adr *v)
+finduse(Reg *r, Addr *v)
{
Reg *r1;
@@ -820,11 +820,11 @@ finduse(Reg *r, Adr *v)
}
int
-xtramodes(Reg *r, Adr *a)
+xtramodes(Reg *r, Addr *a)
{
Reg *r1, *r2, *r3;
Prog *p, *p1;
- Adr v;
+ Addr v;
p = r->prog;
if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG) /* byte load */
@@ -911,7 +911,7 @@ xtramodes(Reg *r, Adr *a)
* 0 otherwise (not touched)
*/
int
-copyu(Prog *p, Adr *v, Adr *s)
+copyu(Prog *p, Addr *v, Addr *s)
{
switch(p->as) {
@@ -1106,7 +1106,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type == D_REG) {
if(v->reg <= REGEXT && v->reg > exregoffset)
return 2;
- if(v->reg == (uchar)REGARG)
+ if(v->reg == REGARG)
return 2;
}
if(v->type == D_FREG)
@@ -1124,7 +1124,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ATEXT: /* funny */
if(v->type == D_REG)
- if(v->reg == (uchar)REGARG)
+ if(v->reg == REGARG)
return 3;
return 0;
}
@@ -1175,7 +1175,7 @@ a2type(Prog *p)
* semantics
*/
int
-copyas(Adr *a, Adr *v)
+copyas(Addr *a, Addr *v)
{
if(regtyp(v)) {
@@ -1197,7 +1197,7 @@ copyas(Adr *a, Adr *v)
* either direct or indirect
*/
int
-copyau(Adr *a, Adr *v)
+copyau(Addr *a, Addr *v)
{
if(copyas(a, v))
@@ -1217,7 +1217,7 @@ copyau(Adr *a, Adr *v)
}
int
-copyau1(Prog *p, Adr *v)
+copyau1(Prog *p, Addr *v)
{
if(regtyp(v)) {
@@ -1236,7 +1236,7 @@ copyau1(Prog *p, Adr *v)
* return failure to substitute
*/
int
-copysub(Adr *a, Adr *v, Adr *s, int f)
+copysub(Addr *a, Addr *v, Addr *s, int f)
{
if(f)
@@ -1253,7 +1253,7 @@ copysub(Adr *a, Adr *v, Adr *s, int f)
}
int
-copysub1(Prog *p1, Adr *v, Adr *s, int f)
+copysub1(Prog *p1, Addr *v, Addr *s, int f)
{
if(f)
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
index 3d67872b4..b9ac21abd 100644
--- a/src/cmd/5c/reg.c
+++ b/src/cmd/5c/reg.c
@@ -480,8 +480,10 @@ brk:
r1 = 0; /* set */
for(r = firstr; r != R; r = r->link) {
p = r->prog;
- if(p->to.type == D_BRANCH)
+ if(p->to.type == D_BRANCH) {
p->to.offset = r->s2->pc;
+ p->to.u.branch = r->s2->prog;
+ }
r1 = r;
}
@@ -535,7 +537,7 @@ void
addmove(Reg *r, int bn, int rn, int f)
{
Prog *p, *p1;
- Adr *a;
+ Addr *a;
Var *v;
p1 = alloc(sizeof(*p1));
@@ -554,7 +556,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->offset = v->offset;
a->etype = v->etype;
a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == S)
+ if(a->etype == TARRAY || a->sym == nil)
a->type = D_CONST;
p1->as = AMOVW;
@@ -592,13 +594,13 @@ addmove(Reg *r, int bn, int rn, int f)
}
Bits
-mkvar(Adr *a, int docon)
+mkvar(Addr *a, int docon)
{
Var *v;
int i, t, n, et, z;
int32 o;
Bits bit;
- Sym *s;
+ LSym *s;
t = a->type;
if(t == D_REG && a->reg != NREG)
@@ -608,13 +610,13 @@ mkvar(Adr *a, int docon)
s = a->sym;
o = a->offset;
et = a->etype;
- if(s == S) {
+ if(s == nil) {
if(t != D_CONST || !docon || a->reg != NREG)
goto none;
et = TLONG;
}
if(t == D_CONST) {
- if(s == S && sval(o))
+ if(s == nil && sval(o))
goto none;
}
@@ -656,7 +658,7 @@ out:
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
if(t == D_CONST) {
- if(s == S) {
+ if(s == nil) {
for(z=0; z<BITS; z++)
consts.b[z] |= bit.b[z];
return bit;
@@ -1135,7 +1137,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
}
void
-addreg(Adr *a, int rn)
+addreg(Addr *a, int rn)
{
a->sym = 0;
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 0f0c457f8..fd81a4e68 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -206,7 +206,7 @@ outstring(char *s, int32 n)
p->from.offset += nstring - NSNAME;
p->reg = NSNAME;
p->to.type = D_SCONST;
- memmove(p->to.sval, string, NSNAME);
+ memmove(p->to.u.sval, string, NSNAME);
mnstring = 0;
}
n--;
@@ -321,7 +321,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w)
p->from.offset += o+e;
p->reg = lw;
p->to.type = D_SCONST;
- memmove(p->to.sval, a->cstring+e, lw);
+ memmove(p->to.u.sval, a->cstring+e, lw);
}
}
@@ -351,48 +351,10 @@ gextern(Sym *s, Node *a, int32 o, int32 w)
p->to.type = D_CONST;
}
-void zname(Biobuf*, Sym*, int);
-char* zaddr(char*, Adr*, int);
-void zwrite(Biobuf*, Prog*, int, int);
-void outhist(Biobuf*);
-
-void
-zwrite(Biobuf *b, Prog *p, int sf, int st)
-{
- char bf[100], *bp;
-
- bf[0] = p->as;
- bf[1] = p->scond;
- bf[2] = p->reg;
- bf[3] = p->lineno;
- bf[4] = p->lineno>>8;
- bf[5] = p->lineno>>16;
- bf[6] = p->lineno>>24;
- bp = zaddr(bf+7, &p->from, sf);
- bp = zaddr(bp, &p->to, st);
- Bwrite(b, bf, bp-bf);
-}
-
void
outcode(void)
{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int sf, st, t, sym;
-
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
-
- Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
if(pragcgobuf.to > pragcgobuf.start) {
Bprint(&outbuf, "\n");
Bprint(&outbuf, "$$ // exports\n\n");
@@ -403,249 +365,10 @@ outcode(void)
}
Bprint(&outbuf, "!\n");
- outhist(&outbuf);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.name;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&outbuf, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.name;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&outbuf, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- zwrite(&outbuf, p, sf, st);
- }
- firstp = P;
+ writeobj(ctxt, &outbuf);
lastp = P;
}
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTC(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- zwrite(b, &pg, 0, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n, bf[7];
- uint32 sig;
-
- n = s->name;
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- bf[0] = ASIGNAME;
- bf[1] = sig;
- bf[2] = sig>>8;
- bf[3] = sig>>16;
- bf[4] = sig>>24;
- bf[5] = t;
- bf[6] = s->sym;
- Bwrite(b, bf, 7);
- s->sig = SIGDONE;
- }
- else{
- bf[0] = ANAME;
- bf[1] = t; /* type */
- bf[2] = s->sym; /* sym */
- Bwrite(b, bf, 3);
- }
- Bwrite(b, n, strlen(n)+1);
-}
-
-char*
-zaddr(char *bp, Adr *a, int s)
-{
- int32 l;
- Ieee e;
-
- bp[0] = a->type;
- bp[1] = a->reg;
- bp[2] = s;
- bp[3] = a->name;
- bp[4] = 0;
- bp += 5;
- switch(a->type) {
- default:
- diag(Z, "unknown type %d in zaddr", a->type);
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- break;
-
- case D_CONST2:
- l = a->offset2;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4; // fall through
- case D_OREG:
- case D_CONST:
- case D_BRANCH:
- case D_SHIFT:
- l = a->offset;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- break;
-
- case D_SCONST:
- memmove(bp, a->sval, NSNAME);
- bp += NSNAME;
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->dval);
- l = e.l;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- l = e.h;
- bp[0] = l;
- bp[1] = l>>8;
- bp[2] = l>>16;
- bp[3] = l>>24;
- bp += 4;
- break;
- }
- return bp;
-}
-
int32
align(int32 i, Type *t, int op, int32 *maxalign)
{
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index 6d9b69d00..a753510ca 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -31,13 +31,22 @@
#include "gc.h"
+
+int thechar = '5';
+char *thestring = "arm";
+
+LinkArch *thelinkarch = &linkarm;
+
+void
+linkarchinit(void)
+{
+}
+
void
ginit(void)
{
Type *t;
- thechar = '5';
- thestring = "arm";
exregoffset = REGEXT;
exfregoffset = FREGEXT;
listinit();
@@ -48,7 +57,6 @@ ginit(void)
breakpc = -1;
continpc = -1;
cases = C;
- firstp = P;
lastp = P;
tfield = types[TLONG];
@@ -149,17 +157,17 @@ gclean(void)
void
nextpc(void)
{
+ Plist *pl;
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
+ if(lastp == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastp->link = p;
lastp = p;
}
@@ -422,7 +430,7 @@ regind(Node *n, Node *nn)
void
raddr(Node *n, Prog *p)
{
- Adr a;
+ Addr a;
naddr(n, &a);
if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
@@ -440,7 +448,7 @@ raddr(Node *n, Prog *p)
}
void
-naddr(Node *n, Adr *a)
+naddr(Node *n, Addr *a)
{
int32 v;
@@ -455,7 +463,7 @@ naddr(Node *n, Adr *a)
case OREGISTER:
a->type = D_REG;
- a->sym = S;
+ a->sym = nil;
a->reg = n->reg;
if(a->reg >= NREG) {
a->type = D_FREG;
@@ -477,7 +485,7 @@ naddr(Node *n, Adr *a)
case OINDREG:
a->type = D_OREG;
- a->sym = S;
+ a->sym = nil;
a->offset = n->xoffset;
a->reg = n->reg;
break;
@@ -486,7 +494,7 @@ naddr(Node *n, Adr *a)
a->etype = n->etype;
a->type = D_OREG;
a->name = D_STATIC;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
@@ -505,11 +513,11 @@ naddr(Node *n, Adr *a)
goto bad;
case OCONST:
- a->sym = S;
+ a->sym = nil;
a->reg = NREG;
if(typefd[n->type->etype]) {
a->type = D_FCONST;
- a->dval = n->fconst;
+ a->u.dval = n->fconst;
} else {
a->type = D_CONST;
a->offset = n->vconst;
@@ -930,7 +938,7 @@ void
gopcode(int o, Node *f1, Node *f2, Node *t)
{
int a, et;
- Adr ta;
+ Addr ta;
et = TLONG;
if(f1 != Z && f1->type != T)
@@ -1177,7 +1185,7 @@ gpseudo(int a, Sym *s, Node *n)
nextpc();
p->as = a;
p->from.type = D_OREG;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.name = D_EXTERN;
switch(a) {
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 2d260e72d..9011b2022 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -254,6 +254,7 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
+ case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
goto sbop;
@@ -604,6 +605,7 @@ agen(Node *n, Node *res)
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
+ gvardef(&n1);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(AMOVW, &n1, &n2);
@@ -1410,10 +1412,11 @@ stkof(Node *n)
void
sgen(Node *n, Node *res, int64 w)
{
- Node dst, src, tmp, nend;
+ Node dst, src, tmp, nend, r0, r1, r2, *f;
int32 c, odst, osrc;
int dir, align, op;
Prog *p, *ploop;
+ NodeList *l;
if(debug['g']) {
print("\nsgen w=%lld\n", w);
@@ -1439,6 +1442,13 @@ sgen(Node *n, Node *res, int64 w)
return;
}
+ // If copying .args, that's all the results, so record definition sites
+ // for them for the liveness analysis.
+ if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
+ for(l = curfn->dcl; l != nil; l = l->next)
+ if(l->n->class == PPARAMOUT)
+ gvardef(l->n);
+
// Avoid taking the address for simple enough types.
if(componentgen(n, res))
return;
@@ -1480,18 +1490,59 @@ sgen(Node *n, Node *res, int64 w)
}
if(osrc%align != 0 || odst%align != 0)
fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
+
// if we are copying forward on the stack and
// the src and dst overlap, then reverse direction
dir = align;
if(osrc < odst && odst < osrc+w)
dir = -dir;
+ if(op == AMOVW && dir > 0 && c >= 4 && c <= 128) {
+ r0.op = OREGISTER;
+ r0.val.u.reg = REGALLOC_R0;
+ r1.op = OREGISTER;
+ r1.val.u.reg = REGALLOC_R0 + 1;
+ r2.op = OREGISTER;
+ r2.val.u.reg = REGALLOC_R0 + 2;
+
+ regalloc(&src, types[tptr], &r1);
+ regalloc(&dst, types[tptr], &r2);
+ if(n->ullman >= res->ullman) {
+ // eval n first
+ agen(n, &src);
+ if(res->op == ONAME)
+ gvardef(res);
+ agen(res, &dst);
+ } else {
+ // eval res first
+ if(res->op == ONAME)
+ gvardef(res);
+ agen(res, &dst);
+ agen(n, &src);
+ }
+ regalloc(&tmp, types[tptr], &r0);
+ f = sysfunc("duffcopy");
+ p = gins(ADUFFCOPY, N, f);
+ afunclit(&p->to, f);
+ // 8 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s
+ p->to.offset = 8*(128-c);
+
+ regfree(&tmp);
+ regfree(&src);
+ regfree(&dst);
+ return;
+ }
+
if(n->ullman >= res->ullman) {
agenr(n, &dst, res); // temporarily use dst
regalloc(&src, types[tptr], N);
gins(AMOVW, &dst, &src);
+ if(res->op == ONAME)
+ gvardef(res);
agen(res, &dst);
} else {
+ if(res->op == ONAME)
+ gvardef(res);
agenr(res, &dst, res);
agenr(n, &src, N);
}
@@ -1624,8 +1675,17 @@ componentgen(Node *nr, Node *nl)
freer = 1;
}
+ // nl and nr are 'cadable' which basically means they are names (variables) now.
+ // If they are the same variable, don't generate any code, because the
+ // VARDEF we generate will mark the old value as dead incorrectly.
+ // (And also the assignments are useless.)
+ if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
+ goto yes;
+
switch(nl->type->etype) {
case TARRAY:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(nl->type->type);
@@ -1656,6 +1716,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TSTRING:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
@@ -1677,6 +1739,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TINTER:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 1fbf633f9..a62102ef8 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -8,6 +8,12 @@
int thechar = '5';
char* thestring = "arm";
+LinkArch* thelinkarch = &linkarm;
+
+void
+linkarchinit(void)
+{
+}
vlong MAXWIDTH = (1LL<<32) - 1;
@@ -28,6 +34,7 @@ betypeinit(void)
{
widthptr = 4;
widthint = 4;
+ widthreg = 4;
zprog.link = P;
zprog.as = AGOK;
@@ -38,5 +45,5 @@ betypeinit(void)
zprog.from.reg = NREG;
zprog.to = zprog.from;
- listinit();
+ listinit5();
}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 860817f69..413e93c24 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -9,44 +9,6 @@
#include "../gc/go.h"
#include "../5l/5.out.h"
-typedef struct Addr Addr;
-
-struct Addr
-{
- int32 offset;
- int32 offset2;
-
- union {
- double dval;
- vlong vval;
- Prog* branch;
- char sval[NSNAME];
- } u;
-
- Sym* sym;
- Sym* gotype;
- Node* node;
- int width;
- uchar type;
- char name;
- uchar reg;
- uchar etype;
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Prog* link; // next instruction in this func
- void* opt; // for optimizer passes
- short as; // opcode
- uchar reg; // doubles as width in DATA op
- uchar scond;
- Addr from; // src address
- Addr to; // dst address
-};
-
#define TEXTFLAG reg
#define REGALLOC_R0 0
@@ -58,7 +20,6 @@ EXTERN int32 dynloc;
EXTERN uchar reg[REGALLOC_FMAX+1];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
-extern char* anames[];
EXTERN Prog zprog;
EXTERN Node* newproc;
EXTERN Node* deferproc;
@@ -67,7 +28,6 @@ EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
extern long unmappedzero;
-EXTERN int maxstksize;
/*
* gen.c
@@ -156,16 +116,6 @@ void datastring(char*, int, Addr*);
/*
* list.c
*/
-int Aconv(Fmt*);
-int Cconv(Fmt*);
-int Dconv(Fmt*);
-int Mconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
-
-#pragma varargck type "D" Addr*
-#pragma varargck type "M" Addr*
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 040c3d2a9..fb32c2f36 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -9,78 +9,114 @@
#include "gg.h"
#include "opt.h"
-static Prog* appendp(Prog*, int, int, int, int32, int, int, int32);
+static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32);
+static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0);
void
-defframe(Prog *ptxt, Bvec *bv)
+defframe(Prog *ptxt)
{
- int i, j, first;
- uint32 frame;
- Prog *p, *p1;
-
+ uint32 frame, r0;
+ Prog *p;
+ vlong hi, lo;
+ NodeList *l;
+ Node *n;
+
// fill in argument size
ptxt->to.type = D_CONST2;
ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
- if(stksize > maxstksize)
- maxstksize = stksize;
- frame = rnd(maxstksize+maxarg, widthptr);
+ frame = rnd(stksize+maxarg, widthptr);
ptxt->to.offset = frame;
- maxstksize = 0;
-
- // insert code to clear pointered part of the frame,
+
+ // insert code to contain ambiguously live variables
// so that garbage collector only sees initialized values
// when it looks for pointers.
p = ptxt;
- while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE)
- p = p->link;
- if(stkzerosize >= 8*widthptr) {
- p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
- p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkzerosize, D_REG, 1, 0);
+ lo = hi = 0;
+ r0 = 0;
+ for(l=curfn->dcl; l != nil; l = l->next) {
+ n = l->n;
+ if(!n->needzero)
+ continue;
+ if(n->class != PAUTO)
+ fatal("needzero class %d", n->class);
+ if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
+ fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
+ if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) {
+ // merge with range we already have
+ lo = rnd(n->xoffset, widthptr);
+ continue;
+ }
+ // zero old range
+ p = zerorange(p, frame, lo, hi, &r0);
+
+ // set new range
+ hi = n->xoffset + n->type->width;
+ lo = n->xoffset;
+ }
+ // zero final range
+ zerorange(p, frame, lo, hi, &r0);
+}
+
+static Prog*
+zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0)
+{
+ vlong cnt, i;
+ Prog *p1;
+ Node *f;
+
+ cnt = hi - lo;
+ if(cnt == 0)
+ return p;
+ if(*r0 == 0) {
+ p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
+ *r0 = 1;
+ }
+ if(cnt < 4*widthptr) {
+ for(i = 0; i < cnt; i += widthptr)
+ p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i);
+ } else if(cnt <= 128*widthptr) {
+ p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
p->reg = REGSP;
- p = appendp(p, AADD, D_CONST, NREG, stkzerosize, D_REG, 2, 0);
+ p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0);
+ f = sysfunc("duffzero");
+ naddr(f, &p->to, 1);
+ afunclit(&p->to, f);
+ p->to.offset = 4*(128-cnt/widthptr);
+ } else {
+ p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
+ p->reg = REGSP;
+ p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0);
p->reg = 1;
- p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
+ p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
p->scond |= C_PBIT;
- p = appendp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
+ p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
p->reg = 2;
- p = appendp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
+ p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
patch(p, p1);
- } else {
- first = 1;
- j = (stkptrsize - stkzerosize)/widthptr * 2;
- for(i=0; i<stkzerosize; i+=widthptr) {
- if(bvget(bv, j) || bvget(bv, j+1)) {
- if(first) {
- p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
- first = 0;
- }
- p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkzerosize+i);
- }
- j += 2;
- }
}
+ return p;
}
-static Prog*
-appendp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset)
-{
- Prog *q;
-
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.reg = freg;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.reg = treg;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
+static Prog*
+appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset)
+{
+ Prog *q;
+
+ q = mal(sizeof(*q));
+ clearp(q);
+ q->as = as;
+ q->lineno = p->lineno;
+ q->from.type = ftype;
+ q->from.reg = freg;
+ q->from.offset = foffset;
+ q->to.type = ttype;
+ q->to.reg = treg;
+ q->to.offset = toffset;
+ q->link = p->link;
+ p->link = q;
+ return q;
}
// Sweep the prog list to mark any used nodes.
@@ -88,13 +124,13 @@ void
markautoused(Prog* p)
{
for (; p; p = p->link) {
- if (p->as == ATYPE)
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
continue;
- if (p->from.name == D_AUTO && p->from.node)
+ if (p->from.node)
p->from.node->used = 1;
- if (p->to.name == D_AUTO && p->to.node)
+ if (p->to.node)
p->to.node->used = 1;
}
}
@@ -110,6 +146,16 @@ fixautoused(Prog* p)
*lp = p->link;
continue;
}
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ p->to.type = D_NONE;
+ p->to.node = N;
+ p->as = ANOP;
+ continue;
+ }
if (p->from.name == D_AUTO && p->from.node)
p->from.offset += p->from.node->stkdelta;
@@ -245,7 +291,9 @@ ginscall(Node *f, int proc)
nodconst(&con, types[TINT32], 0);
p = gins(ACMP, &con, N);
p->reg = 0;
- patch(gbranch(ABNE, T, -1), retpc);
+ p = gbranch(ABEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
}
break;
}
@@ -459,16 +507,16 @@ cgen_ret(Node *n)
{
Prog *p;
- genlist(n->list); // copy out args
- if(hasdefer || curfn->exit) {
- gjmp(retpc);
- return;
- }
+ if(n != N)
+ genlist(n->list); // copy out args
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ genlist(curfn->exit);
p = gins(ARET, N, N);
- if(n->op == ORETJMP) {
+ if(n != N && n->op == ORETJMP) {
p->to.name = D_EXTERN;
p->to.type = D_CONST;
- p->to.sym = n->left->sym;
+ p->to.sym = linksym(n->left->sym);
}
}
@@ -816,14 +864,13 @@ void
clearfat(Node *nl)
{
uint32 w, c, q;
- Node dst, nc, nz, end;
+ Node dst, nc, nz, end, r0, r1, *f;
Prog *p, *pl;
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
-
w = nl->type->width;
// Avoid taking the address for simple enough types.
if(componentgen(N, nl))
@@ -832,13 +879,17 @@ clearfat(Node *nl)
c = w % 4; // bytes
q = w / 4; // quads
- regalloc(&dst, types[tptr], N);
+ r0.op = OREGISTER;
+ r0.val.u.reg = REGALLOC_R0;
+ r1.op = OREGISTER;
+ r1.val.u.reg = REGALLOC_R0 + 1;
+ regalloc(&dst, types[tptr], &r1);
agen(nl, &dst);
nodconst(&nc, types[TUINT32], 0);
- regalloc(&nz, types[TUINT32], 0);
+ regalloc(&nz, types[TUINT32], &r0);
cgen(&nc, &nz);
- if(q >= 4) {
+ if(q > 128) {
regalloc(&end, types[tptr], N);
p = gins(AMOVW, &dst, &end);
p->from.type = D_CONST;
@@ -855,6 +906,12 @@ clearfat(Node *nl)
patch(gbranch(ABNE, T, 0), pl);
regfree(&end);
+ } else if(q >= 4) {
+ f = sysfunc("duffzero");
+ p = gins(ADUFFZERO, N, f);
+ afunclit(&p->to, f);
+ // 4 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s
+ p->to.offset = 4*(128-q);
} else
while(q > 0) {
p = gins(AMOVW, &nz, &dst);
@@ -901,7 +958,7 @@ expandchecks(Prog *firstp)
p1->link = p->link;
p->link = p1;
p1->lineno = p->lineno;
- p1->loc = 9999;
+ p1->pc = 9999;
p1->as = AMOVW;
p1->from.type = D_REG;
p1->from.reg = reg;
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index 212ffc271..5e988878f 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -32,235 +32,6 @@
#include <libc.h>
#include "gg.h"
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- BPUTC(b, ANAME); /* as */
- BPUTC(b, t); /* type */
- BPUTC(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- BPUTC(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- BPUTC(b, AHISTORY);
- BPUTC(b, C_SCOND_NONE);
- BPUTC(b, NREG);
- BPUTLE4(b, line);
- zaddr(b, &zprog.from, 0, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s, int gotype)
-{
- int32 l;
- uint64 e;
- int i;
- char *n;
-
- switch(a->type) {
- case D_STATIC:
- case D_AUTO:
- case D_EXTERN:
- case D_PARAM:
- // TODO(kaib): remove once everything seems to work
- fatal("We should no longer generate these as types");
-
- default:
- BPUTC(b, a->type);
- BPUTC(b, a->reg);
- BPUTC(b, s);
- BPUTC(b, a->name);
- BPUTC(b, gotype);
- }
-
- switch(a->type) {
- default:
- print("unknown type %d in zaddr\n", a->type);
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- break;
-
- case D_CONST2:
- l = a->offset2;
- BPUTLE4(b, l); // fall through
- case D_OREG:
- case D_CONST:
- case D_SHIFT:
- case D_STATIC:
- case D_AUTO:
- case D_EXTERN:
- case D_PARAM:
- l = a->offset;
- BPUTLE4(b, l);
- break;
-
- case D_BRANCH:
- if(a->u.branch == nil)
- fatal("unpatched branch");
- a->offset = a->u.branch->loc;
- l = a->offset;
- BPUTLE4(b, l);
- break;
-
- case D_SCONST:
- n = a->u.sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(b, *n);
- n++;
- }
- break;
-
- case D_REGREG:
- case D_REGREG2:
- BPUTC(b, a->offset);
- break;
-
- case D_FCONST:
- ieeedtod(&e, a->u.dval);
- BPUTLE4(b, e);
- BPUTLE4(b, e >> 32);
- break;
- }
-}
-
-static struct {
- struct { Sym *sym; short type; } h[NSYM];
- int sym;
-} z;
-
-static void
-zsymreset(void)
-{
- for(z.sym=0; z.sym<NSYM; z.sym++) {
- z.h[z.sym].sym = S;
- z.h[z.sym].type = 0;
- }
- z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
- int i;
-
- *new = 0;
- if(s == S)
- return 0;
-
- i = s->sym;
- if(i < 0 || i >= NSYM)
- i = 0;
- if(z.h[i].type == t && z.h[i].sym == s)
- return i;
- i = z.sym;
- s->sym = i;
- zname(bout, s, t);
- z.h[i].sym = s;
- z.h[i].type = t;
- if(++z.sym >= NSYM)
- z.sym = 1;
- *new = 1;
- return i;
-}
-
-static int
-zsymaddr(Addr *a, int *new)
-{
- int t;
-
- t = a->name;
- if(t == D_ADDR)
- t = a->name;
- return zsym(a->sym, t, new);
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, gf, gt, new;
- Sym *s;
- Prog *p;
-
- zsymreset();
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- // -S prints code; -SS prints code and data
- if(debug['S'] && (pl->name || debug['S']>1)) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- for(;;) {
- sf = zsymaddr(&p->from, &new);
- gf = zsym(p->from.gotype, D_EXTERN, &new);
- if(new && sf == gf)
- continue;
- st = zsymaddr(&p->to, &new);
- if(new && (st == sf || st == gf))
- continue;
- gt = zsym(p->to.gotype, D_EXTERN, &new);
- if(new && (gt == sf || gt == gf || gt == st))
- continue;
- break;
- }
-
- BPUTC(bout, p->as);
- BPUTC(bout, p->scond);
- BPUTC(bout, p->reg);
- BPUTLE4(bout, p->lineno);
- zaddr(bout, &p->from, sf, gf);
- zaddr(bout, &p->to, st, gt);
- }
- }
-}
-
int
dsname(Sym *sym, int off, char *t, int n)
{
@@ -272,7 +43,7 @@ dsname(Sym *sym, int off, char *t, int n)
p->from.etype = TINT32;
p->from.offset = off;
p->from.reg = NREG;
- p->from.sym = sym;
+ p->from.sym = linksym(sym);
p->reg = n;
@@ -299,7 +70,7 @@ datastring(char *s, int len, Addr *a)
a->etype = TINT32;
a->offset = widthptr+4; // skip header
a->reg = NREG;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
}
@@ -318,7 +89,7 @@ datagostring(Strlit *sval, Addr *a)
a->etype = TINT32;
a->offset = 0; // header
a->reg = NREG;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
}
@@ -401,7 +172,7 @@ dstringptr(Sym *s, int off, char *str)
p = gins(ADATA, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->reg = widthptr;
@@ -425,7 +196,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
p = gins(ADATA, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->reg = widthptr;
datagostring(lit, &p->to);
@@ -453,27 +224,6 @@ dgostringptr(Sym *s, int off, char *str)
}
int
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = off;
- p->reg = wid;
- p->to.type = D_CONST;
- p->to.name = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
-int
dsymptr(Sym *s, int off, Sym *x, int xoff)
{
Prog *p;
@@ -483,12 +233,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
p = gins(ADATA, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->reg = widthptr;
p->to.type = D_CONST;
p->to.name = D_EXTERN;
- p->to.sym = x;
+ p->to.sym = linksym(x);
p->to.offset = xoff;
off += widthptr;
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 27749b7a7..f66c87b5a 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -50,7 +50,7 @@ clearp(Prog *p)
p->to.type = D_NONE;
p->to.name = D_NONE;
p->to.reg = NREG;
- p->loc = pcloc;
+ p->pc = pcloc;
pcloc++;
}
@@ -138,7 +138,7 @@ patch(Prog *p, Prog *to)
if(p->to.type != D_BRANCH)
fatal("patch: not a branch");
p->to.u.branch = to;
- p->to.offset = to->loc;
+ p->to.offset = to->pc;
}
Prog*
@@ -162,12 +162,7 @@ newplist(void)
{
Plist *pl;
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
+ pl = linknewplist(ctxt);
pc = mal(sizeof(*pc));
clearp(pc);
@@ -200,8 +195,8 @@ ggloblnod(Node *nam)
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
- p->from.gotype = ngotype(nam);
- p->to.sym = S;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
p->to.type = D_CONST;
p->to.offset = nam->type->width;
if(nam->readonly)
@@ -228,7 +223,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata)
p = gins(AGLOBL, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->to.type = D_CONST;
p->to.name = D_NONE;
p->to.offset = width;
@@ -246,7 +241,7 @@ gtrack(Sym *s)
p = gins(AUSEFIELD, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
}
int
@@ -275,7 +270,7 @@ afunclit(Addr *a, Node *n)
if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
a->type = D_OREG;
if(n->op == ONAME)
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
}
}
@@ -475,6 +470,7 @@ Node*
nodarg(Type *t, int fp)
{
Node *n;
+ NodeList *l;
Type *first;
Iter savet;
@@ -496,6 +492,14 @@ nodarg(Type *t, int fp)
if(t->etype != TFIELD)
fatal("nodarg: not field %T", t);
+ if(fp == 1) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
+ return n;
+ }
+ }
+
n = nod(ONAME, N, N);
n->type = t->type;
n->sym = t->sym;
@@ -1196,10 +1200,12 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
void
naddr(Node *n, Addr *a, int canemitcode)
{
+ Sym *s;
+
a->type = D_NONE;
a->name = D_NONE;
a->reg = NREG;
- a->gotype = S;
+ a->gotype = nil;
a->node = N;
a->etype = 0;
if(n == N)
@@ -1223,7 +1229,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->type = D_FREG;
a->reg = n->val.u.reg - REGALLOC_F0;
}
- a->sym = S;
+ a->sym = nil;
break;
case OINDEX:
@@ -1250,7 +1256,7 @@ naddr(Node *n, Addr *a, int canemitcode)
case OINDREG:
a->type = D_OREG;
a->reg = n->val.u.reg;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
break;
@@ -1260,22 +1266,24 @@ naddr(Node *n, Addr *a, int canemitcode)
a->etype = simtype[n->left->type->etype];
a->width = n->left->type->width;
a->offset = n->xoffset;
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
a->type = D_OREG;
a->name = D_PARAM;
a->node = n->left->orig;
break;
case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
a->type = D_OREG;
a->reg = 7;
a->offset = n->xoffset;
- a->sym = S;
+ a->sym = nil;
break;
case OCFUNC:
naddr(n->left, a, canemitcode);
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
break;
case ONAME:
@@ -1287,17 +1295,17 @@ naddr(Node *n, Addr *a, int canemitcode)
a->width = n->type->width;
}
a->offset = n->xoffset;
- a->sym = n->sym;
+ s = n->sym;
a->node = n->orig;
//if(a->node >= (Node*)&n)
// fatal("stack node");
- if(a->sym == S)
- a->sym = lookup(".noname");
+ if(s == S)
+ s = lookup(".noname");
if(n->method) {
if(n->type != T)
if(n->type->sym != S)
if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ s = pkglookup(s->name, n->type->sym->pkg);
}
a->type = D_OREG;
@@ -1317,9 +1325,10 @@ naddr(Node *n, Addr *a, int canemitcode)
case PFUNC:
a->name = D_EXTERN;
a->type = D_CONST;
- a->sym = funcsym(a->sym);
+ s = funcsym(s);
break;
}
+ a->sym = linksym(s);
break;
case OLITERAL:
@@ -1333,7 +1342,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case CTINT:
case CTRUNE:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
break;
@@ -1341,12 +1350,12 @@ naddr(Node *n, Addr *a, int canemitcode)
datagostring(n->val.u.sval, a);
break;
case CTBOOL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = n->val.u.bval;
break;
case CTNIL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = 0;
break;
@@ -1366,7 +1375,7 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // ptr(nil)
- a->etype = simtype[TUINTPTR];
+ a->etype = simtype[tptr];
a->offset += Array_array;
a->width = widthptr;
break;
@@ -1592,6 +1601,7 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
+ case CASE(OADDPTR, TPTR32):
a = AADD;
break;
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
deleted file mode 100644
index 6c3f1d744..000000000
--- a/src/cmd/5g/list.c
+++ /dev/null
@@ -1,342 +0,0 @@
-// Derived from Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-// TODO(kaib): make 5g/list.c congruent with 5l/list.c
-
-static int sconsize;
-void
-listinit(void)
-{
-
- fmtinstall('A', Aconv); // as
- fmtinstall('C', Cconv); // conditional execution bit
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('Y', Yconv); // sconst
- fmtinstall('R', Rconv); // register
- fmtinstall('M', Mconv); // names
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ], str1[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- sconsize = 8;
- switch(p->as) {
- default:
- snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
- if(p->reg == NREG && p->as != AGLOBL)
- snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
- p->loc, p->lineno, str1, &p->from, &p->to);
- else
- if (p->from.type != D_FREG) {
- snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D",
- p->loc, p->lineno, str1, &p->from, p->reg, &p->to);
- } else
- snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case ADATA:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, p->reg, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- const char *op;
- Addr *a;
- int i;
- int32 v;
-
- a = va_arg(fp->args, Addr*);
- if(a == A) {
- sprint(str, "<nil>");
- goto conv;
- }
- i = a->type;
- switch(i) {
-
- default:
- sprint(str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%M(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg != NREG)
- sprint(str, "$%M(R%d)", a, a->reg);
- else
- sprint(str, "$%M", a);
- break;
-
- case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
- if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
- break;
-
- case D_OCONST:
- sprint(str, "$*$%M", a);
- if(a->reg != NREG)
- sprint(str, "%M(R%d)(CONST)", a, a->reg);
- break;
-
- case D_OREG:
- if(a->reg != NREG)
- sprint(str, "%M(R%d)", a, a->reg);
- else
- sprint(str, "%M", a);
- break;
-
- case D_REG:
- sprint(str, "R%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG:
- sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG2:
- sprint(str, "R%d,R%d", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_FREG:
- sprint(str, "F%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- sprint(str, "%M(R%d)(REG)", a, a->reg);
- break;
-
- case D_BRANCH:
- if(a->u.branch == P || a->u.branch->loc == 0) {
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- sprint(str, "%d(APC)", a->offset);
- } else
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->u.branch->loc);
- else
- sprint(str, "%d(APC)", a->u.branch->loc);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->u.dval);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->u.sval);
- break;
-
- // TODO(kaib): Add back
-// case D_ADDR:
-// a->type = a->index;
-// a->index = D_NONE;
-// snprint(str, sizeof(str), "$%D", a);
-// a->index = a->type;
-// a->type = D_ADDR;
-// goto conv;
- }
-conv:
- fmtstrcpy(fp, str);
- if(a->gotype)
- fmtprint(fp, "{%s}", a->gotype->name);
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-char* strcond[16] =
-{
- ".EQ",
- ".NE",
- ".HS",
- ".LO",
- ".MI",
- ".PL",
- ".VS",
- ".VC",
- ".HI",
- ".LS",
- ".GE",
- ".LT",
- ".GT",
- ".LE",
- "",
- ".NV"
-};
-
-int
-Cconv(Fmt *fp)
-{
- char s[STRINGSZ];
- int c;
-
- c = va_arg(fp->args, int);
- strcpy(s, strcond[c & C_SCOND]);
- if(c & C_SBIT)
- strcat(s, ".S");
- if(c & C_PBIT)
- strcat(s, ".P");
- if(c & C_WBIT)
- strcat(s, ".W");
- if(c & C_UBIT) /* ambiguous with FBIT */
- strcat(s, ".U");
- return fmtstrcpy(fp, s);
-}
-
-int
-Yconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sconsize; i++) {
- c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
-int
-Rconv(Fmt *fp)
-{
- int r;
- char str[STRINGSZ];
-
- r = va_arg(fp->args, int);
- snprint(str, sizeof(str), "R%d", r);
- return fmtstrcpy(fp, str);
-}
-
-int
-Mconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Addr *a;
-
- a = va_arg(fp->args, Addr*);
- switch(a->name) {
- default:
- snprint(str, sizeof(str), "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- snprint(str, sizeof(str), "%d", a->offset);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
- break;
-
- case D_PARAM:
- snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
- break;
- }
- return fmtstrcpy(fp, str);
-}
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 15b9d1458..e3e3f78ed 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -96,6 +96,7 @@ EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
+EXTERN Bits ivar;
EXTERN Bits ovar;
EXTERN int change;
EXTERN int32 maxnr;
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index c78fb3d1c..4aa645206 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -287,6 +287,8 @@ subprop(Flow *r0)
if(uniqs(r) == nil)
break;
p = r->prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
if(info.flags & Call)
return 0;
@@ -397,7 +399,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
if(debug['P'])
print("; merge; f=%d", f);
}
- t = copyu(p, v2, A);
+ t = copyu(p, v2, nil);
switch(t) {
case 2: /* rar, can't split */
if(debug['P'])
@@ -435,7 +437,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
break;
}
if(!f) {
- t = copyu(p, v1, A);
+ t = copyu(p, v1, nil);
if(!f && (t == 2 || t == 3 || t == 4)) {
f = 1;
if(debug['P'])
@@ -479,7 +481,7 @@ constprop(Adr *c1, Adr *v1, Flow *r)
if(debug['P'])
print("; sub%D/%D", &p->from, v1);
p->from = *v1;
- } else if(copyu(p, v1, A) > 1) {
+ } else if(copyu(p, v1, nil) > 1) {
if(debug['P'])
print("; %Dset; return\n", v1);
return;
@@ -592,10 +594,10 @@ shiftprop(Flow *r)
p1 = r1->prog;
if(debug['P'])
print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
+ switch(copyu(p1, &p->to, nil)) {
case 0: /* not used or set */
- if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
- (a.type == D_REG && copyu(p1, &a, A) > 1))
+ if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) ||
+ (a.type == D_REG && copyu(p1, &a, nil) > 1))
FAIL("args modified");
continue;
case 3: /* set, not used */
@@ -663,7 +665,7 @@ shiftprop(Flow *r)
p1 = r1->prog;
if(debug['P'])
print("\n%P", p1);
- switch(copyu(p1, &p->to, A)) {
+ switch(copyu(p1, &p->to, nil)) {
case 0: /* not used or set */
continue;
case 3: /* set, not used */
@@ -719,7 +721,7 @@ findpre(Flow *r, Adr *v)
for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
if(uniqs(r1) != r)
return nil;
- switch(copyu(r1->prog, v, A)) {
+ switch(copyu(r1->prog, v, nil)) {
case 1: /* used */
case 2: /* read-alter-rewrite */
return nil;
@@ -745,7 +747,7 @@ findinc(Flow *r, Flow *r2, Adr *v)
for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
if(uniqp(r1) != r)
return nil;
- switch(copyu(r1->prog, v, A)) {
+ switch(copyu(r1->prog, v, nil)) {
case 0: /* not touched */
continue;
case 4: /* set and used */
@@ -787,7 +789,7 @@ nochange(Flow *r, Flow *r2, Prog *p)
for(; r!=nil && r!=r2; r=uniqs(r)) {
p = r->prog;
for(i=0; i<n; i++)
- if(copyu(p, &a[i], A) > 1)
+ if(copyu(p, &a[i], nil) > 1)
return 0;
}
return 1;
@@ -800,7 +802,7 @@ findu1(Flow *r, Adr *v)
if(r->active)
return 0;
r->active = 1;
- switch(copyu(r->prog, v, A)) {
+ switch(copyu(r->prog, v, nil)) {
case 1: /* used */
case 2: /* read-alter-rewrite */
case 4: /* set and used */
@@ -943,7 +945,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type != D_REG)
return 0;
if(p->from.type == D_CONST) { /* read reglist, read/rar */
- if(s != A) {
+ if(s != nil) {
if(p->from.offset&(1<<v->reg))
return 1;
if(copysub(&p->to, v, s, 1))
@@ -958,7 +960,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(p->from.offset&(1<<v->reg))
return 1;
} else { /* read/rar, write reglist */
- if(s != A) {
+ if(s != nil) {
if(p->to.offset&(1<<v->reg))
return 1;
if(copysub(&p->from, v, s, 1))
@@ -1003,7 +1005,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 2;
}
}
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->from, v, s, 1))
return 1;
if(!copyas(&p->to, v))
@@ -1063,7 +1065,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ACMN:
case ACASE:
case ATST: /* read,, */
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->from, v, s, 1))
return 1;
if(copysub1(p, v, s, 1))
@@ -1108,7 +1110,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ABLT:
case ABGT:
case ABLE:
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub1(p, v, s, 1);
@@ -1120,7 +1122,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case AB: /* funny */
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -1130,7 +1132,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case ARET: /* funny */
- if(s != A)
+ if(s != nil)
return 1;
return 3;
@@ -1138,7 +1140,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type == D_REG) {
if(v->reg <= REGEXT && v->reg > exregoffset)
return 2;
- if(v->reg == (uchar)REGARG)
+ if(v->reg == REGARG)
return 2;
}
if(v->type == D_FREG)
@@ -1147,7 +1149,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
return 2;
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -1155,15 +1157,37 @@ copyu(Prog *p, Adr *v, Adr *s)
if(copyau(&p->to, v))
return 4;
return 3;
-
+ case ADUFFZERO:
+ // R0 is zero, used by DUFFZERO, cannot be substituted.
+ // R1 is ptr to memory, used and set, cannot be substituted.
+ if(v->type == D_REG) {
+ if(v->reg == REGALLOC_R0)
+ return 1;
+ if(v->reg == REGALLOC_R0+1)
+ return 2;
+ }
+ return 0;
+ case ADUFFCOPY:
+ // R0 is scratch, set by DUFFCOPY, cannot be substituted.
+ // R1, R2 areptr to src, dst, used and set, cannot be substituted.
+ if(v->type == D_REG) {
+ if(v->reg == REGALLOC_R0)
+ return 3;
+ if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2)
+ return 2;
+ }
+ return 0;
+
case ATEXT: /* funny */
if(v->type == D_REG)
- if(v->reg == (uchar)REGARG)
+ if(v->reg == REGARG)
return 3;
return 0;
case APCDATA:
case AFUNCDATA:
+ case AVARDEF:
+ case AVARKILL:
return 0;
}
}
@@ -1241,35 +1265,79 @@ copyau(Adr *a, Adr *v)
return 0;
}
+static int
+a2type(Prog *p)
+{
+ if(p->reg == NREG)
+ return D_NONE;
+
+ switch(p->as) {
+ default:
+ fatal("a2type: unhandled %P", p);
+
+ case AAND:
+ case AEOR:
+ case ASUB:
+ case ARSB:
+ case AADD:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ case ATST:
+ case ATEQ:
+ case ACMP:
+ case ACMN:
+ case AORR:
+ case ABIC:
+ case AMVN:
+ case ASRL:
+ case ASRA:
+ case ASLL:
+ case AMULU:
+ case ADIVU:
+ case AMUL:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case AMULA:
+ case AMULL:
+ case AMULAL:
+ case AMULLU:
+ case AMULALU:
+ case AMULWT:
+ case AMULWB:
+ case AMULAWT:
+ case AMULAWB:
+ return D_REG;
+
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case ASQRTF:
+ case ASQRTD:
+ case AABSF:
+ case AABSD:
+ return D_FREG;
+ }
+}
+
/*
* compare v to the center
* register in p (p->reg)
- * the trick is that this
- * register might be D_REG
- * D_FREG. there are basically
- * two cases,
- * ADD r,r,r
- * CMP r,r,
*/
static int
copyau1(Prog *p, Adr *v)
{
-
- if(regtyp(v))
- if(p->reg == v->reg) {
- if(p->to.type != D_NONE) {
- if(v->type == p->to.type)
- return 1;
- return 0;
- }
- if(p->from.type != D_NONE) {
- if(v->type == p->from.type)
- return 1;
- return 0;
- }
- print("copyau1: can't tell %P\n", p);
- }
- return 0;
+ if(v->type == D_REG && v->reg == NREG)
+ return 0;
+ return p->reg == v->reg && a2type(p) == v->type;
}
/*
diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c
index 5aa6163d8..797bc0718 100644
--- a/src/cmd/5g/prog.c
+++ b/src/cmd/5g/prog.c
@@ -26,9 +26,11 @@ static ProgInfo progtable[ALAST] = {
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
- [AUNDEF]= {OK},
+ [AUNDEF]= {Break},
[AUSEFIELD]= {OK},
[ACHECKNIL]= {LeftRead},
+ [AVARDEF]= {Pseudo | RightWrite},
+ [AVARKILL]= {Pseudo | RightWrite},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
@@ -91,6 +93,12 @@ static ProgInfo progtable[ALAST] = {
[AMOVF]= {SizeF | LeftRead | RightWrite | Move},
[AMOVH]= {SizeW | LeftRead | RightWrite | Move},
[AMOVW]= {SizeL | LeftRead | RightWrite | Move},
+ // In addtion, duffzero reads R0,R1 and writes R1. This fact is
+ // encoded in peep.c
+ [ADUFFZERO]= {Call},
+ // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is
+ // encoded in peep.c
+ [ADUFFCOPY]= {Call},
// These should be split into the two different conversions instead
// of overloading the one.
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index d2a8cc488..4762df506 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -56,30 +56,6 @@ rcmp(const void *a1, const void *a2)
return p2->varno - p1->varno;
}
-static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(&ovar))
-//print("ovar = %Q\n", ovar);
-}
-
void
excise(Flow *r)
{
@@ -153,13 +129,15 @@ static char* regname[] = {
static Node* regnodes[NREGVAR];
+static void walkvardef(Node *n, Reg *r, int active);
+
void
regopt(Prog *firstp)
{
Reg *r, *r1;
Prog *p;
Graph *g;
- int i, z;
+ int i, z, active;
uint32 vreg;
Bits bit;
ProgInfo info;
@@ -168,8 +146,7 @@ regopt(Prog *firstp)
fmtinstall('Q', Qconv);
first = 0;
}
-
- fixjmp(firstp);
+
mergetemp(firstp);
/*
@@ -191,12 +168,10 @@ regopt(Prog *firstp)
params.b[z] = 0;
consts.b[z] = 0;
addrs.b[z] = 0;
+ ivar.b[z] = 0;
ovar.b[z] = 0;
}
- // build list of return variables
- setoutvar();
-
/*
* pass 1
* build aux data structure
@@ -204,12 +179,18 @@ regopt(Prog *firstp)
* find use and set of variables
*/
g = flowstart(firstp, sizeof(Reg));
- if(g == nil)
+ if(g == nil) {
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
return;
+ }
+
firstr = (Reg*)g->start;
for(r = firstr; r != R; r = (Reg*)r->f.link) {
p = r->f.prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
// Avoid making variables for direct-called functions.
@@ -271,6 +252,26 @@ regopt(Prog *firstp)
dumpit("pass2", &firstr->f, 1);
/*
+ * pass 2.5
+ * iterate propagating fat vardef covering forward
+ * r->act records vars with a VARDEF since the last CALL.
+ * (r->act will be reused in pass 5 for something else,
+ * but we'll be done with it by then.)
+ */
+ active = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ r->f.active = 0;
+ r->act = zbits;
+ }
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ p = r->f.prog;
+ if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+ active++;
+ walkvardef(p->to.node, r, active);
+ }
+ }
+
+ /*
* pass 3
* iterate propagating usage
* back until flow graph is complete
@@ -471,6 +472,14 @@ brk:
dumpit("pass6", &firstr->f, 1);
/*
+ * free aux structures. peep allocates new ones.
+ */
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
+ flowend(g);
+ firstr = R;
+
+ /*
* pass 7
* peep-hole on basic block
*/
@@ -523,20 +532,44 @@ brk:
}
if(p->as == AMOVW && vreg != 0) {
- if(p->from.sym != S)
+ if(p->from.sym != nil)
if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
p->from.offset += vreg;
// print("%P adjusting from %d %d\n", p, vreg, p->from.type);
}
- if(p->to.sym != S)
+ if(p->to.sym != nil)
if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
p->to.offset += vreg;
// print("%P adjusting to %d %d\n", p, vreg, p->from.type);
}
}
}
+}
- flowend(g);
+static void
+walkvardef(Node *n, Reg *r, int active)
+{
+ Reg *r1, *r2;
+ int bn;
+ Var *v;
+
+ for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
+ if(r1->f.active == active)
+ break;
+ r1->f.active = active;
+ if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
+ break;
+ for(v=n->opt; v!=nil; v=v->nextinnode) {
+ bn = v - var;
+ r1->act.b[bn/32] |= 1L << (bn%32);
+ }
+ if(r1->f.prog->as == ABL)
+ break;
+ }
+
+ for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
+ if(r2->f.s2 != nil)
+ walkvardef(n, (Reg*)r2->f.s2, active);
}
void
@@ -551,6 +584,10 @@ addsplits(void)
continue;
if(r->f.prog->as == ABL)
continue;
+ if(r->f.prog->as == ADUFFZERO)
+ continue;
+ if(r->f.prog->as == ADUFFCOPY)
+ continue;
for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) {
if(r1->f.loop <= 1)
continue;
@@ -596,11 +633,11 @@ addmove(Reg *r, int bn, int rn, int f)
a = &p1->to;
a->name = v->name;
a->node = v->node;
- a->sym = v->node->sym;
+ a->sym = linksym(v->node->sym);
a->offset = v->offset;
a->etype = v->etype;
a->type = D_OREG;
- if(a->etype == TARRAY || a->sym == S)
+ if(a->etype == TARRAY || a->sym == nil)
a->type = D_CONST;
if(v->addr)
@@ -790,6 +827,16 @@ mkvar(Reg *r, Adr *a)
if(nvar >= NVAR) {
if(debug['w'] > 1 && node)
fatal("variable not optimized: %D", a);
+
+ // If we're not tracking a word in a variable, mark the rest as
+ // having its address taken, so that we keep the whole thing
+ // live at all calls. otherwise we might optimize away part of
+ // a variable but not all of it.
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node)
+ v->addr = 1;
+ }
goto none;
}
@@ -804,9 +851,13 @@ mkvar(Reg *r, Adr *a)
v->addr = flag; // funny punning
v->node = node;
- if(debug['R'])
- print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-
+ // node->opt is the head of a linked list
+ // of Vars within the given Node, so that
+ // we can start at a Var and find all the other
+ // Vars in the same Go variable.
+ v->nextinnode = node->opt;
+ node->opt = v;
+
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
for(z=0; z<BITS; z++)
@@ -815,6 +866,45 @@ mkvar(Reg *r, Adr *a)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
+ if(node->class == PPARAM)
+ for(z=0; z<BITS; z++)
+ ivar.b[z] |= bit.b[z];
+ if(node->class == PPARAMOUT)
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+
+ // Treat values with their address taken as live at calls,
+ // because the garbage collector's liveness analysis in ../gc/plive.c does.
+ // These must be consistent or else we will elide stores and the garbage
+ // collector will see uninitialized data.
+ // The typical case where our own analysis is out of sync is when the
+ // node appears to have its address taken but that code doesn't actually
+ // get generated and therefore doesn't show up as an address being
+ // taken when we analyze the instruction stream.
+ // One instance of this case is when a closure uses the same name as
+ // an outer variable for one of its own variables declared with :=.
+ // The parser flags the outer variable as possibly shared, and therefore
+ // sets addrtaken, even though it ends up not being actually shared.
+ // If we were better about _ elision, _ = &x would suffice too.
+ // The broader := in a closure problem is mentioned in a comment in
+ // closure.c:/^typecheckclosure and dcl.c:/^oldname.
+ if(node->addrtaken)
+ v->addr = 1;
+
+ // Disable registerization for globals, because:
+ // (1) we might panic at any time and we want the recovery code
+ // to see the latest values (issue 1304).
+ // (2) we don't know what pointers might point at them and we want
+ // loads via those pointers to see updated values and vice versa (issue 7995).
+ //
+ // Disable registerization for results if using defer, because the deferred func
+ // might recover and return, causing the current values to be used.
+ if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
+ v->addr = 1;
+
+ if(debug['R'])
+ print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+
return bit;
none:
@@ -825,7 +915,8 @@ void
prop(Reg *r, Bits ref, Bits cal)
{
Reg *r1, *r2;
- int z;
+ int z, i, j;
+ Var *v, *v1;
for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
for(z=0; z<BITS; z++) {
@@ -844,10 +935,61 @@ prop(Reg *r, Bits ref, Bits cal)
case ABL:
if(noreturn(r1->f.prog))
break;
+
+ // Mark all input variables (ivar) as used, because that's what the
+ // liveness bitmaps say. The liveness bitmaps say that so that a
+ // panic will not show stale values in the parameter dump.
+ // Mark variables with a recent VARDEF (r1->act) as used,
+ // so that the optimizer flushes initializations to memory,
+ // so that if a garbage collection happens during this CALL,
+ // the collector will see initialized memory. Again this is to
+ // match what the liveness bitmaps say.
for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
+ cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
ref.b[z] = 0;
}
+
+ // cal.b is the current approximation of what's live across the call.
+ // Every bit in cal.b is a single stack word. For each such word,
+ // find all the other tracked stack words in the same Go variable
+ // (struct/slice/string/interface) and mark them live too.
+ // This is necessary because the liveness analysis for the garbage
+ // collector works at variable granularity, not at word granularity.
+ // It is fundamental for slice/string/interface: the garbage collector
+ // needs the whole value, not just some of the words, in order to
+ // interpret the other bits correctly. Specifically, slice needs a consistent
+ // ptr and cap, string needs a consistent ptr and len, and interface
+ // needs a consistent type word and data word.
+ for(z=0; z<BITS; z++) {
+ if(cal.b[z] == 0)
+ continue;
+ for(i=0; i<32; i++) {
+ if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ continue;
+ v = var+z*32+i;
+ if(v->node->opt == nil) // v represents fixed register, not Go variable
+ continue;
+
+ // v->node->opt is the head of a linked list of Vars
+ // corresponding to tracked words from the Go variable v->node.
+ // Walk the list and set all the bits.
+ // For a large struct this could end up being quadratic:
+ // after the first setting, the outer loop (for z, i) would see a 1 bit
+ // for all of the remaining words in the struct, and for each such
+ // word would go through and turn on all the bits again.
+ // To avoid the quadratic behavior, we only turn on the bits if
+ // v is the head of the list or if the head's bit is not yet turned on.
+ // This will set the bits at most twice, keeping the overall loop linear.
+ v1 = v->node->opt;
+ j = v1 - var;
+ if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ for(; v1 != nil; v1 = v1->nextinnode) {
+ j = v1 - var;
+ cal.b[j/32] |= 1<<(j&31);
+ }
+ }
+ }
+ }
break;
case ATEXT:
@@ -863,17 +1005,6 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
-
- default:
- // Work around for issue 1304:
- // flush modified globals before each instruction.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= externs.b[z];
- // issue 4066: flush modified return variables in case of panic
- if(hasdefer)
- cal.b[z] |= ovar.b[z];
- }
- break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1004,18 +1135,20 @@ paint1(Reg *r, int bn)
r->act.b[z] |= bb;
p = r->f.prog;
- if(r->use1.b[z] & bb) {
- change += CREF * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\tu1 %Q $%d\n", r->f.loop,
- p, blsh(bn), change);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\tu2 %Q $%d\n", r->f.loop,
- p, blsh(bn), change);
+ if(r->f.prog->as != ANOP) { // don't give credit for NOPs
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->f.loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu1 %Q $%d\n", r->f.loop,
+ p, blsh(bn), change);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->f.loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu2 %Q $%d\n", r->f.loop,
+ p, blsh(bn), change);
+ }
}
if(STORE(r) & r->regdiff.b[z] & bb) {
@@ -1172,7 +1305,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
void
addreg(Adr *a, int rn)
{
- a->sym = 0;
+ a->sym = nil;
a->name = D_NONE;
a->type = D_REG;
a->reg = rn;
@@ -1292,9 +1425,9 @@ dumpit(char *str, Flow *r0, int isreg)
if(r1 != nil) {
print(" pred:");
for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
+ print(" %.4ud", (int)r1->prog->pc);
if(r->p1 != nil)
- print(" (and %.4ud)", r->p1->prog->loc);
+ print(" (and %.4ud)", (int)r->p1->prog->pc);
else
print(" (only)");
print("\n");
@@ -1303,7 +1436,7 @@ dumpit(char *str, Flow *r0, int isreg)
// if(r1 != nil) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
+// print(" %.4ud", (int)r1->prog->pc);
// print("\n");
// }
}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index e8cf83ddd..9e8aceecb 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -198,6 +198,12 @@ enum as
AFUNCDATA,
APCDATA,
ACHECKNIL,
+ AVARDEF,
+ AVARKILL,
+ ADUFFCOPY,
+ ADUFFZERO,
+
+ AMRC, // MRC/MCR
ALAST,
};
@@ -233,62 +239,43 @@ enum as
#define SHIFT_AR 2<<5
#define SHIFT_RR 3<<5
+enum
+{
/* type/name */
-#define D_GOK 0
-#define D_NONE 1
+ D_GOK = 0,
+ D_NONE = 1,
/* type */
-#define D_BRANCH (D_NONE+1)
-#define D_OREG (D_NONE+2)
-#define D_CONST (D_NONE+7)
-#define D_FCONST (D_NONE+8)
-#define D_SCONST (D_NONE+9)
-#define D_PSR (D_NONE+10)
-#define D_REG (D_NONE+12)
-#define D_FREG (D_NONE+13)
-#define D_FILE (D_NONE+16)
-#define D_OCONST (D_NONE+17)
-#define D_FILE1 (D_NONE+18)
-
-#define D_SHIFT (D_NONE+19)
-#define D_FPCR (D_NONE+20)
-#define D_REGREG (D_NONE+21) // (reg, reg)
-#define D_ADDR (D_NONE+22)
-
-#define D_SBIG (D_NONE+23)
-#define D_CONST2 (D_NONE+24)
-
-#define D_REGREG2 (D_NONE+25) // reg, reg
+ D_BRANCH = (D_NONE+1),
+ D_OREG = (D_NONE+2),
+ D_CONST = (D_NONE+7),
+ D_FCONST = (D_NONE+8),
+ D_SCONST = (D_NONE+9),
+ D_PSR = (D_NONE+10),
+ D_REG = (D_NONE+12),
+ D_FREG = (D_NONE+13),
+ D_FILE = (D_NONE+16),
+ D_OCONST = (D_NONE+17),
+ D_FILE1 = (D_NONE+18),
+
+ D_SHIFT = (D_NONE+19),
+ D_FPCR = (D_NONE+20),
+ D_REGREG = (D_NONE+21), // (reg, reg)
+ D_ADDR = (D_NONE+22),
+
+ D_SBIG = (D_NONE+23),
+ D_CONST2 = (D_NONE+24),
+
+ D_REGREG2 = (D_NONE+25), // reg, reg
/* name */
-#define D_EXTERN (D_NONE+3)
-#define D_STATIC (D_NONE+4)
-#define D_AUTO (D_NONE+5)
-#define D_PARAM (D_NONE+6)
-
-/* internal only */
-#define D_SIZE (D_NONE+40)
-#define D_PCREL (D_NONE+41)
-#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF
-#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
-#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
-#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
-#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
-#define D_TLS (D_NONE+47) // R_ARM_TLS_LE32
+ D_EXTERN = (D_NONE+3),
+ D_STATIC = (D_NONE+4),
+ D_AUTO = (D_NONE+5),
+ D_PARAM = (D_NONE+6),
+};
/*
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 33cdf8096..5e9267b5b 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -35,43 +35,26 @@
#include "../ld/elf.h"
#include "../ld/dwarf.h"
-static Prog *PP;
char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
char openbsddynld[] = "XXX";
char netbsddynld[] = "/libexec/ld.elf_so";
char dragonflydynld[] = "XXX";
-
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
+char solarisdynld[] = "XXX";
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -82,9 +65,9 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
-static void addgotsyminternal(Sym*);
+static void addpltsym(Link*, LSym*);
+static void addgotsym(Link*, LSym*);
+static void addgotsyminternal(Link*, LSym*);
// Preserve highest 8 bits of a, and do addition to lower 24-bit
// of a and b; used to adjust ARM branch intruction's target
@@ -95,19 +78,19 @@ braddoff(int32 a, int32 b)
}
void
-adddynrela(Sym *rel, Sym *s, Reloc *r)
+adddynrela(LSym *rel, LSym *s, Reloc *r)
{
- addaddrplus(rel, s, r->off);
- adduint32(rel, R_ARM_RELATIVE);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, R_ARM_RELATIVE);
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rel;
+ LSym *targ, *rel;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -119,10 +102,10 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files.
case 256 + R_ARM_PLT32:
- r->type = D_CALL;
+ r->type = R_CALLARM;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
@@ -134,54 +117,54 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
if(targ->type != SDYNIMPORT) {
- addgotsyminternal(targ);
+ addgotsyminternal(ctxt, targ);
} else {
- addgotsym(targ);
+ addgotsym(ctxt, targ);
}
- r->type = D_CONST; // write r->add during relocsym
+ r->type = R_CONST; // write r->add during relocsym
r->sym = S;
r->add += targ->got;
return;
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
if(targ->type != SDYNIMPORT) {
- addgotsyminternal(targ);
+ addgotsyminternal(ctxt, targ);
} else {
- addgotsym(targ);
+ addgotsym(ctxt, targ);
}
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->type = R_PCREL;
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got + 4;
return;
case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
- r->type = D_GOTOFF;
+ r->type = R_GOTOFF;
return;
case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->type = R_PCREL;
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
return;
case 256 + R_ARM_CALL:
- r->type = D_CALL;
+ r->type = R_CALLARM;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
case 256 + R_ARM_REL32: // R_ARM_REL32
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
return;
case 256 + R_ARM_ABS32:
if(targ->type == SDYNIMPORT)
diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
- r->type = D_ADDR;
+ r->type = R_ADDR;
return;
case 256 + R_ARM_V4BX:
@@ -195,10 +178,10 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_PC24:
case 256 + R_ARM_JUMP24:
- r->type = D_CALL;
+ r->type = R_CALLARM;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
return;
@@ -209,28 +192,28 @@ adddynrel(Sym *s, Reloc *r)
return;
switch(r->type) {
- case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ case R_CALLARM:
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
- case D_ADDR:
+ case R_ADDR:
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rel = lookup(".rel", 0);
- addaddrplus(rel, s, r->off);
- adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
- r->type = D_CONST; // write r->add during relocsym
+ adddynsym(ctxt, targ);
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
+ r->type = R_CONST; // write r->add during relocsym
r->sym = S;
return;
}
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -246,21 +229,21 @@ elfreloc1(Reloc *r, vlong sectoff)
default:
return -1;
- case D_ADDR:
+ case R_ADDR:
if(r->siz == 4)
LPUT(R_ARM_ABS32 | elfsym<<8);
else
return -1;
break;
- case D_PCREL:
+ case R_PCREL:
if(r->siz == 4)
LPUT(R_ARM_REL32 | elfsym<<8);
else
return -1;
break;
- case D_CALL:
+ case R_CALLARM:
if(r->siz == 4) {
if((r->add & 0xff000000) == 0xeb000000) // BL
LPUT(R_ARM_CALL | elfsym<<8);
@@ -270,7 +253,7 @@ elfreloc1(Reloc *r, vlong sectoff)
return -1;
break;
- case D_TLS:
+ case R_TLS:
if(r->siz == 4) {
if(flag_shared)
LPUT(R_ARM_TLS_IE32 | elfsym<<8);
@@ -287,26 +270,26 @@ elfreloc1(Reloc *r, vlong sectoff)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// str lr, [sp, #-4]!
- adduint32(plt, 0xe52de004);
+ adduint32(ctxt, plt, 0xe52de004);
// ldr lr, [pc, #4]
- adduint32(plt, 0xe59fe004);
+ adduint32(ctxt, plt, 0xe59fe004);
// add lr, pc, lr
- adduint32(plt, 0xe08fe00e);
+ adduint32(ctxt, plt, 0xe08fe00e);
// ldr pc, [lr, #8]!
- adduint32(plt, 0xe5bef008);
+ adduint32(ctxt, plt, 0xe5bef008);
// .word &GLOBAL_OFFSET_TABLE[0] - .
- addpcrelplus(plt, got, 4);
+ addpcrelplus(ctxt, plt, got, 4);
// the first .plt entry requires 3 .plt.got entries
- adduint32(got, 0);
- adduint32(got, 0);
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
}
}
@@ -321,13 +304,13 @@ machoreloc1(Reloc *r, vlong sectoff)
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
- Sym *rs;
+ LSym *rs;
if(linkmode == LinkExternal) {
switch(r->type) {
- case D_CALL:
+ case R_CALLARM:
r->done = 0;
// set up addend for eventual relocation via outer symbol.
@@ -352,29 +335,29 @@ archreloc(Reloc *r, Sym *s, vlong *val)
return -1;
}
switch(r->type) {
- case D_CONST:
+ case R_CONST:
*val = r->add;
return 0;
- case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ case R_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
// The following three arch specific relocations are only for generation of
// Linux/ARM ELF's PLT entry (3 assembler instruction)
- case D_PLT0: // add ip, pc, #0xXX00000
- if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
+ case R_PLT0: // add ip, pc, #0xXX00000
+ if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0)))
diag(".got.plt should be placed after .plt section.");
*val = 0xe28fc600U +
- (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20));
return 0;
- case D_PLT1: // add ip, ip, #0xYY000
+ case R_PLT1: // add ip, ip, #0xYY000
*val = 0xe28cca00U +
- (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
+ (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12));
return 0;
- case D_PLT2: // ldr pc, [ip, #0xZZZ]!
+ case R_PLT2: // ldr pc, [ip, #0xZZZ]!
*val = 0xe5bcf000U +
- (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
+ (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8));
return 0;
- case D_CALL: // bl XXXXXX or b YYYYYY
+ case R_CALLARM: // bl XXXXXX or b YYYYYY
*val = braddoff((0xff000000U & (uint32)r->add),
(0xffffff & (uint32)
((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
@@ -384,7 +367,7 @@ archreloc(Reloc *r, Sym *s, vlong *val)
}
static Reloc *
-addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
+addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
{
Reloc *r;
@@ -397,25 +380,25 @@ addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
plt->reachable = 1;
plt->size += 4;
- symgrow(plt, plt->size);
+ symgrow(ctxt, plt, plt->size);
return r;
}
static void
-addpltsym(Sym *s)
+addpltsym(Link *ctxt, LSym *s)
{
- Sym *plt, *got, *rel;
+ LSym *plt, *got, *rel;
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rel = lookup(".rel.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rel = linklookup(ctxt, ".rel.plt", 0);
if(plt->size == 0)
elfsetupplt();
@@ -424,34 +407,34 @@ addpltsym(Sym *s)
// In theory, all GOT should point to the first PLT entry,
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
// dynamic linker won't, so we'd better do it ourselves.
- addaddrplus(got, plt, 0);
+ addaddrplus(ctxt, got, plt, 0);
// .plt entry, this depends on the .got entry
s->plt = plt->size;
- addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
- addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
- addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
+ addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000
+ addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000
+ addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]!
// rel
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsyminternal(Sym *s)
+addgotsyminternal(Link *ctxt, LSym *s)
{
- Sym *got;
+ LSym *got;
if(s->got >= 0)
return;
- got = lookup(".got", 0);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- addaddrplus(got, s, 0);
+ addaddrplus(ctxt, got, s, 0);
if(iself) {
;
@@ -461,31 +444,31 @@ addgotsyminternal(Sym *s)
}
static void
-addgotsym(Sym *s)
+addgotsym(Link *ctxt, LSym *s)
{
- Sym *got, *rel;
+ LSym *got, *rel;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
if(iself) {
- rel = lookup(".rel", 0);
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -495,20 +478,20 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
/* name */
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* value */
if(s->type == SDYNIMPORT)
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size */
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
/* type */
t = STB_GLOBAL << 4;
@@ -516,12 +499,12 @@ adddynsym(Sym *s)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
- adduint8(d, 0);
+ adduint8(ctxt, d, t);
+ adduint8(ctxt, d, 0);
/* shndx */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -538,7 +521,7 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
} else {
diag("adddynsym: unsupported binary format");
@@ -548,39 +531,27 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else {
diag("adddynlib: unsupported binary format");
}
}
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#x", addr);
- return 0;
-}
-
void
asmb(void)
{
- int32 t;
uint32 symo;
Section *sect;
- Sym *sym;
+ LSym *sym;
int i;
if(debug['v'])
@@ -627,13 +598,7 @@ asmb(void)
default:
if(iself)
goto ElfSym;
- case Hnoheader:
- case Hrisc:
- case Hixp1200:
- case Hipaq:
- debug['s'] = 1;
- break;
- case Hplan9x32:
+ case Hplan9:
symo = HEADR+segtext.len+segdata.filelen;
break;
ElfSym:
@@ -659,11 +624,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x32:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -675,46 +640,14 @@ asmb(void)
}
}
- cursym = nil;
+ ctxt->cursym = nil;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
cseek(0L);
switch(HEADTYPE) {
default:
- case Hnoheader: /* no header */
- break;
- case Hrisc: /* aif for risc os */
- lputl(0xe1a00000); /* NOP - decompress code */
- lputl(0xe1a00000); /* NOP - relocation code */
- lputl(0xeb000000 + 12); /* BL - zero init code */
- lputl(0xeb000000 +
- (entryvalue()
- - INITTEXT
- + HEADR
- - 12
- - 8) / 4); /* BL - entry code */
-
- lputl(0xef000011); /* SWI - exit code */
- lputl(segtext.filelen+HEADR); /* text size */
- lputl(segdata.filelen); /* data size */
- lputl(0); /* sym size */
-
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* sym type */
- lputl(INITTEXT-HEADR); /* text addr */
- lputl(0); /* workspace - ignored */
-
- lputl(32); /* addr mode / data addr flag */
- lputl(0); /* data addr */
- for(t=0; t<2; t++)
- lputl(0); /* reserved */
-
- for(t=0; t<15; t++)
- lputl(0xe1a00000); /* NOP - zero init code */
- lputl(0xe1a0f00e); /* B (R14) - zero init return */
- break;
- case Hplan9x32: /* plan 9 */
+ case Hplan9: /* plan 9 */
lput(0x647); /* magic */
lput(segtext.filelen); /* sizes */
lput(segdata.filelen);
@@ -724,14 +657,6 @@ asmb(void)
lput(0L);
lput(lcsize);
break;
- case Hixp1200: /* boot for IXP1200 */
- break;
- case Hipaq: /* boot for ipaq */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- lputl(0xe3300000); /* nop */
- break;
case Hlinux:
case Hfreebsd:
case Hnetbsd:
@@ -808,1224 +733,17 @@ nopstat(char *f, Count *c)
(double)(c->outof - c->count)/c->outof);
}
-void
-asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym)
-{
- int32 o1, o2, o3, o4, o5, o6, v;
- int r, rf, rt, rt2;
- Reloc *rel;
-
-PP = p;
- o1 = 0;
- o2 = 0;
- o3 = 0;
- o4 = 0;
- o5 = 0;
- o6 = 0;
- armsize += o->size;
-if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
- switch(o->type) {
- default:
- diag("unknown asm %d", o->type);
- prasm(p);
- break;
-
- case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
- break;
-
- case 1: /* op R,[R],R */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
- r = 0;
- else
- if(r == NREG)
- r = rt;
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 2: /* movbu $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= immrot(instoffset);
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 3: /* add R<<[IR],[R],R */
- mov:
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- o1 |= p->from.offset;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 4: /* add $I,[R],R */
- aclass(&p->from);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 |= r << 16;
- o1 |= p->to.reg << 12;
- break;
-
- case 5: /* bra s */
- o1 = opbra(p->as, p->scond);
- v = -8;
- if(p->to.sym != S && p->to.sym->type != 0) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- rel->sym = p->to.sym;
- rel->add = o1 | ((v >> 2) & 0xffffff);
- rel->type = D_CALL;
- break;
- }
- if(p->cond != P)
- v = (p->cond->pc - pc) - 8;
- o1 |= (v >> 2) & 0xffffff;
- break;
-
- case 6: /* b ,O(R) -> add $O,R,PC */
- aclass(&p->to);
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGPC << 12;
- break;
-
- case 7: /* bl (R) -> blx R */
- aclass(&p->to);
- if(instoffset != 0)
- diag("%P: doesn't support BL offset(REG) where offset != 0", p);
- o1 = oprrr(ABL, p->scond);
- o1 |= p->to.reg;
- break;
-
- case 8: /* sll $c,[R],R -> mov (R<<$c),R */
- aclass(&p->from);
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (instoffset&31) << 7;
- o1 |= p->to.reg << 12;
- break;
-
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = oprrr(p->as, p->scond);
- r = p->reg;
- if(r == NREG)
- r = p->to.reg;
- o1 |= r;
- o1 |= (p->from.reg << 8) | (1<<4);
- o1 |= p->to.reg << 12;
- break;
-
- case 10: /* swi [$con] */
- o1 = oprrr(p->as, p->scond);
- if(p->to.type != D_NONE) {
- aclass(&p->to);
- o1 |= instoffset & 0xffffff;
- }
- break;
-
- case 11: /* word */
- aclass(&p->to);
- o1 = instoffset;
- if(p->to.sym != S) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
- if(rel->sym == gmsym) {
- rel->type = D_TLS;
- if(flag_shared)
- rel->add += pc - p->pcrel->pc - 8 - rel->siz;
- rel->xadd = rel->add;
- rel->xsym = rel->sym;
- } else if(flag_shared) {
- rel->type = D_PCREL;
- rel->add += pc - p->pcrel->pc - 8;
- } else
- rel->type = D_ADDR;
- o1 = 0;
- }
- break;
-
- case 12: /* movw $lcon, reg */
- o1 = omvl(p, &p->from, p->to.reg);
- if(o->flag & LPCREL) {
- o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
- }
- break;
-
- case 13: /* op $lcon, [R], R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = oprrr(p->as, p->scond);
- o2 |= REGTMP;
- r = p->reg;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = p->to.reg;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 14: /* movb/movbu/movh/movhu R,R */
- o1 = oprrr(ASLL, p->scond);
-
- if(p->as == AMOVBU || p->as == AMOVHU)
- o2 = oprrr(ASRL, p->scond);
- else
- o2 = oprrr(ASRA, p->scond);
-
- r = p->to.reg;
- o1 |= (p->from.reg)|(r<<12);
- o2 |= (r)|(r<<12);
- if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
- o1 |= (24<<7);
- o2 |= (24<<7);
- } else {
- o1 |= (16<<7);
- o2 |= (16<<7);
- }
- break;
-
- case 15: /* mul r,[r,]r */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG)
- r = rt;
- if(rt == r) {
- r = rf;
- rf = rt;
- }
- if(0)
- if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
- diag("bad registers in MUL");
- prasm(p);
- }
- o1 |= (rf<<8) | r | (rt<<16);
- break;
-
-
- case 16: /* div r,[r,]r */
- o1 = 0xf << 28;
- o2 = 0;
- break;
-
- case 17:
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- rt2 = p->to.offset;
- r = p->reg;
- o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
- break;
-
- case 20: /* mov/movb/movbu R,O(R) */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = osr(p->as, p->from.reg, instoffset, r, p->scond);
- break;
-
- case 21: /* mov/movbu O(R),R -> lr */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olr(instoffset, r, p->to.reg, p->scond);
- if(p->as != AMOVW)
- o1 |= 1<<22;
- break;
-
- case 30: /* mov/movb/movbu R,L(R) */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = osrr(p->from.reg, REGTMP,r, p->scond);
- if(p->as != AMOVW)
- o2 |= 1<<22;
- break;
-
- case 31: /* mov/movbu L(R),R -> lr[b] */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olrr(REGTMP,r, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
- o2 |= 1<<22;
- break;
-
- case 34: /* mov $lacon,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
-
- o2 = oprrr(AADD, p->scond);
- o2 |= REGTMP;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 |= r << 16;
- if(p->to.type != D_NONE)
- o2 |= p->to.reg << 12;
- break;
-
- case 35: /* mov PSR,R */
- o1 = (2<<23) | (0xf<<16) | (0<<0);
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->from.reg & 1) << 22;
- o1 |= p->to.reg << 12;
- break;
-
- case 36: /* mov R,PSR */
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 37: /* mov $con,PSR */
- aclass(&p->from);
- o1 = (2<<23) | (0x29f<<12) | (0<<4);
- if(p->scond & C_FBIT)
- o1 ^= 0x010 << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= immrot(instoffset);
- o1 |= (p->to.reg & 1) << 22;
- o1 |= p->from.reg << 0;
- break;
-
- case 38: /* movm $con,oreg -> stm */
- o1 = (0x4 << 25);
- o1 |= p->from.offset & 0xffff;
- o1 |= p->to.reg << 16;
- aclass(&p->to);
- goto movm;
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = (0x4 << 25) | (1 << 20);
- o1 |= p->to.offset & 0xffff;
- o1 |= p->from.reg << 16;
- aclass(&p->from);
- movm:
- if(instoffset != 0)
- diag("offset must be zero in MOVM");
- o1 |= (p->scond & C_SCOND) << 28;
- if(p->scond & C_PBIT)
- o1 |= 1 << 24;
- if(p->scond & C_UBIT)
- o1 |= 1 << 23;
- if(p->scond & C_SBIT)
- o1 |= 1 << 22;
- if(p->scond & C_WBIT)
- o1 |= 1 << 21;
- break;
-
- case 40: /* swp oreg,reg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in SWP");
- o1 = (0x2<<23) | (0x9<<4);
- if(p->as != ASWPW)
- o1 |= 1 << 22;
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
-
- case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
- o1 = 0xe8fd8000;
- break;
-
- case 50: /* floating point store */
- v = regoff(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p);
- break;
-
- case 51: /* floating point load */
- v = regoff(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
- break;
-
- case 52: /* floating point store, int32 offset UGLY */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- break;
-
- case 53: /* floating point load, int32 offset UGLY */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
- o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- break;
-
- case 54: /* floating point arith */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- if(r == NREG) {
- r = rt;
- if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
- r = 0;
- }
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 56: /* move to FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
- break;
-
- case 57: /* move from FP[CS]R */
- o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
- o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
- break;
- case 58: /* movbu R,R */
- o1 = oprrr(AAND, p->scond);
- o1 |= immrot(0xff);
- rt = p->to.reg;
- r = p->from.reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
- break;
-
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if(p->from.reg == NREG) {
- if(p->as != AMOVW)
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(1<<4))
- diag("bad shift in LDR");
- o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- if(p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 60: /* movb R(R),R -> ldrsb indexed */
- if(p->from.reg == NREG) {
- diag("byte MOV from shifter operand");
- goto mov;
- }
- if(p->from.offset&(~0xf))
- diag("bad shift in LDRSB");
- o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond);
- o1 ^= (1<<5)|(1<<6);
- break;
-
- case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
- if(p->to.reg == NREG)
- diag("MOV to shifter operand");
- o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
- o1 |= 1<<22;
- break;
-
- case 62: /* case R -> movw R<<2(PC),PC */
- if(o->flag & LPCREL) {
- o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
- o2 = olrr(REGTMP, REGPC, REGTMP, p->scond);
- o2 |= 2<<7;
- o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
- } else {
- o1 = olrr(p->from.reg, REGPC, REGPC, p->scond);
- o1 |= 2<<7;
- }
- break;
-
- case 63: /* bcase */
- if(p->cond != P) {
- rel = addrel(cursym);
- rel->off = pc - cursym->value;
- rel->siz = 4;
- if(p->to.sym != S && p->to.sym->type != 0) {
- rel->sym = p->to.sym;
- rel->add = p->to.offset;
- } else {
- rel->sym = cursym;
- rel->add = p->cond->pc - cursym->value;
- }
- if(o->flag & LPCREL) {
- rel->type = D_PCREL;
- rel->add += pc - p->pcrel->pc - 16 + rel->siz;
- } else
- rel->type = D_ADDR;
- o1 = 0;
- }
- break;
-
- /* reloc ops */
- case 64: /* mov/movb/movbu R,addr */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 65: /* mov/movbu addr,R */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
- o2 |= 1<<22;
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 68: /* floating point store -> ADDR */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- case 69: /* floating point load <- ADDR */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
-
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = oshr(p->from.reg, instoffset, r, p->scond);
- break;
- case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olhr(instoffset, r, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o1 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o1 ^= (1<<6);
- break;
- case 72: /* movh/movhu R,L(R) -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = oshrr(p->from.reg, REGTMP,r, p->scond);
- break;
- case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o2 = olhrr(REGTMP, r, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o2 ^= (1<<6);
- break;
- case 74: /* bx $I */
- diag("ABX $I");
- break;
- case 75: /* bx O(R) */
- aclass(&p->to);
- if(instoffset != 0)
- diag("non-zero offset in ABX");
-/*
- o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
-*/
- // p->to.reg may be REGLINK
- o1 = oprrr(AADD, p->scond);
- o1 |= immrot(instoffset);
- o1 |= p->to.reg << 16;
- o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
- break;
- case 76: /* bx O(R) when returning from fn*/
- diag("ABXRET");
- break;
- case 77: /* ldrex oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x19<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 78: /* strex reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x18<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 80: /* fmov zfcon,freg */
- if(p->as == AMOVD) {
- o1 = 0xeeb00b00; // VMOV imm 64
- o2 = oprrr(ASUBD, p->scond);
- } else {
- o1 = 0x0eb00a00; // VMOV imm 32
- o2 = oprrr(ASUBF, p->scond);
- }
- v = 0x70; // 1.0
- r = p->to.reg;
-
- // movf $1.0, r
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= r << 12;
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
-
- // subf r,r,r
- o2 |= r | (r<<16) | (r<<12);
- break;
- case 81: /* fmov sfcon,freg */
- o1 = 0x0eb00a00; // VMOV imm 32
- if(p->as == AMOVD)
- o1 = 0xeeb00b00; // VMOV imm 64
- o1 |= (p->scond & C_SCOND) << 28;
- o1 |= p->to.reg << 12;
- v = chipfloat(&p->from.ieee);
- o1 |= (v&0xf) << 0;
- o1 |= (v&0xf0) << 12;
- break;
- case 82: /* fcmp freg,freg, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->reg<<12) | (p->from.reg<<0);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 83: /* fcmp freg,, */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<12) | (1<<16);
- o2 = 0x0ef1fa10; // VMRS R15
- o2 |= (p->scond & C_SCOND) << 28;
- break;
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (p->to.reg<<12);
- break;
- case 86: /* movfw freg,reg - truncate float-to-fix */
- // macro for movfw freg,FTMP; movw FTMP,reg
- o1 = oprrr(p->as, p->scond);
- o1 |= (p->from.reg<<0);
- o1 |= (FREGTMP<<12);
- o2 = oprrr(AMOVFW+AEND, p->scond);
- o2 |= (FREGTMP<<16);
- o2 |= (p->to.reg<<12);
- break;
- case 87: /* movwf reg,freg - fix-to-float */
- // macro for movw reg,FTMP; movwf FTMP,freg
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (FREGTMP<<16);
- o2 = oprrr(p->as, p->scond);
- o2 |= (FREGTMP<<0);
- o2 |= (p->to.reg<<12);
- break;
- case 88: /* movw reg,freg */
- o1 = oprrr(AMOVWF+AEND, p->scond);
- o1 |= (p->from.reg<<12);
- o1 |= (p->to.reg<<16);
- break;
- case 89: /* movw freg,reg */
- o1 = oprrr(AMOVFW+AEND, p->scond);
- o1 |= (p->from.reg<<16);
- o1 |= (p->to.reg<<12);
- break;
- case 90: /* tst reg */
- o1 = oprrr(ACMP+AEND, p->scond);
- o1 |= p->from.reg<<16;
- break;
- case 91: /* ldrexd oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in LDREX");
- o1 = (0x1b<<20) | (0xf9f);
- o1 |= p->from.reg << 16;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 92: /* strexd reg,oreg,reg */
- aclass(&p->from);
- if(instoffset != 0)
- diag("offset must be zero in STREX");
- o1 = (0x1a<<20) | (0xf90);
- o1 |= p->from.reg << 16;
- o1 |= p->reg << 0;
- o1 |= p->to.reg << 12;
- o1 |= (p->scond & C_SCOND) << 28;
- break;
- case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(p, &p->from, REGTMP);
- if(!o1)
- break;
- o2 = olhr(0, REGTMP, p->to.reg, p->scond);
- if(p->as == AMOVB || p->as == AMOVBS)
- o2 ^= (1<<5)|(1<<6);
- else if(p->as == AMOVH || p->as == AMOVHS)
- o2 ^= (1<<6);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
- case 94: /* movh/movhu R,addr -> strh */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
- if(o->flag & LPCREL) {
- o3 = o2;
- o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
- }
- break;
- case 95: /* PLD off(reg) */
- o1 = 0xf5d0f000;
- o1 |= p->from.reg << 16;
- if(p->from.offset < 0) {
- o1 &= ~(1 << 23);
- o1 |= (-p->from.offset) & 0xfff;
- } else
- o1 |= p->from.offset & 0xfff;
- break;
- case 96: /* UNDEF */
- // This is supposed to be something that stops execution.
- // It's not supposed to be reached, ever, but if it is, we'd
- // like to be able to tell how we got there. Assemble as
- // 0xf7fabcfd which is guranteed to raise undefined instruction
- // exception.
- o1 = 0xf7fabcfd;
- break;
- case 97: /* CLZ Rm, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 12;
- o1 |= p->from.reg;
- break;
- case 98: /* MULW{T,B} Rs, Rm, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 16;
- o1 |= p->from.reg << 8;
- o1 |= p->reg;
- break;
- case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
- o1 = oprrr(p->as, p->scond);
- o1 |= p->to.reg << 12;
- o1 |= p->from.reg << 8;
- o1 |= p->reg;
- o1 |= p->to.offset << 16;
- break;
- }
-
- out[0] = o1;
- out[1] = o2;
- out[2] = o3;
- out[3] = o4;
- out[4] = o5;
- out[5] = o6;
- return;
-
-#ifdef NOTDEF
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- lputl(o1);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
- lputl(o1);
- lputl(o2);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- break;
- case 16:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- break;
- case 20:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- break;
- case 24:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, o6, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- lputl(o6);
- break;
- }
-#endif
-}
-
-int32
-oprrr(int a, int sc)
-{
- int32 o;
-
- o = (sc & C_SCOND) << 28;
- if(sc & C_SBIT)
- o |= 1 << 20;
- if(sc & (C_PBIT|C_WBIT))
- diag(".P/.W on dp instruction");
- switch(a) {
- case AMULU:
- case AMUL: return o | (0x0<<21) | (0x9<<4);
- case AMULA: return o | (0x1<<21) | (0x9<<4);
- case AMULLU: return o | (0x4<<21) | (0x9<<4);
- case AMULL: return o | (0x6<<21) | (0x9<<4);
- case AMULALU: return o | (0x5<<21) | (0x9<<4);
- case AMULAL: return o | (0x7<<21) | (0x9<<4);
- case AAND: return o | (0x0<<21);
- case AEOR: return o | (0x1<<21);
- case ASUB: return o | (0x2<<21);
- case ARSB: return o | (0x3<<21);
- case AADD: return o | (0x4<<21);
- case AADC: return o | (0x5<<21);
- case ASBC: return o | (0x6<<21);
- case ARSC: return o | (0x7<<21);
- case ATST: return o | (0x8<<21) | (1<<20);
- case ATEQ: return o | (0x9<<21) | (1<<20);
- case ACMP: return o | (0xa<<21) | (1<<20);
- case ACMN: return o | (0xb<<21) | (1<<20);
- case AORR: return o | (0xc<<21);
- case AMOVB:
- case AMOVH:
- case AMOVW: return o | (0xd<<21);
- case ABIC: return o | (0xe<<21);
- case AMVN: return o | (0xf<<21);
- case ASLL: return o | (0xd<<21) | (0<<5);
- case ASRL: return o | (0xd<<21) | (1<<5);
- case ASRA: return o | (0xd<<21) | (2<<5);
- case ASWI: return o | (0xf<<24);
-
- case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
- case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
- case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
- case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
- case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
- case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
- case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
- case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
- case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
- case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
- case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
- case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
- case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
- case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
-
- case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
- case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
-
- case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (1<<8); // dtof
- case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
- (0<<8); // dtof
-
- case AMOVWF:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (0<<8); // toint, double
- case AMOVWD:
- if((sc & C_UBIT) == 0)
- o |= 1<<7; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (0<<18) | (1<<8); // toint, double
-
- case AMOVFW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
- case AMOVDW:
- if((sc & C_UBIT) == 0)
- o |= 1<<16; /* signed */
- return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
- (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
-
- case AMOVWF+AEND: // copy WtoF
- return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
- case AMOVFW+AEND: // copy FtoW
- return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
- case ACMP+AEND: // cmp imm
- return o | (0x3<<24) | (0x5<<20);
-
- case ACLZ:
- // CLZ doesn't support .S
- return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
-
- case AMULWT:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
- case AMULWB:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
- case AMULAWT:
- return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
- case AMULAWB:
- return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
-
- case ABL: // BLX REG
- return (o & (0xf<<28)) | (0x12fff3 << 4);
- }
- diag("bad rrr %d", a);
- prasm(curp);
- return 0;
-}
-
-int32
-opbra(int a, int sc)
-{
-
- if(sc & (C_SBIT|C_PBIT|C_WBIT))
- diag(".S/.P/.W on bra instruction");
- sc &= C_SCOND;
- if(a == ABL)
- return (sc<<28)|(0x5<<25)|(0x1<<24);
- if(sc != 0xe)
- diag(".COND on bcond instruction");
- switch(a) {
- case ABEQ: return (0x0<<28)|(0x5<<25);
- case ABNE: return (0x1<<28)|(0x5<<25);
- case ABCS: return (0x2<<28)|(0x5<<25);
- case ABHS: return (0x2<<28)|(0x5<<25);
- case ABCC: return (0x3<<28)|(0x5<<25);
- case ABLO: return (0x3<<28)|(0x5<<25);
- case ABMI: return (0x4<<28)|(0x5<<25);
- case ABPL: return (0x5<<28)|(0x5<<25);
- case ABVS: return (0x6<<28)|(0x5<<25);
- case ABVC: return (0x7<<28)|(0x5<<25);
- case ABHI: return (0x8<<28)|(0x5<<25);
- case ABLS: return (0x9<<28)|(0x5<<25);
- case ABGE: return (0xa<<28)|(0x5<<25);
- case ABLT: return (0xb<<28)|(0x5<<25);
- case ABGT: return (0xc<<28)|(0x5<<25);
- case ABLE: return (0xd<<28)|(0x5<<25);
- case AB: return (0xe<<28)|(0x5<<25);
- }
- diag("bad bra %A", a);
- prasm(curp);
- return 0;
-}
-
int32
-olr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDR/STR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(!(sc & C_UBIT))
- o |= 1 << 23;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<26) | (1<<20);
- if(v < 0) {
- if(sc & C_UBIT) diag(".U on neg offset");
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<12) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= v;
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-olhr(int32 v, int b, int r, int sc)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on LDRH/STRH instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (1<<23) | (1<<20)|(0xb<<4);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v >= (1<<8) || v < 0)
- diag("literal span too large: %d (R%d)\n%P", v, b, PP);
- o |= (v&0xf)|((v>>4)<<8)|(1<<22);
- o |= b << 16;
- o |= r << 12;
- return o;
-}
-
-int32
-osr(int a, int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olr(v, b, r, sc) ^ (1<<20);
- if(a != AMOVW)
- o |= 1<<22;
- return o;
-}
-
-int32
-oshr(int r, int32 v, int b, int sc)
-{
- int32 o;
-
- o = olhr(v, b, r, sc) ^ (1<<20);
- return o;
-}
-
-
-int32
-osrr(int r, int i, int b, int sc)
-{
-
- return olr(i, b, r, sc) ^ ((1<<25) | (1<<20));
-}
-
-int32
-oshrr(int r, int i, int b, int sc)
-{
- return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20));
-}
-
-int32
-olrr(int i, int b, int r, int sc)
-{
-
- return olr(i, b, r, sc) ^ (1<<25);
-}
-
-int32
-olhrr(int i, int b, int r, int sc)
-{
- return olhr(i, b, r, sc) ^ (1<<22);
-}
-
-int32
-ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
-{
- int32 o;
-
- if(sc & C_SBIT)
- diag(".S on FLDR/FSTR instruction");
- o = (sc & C_SCOND) << 28;
- if(!(sc & C_PBIT))
- o |= 1 << 24;
- if(sc & C_WBIT)
- o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
- if(v < 0) {
- v = -v;
- o ^= 1 << 23;
- }
- if(v & 3)
- diag("odd offset for floating point op: %d\n%P", v, p);
- else
- if(v >= (1<<10) || v < 0)
- diag("literal span too large: %d\n%P", v, p);
- o |= (v>>2) & 0xFF;
- o |= b << 16;
- o |= r << 12;
-
- switch(a) {
- default:
- diag("bad fst %A", a);
- case AMOVD:
- o |= 1 << 8;
- case AMOVF:
- break;
- }
- return o;
-}
-
-int32
-omvl(Prog *p, Adr *a, int dr)
-{
- int32 v, o1;
- if(!p->cond) {
- aclass(a);
- v = immrot(~instoffset);
- if(v == 0) {
- diag("missing literal");
- prasm(p);
- return 0;
- }
- o1 = oprrr(AMVN, p->scond&C_SCOND);
- o1 |= v;
- o1 |= dr << 12;
- } else {
- v = p->cond->pc - p->pc - 8;
- o1 = olr(v, REGPC, dr, p->scond&C_SCOND);
- }
- return o1;
-}
-
-int
-chipzero(Ieee *e)
-{
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if(goarm < 7 || e->l != 0 || e->h != 0)
- return -1;
- return 0;
-}
-
-int
-chipfloat(Ieee *e)
-{
- int n;
- ulong h;
-
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if(goarm < 7)
- goto no;
-
- if(e->l != 0 || (e->h&0xffff) != 0)
- goto no;
- h = e->h & 0x7fc00000;
- if(h != 0x40000000 && h != 0x3fc00000)
- goto no;
- n = 0;
-
- // sign bit (a)
- if(e->h & 0x80000000)
- n |= 1<<7;
-
- // exp sign bit (b)
- if(h == 0x3fc00000)
- n |= 1<<6;
-
- // rest of exp and mantissa (cd-efgh)
- n |= (e->h >> 16) & 0x3f;
-
-//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
- return n;
-
-no:
- return -1;
+rnd(int32 v, int32 r)
+{
+ int32 c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
}
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index ae4b05ba1..761bc861a 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "5.out.h"
enum
@@ -38,6 +39,7 @@ enum
thechar = '5',
PtrSize = 4,
IntSize = 4,
+ RegSize = 4,
MaxAlign = 8, // max data alignment
FuncAlign = 4 // single-instruction alignment
};
@@ -51,167 +53,13 @@ enum
#define dynptrsize 0
-typedef struct Adr Adr;
-typedef struct Sym Sym;
-typedef struct Autom Auto;
-typedef struct Prog Prog;
-typedef struct Reloc Reloc;
-typedef struct Optab Optab;
-typedef struct Oprang Oprang;
-typedef uchar Opcross[32][2][32];
-typedef struct Count Count;
-
#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-struct Adr
-{
- union
- {
- struct {
- int32 u0offset;
- int32 u0offset2; // argsize
- } u0off;
- char* u0sval;
- Ieee u0ieee;
- char* u0sbig;
- } u0;
- Sym* sym;
- Sym* gotype;
- char type;
- char reg;
- char name;
- char class;
-};
-
-#define offset u0.u0off.u0offset
-#define offset2 u0.u0off.u0offset2
-#define sval u0.u0sval
-#define scon sval
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int16 type;
- int32 add;
- int32 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- union
- {
- int32 u0regused;
- Prog* u0forwd;
- } u0;
- Prog* cond;
- Prog* link;
- Prog* pcrel;
- int32 pc;
- int32 line;
- int32 spadj;
- uchar mark;
- uchar optab;
- uchar as;
- uchar scond;
- uchar reg;
- uchar align; // unused
-};
-
-#define regused u0.u0regused
-#define forwd u0.u0forwd
-#define datasize reg
-#define textflag reg
-
-#define iscall(p) ((p)->as == ABL)
-
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar leaf;
- int32 dynid;
- int32 plt;
- int32 got;
- int32 value;
- int32 sig;
- int32 size;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 locals; // size of stack frame locals area
- int32 args; // size of stack frame incoming arguments area
- uchar special;
- uchar fnptr; // used as fn ptr
- uchar stkcheck;
- uchar hide;
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- Sym* gotype;
- Sym* reachparent;
- Sym* queue;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist;
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
#define SIGNINTERN (1729*325*1729)
-struct Autom
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Optab
-{
- char as;
- uchar a1;
- char a2;
- uchar a3;
- uchar type;
- char size;
- char param;
- char flag;
- uchar pcrelsiz;
-};
-struct Oprang
-{
- Optab* start;
- Optab* stop;
-};
+typedef struct Count Count;
struct Count
{
int32 count;
@@ -220,10 +68,17 @@ struct Count
enum
{
- LFROM = 1<<0,
- LTO = 1<<1,
- LPOOL = 1<<2,
- LPCREL = 1<<3,
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+
+ STRINGSZ = 200,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 40, /* limit of path elements for history symbols */
+ MINLC = 4,
C_NONE = 0,
C_REG,
@@ -260,7 +115,7 @@ enum
C_HFOREG,
C_SOREG,
C_ROREG,
- C_SROREG, /* both S and R */
+ C_SROREG, /* both nil and R */
C_LOREG,
C_PC,
@@ -270,179 +125,45 @@ enum
C_ADDR, /* reference to relocatable address */
C_GOK,
-
-/* mark flags */
- FOLL = 1<<0,
- LABEL = 1<<1,
- LEAF = 1<<2,
-
- STRINGSZ = 200,
- MINSIZ = 64,
- NENT = 100,
- MAXIO = 8192,
- MAXHIST = 40, /* limit of path elements for history symbols */
- MINLC = 4,
};
#ifndef COFFCVT
-EXTERN int32 HEADR; /* length of header */
-EXTERN int HEADTYPE; /* type of header */
-EXTERN int32 INITDAT; /* data location */
-EXTERN int32 INITRND; /* data round above text location */
-EXTERN int32 INITTEXT; /* text location */
-EXTERN char* INITENTRY; /* entry point */
EXTERN int32 autosize;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
-EXTERN Sym* etextp;
EXTERN char* noname;
EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN char literal[32];
EXTERN int nerrors;
EXTERN int32 instoffset;
-EXTERN Opcross opcross[8];
-EXTERN Oprang oprange[ALAST];
-EXTERN char* outfile;
-EXTERN int32 pc;
-EXTERN uchar repop[ALAST];
-EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
-EXTERN Sym* textp;
-EXTERN char xcmp[C_GOK+1][C_GOK+1];
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int tlsoffset;
EXTERN int armsize;
-EXTERN int goarm;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-extern char* anames[];
-extern Optab optab[];
-
-void addpool(Prog*, Adr*);
-EXTERN Prog* blitrl;
-EXTERN Prog* elitrl;
-EXTERN int goarm;
+#pragma varargck type "I" uint32*
-void initdiv(void);
-EXTERN Prog* prog_div;
-EXTERN Prog* prog_divu;
-EXTERN Prog* prog_mod;
-EXTERN Prog* prog_modu;
-
-#pragma varargck type "A" int
-#pragma varargck type "C" int
-#pragma varargck type "D" Adr*
-#pragma varargck type "I" uchar*
-#pragma varargck type "N" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "S" char*
-#pragma varargck type "Z" char*
-#pragma varargck type "i" char*
-
-int Aconv(Fmt*);
-int Cconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Nconv(Fmt*);
-int Oconv(Fmt*);
-int Pconv(Fmt*);
-int Sconv(Fmt*);
-int aclass(Adr*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
+int Iconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rel, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmout(Prog*, Optab*, int32*, Sym*);
-int32 atolwhex(char*);
-Prog* brloop(Prog*);
-void buildop(void);
-void buildrep(int, int);
-void cflush(void);
-int chipzero(Ieee*);
-int chipfloat(Ieee*);
-int cmp(int, int);
-int compound(Prog*);
-double cputime(void);
-void diag(char*, ...);
-void divsig(void);
-void dodata(void);
-void doprof1(void);
-void doprof2(void);
-int32 entryvalue(void);
-void exchange(Prog*);
-void follow(void);
-void hputl(int);
-int isnop(Prog*);
+void cput(int32 c);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
+void hput(int32 l);
void listinit(void);
-Sym* lookup(char*, int);
-void cput(int);
-void hput(int32);
-void lput(int32);
-void lputb(int32);
-void lputl(int32);
-void* mysbrk(uint32);
-void names(void);
-void nocache(Prog*);
-int ocmp(const void*, const void*);
-int32 opirr(int);
-Optab* oplook(Prog*);
-int32 oprrr(int, int);
-int32 olr(int32, int, int, int);
-int32 olhr(int32, int, int, int);
-int32 olrr(int, int, int, int);
-int32 olhrr(int, int, int, int);
-int32 osr(int, int, int32, int, int);
-int32 oshr(int, int32, int, int);
-int32 ofsr(int, int, int32, int, int, Prog*);
-int32 osrr(int, int, int, int);
-int32 oshrr(int, int, int, int);
-int32 omvl(Prog*, Adr*, int);
-void patch(void);
-void prasm(Prog*);
-void prepend(Prog*, Prog*);
-Prog* prg(void);
-int pseudo(Prog*);
-int32 regoff(Adr*);
-int relinv(int);
-int32 rnd(int32, int32);
-void softfloat(void);
-void span(void);
-void strnput(char*, int);
-int32 symaddr(Sym*);
-void undef(void);
-void vputb(uint64);
-void vputl(uint64);
-void wputb(uint16);
-void wput(int32);
-void wputl(ushort w);
-void xdefine(char*, int, int32);
+void lput(int32 l);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
void noops(void);
-int32 immrot(uint32);
-int32 immaddr(int32);
-int32 opbra(int, int);
-int brextra(Prog*);
-int isbranch(Prog*);
-void doelf(void);
-void dozerostk(void); // used by -Z
-
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
+void nopstat(char *f, Count *c);
+int32 rnd(int32 v, int32 r);
+void wput(int32 l);
/* Native is little-endian */
#define LPUT(a) lputl(a)
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 7502a3b81..875fc3e6b 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -36,355 +36,10 @@
void
listinit(void)
{
-
- fmtinstall('A', Aconv);
- fmtinstall('C', Cconv);
- fmtinstall('D', Dconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('N', Nconv);
- fmtinstall('O', Oconv); // C_type constants
+ listinit5();
fmtinstall('I', Iconv);
}
-void
-prasm(Prog *p)
-{
- print("%P\n", p);
-}
-
-int
-Pconv(Fmt *fp)
-{
- Prog *p;
- int a;
-
- p = va_arg(fp->args, Prog*);
- curp = p;
- a = p->as;
- switch(a) {
- default:
- fmtprint(fp, "(%d)", p->line);
- if(p->reg == NREG && p->as != AGLOBL)
- fmtprint(fp, " %A%C %D,%D",
- a, p->scond, &p->from, &p->to);
- else
- if(p->from.type != D_FREG)
- fmtprint(fp, " %A%C %D,R%d,%D",
- a, p->scond, &p->from, p->reg, &p->to);
- else
- fmtprint(fp, " %A%C %D,F%d,%D",
- a, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case ASWPW:
- case ASWPBU:
- fmtprint(fp, "(%d) %A%C R%d,%D,%D",
- p->line, a, p->scond, p->reg, &p->from, &p->to);
- break;
-
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A%C %D/%d,%D",
- p->line, a, p->scond, &p->from, p->reg, &p->to);
- break;
-
- case AWORD:
- fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
- break;
-
- case ADWORD:
- fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
- break;
- }
-
- if(p->spadj)
- fmtprint(fp, " (spadj%+d)", p->spadj);
-
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- char *s;
- int a;
-
- a = va_arg(fp->args, int);
- s = "???";
- if(a >= AXXX && a < ALAST)
- s = anames[a];
- return fmtstrcpy(fp, s);
-}
-
-char* strcond[16] =
-{
- ".EQ",
- ".NE",
- ".HS",
- ".LO",
- ".MI",
- ".PL",
- ".VS",
- ".VC",
- ".HI",
- ".LS",
- ".GE",
- ".LT",
- ".GT",
- ".LE",
- "",
- ".NV"
-};
-
-int
-Cconv(Fmt *fp)
-{
- char s[20];
- int c;
-
- c = va_arg(fp->args, int);
- strcpy(s, strcond[c & C_SCOND]);
- if(c & C_SBIT)
- strcat(s, ".S");
- if(c & C_PBIT)
- strcat(s, ".P");
- if(c & C_WBIT)
- strcat(s, ".W");
- if(c & C_UBIT) /* ambiguous with FBIT */
- strcat(s, ".U");
- return fmtstrcpy(fp, s);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ];
- const char *op;
- Adr *a;
- int32 v;
-
- a = va_arg(fp->args, Adr*);
- switch(a->type) {
-
- default:
- snprint(str, sizeof str, "GOK-type(%d)", a->type);
- break;
-
- case D_NONE:
- str[0] = 0;
- if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
- break;
-
- case D_CONST:
- if(a->reg == NREG)
- snprint(str, sizeof str, "$%N", a);
- else
- snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
- break;
-
- case D_CONST2:
- snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_SHIFT:
- v = a->offset;
- op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
- if(v & (1<<4))
- snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
- else
- snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
- if(a->reg != NREG)
- seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
- break;
-
- case D_OCONST:
- snprint(str, sizeof str, "$*$%N", a);
- if(a->reg != NREG)
- snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
- break;
-
- case D_OREG:
- if(a->reg != NREG)
- snprint(str, sizeof str, "%N(R%d)", a, a->reg);
- else
- snprint(str, sizeof str, "%N", a);
- break;
-
- case D_REG:
- snprint(str, sizeof str, "R%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG:
- snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_REGREG2:
- snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_FREG:
- snprint(str, sizeof str, "F%d", a->reg);
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
- break;
-
- case D_PSR:
- switch(a->reg) {
- case 0:
- snprint(str, sizeof str, "CPSR");
- break;
- case 1:
- snprint(str, sizeof str, "SPSR");
- break;
- default:
- snprint(str, sizeof str, "PSR%d", a->reg);
- break;
- }
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
- break;
-
- case D_FPCR:
- switch(a->reg){
- case 0:
- snprint(str, sizeof str, "FPSR");
- break;
- case 1:
- snprint(str, sizeof str, "FPCR");
- break;
- default:
- snprint(str, sizeof str, "FCR%d", a->reg);
- break;
- }
- if(a->name != D_NONE || a->sym != S)
- snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
-
- break;
-
- case D_BRANCH: /* botch */
- if(curp->cond != P) {
- v = curp->cond->pc;
- if(a->sym != S)
- snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
- else
- snprint(str, sizeof str, "%.5ux(BRANCH)", v);
- } else
- if(a->sym != S)
- snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- snprint(str, sizeof str, "%d(APC)", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
- break;
-
- case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->sval);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Nconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Adr *a;
- Sym *s;
-
- a = va_arg(fp->args, Adr*);
- s = a->sym;
- switch(a->name) {
- default:
- sprint(str, "GOK-name(%d)", a->name);
- break;
-
- case D_NONE:
- sprint(str, "%d", a->offset);
- break;
-
- case D_EXTERN:
- if(s == S)
- sprint(str, "%d(SB)", a->offset);
- else
- sprint(str, "%s+%d(SB)", s->name, a->offset);
- break;
-
- case D_STATIC:
- if(s == S)
- sprint(str, "<>+%d(SB)", a->offset);
- else
- sprint(str, "%s<>+%d(SB)", s->name, a->offset);
- break;
-
- case D_AUTO:
- if(s == S)
- sprint(str, "%d(SP)", a->offset);
- else
- sprint(str, "%s-%d(SP)", s->name, -a->offset);
- break;
-
- case D_PARAM:
- if(s == S)
- sprint(str, "%d(FP)", a->offset);
- else
- sprint(str, "%s+%d(FP)", s->name, a->offset);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(int32); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9' ||
- c == ' ' || c == '%') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
int
Iconv(Fmt *fp)
{
@@ -413,83 +68,3 @@ Iconv(Fmt *fp)
free(s);
return 0;
}
-
-static char*
-cnames[] =
-{
- [C_ADDR] = "C_ADDR",
- [C_FAUTO] = "C_FAUTO",
- [C_ZFCON] = "C_SFCON",
- [C_SFCON] = "C_SFCON",
- [C_LFCON] = "C_LFCON",
- [C_FCR] = "C_FCR",
- [C_FOREG] = "C_FOREG",
- [C_FREG] = "C_FREG",
- [C_GOK] = "C_GOK",
- [C_HAUTO] = "C_HAUTO",
- [C_HFAUTO] = "C_HFAUTO",
- [C_HFOREG] = "C_HFOREG",
- [C_HOREG] = "C_HOREG",
- [C_HREG] = "C_HREG",
- [C_LACON] = "C_LACON",
- [C_LAUTO] = "C_LAUTO",
- [C_LBRA] = "C_LBRA",
- [C_LCON] = "C_LCON",
- [C_LCONADDR] = "C_LCONADDR",
- [C_LOREG] = "C_LOREG",
- [C_NCON] = "C_NCON",
- [C_NONE] = "C_NONE",
- [C_PC] = "C_PC",
- [C_PSR] = "C_PSR",
- [C_RACON] = "C_RACON",
- [C_RCON] = "C_RCON",
- [C_REG] = "C_REG",
- [C_REGREG] = "C_REGREG",
- [C_REGREG2] = "C_REGREG2",
- [C_ROREG] = "C_ROREG",
- [C_SAUTO] = "C_SAUTO",
- [C_SBRA] = "C_SBRA",
- [C_SCON] = "C_SCON",
- [C_SHIFT] = "C_SHIFT",
- [C_SOREG] = "C_SOREG",
- [C_SP] = "C_SP",
- [C_SROREG] = "C_SROREG"
-};
-
-int
-Oconv(Fmt *fp)
-{
- char buf[500];
- int o;
-
- o = va_arg(fp->args, int);
- if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) {
- snprint(buf, sizeof(buf), "C_%d", o);
- return fmtstrcpy(fp, buf);
- }
- return fmtstrcpy(fp, cnames[o]);
-}
-
-void
-diag(char *fmt, ...)
-{
- char buf[1024], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 305ed684e..d42c86289 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -32,677 +32,12 @@
#include "l.h"
#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static Sym* sym_div;
-static Sym* sym_divu;
-static Sym* sym_mod;
-static Sym* sym_modu;
-static Sym* symmorestack;
-static Prog* pmorestack;
-
-static Prog* stacksplit(Prog*, int32);
-
-static void
-linkcase(Prog *casep)
-{
- Prog *p;
-
- for(p = casep; p != P; p = p->link){
- if(p->as == ABCASE) {
- for(; p != P && p->as == ABCASE; p = p->link)
- p->pcrel = casep;
- break;
- }
- }
-}
void
noops(void)
{
- Prog *p, *q, *q1, *q2;
- int o;
- Sym *tlsfallback, *gmsym;
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- * fixup TLS
- */
-
- if(debug['v'])
- Bprint(&bso, "%5.2f noops\n", cputime());
- Bflush(&bso);
-
- symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type != STEXT) {
- diag("runtime·morestack not defined");
- errorexit();
- }
- pmorestack = symmorestack->text;
- pmorestack->reg |= NOSPLIT;
-
- tlsfallback = lookup("runtime.read_tls_fallback", 0);
- gmsym = S;
- if(linkmode == LinkExternal)
- gmsym = lookup("runtime.tlsgm", 0);
- q = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case ACASE:
- if(flag_shared)
- linkcase(p);
- break;
-
- case ATEXT:
- p->mark |= LEAF;
- break;
-
- case ARET:
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- q = p;
- if(prog_div == P)
- initdiv();
- cursym->text->mark &= ~LEAF;
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- if(q1 != P)
- q1->mark |= p->mark;
- continue;
-
- case ABL:
- case ABX:
- cursym->text->mark &= ~LEAF;
-
- case ABCASE:
- case AB:
-
- case ABEQ:
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
- q1 = p->cond;
- if(q1 != P) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->cond = q1;
- }
- }
- break;
- case AWORD:
- // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
- if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
- if(HEADTYPE == Hopenbsd) {
- p->as = ARET;
- } else if(goarm < 7) {
- if(tlsfallback->type != STEXT) {
- diag("runtime·read_tls_fallback not defined");
- errorexit();
- }
- // BL runtime.read_tls_fallback(SB)
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = tlsfallback;
- p->cond = tlsfallback->text;
- p->to.offset = 0;
- cursym->text->mark &= ~LEAF;
- }
- if(linkmode == LinkExternal) {
- // runtime.tlsgm is relocated with R_ARM_TLS_LE32
- // and $runtime.tlsgm will contain the TLS offset.
- //
- // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP
- // ADD REGTMP, <reg>
- //
- // In shared mode, runtime.tlsgm is relocated with
- // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
- // to the GOT entry containing the TLS offset.
- //
- // MOV runtime.tlsgm(SB), REGTMP
- // ADD REGTMP, <reg>
- // SUB -tlsoffset, <reg>
- //
- // The SUB compensates for tlsoffset
- // used in runtime.save_gm and runtime.load_gm.
- q = p;
- p = appendp(p);
- p->as = AMOVW;
- p->scond = 14;
- p->reg = NREG;
- if(flag_shared) {
- p->from.type = D_OREG;
- p->from.offset = 0;
- } else {
- p->from.type = D_CONST;
- p->from.offset = tlsoffset;
- }
- p->from.sym = gmsym;
- p->from.name = D_EXTERN;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
- p->to.offset = 0;
-
- p = appendp(p);
- p->as = AADD;
- p->scond = 14;
- p->reg = NREG;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->to.type = D_REG;
- p->to.reg = (q->to.offset & 0xf000) >> 12;
- p->to.offset = 0;
-
- if(flag_shared) {
- p = appendp(p);
- p->as = ASUB;
- p->scond = 14;
- p->reg = NREG;
- p->from.type = D_CONST;
- p->from.offset = -tlsoffset;
- p->to.type = D_REG;
- p->to.reg = (q->to.offset & 0xf000) >> 12;
- p->to.offset = 0;
- }
- }
- }
- }
- q = p;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- o = p->as;
- switch(o) {
- case ATEXT:
- autosize = p->to.offset + 4;
- if(autosize <= 4)
- if(cursym->text->mark & LEAF) {
- p->to.offset = -4;
- autosize = 0;
- }
-
- if(!autosize && !(cursym->text->mark & LEAF)) {
- if(debug['v'])
- Bprint(&bso, "save suppressed in: %s\n",
- cursym->name);
- Bflush(&bso);
- cursym->text->mark |= LEAF;
- }
- if(cursym->text->mark & LEAF) {
- cursym->leaf = 1;
- if(!autosize)
- break;
- }
-
- if(!(p->reg & NOSPLIT))
- p = stacksplit(p, autosize); // emit split check
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
-
- if(cursym->text->reg & WRAPPER) {
- // g->panicwrap += autosize;
- // MOVW panicwrap_offset(g), R3
- // ADD $autosize, R3
- // MOVW R3 panicwrap_offset(g)
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->from.offset = 2*PtrSize;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- p = appendp(p);
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*PtrSize;
- }
- break;
-
- case ARET:
- nocache(p);
- if(cursym->text->mark & LEAF) {
- if(!autosize) {
- p->as = AB;
- p->from = zprg.from;
- if(p->to.sym) { // retjmp
- p->to.type = D_BRANCH;
- p->cond = p->to.sym->text;
- } else {
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- }
- break;
- }
- }
-
- if(cursym->text->reg & WRAPPER) {
- int cond;
-
- // Preserve original RET's cond, to allow RET.EQ
- // in the implementation of reflect.call.
- cond = p->scond;
- p->scond = C_SCOND_NONE;
-
- // g->panicwrap -= autosize;
- // MOVW panicwrap_offset(g), R3
- // SUB $autosize, R3
- // MOVW R3 panicwrap_offset(g)
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->from.offset = 2*PtrSize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(p);
-
- p->as = ASUB;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(p);
-
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
-
- p->scond = cond;
- }
-
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
-
- if(p->to.sym) { // retjmp
- p->to.reg = REGLINK;
- q2 = appendp(p);
- q2->as = AB;
- q2->to.type = D_BRANCH;
- q2->to.sym = p->to.sym;
- q2->cond = p->to.sym->text;
- p->to.sym = nil;
- p = q2;
- }
- break;
-
- case AADD:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = p->from.offset;
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- if(debug['M'])
- break;
- if(p->from.type != D_REG)
- break;
- if(p->to.type != D_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->from.reg;
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- /* MOV b,REGTMP */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->reg;
- if(q1->reg == NREG)
- p->from.reg = q1->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
- p->to.offset = 0;
-
- /* CALL appropriate */
- p = appendp(p);
- p->as = ABL;
- p->line = q1->line;
- p->to.type = D_BRANCH;
- p->cond = p;
- switch(o) {
- case ADIV:
- p->cond = prog_div;
- p->to.sym = sym_div;
- break;
- case ADIVU:
- p->cond = prog_divu;
- p->to.sym = sym_divu;
- break;
- case AMOD:
- p->cond = prog_mod;
- p->to.sym = sym_mod;
- break;
- case AMODU:
- p->cond = prog_modu;
- p->to.sym = sym_modu;
- break;
- }
+ LSym *s;
- /* MOV REGTMP, b */
- p = appendp(p);
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- p = appendp(p);
- p->as = AADD;
- p->line = q1->line;
- p->from.type = D_CONST;
- p->from.reg = NREG;
- p->from.offset = 8;
- p->reg = NREG;
- p->to.type = D_REG;
- p->to.reg = REGSP;
- p->spadj = -8;
-
- /* 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;
- case AMOVW:
- if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
- p->spadj = -p->to.offset;
- if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
- p->spadj = -p->from.offset;
- if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
- p->spadj = -p->from.offset;
- break;
- }
- }
- }
-}
-
-static Prog*
-stacksplit(Prog *p, int32 framesize)
-{
- int32 arg;
-
- // MOVW g_stackguard(g), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- if(framesize <= StackSmall) {
- // small stack: SP < stackguard
- // CMP stackguard, SP
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = REGSP;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize < stackguard-StackSmall
- // MOVW $-framesize(SP), R2
- // CMP stackguard, R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = -framesize;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
- } else {
- // Such a large stack we need to protect against wraparound
- // if SP is close to zero.
- // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- // CMP $StackPreempt, R1
- // MOVW.NE $StackGuard(SP), R2
- // SUB.NE R1, R2
- // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
- // CMP.NE R3, R2
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_CONST;
- p->from.offset = (uint32)StackPreempt;
- p->reg = 1;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = StackGuard;
- p->to.type = D_REG;
- p->to.reg = 2;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = ASUB;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->to.type = D_REG;
- p->to.reg = 2;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = framesize + (StackGuard - StackSmall);
- p->to.type = D_REG;
- p->to.reg = 3;
- p->scond = C_SCOND_NE;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->reg = 2;
- p->scond = C_SCOND_NE;
- }
-
- // MOVW.LS $framesize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_CONST;
- p->from.offset = framesize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LS $args, R2
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_CONST;
- arg = cursym->text->to.offset2;
- if(arg == 1) // special marker for known 0
- arg = 0;
- if(arg&3)
- diag("misaligned argument size in stack split");
- p->from.offset = arg;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LS R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LS;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LS;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // BLS start
- p = appendp(p);
- p->as = ABLS;
- p->to.type = D_BRANCH;
- p->cond = cursym->text->link;
-
- return p;
-}
-
-static void
-sigdiv(char *n)
-{
- Sym *s;
-
- s = lookup(n, 0);
- if(s->type == STEXT)
- if(s->sig == 0)
- s->sig = SIGNINTERN;
-}
-
-void
-divsig(void)
-{
- sigdiv("_div");
- sigdiv("_divu");
- sigdiv("_mod");
- sigdiv("_modu");
-}
-
-void
-initdiv(void)
-{
- Sym *s2, *s3, *s4, *s5;
-
- if(prog_div != P)
- return;
- sym_div = s2 = lookup("_div", 0);
- sym_divu = s3 = lookup("_divu", 0);
- sym_mod = s4 = lookup("_mod", 0);
- sym_modu = s5 = lookup("_modu", 0);
- prog_div = s2->text;
- prog_divu = s3->text;
- prog_mod = s4->text;
- prog_modu = s5->text;
- if(prog_div == P) {
- diag("undefined: %s", s2->name);
- prog_div = cursym->text;
- }
- if(prog_divu == P) {
- diag("undefined: %s", s3->name);
- prog_divu = cursym->text;
- }
- if(prog_mod == P) {
- diag("undefined: %s", s4->name);
- prog_mod = cursym->text;
- }
- if(prog_modu == P) {
- diag("undefined: %s", s5->name);
- prog_modu = cursym->text;
- }
-}
-
-void
-nocache(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->to.class = 0;
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->addstacksplit(ctxt, s);
}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 80f5787dc..86a0ece2e 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -30,120 +30,24 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/dwarf.h"
#include <ar.h>
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "arm";
-
-Header headers[] = {
- "noheader", Hnoheader,
- "risc", Hrisc,
- "plan9", Hplan9x32,
- "ixp1200", Hixp1200,
- "ipaq", Hipaq,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- 0, 0
-};
-
-/*
- * -Hrisc -T0x10005000 -R4 is aif for risc os
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hixp1200 is IXP1200 (raw)
- * -Hipaq -T0xC0008010 -R1024 is ipaq
- * -Hlinux -Tx -Rx is linux elf
- * -Hfreebsd is freebsd elf
- * -Hnetbsd is netbsd elf
- */
+char *thestring = "arm";
+LinkArch *thelinkarch = &linkarm;
void
-main(int argc, char *argv[])
+linkarchinit(void)
{
- char *p;
- Sym *s;
-
- Binit(&bso, 1, OWRITE);
- listinit();
- nerrors = 0;
- outfile = "5.out";
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- p = getgoarm();
- if(p != nil)
- goarm = atoi(p);
- else
- goarm = 6;
- if(goarm == 5)
- debug['F'] = 1;
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagint32("D", "addr: data address", &INITDAT);
- flagcount("G", "debug pseudo-ops", &debug['G']);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("M", "disable software div/mod", &debug['M']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("P", "debug code generation", &debug['P']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagint32("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- if(flag_shared)
- linkmode = LinkExternal;
-
- mywhatsys();
+}
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
+void
+archinit(void)
+{
+ LSym *s;
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
@@ -158,34 +62,15 @@ main(int argc, char *argv[])
sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
break;
case Hlinux:
+ case Hfreebsd:
break;
}
- libinit();
-
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hnoheader: /* no header */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hrisc: /* aif for risc os */
- HEADR = 128L;
- if(INITTEXT == -1)
- INITTEXT = 0x10005000 + HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hplan9x32: /* plan 9 */
+ case Hplan9: /* plan 9 */
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4128;
@@ -194,30 +79,11 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case Hixp1200: /* boot for IXP1200 */
- HEADR = 0L;
- if(INITTEXT == -1)
- INITTEXT = 0x0;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hipaq: /* boot for ipaq */
- HEADR = 16L;
- if(INITTEXT == -1)
- INITTEXT = 0xC0008010;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 1024;
- break;
case Hlinux: /* arm elf */
case Hfreebsd:
case Hnetbsd:
+ case Hnacl:
debug['d'] = 0; // with dynamic linking
- tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
- // this number is known to ../../pkg/runtime/rt0_*_arm.s
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -231,578 +97,9 @@ main(int argc, char *argv[])
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- zprg.as = AGOK;
- zprg.scond = 14;
- zprg.reg = NREG;
- zprg.from.name = D_NONE;
- zprg.from.type = D_NONE;
- zprg.from.reg = NREG;
- zprg.to = zprg.from;
- buildop();
- histgen = 0;
- pc = 0;
- dtype = 4;
-
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
// embed goarm to runtime.goarm
- s = lookup("runtime.goarm", 0);
- s->dupok = 1;
- adduint8(s, goarm);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
-
- // mark some functions that are only referenced after linker code editing
- if(debug['F'])
- mark(rlookup("_sfloat", 0));
- mark(lookup("runtime.read_tls_fallback", 0));
- deadcode();
- if(textp == nil) {
- diag("no code");
- errorexit();
- }
-
- patch();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- doelf();
- follow();
- softfloat();
- // 5l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- if(debug['Z'])
- dozerostk();
- noops(); // generate stack split prolog, handle div/mod, etc.
- dostkcheck();
- span();
- addexport();
- // textaddress() functionality is handled in span()
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
-
- if(debug['c'])
- print("ARM size = %d\n", armsize);
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o == 0)
- return S;
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int i, c;
- int32 l;
- Sym *s;
- Auto *u;
-
- a->type = BGETC(f);
- a->reg = BGETC(f);
- c = BGETC(f);
- if(c < 0 || c > NSYM){
- print("sym out of range: %d\n", c);
- BPUTC(f, ALAST+1);
- return;
- }
- a->sym = h[c];
- a->name = BGETC(f);
- adrgotype = zsym(pn, f, h);
-
- if((schar)a->reg < 0 || a->reg > NREG) {
- print("register out of range %d\n", a->reg);
- BPUTC(f, ALAST+1);
- return; /* force real diagnostic */
- }
-
- if(a->type == D_CONST || a->type == D_OCONST) {
- if(a->name == D_EXTERN || a->name == D_STATIC) {
- s = a->sym;
- if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
- if(0 && !s->fnptr && s->name[0] != '.')
- print("%s used as function pointer\n", s->name);
- s->fnptr = 1; // over the top cos of SXREF
- }
- }
- }
-
- switch(a->type) {
- default:
- print("unknown type %d\n", a->type);
- BPUTC(f, ALAST+1);
- return; /* force real diagnostic */
-
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
-
- case D_REGREG:
- case D_REGREG2:
- a->offset = BGETC(f);
- break;
-
- case D_CONST2:
- a->offset2 = BGETLE4(f); // fall through
- case D_BRANCH:
- case D_OREG:
- case D_CONST:
- case D_OCONST:
- case D_SHIFT:
- a->offset = BGETLE4(f);
- break;
-
- case D_SCONST:
- a->sval = mal(NSNAME);
- Bread(f, a->sval, NSNAME);
- break;
-
- case D_FCONST:
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- break;
- }
- s = a->sym;
- if(s == S)
- return;
- i = a->name;
- if(i != D_AUTO && i != D_PARAM) {
- if(s && adrgotype)
- s->gotype = adrgotype;
- return;
- }
-
- l = a->offset;
- for(u=curauto; u; u=u->link)
- if(u->asym == s)
- if(u->type == i) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
-
- u = mal(sizeof(Auto));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = i;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- Sym *h[NSYM], *s;
- int v, o, r, skip;
- uint32 sig;
- char *name;
- int ntext;
- int32 eof;
- char src[1024], *x;
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
-
- if(o <= AXXX || o >= ALAST) {
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .5 file\n");
- errorexit();
- }
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h)) {
- fprint(2, "%s: mangled input file\n", pn);
- errorexit();
- }
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(Prog));
- p->as = o;
- p->scond = BGETC(f);
- p->reg = BGETC(f);
- p->line = BGETLE4(f);
-
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
- diag("register out of range %A %d", p->as, p->reg);
-
- p->link = P;
- p->cond = P;
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(o) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s == S) {
- diag("GLOBL must have a name\n%P", p);
- errorexit();
- }
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->value = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("redefinition: %s\n%P", s->name, p);
- s->type = SBSS;
- s->value = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->reg & DUPOK)
- s->dupok = 1;
- if(p->reg & RODATA)
- s->type = SRODATA;
- else if(p->reg & NOPTR)
- s->type = SNOPTRBSS;
- break;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- break;
-
- case AGOK:
- diag("unknown opcode\n%P", p);
- p->pc = pc;
- pc++;
- break;
-
- case ATYPE:
- if(skip)
- goto casedef;
- pc++;
- goto loop;
-
- case ATEXT:
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- s = p->from.sym;
- if(s == S) {
- diag("TEXT must have a name\n%P", p);
- errorexit();
- }
- cursym = s;
- if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
- skip = 1;
- goto casedef;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- skip = 0;
- if(s->type != 0 && s->type != SXREF)
- diag("redefinition: %s\n%P", s->name, p);
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- if(fromgotype) {
- if(s->gotype && s->gotype != fromgotype)
- diag("%s: type mismatch for %s", pn, s->name);
- s->gotype = fromgotype;
- }
- etextp = s;
- p->align = 4;
- autosize = (p->to.offset+3L) & ~3L;
- p->to.offset = autosize;
- autosize += 4;
- s->type = STEXT;
- s->hist = gethist();
- s->text = p;
- s->value = pc;
- s->args = p->to.offset2;
- lastp = p;
- p->pc = pc;
- pc++;
- break;
-
- case ASUB:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = AADD;
- }
- goto casedef;
-
- case AADD:
- if(p->from.type == D_CONST)
- if(p->from.name == D_NONE)
- if(p->from.offset < 0) {
- p->from.offset = -p->from.offset;
- p->as = ASUB;
- }
- goto casedef;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- // case AMOVF:
- // case AMOVD:
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- goto casedef;
-
- case AMOVF:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- case AMOVD:
- if(skip)
- goto casedef;
-
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
- (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_OREG;
- p->from.sym = s;
- p->from.name = D_EXTERN;
- p->from.offset = 0;
- }
- goto casedef;
-
- default:
- casedef:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- break;
- }
- lastp->link = p;
- lastp = p;
- break;
- }
- goto loop;
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
+ s = linklookup(ctxt, "runtime.goarm", 0);
+ s->type = SRODATA;
+ adduint8(ctxt, s, ctxt->goarm);
}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
deleted file mode 100644
index 3d05d6d09..000000000
--- a/src/cmd/5l/optab.c
+++ /dev/null
@@ -1,277 +0,0 @@
-// Inferno utils/5l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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 "l.h"
-
-Optab optab[] =
-{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
-
- { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
- { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
-
- { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
- { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
- { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
-
- { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
- { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
- { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
-
- { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
-
- { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
- { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
- { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
-
- { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
- { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
- { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 },
- { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
- { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
-
- { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
- { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
-
- { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
- { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
-
- { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
- { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
-
- { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
-
- { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
- { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
- { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
-
- { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
- { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
- { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
- { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
- { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
- { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
-
- { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 },
- { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 },
- { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
-
- { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
- { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
-
- { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
- { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
-
- { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
- { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
- { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
-
- { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
- { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
- { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
- { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
-
- { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
- { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
- { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
-
- { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
-
- { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
- { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
-
- { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
- { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
-
- { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
-
- { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
- { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
-
- { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
- { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
-
- { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
- { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
-
- { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
- { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
-
- { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 },
- { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
-
- { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
- { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
-
- { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
- { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
-
- { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
- { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
-
- { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
-
- { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
- { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 },
-
- { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
- { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
- { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
- { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
-
- { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
- { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
- { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
- { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
-
- { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
-
- { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
- { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
-
- { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 },
- { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
-
- { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
- { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
- { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
- { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
-
- { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
- { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
-
- { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
-
- { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
- { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
-
- { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 },
-
- { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 },
-
- { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 },
-
- { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
- { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
-
- { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
- { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 },
- { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 },
-
- { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
-};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
deleted file mode 100644
index cd8897989..000000000
--- a/src/cmd/5l/pass.c
+++ /dev/null
@@ -1,409 +0,0 @@
-// Inferno utils/5l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AB)
- return p;
- p = p->cond;
- }
- return P;
-}
-
-int
-relinv(int a)
-{
- switch(a) {
- case ABEQ: return ABNE;
- case ABNE: return ABEQ;
- case ABCS: return ABCC;
- case ABHS: return ABLO;
- case ABCC: return ABCS;
- case ABLO: return ABHS;
- case ABMI: return ABPL;
- case ABPL: return ABMI;
- case ABVS: return ABVC;
- case ABVC: return ABVS;
- case ABHI: return ABLS;
- case ABLS: return ABHI;
- case ABGE: return ABLT;
- case ABLT: return ABGE;
- case ABGT: return ABLE;
- case ABLE: return ABGT;
- }
- diag("unknown relation: %s", anames[a]);
- return a;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q, *r;
- int a, i;
-
-loop:
- if(p == P)
- return;
- a = p->as;
- if(a == AB) {
- q = p->cond;
- if(q != P && q->as != ATEXT) {
- p->mark |= FOLL;
- p = q;
- if(!(p->mark & FOLL))
- goto loop;
- }
- }
- if(p->mark & FOLL) {
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == *last || q == nil)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
- goto copy;
- if(q->cond == P || (q->cond->mark&FOLL))
- continue;
- if(a != ABEQ && a != ABNE)
- continue;
- copy:
- for(;;) {
- r = prg();
- *r = *p;
- if(!(r->mark&FOLL))
- print("can't happen 1\n");
- r->mark |= FOLL;
- if(p != q) {
- p = p->link;
- (*last)->link = r;
- *last = r;
- continue;
- }
- (*last)->link = r;
- *last = r;
- if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF)
- return;
- r->as = ABNE;
- if(a == ABNE)
- r->as = ABEQ;
- r->cond = p->link;
- r->link = p->cond;
- if(!(r->link->mark&FOLL))
- xfol(r->link, last);
- if(!(r->cond->mark&FOLL))
- print("can't happen 2\n");
- return;
- }
- }
- a = AB;
- q = prg();
- q->as = a;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->cond = p;
- p = q;
- }
- p->mark |= FOLL;
- (*last)->link = p;
- *last = p;
- if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){
- return;
- }
- if(p->cond != P)
- if(a != ABL && a != ABX && p->link != P) {
- q = brchain(p->link);
- if(a != ATEXT && a != ABCASE)
- if(q != P && (q->mark&FOLL)) {
- p->as = relinv(a);
- p->link = p->cond;
- p->cond = q;
- }
- xfol(p->link, last);
- q = brchain(p->cond);
- if(q == P)
- q = p->cond;
- if(q->mark&FOLL) {
- p->cond = q;
- return;
- }
- p = q;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-void
-patch(void)
-{
- int32 c, vexit;
- Prog *p, *q;
- Sym *s;
- int a;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- mkfwd();
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- a = p->as;
- if((a == ABL || a == ABX || a == AB || a == ARET) &&
- p->to.type != D_BRANCH && p->to.sym != S) {
- s = p->to.sym;
- if(s->text == nil)
- continue;
- switch(s->type&SMASK) {
- default:
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- p->to.type = D_BRANCH;
- p->cond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range %d\n%P", c, p);
- p->to.type = D_NONE;
- }
- p->cond = q;
- }
- }
- if(flag_shared) {
- s = lookup("init_array", 0);
- s->type = SINITARR;
- s->reachable = 1;
- s->hide = 1;
- addaddr(s, lookup(INITENTRY, 0));
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->cond != P) {
- p->cond = brloop(p->cond);
- if(p->cond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->cond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- Prog *q;
- int c;
-
- for(c=0; p!=P;) {
- if(p->as != AB)
- return p;
- q = p->cond;
- if(q <= p) {
- c++;
- if(q == p || c > 5000)
- break;
- }
- p = q;
- }
- return P;
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
-void
-dozerostk(void)
-{
- Prog *p, *pl;
- int32 autoffset;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
- if(autoffset && !(p->reg&NOSPLIT)) {
- // MOVW $4(R13), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = 13;
- p->from.offset = 4;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $n(R13), R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = 13;
- p->from.offset = 4 + autoffset;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW $0, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // L:
- // MOVW.P R3, 0(R1) +4
- // CMP R1, R2
- // BNE L
- p = pl = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = 1;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
-
- p = appendp(p);
- p->as = ABNE;
- p->to.type = D_BRANCH;
- p->cond = pl;
- }
- }
-}
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
deleted file mode 100644
index 225a52435..000000000
--- a/src/cmd/5l/prof.c
+++ /dev/null
@@ -1,211 +0,0 @@
-// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->reg = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = n*4 + 4;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_REG;
- p->to.reg = REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGTMP;
- p->to.type = D_OREG;
- p->to.name = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.sym = s;
- q->reg = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(cursym == s2) {
- ps2 = p;
- p->reg = 1;
- }
- if(cursym == s4) {
- ps4 = p;
- p->reg = 1;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->reg & NOPROF) {
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * BL profin, R2
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->cond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * BL profout
- */
- p->as = ABL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->cond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
deleted file mode 100644
index de6481c71..000000000
--- a/src/cmd/5l/softfloat.c
+++ /dev/null
@@ -1,91 +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.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-// Software floating point.
-
-void
-softfloat(void)
-{
- Prog *p, *next, *psfloat;
- Sym *symsfloat;
- int wasfloat;
-
- if(!debug['F'])
- return;
-
- symsfloat = lookup("_sfloat", 0);
- psfloat = P;
- if(symsfloat->type == STEXT)
- psfloat = symsfloat->text;
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- wasfloat = 0;
- for(p = cursym->text; p != P; p = p->link)
- if(p->cond != P)
- p->cond->mark |= LABEL;
- for(p = cursym->text; p != P; p = p->link) {
- switch(p->as) {
- case AMOVW:
- if(p->to.type == D_FREG || p->from.type == D_FREG)
- goto soft;
- goto notsoft;
-
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- case AMOVF:
- case AMOVD:
-
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case ASQRTF:
- case ASQRTD:
- case AABSF:
- case AABSD:
- goto soft;
-
- default:
- goto notsoft;
-
- soft:
- if (psfloat == P)
- diag("floats used with _sfloat not defined");
- if (!wasfloat || (p->mark&LABEL)) {
- next = prg();
- *next = *p;
-
- // BL _sfloat(SB)
- *p = zprg;
- p->link = next;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symsfloat;
- p->cond = psfloat;
- p->line = next->line;
-
- p = next;
- wasfloat = 1;
- }
- break;
-
- notsoft:
- wasfloat = 0;
- }
- }
- }
-}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
deleted file mode 100644
index e7cc0b4b1..000000000
--- a/src/cmd/5l/span.c
+++ /dev/null
@@ -1,937 +0,0 @@
-// Inferno utils/5l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static struct {
- uint32 start;
- uint32 size;
- uint32 extra;
-} pool;
-
-int checkpool(Prog*, int);
-int flushpool(Prog*, int, int);
-
-int
-isbranch(Prog *p)
-{
- int as = p->as;
- return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;
-}
-
-static int
-scan(Prog *op, Prog *p, int c)
-{
- Prog *q;
-
- for(q = op->link; q != p && q != P; q = q->link){
- q->pc = c;
- c += oplook(q)->size;
- nocache(q);
- }
- return c;
-}
-
-/* size of a case statement including jump table */
-static int32
-casesz(Prog *p)
-{
- int jt = 0;
- int32 n = 0;
- Optab *o;
-
- for( ; p != P; p = p->link){
- if(p->as == ABCASE)
- jt = 1;
- else if(jt)
- break;
- o = oplook(p);
- n += o->size;
- }
- return n;
-}
-
-void
-span(void)
-{
- Prog *p, *op;
- Optab *o;
- int m, bflag, i, v;
- int32 c, otxt, out[6];
- Section *sect;
- uchar *bp;
- Sym *sub, *gmsym;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
-
- sect = addsection(&segtext, ".text", 05);
- lookup("text", 0)->sect = sect;
- lookup("etext", 0)->sect = sect;
-
- bflag = 0;
- c = INITTEXT;
- otxt = c;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- cursym->sect = sect;
- p = cursym->text;
- if(p == P || p->link == P) { // handle external functions and ELF section symbols
- if(cursym->type & SSUB)
- continue;
- if(cursym->align != 0)
- c = rnd(c, cursym->align);
- cursym->value = 0;
- for(sub = cursym; sub != S; sub = sub->sub) {
- sub->value += c;
- for(p = sub->text; p != P; p = p->link)
- p->pc += sub->value;
- }
- c += cursym->size;
- continue;
- }
- p->pc = c;
- cursym->value = c;
-
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
-
- for(op = p, p = p->link; p != P; op = p, p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- break;
- }
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- }
- if(blitrl){
- if(checkpool(op, 0))
- c = scan(op, P, c);
- }
- cursym->size = c - cursym->value;
- }
-
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- while(bflag) {
- if(debug['v'])
- Bprint(&bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = INITTEXT;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(!cursym->text || !cursym->text->link)
- continue;
- cursym->value = c;
- for(p = cursym->text; p != P; p = p->link) {
- curp = p;
- p->pc = c;
- o = oplook(p);
-/* very large branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
- }
- }
- */
- m = o->size;
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
- if(p->as == ATEXT) {
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- diag("zero-width instruction\n%P", p);
- continue;
- }
- c += m;
- }
- cursym->size = c - cursym->value;
- }
- }
-
- c = rnd(c, 8);
-
- /*
- * lay out the code. all the pc-relative code references,
- * even cross-function, are resolved now;
- * only data references need to be relocated.
- * with more work we could leave cross-function
- * code references to be relocated too, and then
- * perhaps we'd be able to parallelize the span loop above.
- */
- gmsym = S;
- if(linkmode == LinkExternal)
- gmsym = lookup("runtime.tlsgm", 0);
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p == P || p->link == P)
- continue;
- autosize = p->to.offset + 4;
- symgrow(cursym, cursym->size);
-
- bp = cursym->p;
- for(p = p->link; p != P; p = p->link) {
- pc = p->pc;
- curp = p;
- o = oplook(p);
- asmout(p, o, out, gmsym);
- for(i=0; i<o->size/4; i++) {
- v = out[i];
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp++ = v>>24;
- }
- }
- }
- sect->vaddr = INITTEXT;
- sect->len = c - INITTEXT;
-}
-
-/*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
-int
-checkpool(Prog *p, int sz)
-{
- if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
- return flushpool(p, 1, 0);
- else if(p->link == P)
- return flushpool(p, 2, 0);
- return 0;
-}
-
-int
-flushpool(Prog *p, int skip, int force)
-{
- Prog *q;
-
- if(blitrl) {
- if(skip){
- if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
- q = prg();
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->link;
- q->link = blitrl;
- q->line = p->line;
- blitrl = q;
- }
- else if(!force && (p->pc+pool.size-pool.start < 2048))
- return 0;
- elitrl->link = p->link;
- p->link = blitrl;
- // BUG(minux): how to correctly handle line number for constant pool entries?
- // for now, we set line number to the last instruction preceding them at least
- // this won't bloat the .debug_line tables
- while(blitrl) {
- blitrl->line = p->line;
- blitrl = blitrl->link;
- }
- blitrl = 0; /* BUG: should refer back to values until out-of-range */
- elitrl = 0;
- pool.size = 0;
- pool.start = 0;
- pool.extra = 0;
- return 1;
- }
- return 0;
-}
-
-void
-addpool(Prog *p, Adr *a)
-{
- Prog *q, t;
- int c;
-
- c = aclass(a);
-
- t = zprg;
- t.as = AWORD;
-
- switch(c) {
- default:
- t.to = *a;
- if(flag_shared && t.to.sym != S)
- t.pcrel = p;
- break;
-
- case C_SROREG:
- case C_LOREG:
- case C_ROREG:
- case C_FOREG:
- case C_SOREG:
- case C_HOREG:
- case C_FAUTO:
- case C_SAUTO:
- case C_LAUTO:
- case C_LACON:
- t.to.type = D_CONST;
- t.to.offset = instoffset;
- break;
- }
-
- if(t.pcrel == P) {
- for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
- if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
- p->cond = q;
- return;
- }
- }
-
- q = prg();
- *q = t;
- q->pc = pool.size;
-
- if(blitrl == P) {
- blitrl = q;
- pool.start = p->pc;
- q->align = 4;
- } else
- elitrl->link = q;
- elitrl = q;
- pool.size += 4;
-
- p->cond = q;
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-int32
-regoff(Adr *a)
-{
-
- instoffset = 0;
- aclass(a);
- return instoffset;
-}
-
-int32
-immrot(uint32 v)
-{
- int i;
-
- for(i=0; i<16; i++) {
- if((v & ~0xff) == 0)
- return (i<<8) | v | (1<<25);
- v = (v<<2) | (v>>30);
- }
- return 0;
-}
-
-int32
-immaddr(int32 v)
-{
- if(v >= 0 && v <= 0xfff)
- return (v & 0xfff) |
- (1<<24) | /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xfff && v < 0)
- return (-v & 0xfff) |
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int
-immfloat(int32 v)
-{
- return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
-}
-
-int
-immhalf(int32 v)
-{
- if(v >= 0 && v <= 0xff)
- return v|
- (1<<24)| /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xff && v < 0)
- return (-v & 0xff)|
- (1<<24); /* pre indexing */
- return 0;
-}
-
-int32
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-int
-aclass(Adr *a)
-{
- Sym *s;
- int t;
-
- switch(a->type) {
- case D_NONE:
- return C_NONE;
-
- case D_REG:
- return C_REG;
-
- case D_REGREG:
- return C_REGREG;
-
- case D_REGREG2:
- return C_REGREG2;
-
- case D_SHIFT:
- return C_SHIFT;
-
- case D_FREG:
- return C_FREG;
-
- case D_FPCR:
- return C_FCR;
-
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case D_NONE:
- instoffset = a->offset;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
- return immfloat(t) ? C_HFOREG : C_HOREG;
- if(immfloat(t))
- return C_FOREG; /* n.b. that it will also satisfy immrot */
- t = immrot(instoffset);
- if(t)
- return C_SROREG;
- if(immhalf(instoffset))
- return C_HOREG;
- return C_SOREG;
- }
- t = immrot(instoffset);
- if(t)
- return C_ROREG;
- return C_LOREG;
- }
- return C_GOK;
-
- case D_PSR:
- return C_PSR;
-
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- instoffset = 0; // s.b. unused but just in case
- return C_ADDR;
- }
- return C_GOK;
-
- case D_FCONST:
- if(chipzero(&a->ieee) >= 0)
- return C_ZFCON;
- if(chipfloat(&a->ieee) >= 0)
- return C_SFCON;
- return C_LFCON;
-
- case D_CONST:
- case D_CONST2:
- switch(a->name) {
-
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
-
- t = immrot(instoffset);
- if(t)
- return C_RCON;
- t = immrot(~instoffset);
- if(t)
- return C_NCON;
- return C_LCON;
-
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- instoffset = 0; // s.b. unused but just in case
- return C_LCONADDR;
-
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
-
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- t = immrot(instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
- }
- return C_GOK;
-
- case D_BRANCH:
- return C_SBRA;
- }
- return C_GOK;
-}
-
-Optab*
-oplook(Prog *p)
-{
- int a1, a2, a3, r;
- char *c1, *c3;
- Optab *o, *e;
-
- a1 = p->optab;
- if(a1)
- return optab+(a1-1);
- a1 = p->from.class;
- if(a1 == 0) {
- a1 = aclass(&p->from) + 1;
- p->from.class = a1;
- }
- a1--;
- a3 = p->to.class;
- if(a3 == 0) {
- a3 = aclass(&p->to) + 1;
- p->to.class = a3;
- }
- a3--;
- a2 = C_NONE;
- if(p->reg != NREG)
- a2 = C_REG;
- r = p->as;
- o = oprange[r].start;
- if(o == 0) {
- a1 = opcross[repop[r]][a1][a2][a3];
- if(a1) {
- p->optab = a1+1;
- return optab+a1;
- }
- o = oprange[r].stop; /* just generate an error */
- }
- if(debug['O']) {
- print("oplook %A %O %O %O\n",
- (int)p->as, a1, a2, a3);
- print(" %d %d\n", p->from.type, p->to.type);
- }
- e = oprange[r].stop;
- c1 = xcmp[a1];
- c3 = xcmp[a3];
- for(; o<e; o++)
- if(o->a2 == a2)
- if(c1[o->a1])
- if(c3[o->a3]) {
- p->optab = (o-optab)+1;
- return o;
- }
- diag("illegal combination %A %O %O %O, %d %d",
- p->as, a1, a2, a3, p->from.type, p->to.type);
- prasm(p);
- if(o == 0)
- o = optab;
- return o;
-}
-
-int
-cmp(int a, int b)
-{
-
- if(a == b)
- return 1;
- switch(a) {
- case C_LCON:
- if(b == C_RCON || b == C_NCON)
- return 1;
- break;
- case C_LACON:
- if(b == C_RACON)
- return 1;
- break;
- case C_LFCON:
- if(b == C_ZFCON || b == C_SFCON)
- return 1;
- break;
-
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO;
- case C_FAUTO:
- case C_HAUTO:
- return b == C_HFAUTO;
- case C_SAUTO:
- return cmp(C_HFAUTO, b);
- case C_LAUTO:
- return cmp(C_SAUTO, b);
-
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG;
- case C_FOREG:
- case C_HOREG:
- return b == C_HFOREG;
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b);
- case C_SOREG:
- case C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b);
- case C_LOREG:
- return cmp(C_SROREG, b);
-
- case C_LBRA:
- if(b == C_SBRA)
- return 1;
- break;
-
- case C_HREG:
- return cmp(C_SP, b) || cmp(C_PC, b);
-
- }
- return 0;
-}
-
-int
-ocmp(const void *a1, const void *a2)
-{
- Optab *p1, *p2;
- int n;
-
- p1 = (Optab*)a1;
- p2 = (Optab*)a2;
- n = p1->as - p2->as;
- if(n)
- return n;
- n = p1->a1 - p2->a1;
- if(n)
- return n;
- n = p1->a2 - p2->a2;
- if(n)
- return n;
- n = p1->a3 - p2->a3;
- if(n)
- return n;
- return 0;
-}
-
-void
-buildop(void)
-{
- int i, n, r;
-
- for(i=0; i<C_GOK; i++)
- for(n=0; n<C_GOK; n++)
- xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++) {
- if((optab[n].flag & LPCREL) != 0) {
- if(flag_shared)
- optab[n].size += optab[n].pcrelsiz;
- else
- optab[n].flag &= ~LPCREL;
- }
- }
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
-
- switch(r)
- {
- default:
- diag("unknown op in build: %A", r);
- errorexit();
- case AADD:
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[ASUB] = oprange[r];
- oprange[ARSB] = oprange[r];
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[ARSC] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- break;
- case ACMP:
- oprange[ATEQ] = oprange[r];
- oprange[ACMN] = oprange[r];
- break;
- case AMVN:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case ASLL:
- oprange[ASRL] = oprange[r];
- oprange[ASRA] = oprange[r];
- break;
- case AMUL:
- oprange[AMULU] = oprange[r];
- break;
- case ADIV:
- oprange[AMOD] = oprange[r];
- oprange[AMODU] = oprange[r];
- oprange[ADIVU] = oprange[r];
- break;
- case AMOVW:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- break;
- case ASWPW:
- oprange[ASWPBU] = oprange[r];
- break;
- case AB:
- case ABL:
- case ABX:
- case ABXRET:
- case ASWI:
- case AWORD:
- case AMOVM:
- case ARFE:
- case ATEXT:
- case AUSEFIELD:
- case ACASE:
- case ABCASE:
- case ATYPE:
- break;
- case AADDF:
- oprange[AADDD] = oprange[r];
- oprange[ASUBF] = oprange[r];
- oprange[ASUBD] = oprange[r];
- oprange[AMULF] = oprange[r];
- oprange[AMULD] = oprange[r];
- oprange[ADIVF] = oprange[r];
- oprange[ADIVD] = oprange[r];
- oprange[ASQRTF] = oprange[r];
- oprange[ASQRTD] = oprange[r];
- oprange[AMOVFD] = oprange[r];
- oprange[AMOVDF] = oprange[r];
- oprange[AABSF] = oprange[r];
- oprange[AABSD] = oprange[r];
- break;
-
- case ACMPF:
- oprange[ACMPD] = oprange[r];
- break;
-
- case AMOVF:
- oprange[AMOVD] = oprange[r];
- break;
-
- case AMOVFW:
- oprange[AMOVDW] = oprange[r];
- break;
-
- case AMOVWF:
- oprange[AMOVWD] = oprange[r];
- break;
-
- case AMULL:
- oprange[AMULAL] = oprange[r];
- oprange[AMULLU] = oprange[r];
- oprange[AMULALU] = oprange[r];
- break;
-
- case AMULWT:
- oprange[AMULWB] = oprange[r];
- break;
-
- case AMULAWT:
- oprange[AMULAWB] = oprange[r];
- break;
-
- case AMULA:
- case ALDREX:
- case ASTREX:
- case ALDREXD:
- case ASTREXD:
- case ATST:
- case APLD:
- case AUNDEF:
- case ACLZ:
- case AFUNCDATA:
- case APCDATA:
- break;
- }
- }
-}
-
-/*
-void
-buildrep(int x, int as)
-{
- Opcross *p;
- Optab *e, *s, *o;
- int a1, a2, a3, n;
-
- if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
- diag("assumptions fail in buildrep");
- errorexit();
- }
- repop[as] = x;
- p = (opcross + x);
- s = oprange[as].start;
- e = oprange[as].stop;
- for(o=e-1; o>=s; o--) {
- n = o-optab;
- for(a2=0; a2<2; a2++) {
- if(a2) {
- if(o->a2 == C_NONE)
- continue;
- } else
- if(o->a2 != C_NONE)
- continue;
- for(a1=0; a1<32; a1++) {
- if(!xcmp[a1][o->a1])
- continue;
- for(a3=0; a3<32; a3++)
- if(xcmp[a3][o->a3])
- (*p)[a1][a2][a3] = n;
- }
- }
- }
- oprange[as].start = 0;
-}
-*/
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index 5c7868070..b3fb0bb19 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -29,9 +29,9 @@
// THE SOFTWARE.
#include <bio.h>
+#include <link.h>
#include "../6l/6.out.h"
-
#ifndef EXTERN
#define EXTERN extern
#endif
@@ -45,10 +45,8 @@
typedef struct Sym Sym;
typedef struct Ref Ref;
-typedef struct Gen Gen;
typedef struct Io Io;
-typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Addr2 Addr2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -97,36 +95,11 @@ struct Io
};
#define I ((Io*)0)
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- double dval;
- char sval[8];
- vlong offset;
- Sym* sym;
- short type;
- short index;
- short scale;
-};
-struct Gen2
-{
- Gen from;
- Gen to;
-};
-
-struct Hist
+struct Addr2
{
- Hist* link;
- char* name;
- int32 line;
- vlong offset;
+ Addr from;
+ Addr to;
};
-#define H ((Hist*)0)
enum
{
@@ -136,14 +109,11 @@ enum
CPREPROC,
};
-
-EXTERN char debug[256];
+EXTERN int debug[256];
EXTERN Sym* hash[NHASH];
EXTERN char** Dlist;
EXTERN int nDlist;
-EXTERN Hist* ehist;
EXTERN int newflag;
-EXTERN Hist* hist;
EXTERN char* hunk;
EXTERN char** include;
EXTERN Io* iofree;
@@ -154,10 +124,9 @@ EXTERN int nerrors;
EXTERN int32 nhunk;
EXTERN int ninclude;
EXTERN int32 nsymb;
-EXTERN Gen nullgen;
+EXTERN Addr nullgen;
EXTERN char* outfile;
EXTERN int pass;
-EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
EXTERN int32 stmtline;
@@ -167,6 +136,8 @@ EXTERN int thechar;
EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
+EXTERN Link* ctxt;
+EXTERN Biobuf bstdout;
void* alloc(int32);
void* allocn(void*, int32, int32);
@@ -187,12 +158,11 @@ void cinit(void);
void checkscale(int);
void pinit(char*);
void cclean(void);
-int isreg(Gen*);
-void outcode(int, Gen2*);
+int isreg(Addr*);
+void outcode(int, Addr2*);
void outhist(void);
-void zaddr(Gen*, int);
+void zaddr(Addr*, int);
void zname(char*, int, int);
-void ieeedtod(Ieee*, double);
int filbuf(void);
Sym* getsym(void);
void domacro(void);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index ed72916b2..6fd491067 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -40,8 +40,8 @@
vlong lval;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
+ Addr addr;
+ Addr2 addr2;
}
%left '|'
%left '^'
@@ -58,10 +58,10 @@
%token <sval> LSCONST LSP
%token <sym> LNAME LLAB LVAR
%type <lval> con con2 expr pointer offset
-%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
-%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%type <gen2> spec10 spec11 spec12 spec13
+%type <addr> mem imm imm2 reg nam rel rem rim rom omem nmem
+%type <addr2> nonnon nonrel nonrem rimnon rimrem remrim
+%type <addr2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%type <addr2> spec10 spec11 spec12 spec13
%%
prog:
| prog
@@ -367,14 +367,12 @@ rel:
if(pass == 2)
yyerror("undefined label: %s", $1->name);
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $1->value + $2;
}
@@ -444,31 +442,31 @@ imm:
{
$$ = nullgen;
$$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
+ memcpy($$.u.sval, $2, sizeof($$.u.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = $2;
+ $$.u.dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = $3;
+ $$.u.dval = $3;
}
| '$' '(' '-' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = -$4;
+ $$.u.dval = -$4;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = -$3;
+ $$.u.dval = -$3;
}
mem:
@@ -572,14 +570,14 @@ nam:
{
$$ = nullgen;
$$.type = $4;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 0);
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
$$.type = D_STATIC;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 1);
$$.offset = $4;
}
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index ab34e8220..167e6b6c1 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -57,56 +57,80 @@ pathchar(void)
return '/';
}
+int
+Lconv(Fmt *fp)
+{
+ return linklinefmt(ctxt, fp);
+}
+
+void
+dodef(char *p)
+{
+ if(nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+}
+
+LinkArch* thelinkarch = &linkamd64;
+
+void
+usage(void)
+{
+ print("usage: %ca [options] file.c...\n", thechar);
+ flagprint(1);
+ errorexit();
+}
+
void
main(int argc, char *argv[])
{
char *p;
- int c;
thechar = '6';
thestring = "amd64";
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+ if(strcmp(p, "amd64p32") == 0)
+ thelinkarch = &linkamd64p32;
+
+ ctxt = linknew(thelinkarch);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+ listinit6();
+ fmtinstall('L', Lconv);
+
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
cinit();
outfile = 0;
setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
+
+ flagfn1("D", "name[=value]: add #define", dodef);
+ flagfn1("I", "dir: add dir to include path", setinclude);
+ flagcount("S", "print assembly and machine code", &debug['S']);
+ flagcount("m", "debug preprocessor macros", &debug['m']);
+ flagstr("o", "file: set output file", &outfile);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
+ flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
+ if(argc < 1)
+ usage();
if(argc > 1){
print("can't assemble multiple files\n");
errorexit();
}
+
if(assemble(argv[0]))
errorexit();
+ Bflush(&bstdout);
exits(0);
}
@@ -145,30 +169,22 @@ assemble(char *file)
errorexit();
}
Binit(&obuf, of, OWRITE);
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+ Bprint(&obuf, "!\n");
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
+ for(pass = 1; pass <= 2; pass++) {
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
cclean();
- return nerrors;
+ if(nerrors)
+ return nerrors;
}
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
+ writeobj(ctxt, &obuf);
+ Bflush(&obuf);
+ return 0;
}
struct
@@ -313,6 +329,7 @@ struct
"TR5", LBREG, D_TR+5,
"TR6", LBREG, D_TR+6,
"TR7", LBREG, D_TR+7,
+ "TLS", LSREG, D_TLS,
"AAA", LTYPE0, AAAA,
"AAD", LTYPE0, AAAD,
@@ -503,6 +520,7 @@ struct
"MOVLQZX", LTYPE3, AMOVLQZX,
"MOVNTIL", LTYPE3, AMOVNTIL,
"MOVNTIQ", LTYPE3, AMOVNTIQ,
+ "MOVQL", LTYPE3, AMOVQL,
"MOVWLSX", LTYPE3, AMOVWLSX,
"MOVWLZX", LTYPE3, AMOVWLZX,
"MOVWQSX", LTYPE3, AMOVWQSX,
@@ -1031,15 +1049,8 @@ cinit(void)
Sym *s;
int i;
- nullgen.sym = S;
- nullgen.offset = 0;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
nullgen.type = D_NONE;
nullgen.index = D_NONE;
- nullgen.scale = 0;
nerrors = 0;
iostack = I;
@@ -1055,13 +1066,6 @@ cinit(void)
s->type = itab[i].type;
s->value = itab[i].value;
}
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
}
void
@@ -1089,255 +1093,43 @@ syminit(Sym *s)
void
cclean(void)
{
- Gen2 g2;
+ Addr2 g2;
g2.from = nullgen;
g2.to = nullgen;
outcode(AEND, &g2);
- Bflush(&obuf);
}
-void
-zname(char *n, int t, int s)
-{
-
- BPUTLE2(&obuf, ANAME); /* as(2) */
- BPUTC(&obuf, t); /* type */
- BPUTC(&obuf, s); /* sym */
- while(*n) {
- BPUTC(&obuf, *n);
- n++;
- }
- BPUTC(&obuf, 0);
-}
+static Prog *lastpc;
void
-zaddr(Gen *a, int s)
+outcode(int a, Addr2 *g2)
{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_NONE:
- break;
- }
- BPUTC(&obuf, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(&obuf, a->index);
- BPUTC(&obuf, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(&obuf, l);
- if(t & T_64) {
- l = a->offset>>32;
- BPUTLE4(&obuf, l);
- }
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(&obuf, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- BPUTLE4(&obuf, l);
- l = e.h;
- BPUTLE4(&obuf, l);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(&obuf, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(&obuf, a->type);
-}
-
-void
-outcode(int a, Gen2 *g2)
-{
- int sf, st, t;
- Sym *s;
-
+ Prog *p;
+ Plist *pl;
+
if(pass == 1)
goto out;
-jackpot:
- sf = 0;
- s = g2->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g2->from.type;
- if(t == D_ADDR)
- t = g2->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->to.type;
- if(t == D_ADDR)
- t = g2->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- BPUTLE2(&obuf, a);
- BPUTLE4(&obuf, stmtline);
- zaddr(&g2->from, sf);
- zaddr(&g2->to, st);
+ p = malloc(sizeof *p);
+ memset(p, 0, sizeof *p);
+ p->as = a;
+ p->lineno = stmtline;
+ p->from = g2->from;
+ p->to = g2->to;
+ p->pc = pc;
+
+ if(lastpc == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastpc->link = p;
+ lastpc = p;
out:
if(a != AGLOBL && a != ADATA)
pc++;
}
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
-
- g = nullgen;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTLE2(&obuf, ANAME);
- BPUTC(&obuf, D_FILE); /* type */
- BPUTC(&obuf, 1); /* sym */
- BPUTC(&obuf, '<');
- Bwrite(&obuf, p, n);
- BPUTC(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- BPUTLE2(&obuf, AHISTORY);
- BPUTLE4(&obuf, h->line);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
#include "../cc/lexbody"
#include "../cc/macbody"
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
index 3e5058b9d..a4f0f74cc 100644
--- a/src/cmd/6a/y.tab.c
+++ b/src/cmd/6a/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,51 +55,11 @@
/* Pure parsers. */
#define YYPURE 0
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
/* Using locations. */
#define YYLSP_NEEDED 0
-/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../pkg/runtime/funcdata.h"
-
-
-/* Line 268 of yacc.c */
-#line 80 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -180,36 +143,60 @@
+/* Copy the first part of user declarations. */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../pkg/runtime/funcdata.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 293 of yacc.c */
#line 38 "a.y"
-
+{
Sym *sym;
vlong lval;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
-
-
-
-/* Line 293 of yacc.c */
-#line 201 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+ Addr addr;
+ Addr2 addr2;
+}
+/* Line 193 of yacc.c. */
+#line 187 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
+
/* Copy the second part of user declarations. */
-/* Line 343 of yacc.c */
-#line 213 "y.tab.c"
+/* Line 216 of yacc.c. */
+#line 200 "y.tab.c"
#ifdef short
# undef short
@@ -284,14 +271,14 @@ typedef short int yytype_int16;
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -312,11 +299,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -339,24 +326,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -372,9 +359,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -385,27 +372,6 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
@@ -423,7 +389,24 @@ union yyalloc
while (YYID (0))
# endif
# endif
-#endif /* !YYCOPY_NEEDED */
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
@@ -564,13 +547,13 @@ static const yytype_uint16 yyrline[] =
166, 173, 178, 183, 190, 198, 203, 211, 216, 223,
224, 227, 232, 242, 247, 257, 262, 267, 274, 282,
292, 296, 303, 308, 316, 325, 336, 337, 340, 341,
- 342, 346, 350, 351, 354, 355, 358, 364, 373, 382,
- 387, 392, 397, 402, 407, 412, 418, 426, 432, 443,
- 449, 455, 461, 467, 475, 476, 479, 485, 491, 497,
- 503, 512, 521, 530, 535, 540, 548, 558, 562, 571,
- 578, 587, 590, 594, 600, 601, 605, 608, 609, 613,
- 617, 621, 625, 631, 636, 641, 646, 653, 654, 658,
- 662, 666, 670, 674, 678, 682, 686, 690
+ 342, 346, 350, 351, 354, 355, 358, 364, 372, 380,
+ 385, 390, 395, 400, 405, 410, 416, 424, 430, 441,
+ 447, 453, 459, 465, 473, 474, 477, 483, 489, 495,
+ 501, 510, 519, 528, 533, 538, 546, 556, 560, 569,
+ 576, 585, 588, 592, 598, 599, 603, 606, 607, 611,
+ 615, 619, 623, 629, 634, 639, 644, 651, 652, 656,
+ 660, 664, 668, 672, 676, 680, 684, 688
};
#endif
@@ -586,12 +569,11 @@ static const char *const yytname[] =
"LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG",
"LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
"LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'",
- "$accept", "prog", "$@1", "line", "$@2", "$@3", "inst", "nonnon",
- "rimrem", "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2",
- "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10",
- "spec11", "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2",
- "imm", "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2",
- "expr", 0
+ "$accept", "prog", "@1", "line", "@2", "@3", "inst", "nonnon", "rimrem",
+ "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3",
+ "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11",
+ "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2", "imm",
+ "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2", "expr", 0
};
#endif
@@ -647,8 +629,8 @@ static const yytype_uint8 yyr2[] =
3, 3, 3, 4, 4, 3, 3, 3
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
@@ -739,7 +721,8 @@ static const yytype_int16 yypgoto[] =
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
- number is the opposite. If YYTABLE_NINF, syntax error. */
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
static const yytype_uint16 yytable[] =
{
@@ -802,12 +785,6 @@ static const yytype_uint16 yytable[] =
177
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-94))
-
-#define yytable_value_is_error(yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
10, 10, 13, 13, 10, 13, 66, 67, 10, 10,
@@ -915,18 +892,9 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -936,6 +904,7 @@ do \
{ \
yychar = (Token); \
yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK (1); \
goto yybackup; \
} \
@@ -977,10 +946,19 @@ while (YYID (0))
#endif
-/* This macro is provided for backward compatibility. */
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
@@ -1084,20 +1062,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1131,11 +1106,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1172,6 +1147,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1274,142 +1250,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
- about the unexpected token YYTOKEN for the state stack whose top is
- YYSSP.
-
- Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
- not large enough to hold the message. In that case, also set
- *YYMSG_ALLOC to the required number of bytes. Return 2 if the
- required number of bytes is too large to store. */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = 0;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yychar) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yychar.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (yytoken != YYEMPTY)
- {
- int yyn = yypact[*yyssp];
- yyarg[yycount++] = yytname[yytoken];
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yyx;
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
+ int yyn = yypact[yystate];
- switch (yycount)
- {
-# define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
- if (*yymsg_alloc < yysize)
- {
- *yymsg_alloc = 2 * yysize;
- if (! (yysize <= *yymsg_alloc
- && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
- *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
- return 1;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- {
- char *yyp = *yymsg;
- int yyi = 0;
- while ((*yyp = *yyformat) != '\0')
- if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyformat += 2;
- }
- else
- {
- yyp++;
- yyformat++;
- }
- }
- return 0;
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -1441,9 +1390,10 @@ yydestruct (yymsg, yytype, yyvaluep)
break;
}
}
-
+
/* Prevent warnings from -Wmissing-prototypes. */
+
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
@@ -1459,16 +1409,18 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-/* The lookahead symbol. */
+
+/* The look-ahead symbol. */
int yychar;
-/* The semantic value of the lookahead symbol. */
+/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -1495,37 +1447,14 @@ yyparse ()
#endif
#endif
{
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
+
+ int yystate;
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
@@ -1533,28 +1462,51 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
+
yyssp = yyss;
yyvsp = yyvs;
@@ -1584,6 +1536,7 @@ yyparse ()
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
+
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
@@ -1591,6 +1544,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -1613,8 +1567,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1625,6 +1580,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1634,9 +1590,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -1645,16 +1598,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -1680,22 +1633,26 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
*++yyvsp = yylval;
@@ -1735,8 +1692,6 @@ yyreduce:
switch (yyn)
{
case 3:
-
-/* Line 1806 of yacc.c */
#line 68 "a.y"
{
stmtline = lineno;
@@ -1744,8 +1699,6 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
#line 75 "a.y"
{
if((yyvsp[(1) - (2)].sym)->value != pc)
@@ -1755,8 +1708,6 @@ yyreduce:
break;
case 7:
-
-/* Line 1806 of yacc.c */
#line 82 "a.y"
{
(yyvsp[(1) - (2)].sym)->type = LLAB;
@@ -1765,8 +1716,6 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
#line 93 "a.y"
{
(yyvsp[(1) - (3)].sym)->type = LVAR;
@@ -1775,8 +1724,6 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
#line 98 "a.y"
{
if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
@@ -1786,622 +1733,490 @@ yyreduce:
break;
case 14:
-
-/* Line 1806 of yacc.c */
#line 103 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 15:
-
-/* Line 1806 of yacc.c */
#line 104 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 16:
-
-/* Line 1806 of yacc.c */
#line 105 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 17:
-
-/* Line 1806 of yacc.c */
#line 106 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 18:
-
-/* Line 1806 of yacc.c */
#line 107 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 19:
-
-/* Line 1806 of yacc.c */
#line 108 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 20:
-
-/* Line 1806 of yacc.c */
#line 109 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 21:
-
-/* Line 1806 of yacc.c */
#line 110 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 22:
-
-/* Line 1806 of yacc.c */
#line 111 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 23:
-
-/* Line 1806 of yacc.c */
#line 112 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 24:
-
-/* Line 1806 of yacc.c */
#line 113 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 25:
-
-/* Line 1806 of yacc.c */
#line 114 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 26:
-
-/* Line 1806 of yacc.c */
#line 115 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 27:
-
-/* Line 1806 of yacc.c */
#line 116 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 28:
-
-/* Line 1806 of yacc.c */
#line 117 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 29:
-
-/* Line 1806 of yacc.c */
#line 118 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 30:
-
-/* Line 1806 of yacc.c */
#line 119 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 31:
-
-/* Line 1806 of yacc.c */
#line 120 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 32:
-
-/* Line 1806 of yacc.c */
#line 121 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 33:
-
-/* Line 1806 of yacc.c */
#line 124 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = nullgen;
}
break;
case 34:
-
-/* Line 1806 of yacc.c */
#line 129 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = nullgen;
}
break;
case 35:
-
-/* Line 1806 of yacc.c */
#line 136 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 36:
-
-/* Line 1806 of yacc.c */
#line 143 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 37:
-
-/* Line 1806 of yacc.c */
#line 150 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 38:
-
-/* Line 1806 of yacc.c */
#line 155 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 39:
-
-/* Line 1806 of yacc.c */
#line 162 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 40:
-
-/* Line 1806 of yacc.c */
#line 167 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 41:
-
-/* Line 1806 of yacc.c */
#line 174 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 42:
-
-/* Line 1806 of yacc.c */
#line 179 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 43:
-
-/* Line 1806 of yacc.c */
#line 184 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 44:
-
-/* Line 1806 of yacc.c */
#line 191 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 45:
-
-/* Line 1806 of yacc.c */
#line 199 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 46:
-
-/* Line 1806 of yacc.c */
#line 204 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 47:
-
-/* Line 1806 of yacc.c */
#line 212 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 48:
-
-/* Line 1806 of yacc.c */
#line 217 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 51:
-
-/* Line 1806 of yacc.c */
#line 228 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 52:
-
-/* Line 1806 of yacc.c */
#line 233 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- if((yyval.gen2).from.index != D_NONE)
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ if((yyval.addr2).from.index != D_NONE)
yyerror("dp shift with lhs index");
- (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
}
break;
case 53:
-
-/* Line 1806 of yacc.c */
#line 243 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 54:
-
-/* Line 1806 of yacc.c */
#line 248 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- if((yyval.gen2).to.index != D_NONE)
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ if((yyval.addr2).to.index != D_NONE)
yyerror("dp move with lhs index");
- (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
}
break;
case 55:
-
-/* Line 1806 of yacc.c */
#line 258 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 56:
-
-/* Line 1806 of yacc.c */
#line 263 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 57:
-
-/* Line 1806 of yacc.c */
#line 268 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 58:
-
-/* Line 1806 of yacc.c */
#line 275 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- (yyval.gen2).to.offset = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
}
break;
case 59:
-
-/* Line 1806 of yacc.c */
#line 283 "a.y"
{
- (yyval.gen2).from = (yyvsp[(3) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
- if((yyvsp[(1) - (5)].gen).type != D_CONST)
+ (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+ if((yyvsp[(1) - (5)].addr).type != D_CONST)
yyerror("illegal constant");
- (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset;
+ (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
}
break;
case 60:
-
-/* Line 1806 of yacc.c */
#line 292 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = nullgen;
}
break;
case 61:
-
-/* Line 1806 of yacc.c */
#line 297 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 62:
-
-/* Line 1806 of yacc.c */
#line 304 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 63:
-
-/* Line 1806 of yacc.c */
#line 309 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 64:
-
-/* Line 1806 of yacc.c */
#line 317 "a.y"
{
- if((yyvsp[(1) - (3)].gen).type != D_CONST || (yyvsp[(3) - (3)].gen).type != D_CONST)
+ if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 65:
-
-/* Line 1806 of yacc.c */
#line 326 "a.y"
{
- if((yyvsp[(1) - (3)].gen).type != D_CONST)
+ if((yyvsp[(1) - (3)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(3) - (3)].gen).type != D_EXTERN && (yyvsp[(3) - (3)].gen).type != D_STATIC)
+ if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
yyerror("value for FUNCDATA must be symbol reference");
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 70:
-
-/* Line 1806 of yacc.c */
#line 343 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
case 71:
-
-/* Line 1806 of yacc.c */
#line 347 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
case 76:
-
-/* Line 1806 of yacc.c */
#line 359 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
}
break;
case 77:
-
-/* Line 1806 of yacc.c */
#line 365 "a.y"
{
- (yyval.gen) = nullgen;
+ (yyval.addr) = nullgen;
if(pass == 2)
yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 78:
-
-/* Line 1806 of yacc.c */
-#line 374 "a.y"
+#line 373 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 383 "a.y"
+#line 381 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 80:
-
-/* Line 1806 of yacc.c */
-#line 388 "a.y"
+#line 386 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 81:
-
-/* Line 1806 of yacc.c */
-#line 393 "a.y"
+#line 391 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 82:
-
-/* Line 1806 of yacc.c */
-#line 398 "a.y"
+#line 396 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 83:
-
-/* Line 1806 of yacc.c */
-#line 403 "a.y"
+#line 401 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SP;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SP;
}
break;
case 84:
-
-/* Line 1806 of yacc.c */
-#line 408 "a.y"
+#line 406 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 85:
-
-/* Line 1806 of yacc.c */
-#line 413 "a.y"
+#line 411 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 86:
-
-/* Line 1806 of yacc.c */
-#line 419 "a.y"
+#line 417 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST;
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 87:
-
-/* Line 1806 of yacc.c */
-#line 427 "a.y"
+#line 425 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST;
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 88:
-
-/* Line 1806 of yacc.c */
-#line 433 "a.y"
+#line 431 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
- (yyval.gen).index = (yyvsp[(2) - (2)].gen).type;
- (yyval.gen).type = D_ADDR;
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
+ (yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
+ (yyval.addr).type = D_ADDR;
/*
if($2.type == D_AUTO || $2.type == D_PARAM)
yyerror("constant cannot be automatic: %s",
@@ -2411,322 +2226,262 @@ yyreduce:
break;
case 89:
-
-/* Line 1806 of yacc.c */
-#line 444 "a.y"
+#line 442 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SCONST;
- memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SCONST;
+ memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
}
break;
case 90:
-
-/* Line 1806 of yacc.c */
-#line 450 "a.y"
+#line 448 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
}
break;
case 91:
-
-/* Line 1806 of yacc.c */
-#line 456 "a.y"
+#line 454 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = (yyvsp[(3) - (4)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
}
break;
case 92:
-
-/* Line 1806 of yacc.c */
-#line 462 "a.y"
+#line 460 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = -(yyvsp[(4) - (5)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
}
break;
case 93:
-
-/* Line 1806 of yacc.c */
-#line 468 "a.y"
+#line 466 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
}
break;
case 96:
-
-/* Line 1806 of yacc.c */
-#line 480 "a.y"
+#line 478 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
}
break;
case 97:
-
-/* Line 1806 of yacc.c */
-#line 486 "a.y"
+#line 484 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 98:
-
-/* Line 1806 of yacc.c */
-#line 492 "a.y"
+#line 490 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_SP;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_SP;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 99:
-
-/* Line 1806 of yacc.c */
-#line 498 "a.y"
+#line 496 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 100:
-
-/* Line 1806 of yacc.c */
-#line 504 "a.y"
+#line 502 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).offset = (yyvsp[(1) - (6)].lval);
- (yyval.gen).index = (yyvsp[(3) - (6)].lval);
- (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
+ (yyval.addr).index = (yyvsp[(3) - (6)].lval);
+ (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 101:
-
-/* Line 1806 of yacc.c */
-#line 513 "a.y"
+#line 511 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
- (yyval.gen).index = (yyvsp[(6) - (9)].lval);
- (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.addr).index = (yyvsp[(6) - (9)].lval);
+ (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 102:
-
-/* Line 1806 of yacc.c */
-#line 522 "a.y"
+#line 520 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
- (yyval.gen).index = (yyvsp[(6) - (9)].lval);
- (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.addr).index = (yyvsp[(6) - (9)].lval);
+ (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 103:
-
-/* Line 1806 of yacc.c */
-#line 531 "a.y"
+#line 529 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
}
break;
case 104:
-
-/* Line 1806 of yacc.c */
-#line 536 "a.y"
+#line 534 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_SP;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_SP;
}
break;
case 105:
-
-/* Line 1806 of yacc.c */
-#line 541 "a.y"
+#line 539 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).index = (yyvsp[(2) - (5)].lval);
- (yyval.gen).scale = (yyvsp[(4) - (5)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).index = (yyvsp[(2) - (5)].lval);
+ (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 106:
-
-/* Line 1806 of yacc.c */
-#line 549 "a.y"
+#line 547 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
- (yyval.gen).index = (yyvsp[(5) - (8)].lval);
- (yyval.gen).scale = (yyvsp[(7) - (8)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+ (yyval.addr).index = (yyvsp[(5) - (8)].lval);
+ (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 107:
-
-/* Line 1806 of yacc.c */
-#line 559 "a.y"
+#line 557 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (1)].gen);
+ (yyval.addr) = (yyvsp[(1) - (1)].addr);
}
break;
case 108:
-
-/* Line 1806 of yacc.c */
-#line 563 "a.y"
+#line 561 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (6)].gen);
- (yyval.gen).index = (yyvsp[(3) - (6)].lval);
- (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = (yyvsp[(1) - (6)].addr);
+ (yyval.addr).index = (yyvsp[(3) - (6)].lval);
+ (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 109:
-
-/* Line 1806 of yacc.c */
-#line 572 "a.y"
+#line 570 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(4) - (5)].lval);
- (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(4) - (5)].lval);
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
+ (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
}
break;
case 110:
-
-/* Line 1806 of yacc.c */
-#line 579 "a.y"
+#line 577 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_STATIC;
- (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
- (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_STATIC;
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
+ (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
}
break;
case 111:
-
-/* Line 1806 of yacc.c */
-#line 587 "a.y"
+#line 585 "a.y"
{
(yyval.lval) = 0;
}
break;
case 112:
-
-/* Line 1806 of yacc.c */
-#line 591 "a.y"
+#line 589 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 113:
-
-/* Line 1806 of yacc.c */
-#line 595 "a.y"
+#line 593 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 115:
-
-/* Line 1806 of yacc.c */
-#line 602 "a.y"
+#line 600 "a.y"
{
(yyval.lval) = D_AUTO;
}
break;
case 118:
-
-/* Line 1806 of yacc.c */
-#line 610 "a.y"
+#line 608 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
case 119:
-
-/* Line 1806 of yacc.c */
-#line 614 "a.y"
+#line 612 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 120:
-
-/* Line 1806 of yacc.c */
-#line 618 "a.y"
+#line 616 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 121:
-
-/* Line 1806 of yacc.c */
-#line 622 "a.y"
+#line 620 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
case 122:
-
-/* Line 1806 of yacc.c */
-#line 626 "a.y"
+#line 624 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
case 123:
-
-/* Line 1806 of yacc.c */
-#line 632 "a.y"
+#line 630 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
((vlong)ArgsSizeUnknown << 32);
@@ -2734,9 +2489,7 @@ yyreduce:
break;
case 124:
-
-/* Line 1806 of yacc.c */
-#line 637 "a.y"
+#line 635 "a.y"
{
(yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
((vlong)ArgsSizeUnknown << 32);
@@ -2744,9 +2497,7 @@ yyreduce:
break;
case 125:
-
-/* Line 1806 of yacc.c */
-#line 642 "a.y"
+#line 640 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
@@ -2754,9 +2505,7 @@ yyreduce:
break;
case 126:
-
-/* Line 1806 of yacc.c */
-#line 647 "a.y"
+#line 645 "a.y"
{
(yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
(((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
@@ -2764,112 +2513,80 @@ yyreduce:
break;
case 128:
-
-/* Line 1806 of yacc.c */
-#line 655 "a.y"
+#line 653 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
case 129:
-
-/* Line 1806 of yacc.c */
-#line 659 "a.y"
+#line 657 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
case 130:
-
-/* Line 1806 of yacc.c */
-#line 663 "a.y"
+#line 661 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
case 131:
-
-/* Line 1806 of yacc.c */
-#line 667 "a.y"
+#line 665 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
case 132:
-
-/* Line 1806 of yacc.c */
-#line 671 "a.y"
+#line 669 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
case 133:
-
-/* Line 1806 of yacc.c */
-#line 675 "a.y"
+#line 673 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
case 134:
-
-/* Line 1806 of yacc.c */
-#line 679 "a.y"
+#line 677 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
case 135:
-
-/* Line 1806 of yacc.c */
-#line 683 "a.y"
+#line 681 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
case 136:
-
-/* Line 1806 of yacc.c */
-#line 687 "a.y"
+#line 685 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
case 137:
-
-/* Line 1806 of yacc.c */
-#line 691 "a.y"
+#line 689 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
break;
-
-/* Line 1806 of yacc.c */
-#line 2860 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 2588 "y.tab.c"
default: break;
}
- /* User semantic actions sometimes alter yychar, and that requires
- that yytoken be updated with the new translation. We take the
- approach of translating immediately before every use of yytoken.
- One alternative is translating here after every semantic action,
- but that translation would be missed if the semantic action invokes
- YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
- if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
- incorrect destructor might then be invoked immediately. In the
- case of YYERROR or YYBACKUP, subsequent parser actions might lead
- to an incorrect destructor call or verbose syntax error message
- before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -2878,6 +2595,7 @@ yyreduce:
*++yyvsp = yyval;
+
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -2897,10 +2615,6 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -2908,36 +2622,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char const *yymsgp = YY_("syntax error");
- int yysyntax_error_status;
- yysyntax_error_status = YYSYNTAX_ERROR;
- if (yysyntax_error_status == 0)
- yymsgp = yymsg;
- else if (yysyntax_error_status == 1)
- {
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
- if (!yymsg)
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- yysyntax_error_status = 2;
- }
- else
- {
- yysyntax_error_status = YYSYNTAX_ERROR;
- yymsgp = yymsg;
- }
- }
- yyerror (yymsgp);
- if (yysyntax_error_status == 2)
- goto yyexhaustedlab;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -2945,7 +2660,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -2962,7 +2677,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -2996,7 +2711,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -3019,6 +2734,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
@@ -3043,7 +2761,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -3054,14 +2772,9 @@ yyexhaustedlab:
#endif
yyreturn:
- if (yychar != YYEMPTY)
- {
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = YYTRANSLATE (yychar);
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h
index bba6081dc..e0eb5e12c 100644
--- a/src/cmd/6a/y.tab.h
+++ b/src/cmd/6a/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,11 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -116,28 +118,22 @@
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 2068 of yacc.c */
#line 38 "a.y"
-
+{
Sym *sym;
vlong lval;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
-
-
-
-/* Line 2068 of yacc.c */
-#line 135 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+ Addr addr;
+ Addr2 addr2;
+}
+/* Line 1529 of yacc.c. */
+#line 132 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
index c466a3afe..a196e55a8 100644
--- a/src/cmd/6c/gc.h
+++ b/src/cmd/6c/gc.h
@@ -46,11 +46,8 @@
#define SZ_DOUBLE 8
#define FNX 100
-typedef struct Adr Adr;
-typedef struct Prog Prog;
typedef struct Case Case;
typedef struct C1 C1;
-typedef struct Var Var;
typedef struct Reg Reg;
typedef struct Rgn Rgn;
typedef struct Renv Renv;
@@ -64,29 +61,9 @@ EXTERN struct
short ptr;
} idx;
-struct Adr
-{
- vlong offset;
- double dval;
- char sval[NSNAME];
-
- Sym* sym;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Adr*)0)
-
#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- short as;
-};
+
+#define A ((Addr*)0)
#define P ((Prog*)0)
struct Case
@@ -105,14 +82,6 @@ struct C1
int32 label;
};
-struct Var
-{
- vlong offset;
- Sym* sym;
- char name;
- char etype;
-};
-
struct Reg
{
int32 pc;
@@ -171,7 +140,6 @@ EXTERN Node vconstnode;
EXTERN int32 continpc;
EXTERN int32 curarg;
EXTERN int32 cursafe;
-EXTERN Prog* firstp;
EXTERN Prog* lastp;
EXTERN int32 maxargsafe;
EXTERN int mnstring;
@@ -226,7 +194,6 @@ EXTERN Reg* firstr;
EXTERN Reg* lastr;
EXTERN Reg zreg;
EXTERN Reg* freer;
-EXTERN Var var[NVAR];
EXTERN int32* idom;
EXTERN Reg** rpo2r;
EXTERN int32 maxnr;
@@ -282,7 +249,7 @@ void regaalloc1(Node*, Node*);
void regaalloc(Node*, Node*);
void regind(Node*, Node*);
void gprep(Node*, Node*);
-void naddr(Node*, Adr*);
+void naddr(Node*, Addr*);
void gcmp(int, Node*, vlong);
void gmove(Node*, Node*);
void gins(int a, Node*, Node*);
@@ -310,19 +277,11 @@ void nullwarn(Node*, Node*);
void sextern(Sym*, Node*, int32, int32);
void gextern(Sym*, Node*, int32, int32);
void outcode(void);
-void ieeedtod(Ieee*, double);
/*
* list
*/
void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Rconv(Fmt*);
-int Xconv(Fmt*);
-int Bconv(Fmt*);
/*
* reg.c
@@ -331,7 +290,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
+Bits mkvar(Reg*, Addr*);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
@@ -339,7 +298,7 @@ uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
-void addreg(Adr*, int);
+void addreg(Addr*, int);
/*
* peep.c
@@ -348,17 +307,17 @@ void peep(void);
void excise(Reg*);
Reg* uniqp(Reg*);
Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
+int regtyp(Addr*);
+int anyvar(Addr*);
int subprop(Reg*);
int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
+int copy1(Addr*, Addr*, Reg*, int);
+int copyu(Prog*, Addr*, Addr*);
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
+int copyas(Addr*, Addr*);
+int copyau(Addr*, Addr*);
+int copysub(Addr*, Addr*, Addr*, int);
+int copysub1(Prog*, Addr*, Addr*, int);
int32 RtoB(int);
int32 FtoB(int);
@@ -396,14 +355,6 @@ void mulgen(Type*, Node*, Node*);
void genmuladd(Node*, Node*, int, Node*);
void shiftit(Type*, Node*, Node*);
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "lD" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-
#define D_X7 (D_X0+7)
void fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
index b5a60ac9a..28f5b8df7 100644
--- a/src/cmd/6c/list.c
+++ b/src/cmd/6c/list.c
@@ -34,358 +34,5 @@
void
listinit(void)
{
-
- fmtinstall('A', Aconv);
- fmtinstall('B', Bconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%lld", var[i].offset);
- s = ss;
- } else
- s = var[i].sym->name;
- if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
- break;
- strcat(str, s);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- switch(p->as) {
- case ADATA:
- sprint(str, "(%L) %A %D/%d,%D",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
-
- case ATEXT:
- if(p->from.scale) {
- sprint(str, "(%L) %A %D,%d,%lD",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "(%L) %A %D,%D",
- p->lineno, p->as, &p->from, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
-
- if(fp->flags & FmtLong) {
- if(i == D_CONST)
- sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
- else {
- // ATEXT dst is not constant
- sprint(str, "!!%D", a);
- }
- goto brk;
- }
-
- if(i >= D_INDIR) {
- if(a->offset)
- sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
- else
- sprint(str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
- default:
- if(a->offset)
- sprint(str, "$%lld,%R", a->offset, i);
- else
- sprint(str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- sprint(str, "%lld", a->offset);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
- break;
-
- case D_AUTO:
- if(a->sym)
- sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(SP)", a->offset);
- break;
-
- case D_PARAM:
- if(a->sym)
- sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
- else
- sprint(str, "%lld(FP)", a->offset);
- break;
-
- case D_CONST:
- sprint(str, "$%lld", a->offset);
- break;
-
- case D_FCONST:
- sprint(str, "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- sprint(str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
+ listinit6();
}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
index 0a3bd84bc..a11067c84 100644
--- a/src/cmd/6c/peep.c
+++ b/src/cmd/6c/peep.c
@@ -276,7 +276,7 @@ uniqs(Reg *r)
}
int
-regtyp(Adr *a)
+regtyp(Addr *a)
{
int t;
@@ -306,7 +306,7 @@ int
subprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
int t;
@@ -445,7 +445,7 @@ int
copyprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
p = r0->prog;
@@ -459,7 +459,7 @@ copyprop(Reg *r0)
}
int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
{
int t;
Prog *p;
@@ -544,7 +544,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f)
* 0 otherwise (not touched)
*/
int
-copyu(Prog *p, Adr *v, Adr *s)
+copyu(Prog *p, Addr *v, Addr *s)
{
switch(p->as) {
@@ -835,7 +835,7 @@ copyu(Prog *p, Adr *v, Adr *s)
* semantics
*/
int
-copyas(Adr *a, Adr *v)
+copyas(Addr *a, Addr *v)
{
if(a->type != v->type)
return 0;
@@ -851,7 +851,7 @@ copyas(Adr *a, Adr *v)
* either direct or indirect
*/
int
-copyau(Adr *a, Adr *v)
+copyau(Addr *a, Addr *v)
{
if(copyas(a, v))
@@ -870,7 +870,7 @@ copyau(Adr *a, Adr *v)
* return failure to substitute
*/
int
-copysub(Adr *a, Adr *v, Adr *s, int f)
+copysub(Addr *a, Addr *v, Addr *s, int f)
{
int t;
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
index edd93a0a0..348d747b7 100644
--- a/src/cmd/6c/reg.c
+++ b/src/cmd/6c/reg.c
@@ -663,8 +663,10 @@ brk:
r1 = 0; /* set */
for(r = firstr; r != R; r = r->link) {
p = r->prog;
- if(p->to.type == D_BRANCH)
+ if(p->to.type == D_BRANCH) {
p->to.offset = r->s2->pc;
+ p->to.u.branch = r->s2->prog;
+ }
r1 = r;
}
@@ -691,7 +693,7 @@ void
addmove(Reg *r, int bn, int rn, int f)
{
Prog *p, *p1;
- Adr *a;
+ Addr *a;
Var *v;
p1 = alloc(sizeof(*p1));
@@ -715,7 +717,7 @@ addmove(Reg *r, int bn, int rn, int f)
p1->as = AMOVB;
if(v->etype == TSHORT || v->etype == TUSHORT)
p1->as = AMOVW;
- if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+ if(v->etype == TVLONG || v->etype == TUVLONG || (v->etype == TIND && ewidth[TIND] == 8))
p1->as = AMOVQ;
if(v->etype == TFLOAT)
p1->as = AMOVSS;
@@ -759,13 +761,13 @@ doregbits(int r)
}
Bits
-mkvar(Reg *r, Adr *a)
+mkvar(Reg *r, Addr *a)
{
Var *v;
int i, t, n, et, z;
int32 o;
Bits bit;
- Sym *s;
+ LSym *s;
/*
* mark registers used
@@ -792,7 +794,7 @@ mkvar(Reg *r, Adr *a)
break;
}
s = a->sym;
- if(s == S)
+ if(s == nil)
goto none;
if(s->name[0] == '.')
goto none;
@@ -1181,7 +1183,7 @@ uint32
regset(Reg *r, uint32 bb)
{
uint32 b, set;
- Adr v;
+ Addr v;
int c;
set = 0;
@@ -1202,7 +1204,7 @@ uint32
reguse(Reg *r, uint32 bb)
{
uint32 b, set;
- Adr v;
+ Addr v;
int c;
set = 0;
@@ -1349,7 +1351,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
}
void
-addreg(Adr *a, int rn)
+addreg(Addr *a, int rn)
{
a->sym = 0;
@@ -1371,6 +1373,8 @@ BtoR(int32 b)
{
b &= 0xffffL;
+ if(nacl)
+ b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
if(b == 0)
return 0;
return bitno(b) + D_AX;
@@ -1459,10 +1463,11 @@ fixjmp(Reg *firstr)
for(r=firstr; r; r=r->link) {
p = r->prog;
if(debug['R'] && debug['v'])
- print("%04d %P\n", r->pc, p);
+ print("%04d %P\n", (int)r->pc, p);
if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
r->s2 = chasejmp(r->s2, &jmploop);
p->to.offset = r->s2->pc;
+ p->to.u.branch = r->s2->prog;
if(debug['R'] && debug['v'])
print("->%P\n", p);
}
@@ -1483,7 +1488,7 @@ fixjmp(Reg *firstr)
// Let it stay.
} else {
if(debug['R'] && debug['v'])
- print("del %04d %P\n", r->pc, p);
+ print("del %04d %P\n", (int)r->pc, p);
p->as = ANOP;
}
}
@@ -1496,7 +1501,7 @@ fixjmp(Reg *firstr)
p = r->prog;
if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
if(debug['R'] && debug['v'])
- print("del %04d %P\n", r->pc, p);
+ print("del %04d %P\n", (int)r->pc, p);
p->as = ANOP;
}
}
@@ -1517,7 +1522,7 @@ fixjmp(Reg *firstr)
if(debug['R'] && debug['v']) {
print("\n");
for(r=firstr; r; r=r->link)
- print("%04d %P\n", r->pc, r->prog);
+ print("%04d %P\n", (int)r->pc, r->prog);
print("\n");
}
}
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
index 744a60222..ba1c1f652 100644
--- a/src/cmd/6c/sgen.c
+++ b/src/cmd/6c/sgen.c
@@ -207,7 +207,7 @@ xcom(Node *n)
n->addable = 8;
break;
}
- if(n->addable == 8 && !side(n)) {
+ if(n->addable == 8 && !side(n) && !nacl) {
indx(n);
l = new1(OINDEX, idx.basetree, idx.regtree);
l->scale = idx.scale;
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 2496da477..d7713648d 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -164,7 +164,7 @@ outstring(char *s, int32 n)
p->from.offset += nstring - NSNAME;
p->from.scale = NSNAME;
p->to.type = D_SCONST;
- memmove(p->to.sval, string, NSNAME);
+ memmove(p->to.u.sval, string, NSNAME);
mnstring = 0;
}
n--;
@@ -185,7 +185,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w)
p->from.offset += o+e;
p->from.scale = lw;
p->to.type = D_SCONST;
- memmove(p->to.sval, a->cstring+e, lw);
+ memmove(p->to.u.sval, a->cstring+e, lw);
}
}
@@ -215,30 +215,12 @@ gextern(Sym *s, Node *a, int32 o, int32 w)
}
}
-void zname(Biobuf*, Sym*, int);
-void zaddr(Biobuf*, Adr*, int);
-void outhist(Biobuf*);
-
void
outcode(void)
{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int f, sf, st, t, sym;
+ int f;
Biobuf b;
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
-
f = open(outfile, OWRITE);
if(f < 0) {
diag(Z, "cannot open %s", outfile);
@@ -246,7 +228,7 @@ outcode(void)
}
Binit(&b, f, OWRITE);
- Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
if(pragcgobuf.to > pragcgobuf.start) {
Bprint(&b, "\n");
Bprint(&b, "$$ // exports\n\n");
@@ -257,261 +239,12 @@ outcode(void)
}
Bprint(&b, "!\n");
- outhist(&b);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.type;
- if(t == D_ADDR)
- t = p->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.type;
- if(t == D_ADDR)
- t = p->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- BPUTLE2(&b, p->as);
- BPUTLE4(&b, p->lineno);
- zaddr(&b, &p->from, sf);
- zaddr(&b, &p->to, st);
- }
+ writeobj(ctxt, &b);
Bterm(&b);
close(f);
- firstp = P;
lastp = P;
}
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTLE2(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- BPUTLE2(b, pg.as);
- BPUTLE4(b, pg.lineno);
- zaddr(b, &pg.from, 0);
- zaddr(b, &pg.to, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n;
- uint32 sig;
-
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- BPUTLE2(b, ASIGNAME);
- BPUTLE4(b, sig);
- s->sig = SIGDONE;
- }
- else{
- BPUTLE2(b, ANAME); /* as */
- }
- BPUTC(b, t); /* type */
- BPUTC(b, s->sym); /* sym */
- n = s->name;
- while(*n) {
- BPUTC(b, *n);
- n++;
- }
- BPUTC(b, 0);
-}
-
-void
-zaddr(Biobuf *b, Adr *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- case D_NONE:
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- BPUTC(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(b, a->index);
- BPUTC(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(b, l);
- if(t & T_64) {
- l = a->offset>>32;
- BPUTLE4(b, l);
- }
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- l = e.l;
- BPUTLE4(b, l);
- l = e.h;
- BPUTLE4(b, l);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(b, a->type);
-}
-
int32
align(int32 i, Type *t, int op, int32 *maxalign)
{
@@ -559,6 +292,21 @@ align(int32 i, Type *t, int op, int32 *maxalign)
break;
case Aarg1: /* initial align of parameter */
+ if(ewidth[TIND] == 4) {
+ if(typesu[t->etype]) {
+ for(v = t->link; v != T; v = v->down)
+ o = align(o, v, Aarg1, maxalign);
+ goto out;
+ }
+ w = ewidth[t->etype];
+ if(typev[t->etype] || t->etype == TDOUBLE)
+ w = 8;
+ else if(w <= 0 || w >= 4)
+ w = 4;
+ else
+ w = 1;
+ break;
+ }
w = ewidth[t->etype];
if(w <= 0 || w >= SZ_VLONG) {
w = SZ_VLONG;
@@ -569,6 +317,10 @@ align(int32 i, Type *t, int op, int32 *maxalign)
case Aarg2: /* width of a parameter */
o += t->width;
+ if(ewidth[TIND] == 4) {
+ o = align(o, t, Aarg1, maxalign);
+ goto out;
+ }
w = t->width;
if(w > SZ_VLONG)
w = SZ_VLONG;
@@ -582,6 +334,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
o = xround(o, w);
if(maxalign && *maxalign < w)
*maxalign = w;
+out:
if(debug['A'])
print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index 6f5d42da5..4d07436c3 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -30,15 +30,27 @@
#include "gc.h"
+int thechar = '6';
+char *thestring = "amd64";
+
+LinkArch *thelinkarch = &linkamd64;
+
+void
+linkarchinit(void)
+{
+ if(strcmp(getgoarch(), "amd64p32") == 0)
+ thelinkarch = &linkamd64p32;
+}
+
void
ginit(void)
{
int i;
Type *t;
- thechar = '6';
- thestring = "amd64";
- dodefine("_64BIT");
+ dodefine("_64BITREG");
+ if(ewidth[TIND] == 8)
+ dodefine("_64BIT");
listinit();
nstring = 0;
mnstring = 0;
@@ -47,7 +59,6 @@ ginit(void)
breakpc = -1;
continpc = -1;
cases = C;
- firstp = P;
lastp = P;
tfield = types[TINT];
@@ -129,6 +140,10 @@ ginit(void)
if(i >= D_X0 && i <= D_X7)
reg[i] = 0;
}
+ if(nacl) {
+ reg[D_BP] = 1;
+ reg[D_R15] = 1;
+ }
}
void
@@ -138,6 +153,10 @@ gclean(void)
Sym *s;
reg[D_SP]--;
+ if(nacl) {
+ reg[D_BP]--;
+ reg[D_R15]--;
+ }
for(i=D_AX; i<=D_R15; i++)
if(reg[i])
diag(Z, "reg %R left allocated", i);
@@ -168,17 +187,18 @@ gclean(void)
void
nextpc(void)
{
+ Plist *pl;
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
+ p->pc = pc;
pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
+ if(lastp == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastp->link = p;
lastp = p;
}
@@ -441,7 +461,7 @@ regaalloc1(Node *n, Node *nn)
return;
}
nodreg(n, nn, REGARG);
- reg[REGARG]++;
+ reg[(uchar)REGARG]++;
curarg = align(curarg, nn->type, Aarg1, nil);
curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
@@ -474,7 +494,7 @@ regind(Node *n, Node *nn)
}
void
-naddr(Node *n, Adr *a)
+naddr(Node *n, Addr *a)
{
int32 v;
@@ -489,11 +509,11 @@ naddr(Node *n, Adr *a)
case OREGISTER:
a->type = n->reg;
- a->sym = S;
+ a->sym = nil;
break;
case OEXREG:
- a->type = D_INDIR + D_GS;
+ a->type = D_INDIR + D_TLS;
a->offset = n->reg - 1;
break;
@@ -534,14 +554,14 @@ naddr(Node *n, Adr *a)
case OINDREG:
a->type = n->reg+D_INDIR;
- a->sym = S;
+ a->sym = nil;
a->offset = n->xoffset;
break;
case ONAME:
a->etype = n->etype;
a->type = D_STATIC;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
@@ -562,12 +582,12 @@ naddr(Node *n, Adr *a)
case OCONST:
if(typefd[n->type->etype]) {
a->type = D_FCONST;
- a->dval = n->fconst;
+ a->u.dval = n->fconst;
break;
}
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
- if(typev[n->type->etype] || n->type->etype == TIND)
+ if(typev[n->type->etype] || (n->type->etype == TIND && ewidth[TIND] == 8))
a->offset = n->vconst;
else
a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
@@ -630,6 +650,12 @@ gmove(Node *f, Node *t)
ft = f->type->etype;
tt = t->type->etype;
+ if(ewidth[TIND] == 4) {
+ if(ft == TIND)
+ ft = TUINT;
+ if(tt == TIND)
+ tt = TUINT;
+ }
t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
if(debug['M'])
print("gop: %O %O[%s],%O[%s]\n", OAS,
@@ -721,6 +747,8 @@ gmove(Node *f, Node *t)
goto ld;
case TIND:
a = AMOVQ;
+ if(ewidth[TIND] == 4)
+ a = AMOVL;
ld:
regalloc(&nod, f, t);
@@ -1226,6 +1254,8 @@ gopcode(int o, Type *ty, Node *f, Node *t)
et = TLONG;
if(ty != T)
et = ty->etype;
+ if(et == TIND && ewidth[TIND] == 4)
+ et = TUINT;
if(debug['M']) {
if(f != Z && f->type != T)
print("gop: %O %O[%s],", o, f->op, tnames[et]);
@@ -1487,9 +1517,10 @@ gbranch(int o)
void
patch(Prog *op, int32 pc)
{
-
op->to.offset = pc;
op->to.type = D_BRANCH;
+ op->to.u.branch = nil;
+ op->pcond = nil;
}
void
@@ -1499,7 +1530,7 @@ gpseudo(int a, Sym *s, Node *n)
nextpc();
p->as = a;
p->from.type = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
switch(a) {
case ATEXT:
@@ -1561,7 +1592,7 @@ exreg(Type *t)
if(exregoffset >= 64)
return 0;
o = exregoffset;
- exregoffset += 8;
+ exregoffset += ewidth[TIND];
return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
}
return 0;
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index ada2baa81..4dd505b08 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -247,6 +247,7 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
+ case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
@@ -813,6 +814,7 @@ agen(Node *n, Node *res)
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
+ gvardef(&n1);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(ALEAQ, &n1, &n2);
@@ -1060,6 +1062,12 @@ bgen(Node *n, int true, int likely, Prog *to)
}
nr = N;
+ while(n->op == OCONVNOP) {
+ n = n->left;
+ if(n->ninit != nil)
+ genlist(n->ninit);
+ }
+
switch(n->op) {
default:
def:
@@ -1337,6 +1345,8 @@ sgen(Node *n, Node *ns, int64 w)
{
Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp;
vlong c, q, odst, osrc;
+ NodeList *l;
+ Prog *p;
if(debug['g']) {
print("\nsgen w=%lld\n", w);
@@ -1349,6 +1359,13 @@ sgen(Node *n, Node *ns, int64 w)
if(w < 0)
fatal("sgen copy %lld", w);
+
+ // If copying .args, that's all the results, so record definition sites
+ // for them for the liveness analysis.
+ if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0)
+ for(l = curfn->dcl; l != nil; l = l->next)
+ if(l->n->class == PPARAMOUT)
+ gvardef(l->n);
// Avoid taking the address for simple enough types.
if(componentgen(n, ns))
@@ -1380,11 +1397,16 @@ sgen(Node *n, Node *ns, int64 w)
if(n->ullman >= ns->ullman) {
agenr(n, &nodr, N);
+ if(ns->op == ONAME)
+ gvardef(ns);
agenr(ns, &nodl, N);
} else {
+ if(ns->op == ONAME)
+ gvardef(ns);
agenr(ns, &nodl, N);
agenr(n, &nodr, N);
}
+
nodreg(&noddi, types[tptr], D_DI);
nodreg(&nodsi, types[tptr], D_SI);
gmove(&nodl, &noddi);
@@ -1403,23 +1425,23 @@ sgen(Node *n, Node *ns, int64 w)
// reverse direction
gins(ASTD, N, N); // set direction flag
if(c > 0) {
- gconreg(AADDQ, w-1, D_SI);
- gconreg(AADDQ, w-1, D_DI);
+ gconreg(addptr, w-1, D_SI);
+ gconreg(addptr, w-1, D_DI);
- gconreg(AMOVQ, c, D_CX);
+ gconreg(movptr, c, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
}
if(q > 0) {
if(c > 0) {
- gconreg(AADDQ, -7, D_SI);
- gconreg(AADDQ, -7, D_DI);
+ gconreg(addptr, -7, D_SI);
+ gconreg(addptr, -7, D_DI);
} else {
- gconreg(AADDQ, w-8, D_SI);
- gconreg(AADDQ, w-8, D_DI);
+ gconreg(addptr, w-8, D_SI);
+ gconreg(addptr, w-8, D_DI);
}
- gconreg(AMOVQ, q, D_CX);
+ gconreg(movptr, q, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)-
}
@@ -1427,23 +1449,48 @@ sgen(Node *n, Node *ns, int64 w)
gins(ACLD, N, N);
} else {
// normal direction
- if(q >= 4) {
- gconreg(AMOVQ, q, D_CX);
+ if(q > 128 || (nacl && q >= 4)) {
+ gconreg(movptr, q, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
+ } else if (q >= 4) {
+ p = gins(ADUFFCOPY, N, N);
+ p->to.type = D_ADDR;
+ p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
+ // 14 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s
+ p->to.offset = 14*(128-q);
} else
while(q > 0) {
gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
q--;
}
-
- if(c >= 4) {
- gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
- c -= 4;
- }
- while(c > 0) {
- gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
- c--;
+ // copy the remaining c bytes
+ if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) {
+ while(c > 0) {
+ gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
+ c--;
+ }
+ } else if(w < 8 || c <= 4) {
+ nodsi.op = OINDREG;
+ noddi.op = OINDREG;
+ nodsi.type = types[TINT32];
+ noddi.type = types[TINT32];
+ if(c > 4) {
+ nodsi.xoffset = 0;
+ noddi.xoffset = 0;
+ gmove(&nodsi, &noddi);
+ }
+ nodsi.xoffset = c-4;
+ noddi.xoffset = c-4;
+ gmove(&nodsi, &noddi);
+ } else {
+ nodsi.op = OINDREG;
+ noddi.op = OINDREG;
+ nodsi.type = types[TINT64];
+ noddi.type = types[TINT64];
+ nodsi.xoffset = c-8;
+ noddi.xoffset = c-8;
+ gmove(&nodsi, &noddi);
}
}
@@ -1513,7 +1560,7 @@ componentgen(Node *nr, Node *nl)
fatal("componentgen: not a TFIELD: %lT", t);
fldcount++;
}
- if(fldcount == 0 || fldcount > 3)
+ if(fldcount == 0 || fldcount > 4)
goto no;
break;
@@ -1538,10 +1585,19 @@ componentgen(Node *nr, Node *nl)
freer = 1;
}
}
+
+ // nl and nr are 'cadable' which basically means they are names (variables) now.
+ // If they are the same variable, don't generate any code, because the
+ // VARDEF we generate will mark the old value as dead incorrectly.
+ // (And also the assignments are useless.)
+ if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
+ goto yes;
switch(nl->type->etype) {
case TARRAY:
// componentgen for arrays.
+ if(nl->op == ONAME)
+ gvardef(nl);
t = nl->type;
if(!isslice(t)) {
nodl.type = t->type;
@@ -1591,6 +1647,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TSTRING:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
@@ -1614,6 +1672,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TINTER:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
@@ -1637,6 +1697,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TSTRUCT:
+ if(nl->op == ONAME)
+ gvardef(nl);
loffset = nodl.xoffset;
roffset = nodr.xoffset;
// funarg structs may not begin at offset zero.
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 526c04c06..1d32c5a61 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -8,9 +8,22 @@
int thechar = '6';
char* thestring = "amd64";
+LinkArch* thelinkarch = &linkamd64;
+
+void
+linkarchinit(void)
+{
+ if(strcmp(getgoarch(), "amd64p32") == 0)
+ thelinkarch = &linkamd64p32;
+}
vlong MAXWIDTH = 1LL<<50;
+int addptr = AADDQ;
+int movptr = AMOVQ;
+int leaptr = ALEAQ;
+int cmpptr = ACMPQ;
+
/*
* go declares several platform-specific type aliases:
* int, uint, float, and uintptr
@@ -28,6 +41,19 @@ betypeinit(void)
{
widthptr = 8;
widthint = 8;
+ widthreg = 8;
+ if(strcmp(getgoarch(), "amd64p32") == 0) {
+ widthptr = 4;
+ widthint = 4;
+ addptr = AADDL;
+ movptr = AMOVL;
+ leaptr = ALEAL;
+ cmpptr = ACMPL;
+ typedefs[0].sameas = TINT32;
+ typedefs[1].sameas = TUINT32;
+ typedefs[2].sameas = TUINT32;
+
+ }
zprog.link = P;
zprog.as = AGOK;
@@ -36,5 +62,5 @@ betypeinit(void)
zprog.from.scale = 0;
zprog.to = zprog.from;
- listinit();
+ listinit6();
}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 3ef59c788..a5da17d61 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -9,56 +9,25 @@
#include "../gc/go.h"
#include "../6l/6.out.h"
-typedef struct Addr Addr;
-
-struct Addr
-{
- vlong offset;
-
- union {
- double dval;
- vlong vval;
- Prog* branch;
- char sval[NSNAME];
- } u;
-
- Sym* gotype;
- Sym* sym;
- Node* node;
- int64 width;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- short as; // opcode
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Addr from; // src address
- Addr to; // dst address
- Prog* link; // next instruction in this func
- void* opt; // for optimizer passes
-};
-
#define TEXTFLAG from.scale
EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
-extern char* anames[];
EXTERN Prog zprog;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
+EXTERN Node* panicdiv;
EXTERN Node* throwreturn;
extern vlong unmappedzero;
+extern int addptr;
+extern int cmpptr;
+extern int movptr;
+extern int leaptr;
/*
* ggen.c
@@ -150,14 +119,6 @@ void datagostring(Strlit*, Addr*);
/*
* list.c
*/
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
-
-#pragma varargck type "D" Addr*
-#pragma varargck type "lD" Addr*
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 9fad9f7f1..c385798f2 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -9,59 +9,110 @@
#include "gg.h"
#include "opt.h"
-static Prog* appendp(Prog*, int, int, vlong, int, vlong);
+static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
+static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
void
-defframe(Prog *ptxt, Bvec *bv)
+defframe(Prog *ptxt)
{
- int i, j;
- uint32 frame;
+ uint32 frame, ax;
Prog *p;
+ vlong hi, lo;
+ NodeList *l;
+ Node *n;
// fill in argument size
ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
ptxt->to.offset <<= 32;
- frame = rnd(stksize+maxarg, widthptr);
+ frame = rnd(stksize+maxarg, widthreg);
ptxt->to.offset |= frame;
-
- // insert code to clear pointered part of the frame,
- // so that garbage collector only sees initialized values
+
+ // insert code to zero ambiguously live variables
+ // so that the garbage collector only sees initialized values
// when it looks for pointers.
p = ptxt;
- if(stkzerosize >= 8*widthptr) {
- p = appendp(p, AMOVQ, D_CONST, 0, D_AX, 0);
- p = appendp(p, AMOVQ, D_CONST, stkzerosize/widthptr, D_CX, 0);
- p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0);
- p = appendp(p, AREP, D_NONE, 0, D_NONE, 0);
- appendp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
- } else {
- j = (stkptrsize - stkzerosize)/widthptr * 2;
- for(i=0; i<stkzerosize; i+=widthptr) {
- if(bvget(bv, j) || bvget(bv, j+1))
- p = appendp(p, AMOVQ, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
- j += 2;
+ lo = hi = 0;
+ ax = 0;
+ // iterate through declarations - they are sorted in decreasing xoffset order.
+ for(l=curfn->dcl; l != nil; l = l->next) {
+ n = l->n;
+ if(!n->needzero)
+ continue;
+ if(n->class != PAUTO)
+ fatal("needzero class %d", n->class);
+ if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
+ fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
+
+ if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
+ // merge with range we already have
+ lo = n->xoffset;
+ continue;
}
+ // zero old range
+ p = zerorange(p, frame, lo, hi, &ax);
+
+ // set new range
+ hi = n->xoffset + n->type->width;
+ lo = n->xoffset;
}
+ // zero final range
+ zerorange(p, frame, lo, hi, &ax);
}
static Prog*
-appendp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
+zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
+{
+ vlong cnt, i;
+
+ cnt = hi - lo;
+ if(cnt == 0)
+ return p;
+ if(*ax == 0) {
+ p = appendpp(p, AMOVQ, D_CONST, 0, D_AX, 0);
+ *ax = 1;
+ }
+ if(cnt % widthreg != 0) {
+ // should only happen with nacl
+ if(cnt % widthptr != 0)
+ fatal("zerorange count not a multiple of widthptr %d", cnt);
+ p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo);
+ lo += widthptr;
+ cnt -= widthptr;
+ }
+ if(cnt <= 4*widthreg) {
+ for(i = 0; i < cnt; i += widthreg) {
+ p = appendpp(p, AMOVQ, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
+ }
+ } else if(!nacl && (cnt <= 128*widthreg)) {
+ p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 2*(128-cnt/widthreg));
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ } else {
+ p = appendpp(p, AMOVQ, D_CONST, cnt/widthreg, D_CX, 0);
+ p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
+ p = appendpp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
+ }
+ return p;
+}
+
+static Prog*
+appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
{
Prog *q;
-
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
+ q = mal(sizeof(*q));
+ clearp(q);
+ q->as = as;
+ q->lineno = p->lineno;
+ q->from.type = ftype;
+ q->from.offset = foffset;
+ q->to.type = ttype;
+ q->to.offset = toffset;
+ q->link = p->link;
+ p->link = q;
+ return q;
}
// Sweep the prog list to mark any used nodes.
@@ -69,13 +120,13 @@ void
markautoused(Prog* p)
{
for (; p; p = p->link) {
- if (p->as == ATYPE)
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
continue;
- if (p->from.type == D_AUTO && p->from.node)
+ if (p->from.node)
p->from.node->used = 1;
- if (p->to.type == D_AUTO && p->to.node)
+ if (p->to.node)
p->to.node->used = 1;
}
}
@@ -91,6 +142,16 @@ fixautoused(Prog *p)
*lp = p->link;
continue;
}
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ p->to.type = D_NONE;
+ p->to.node = N;
+ p->as = ANOP;
+ continue;
+ }
if (p->from.type == D_AUTO && p->from.node)
p->from.offset += p->from.node->stkdelta;
@@ -179,17 +240,21 @@ ginscall(Node *f, int proc)
case 1: // call in new proc (go)
case 2: // deferred call (defer)
- nodreg(&reg, types[TINT64], D_CX);
- if(flag_largemodel) {
- regalloc(&r1, f->type, f);
+ nodconst(&con, types[TINT64], argsize(f->type));
+ if(widthptr == 4) {
+ nodreg(&r1, types[TINT32], D_CX);
gmove(f, &r1);
- gins(APUSHQ, &r1, N);
- regfree(&r1);
+ nodreg(&reg, types[TINT64], D_CX);
+ nodconst(&r1, types[TINT64], 32);
+ gins(ASHLQ, &r1, &reg);
+ gins(AORQ, &con, &reg);
+ gins(APUSHQ, &reg, N);
} else {
- gins(APUSHQ, f, N);
+ nodreg(&reg, types[TINT64], D_CX);
+ gmove(f, &reg);
+ gins(APUSHQ, &reg, N);
+ gins(APUSHQ, &con, N);
}
- nodconst(&con, types[TINT32], argsize(f->type));
- gins(APUSHQ, &con, N);
if(proc == 1)
ginscall(newproc, 0);
else {
@@ -197,12 +262,16 @@ ginscall(Node *f, int proc)
fatal("hasdefer=0 but has defer");
ginscall(deferproc, 0);
}
+ nodreg(&reg, types[TINT64], D_CX);
gins(APOPQ, N, &reg);
- gins(APOPQ, N, &reg);
+ if(widthptr == 8)
+ gins(APOPQ, N, &reg);
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTQ, &reg, &reg);
- patch(gbranch(AJNE, T, -1), retpc);
+ p = gbranch(AJEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
}
break;
}
@@ -386,11 +455,11 @@ cgen_aret(Node *n, Node *res)
if(res->op != OREGISTER) {
regalloc(&nod2, types[tptr], res);
- gins(ALEAQ, &nod1, &nod2);
- gins(AMOVQ, &nod2, res);
+ gins(leaptr, &nod1, &nod2);
+ gins(movptr, &nod2, res);
regfree(&nod2);
} else
- gins(ALEAQ, &nod1, res);
+ gins(leaptr, &nod1, res);
}
/*
@@ -402,15 +471,15 @@ cgen_ret(Node *n)
{
Prog *p;
- genlist(n->list); // copy out args
- if(hasdefer || curfn->exit) {
- gjmp(retpc);
- return;
- }
+ if(n != N)
+ genlist(n->list); // copy out args
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ genlist(curfn->exit);
p = gins(ARET, N, N);
- if(n->op == ORETJMP) {
+ if(n != N && n->op == ORETJMP) {
p->to.type = D_EXTERN;
- p->to.sym = n->left->sym;
+ p->to.sym = linksym(n->left->sym);
}
}
@@ -633,6 +702,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
}
p2 = P;
+ if(nacl) {
+ // Native Client does not relay the divide-by-zero trap
+ // to the executing program, so we must insert a check
+ // for ourselves.
+ nodconst(&n4, t, 0);
+ gins(optoas(OCMP, t), &n3, &n4);
+ p1 = gbranch(optoas(ONE, t), T, +1);
+ if(panicdiv == N)
+ panicdiv = sysfunc("panicdivide");
+ ginscall(panicdiv, -1);
+ patch(p1, pc);
+ }
if(check) {
nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n3, &n4);
@@ -1025,13 +1106,13 @@ void
clearfat(Node *nl)
{
int64 w, c, q;
- Node n1, oldn1, ax, oldax;
+ Node n1, oldn1, ax, oldax, di, z;
+ Prog *p;
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
-
w = nl->type->width;
// Avoid taking the address for simple enough types.
if(componentgen(N, nl))
@@ -1044,22 +1125,41 @@ clearfat(Node *nl)
agen(nl, &n1);
savex(D_AX, &ax, &oldax, N, types[tptr]);
- gconreg(AMOVQ, 0, D_AX);
+ gconreg(AMOVL, 0, D_AX);
- if(q >= 4) {
- gconreg(AMOVQ, q, D_CX);
+ if(q > 128 || (q >= 4 && nacl)) {
+ gconreg(movptr, q, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
+ } else if(q >= 4) {
+ p = gins(ADUFFZERO, N, N);
+ p->to.type = D_ADDR;
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ // 2 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s
+ p->to.offset = 2*(128-q);
} else
while(q > 0) {
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
q--;
}
- if(c >= 4) {
- gconreg(AMOVQ, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
+ z = ax;
+ di = n1;
+ if(w >= 8 && c >= 4) {
+ di.op = OINDREG;
+ di.type = z.type = types[TINT64];
+ p = gins(AMOVQ, &z, &di);
+ p->to.scale = 1;
+ p->to.offset = c-8;
+ } else if(c >= 4) {
+ di.op = OINDREG;
+ di.type = z.type = types[TINT32];
+ p = gins(AMOVL, &z, &di);
+ if(c > 4) {
+ p = gins(AMOVL, &z, &di);
+ p->to.scale = 1;
+ p->to.offset = c-4;
+ }
} else
while(c > 0) {
gins(ASTOSB, N, N); // STOB AL,*(DI)+
@@ -1095,9 +1195,9 @@ expandchecks(Prog *firstp)
p->link = p1;
p1->lineno = p->lineno;
p2->lineno = p->lineno;
- p1->loc = 9999;
- p2->loc = 9999;
- p->as = ACMPQ;
+ p1->pc = 9999;
+ p2->pc = 9999;
+ p->as = cmpptr;
p->to.type = D_CONST;
p->to.offset = 0;
p1->as = AJNE;
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index a9bd5e833..04e837b13 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -32,231 +32,6 @@
#include <libc.h>
#include "gg.h"
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- BPUTLE2(b, ANAME); /* as */
- BPUTC(b, t); /* type */
- BPUTC(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- BPUTLE2(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- BPUTLE2(b, AHISTORY);
- BPUTLE4(b, line);
- zaddr(b, &zprog.from, 0, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s, int gotype)
-{
- int32 l;
- uint64 e;
- int i, t;
- char *n;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
- if(gotype != 0)
- t |= T_GOTYPE;
-
- switch(a->type) {
-
- case D_BRANCH:
- if(a->u.branch == nil)
- fatal("unpatched branch");
- a->offset = a->u.branch->loc;
-
- default:
- t |= T_TYPE;
-
- case D_NONE:
- if(a->offset != 0) {
- t |= T_OFFSET;
- l = a->offset;
- if((vlong)l != a->offset)
- t |= T_64;
- }
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- BPUTC(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(b, a->index);
- BPUTC(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(b, l);
- if(t & T_64) {
- l = a->offset>>32;
- BPUTLE4(b, l);
- }
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->u.dval);
- BPUTLE4(b, e);
- BPUTLE4(b, e >> 32);
- return;
- }
- if(t & T_SCONST) {
- n = a->u.sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(b, a->type);
- if(t & T_GOTYPE)
- BPUTC(b, gotype);
-}
-
-static struct {
- struct { Sym *sym; short type; } h[NSYM];
- int sym;
-} z;
-
-static void
-zsymreset(void)
-{
- for(z.sym=0; z.sym<NSYM; z.sym++) {
- z.h[z.sym].sym = S;
- z.h[z.sym].type = 0;
- }
- z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
- int i;
-
- *new = 0;
- if(s == S)
- return 0;
-
- i = s->sym;
- if(i < 0 || i >= NSYM)
- i = 0;
- if(z.h[i].type == t && z.h[i].sym == s)
- return i;
- i = z.sym;
- s->sym = i;
- zname(bout, s, t);
- z.h[i].sym = s;
- z.h[i].type = t;
- if(++z.sym >= NSYM)
- z.sym = 1;
- *new = 1;
- return i;
-}
-
-static int
-zsymaddr(Addr *a, int *new)
-{
- int t;
-
- t = a->type;
- if(t == D_ADDR)
- t = a->index;
- return zsym(a->sym, t, new);
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, gf, gt, new;
- Sym *s;
- Prog *p;
-
- zsymreset();
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- // -S prints code; -SS prints code and data
- if(debug['S'] && (pl->name || debug['S']>1)) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- for(;;) {
- sf = zsymaddr(&p->from, &new);
- gf = zsym(p->from.gotype, D_EXTERN, &new);
- if(new && sf == gf)
- continue;
- st = zsymaddr(&p->to, &new);
- if(new && (st == sf || st == gf))
- continue;
- gt = zsym(p->to.gotype, D_EXTERN, &new);
- if(new && (gt == sf || gt == gf || gt == st))
- continue;
- break;
- }
-
- BPUTLE2(bout, p->as);
- BPUTLE4(bout, p->lineno);
- zaddr(bout, &p->from, sf, gf);
- zaddr(bout, &p->to, st, gt);
- }
- }
-}
-
int
dsname(Sym *s, int off, char *t, int n)
{
@@ -267,7 +42,7 @@ dsname(Sym *s, int off, char *t, int n)
p->from.index = D_NONE;
p->from.offset = off;
p->from.scale = n;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->to.type = D_SCONST;
p->to.index = D_NONE;
@@ -286,7 +61,7 @@ datastring(char *s, int len, Addr *a)
sym = stringsym(s, len);
a->type = D_EXTERN;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
a->offset = widthptr+widthint; // skip header
a->etype = simtype[TINT];
@@ -303,7 +78,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_EXTERN;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
@@ -377,7 +152,7 @@ dstringptr(Sym *s, int off, char *str)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
@@ -402,7 +177,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
datagostring(lit, &p->to);
@@ -431,27 +206,6 @@ dgostringptr(Sym *s, int off, char *str)
}
int
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = wid;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
-int
dsymptr(Sym *s, int off, Sym *x, int xoff)
{
Prog *p;
@@ -461,12 +215,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
- p->to.sym = x;
+ p->to.sym = linksym(x);
p->to.offset = xoff;
off += widthptr;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 7318909bb..e4d00bf41 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -46,7 +46,7 @@ clearp(Prog *p)
p->from.index = D_NONE;
p->to.type = D_NONE;
p->to.index = D_NONE;
- p->loc = pcloc;
+ p->pc = pcloc;
pcloc++;
}
@@ -136,7 +136,7 @@ patch(Prog *p, Prog *to)
if(p->to.type != D_BRANCH)
fatal("patch: not a branch");
p->to.u.branch = to;
- p->to.offset = to->loc;
+ p->to.offset = to->pc;
}
Prog*
@@ -160,12 +160,7 @@ newplist(void)
{
Plist *pl;
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
+ pl = linknewplist(ctxt);
pc = mal(sizeof(*pc));
clearp(pc);
@@ -198,8 +193,8 @@ ggloblnod(Node *nam)
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
- p->from.gotype = ngotype(nam);
- p->to.sym = S;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
p->to.type = D_CONST;
p->to.offset = nam->type->width;
if(nam->readonly)
@@ -216,7 +211,7 @@ gtrack(Sym *s)
p = gins(AUSEFIELD, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
}
void
@@ -237,7 +232,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata)
p = gins(AGLOBL, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->to.type = D_CONST;
p->to.index = D_NONE;
p->to.offset = width;
@@ -272,7 +267,7 @@ afunclit(Addr *a, Node *n)
if(a->type == D_ADDR && a->index == D_EXTERN) {
a->type = D_EXTERN;
a->index = D_NONE;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
}
}
@@ -301,6 +296,11 @@ ginit(void)
for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]++;
+
+ if(nacl) {
+ reg[D_BP]++;
+ reg[D_R15]++;
+ }
}
void
@@ -310,6 +310,11 @@ gclean(void)
for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]--;
+ if(nacl) {
+ reg[D_BP]--;
+ reg[D_R15]--;
+ }
+
for(i=D_AX; i<=D_R15; i++)
if(reg[i])
@@ -457,6 +462,7 @@ Node*
nodarg(Type *t, int fp)
{
Node *n;
+ NodeList *l;
Type *first;
Iter savet;
@@ -477,6 +483,14 @@ nodarg(Type *t, int fp)
if(t->etype != TFIELD)
fatal("nodarg: not field %T", t);
+
+ if(fp == 1) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
+ return n;
+ }
+ }
n = nod(ONAME, N, N);
n->type = t->type;
@@ -525,7 +539,16 @@ gconreg(int as, vlong c, int reg)
{
Node nr;
- nodreg(&nr, types[TINT64], reg);
+ switch(as) {
+ case AADDL:
+ case AMOVL:
+ case ALEAL:
+ nodreg(&nr, types[TINT32], reg);
+ break;
+ default:
+ nodreg(&nr, types[TINT64], reg);
+ }
+
ginscon(as, c, &nr);
}
@@ -538,10 +561,18 @@ ginscon(int as, vlong c, Node *n2)
{
Node n1, ntmp;
- nodconst(&n1, types[TINT64], c);
+ switch(as) {
+ case AADDL:
+ case AMOVL:
+ case ALEAL:
+ nodconst(&n1, types[TINT32], c);
+ break;
+ default:
+ nodconst(&n1, types[TINT64], c);
+ }
if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) {
- // cannot have 64-bit immediokate in ADD, etc.
+ // cannot have 64-bit immediate in ADD, etc.
// instead, MOV into register first.
regalloc(&ntmp, types[TINT64], N);
gins(AMOVQ, &n1, &ntmp);
@@ -1098,10 +1129,12 @@ fixlargeoffset(Node *n)
void
naddr(Node *n, Addr *a, int canemitcode)
{
+ Sym *s;
+
a->scale = 0;
a->index = D_NONE;
a->type = D_NONE;
- a->gotype = S;
+ a->gotype = nil;
a->node = N;
a->width = 0;
if(n == N)
@@ -1119,7 +1152,7 @@ naddr(Node *n, Addr *a, int canemitcode)
case OREGISTER:
a->type = n->val.u.reg;
- a->sym = S;
+ a->sym = nil;
break;
// case OINDEX:
@@ -1144,7 +1177,7 @@ naddr(Node *n, Addr *a, int canemitcode)
case OINDREG:
a->type = n->val.u.reg+D_INDIR;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
if(a->offset != (int32)a->offset)
yyerror("offset %lld too large for OINDREG", a->offset);
@@ -1156,20 +1189,22 @@ naddr(Node *n, Addr *a, int canemitcode)
a->etype = simtype[n->left->type->etype];
a->width = n->left->type->width;
a->offset = n->xoffset;
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
a->type = D_PARAM;
a->node = n->left->orig;
break;
case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
a->type = D_DX+D_INDIR;
- a->sym = S;
+ a->sym = nil;
a->offset = n->xoffset;
break;
case OCFUNC:
naddr(n->left, a, canemitcode);
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
break;
case ONAME:
@@ -1177,17 +1212,17 @@ naddr(Node *n, Addr *a, int canemitcode)
if(n->type != T)
a->etype = simtype[n->type->etype];
a->offset = n->xoffset;
- a->sym = n->sym;
+ s = n->sym;
a->node = n->orig;
//if(a->node >= (Node*)&n)
// fatal("stack node");
- if(a->sym == S)
- a->sym = lookup(".noname");
+ if(s == S)
+ s = lookup(".noname");
if(n->method) {
if(n->type != T)
if(n->type->sym != S)
if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ s = pkglookup(s->name, n->type->sym->pkg);
}
switch(n->class) {
@@ -1207,9 +1242,10 @@ naddr(Node *n, Addr *a, int canemitcode)
a->index = D_EXTERN;
a->type = D_ADDR;
a->width = widthptr;
- a->sym = funcsym(a->sym);
+ s = funcsym(s);
break;
}
+ a->sym = linksym(s);
break;
case OLITERAL:
@@ -1223,7 +1259,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case CTINT:
case CTRUNE:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
break;
@@ -1231,12 +1267,12 @@ naddr(Node *n, Addr *a, int canemitcode)
datagostring(n->val.u.sval, a);
break;
case CTBOOL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = n->val.u.bval;
break;
case CTNIL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = 0;
break;
@@ -1273,7 +1309,7 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // ptr(nil)
- a->etype = simtype[TUINTPTR];
+ a->etype = simtype[tptr];
a->offset += Array_array;
a->width = widthptr;
break;
@@ -1506,12 +1542,14 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
+ case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
case CASE(OADD, TINT64):
case CASE(OADD, TUINT64):
case CASE(OADD, TPTR64):
+ case CASE(OADDPTR, TPTR64):
a = AADDQ;
break;
@@ -2042,7 +2080,7 @@ odot:
for(i=1; i<o; i++) {
if(oary[i] >= 0)
fatal("can't happen");
- gins(AMOVQ, &n1, reg);
+ gins(movptr, &n1, reg);
cgen_checknil(reg);
n1.xoffset = -(oary[i]+1);
}
@@ -2254,7 +2292,7 @@ oindex_const_sudo:
if(reg->op == OEMPTY)
regalloc(reg, types[tptr], N);
- p1 = gins(AMOVQ, N, reg);
+ p1 = gins(movptr, N, reg);
p1->from = *a;
n2 = *reg;
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
index 3dcc3d747..bf356af0c 100644
--- a/src/cmd/6g/opt.h
+++ b/src/cmd/6g/opt.h
@@ -94,6 +94,7 @@ EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
+EXTERN Bits ivar;
EXTERN Bits ovar;
EXTERN int change;
EXTERN int32 maxnr;
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index 5ccf90103..0f2720443 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -109,7 +109,7 @@ peep(Prog *firstp)
case ALEAL:
case ALEAQ:
if(regtyp(&p->to))
- if(p->from.sym != S)
+ if(p->from.sym != nil)
if(p->from.index == D_NONE || p->from.index == D_CONST)
conprop(r);
break;
@@ -306,7 +306,7 @@ pushback(Flow *r0)
if(p->as != ANOP) {
if(!regconsttyp(&p->from) || !regtyp(&p->to))
break;
- if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A))
+ if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil))
break;
}
if(p->as == ACALL)
@@ -573,6 +573,8 @@ subprop(Flow *r0)
break;
}
p = r->prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
if(info.flags & Call) {
if(debug['P'] && debug['v'])
@@ -682,7 +684,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
if(debug['P'])
print("; merge; f=%d", f);
}
- t = copyu(p, v2, A);
+ t = copyu(p, v2, nil);
switch(t) {
case 2: /* rar, can't split */
if(debug['P'])
@@ -720,7 +722,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
break;
}
if(!f) {
- t = copyu(p, v1, A);
+ t = copyu(p, v1, nil);
if(!f && (t == 2 || t == 3 || t == 4)) {
f = 1;
if(debug['P'])
@@ -751,7 +753,7 @@ copyu(Prog *p, Adr *v, Adr *s)
switch(p->as) {
case AJMP:
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -761,7 +763,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case ARET:
- if(s != A)
+ if(s != nil)
return 1;
return 3;
@@ -773,7 +775,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type == p->from.type)
return 2;
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -788,6 +790,8 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
}
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ return 0;
proginfo(&info, p);
if((info.reguse|info.regset) & RtoB(v->type))
@@ -803,7 +807,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(info.flags & RightWrite) {
if(copyas(&p->to, v)) {
- if(s != A)
+ if(s != nil)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
@@ -812,7 +816,7 @@ copyu(Prog *p, Adr *v, Adr *s)
}
if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
@@ -940,7 +944,7 @@ loop:
return;
p = r->prog;
- t = copyu(p, v0, A);
+ t = copyu(p, v0, nil);
switch(t) {
case 0: // miss
case 1: // use
@@ -956,7 +960,7 @@ loop:
if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
- if(p->from.u.vval == p0->from.u.vval)
+ if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
if(p->from.index == p0->from.index) {
excise(r);
goto loop;
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
index 90571a21a..ee68399d5 100644
--- a/src/cmd/6g/prog.c
+++ b/src/cmd/6g/prog.c
@@ -38,9 +38,11 @@ static ProgInfo progtable[ALAST] = {
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
- [AUNDEF]= {OK},
+ [AUNDEF]= {Break},
[AUSEFIELD]= {OK},
[ACHECKNIL]= {LeftRead},
+ [AVARDEF]= {Pseudo | RightWrite},
+ [AVARKILL]= {Pseudo | RightWrite},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
@@ -142,6 +144,7 @@ static ProgInfo progtable[ALAST] = {
[AJMP]= {Jump | Break | KillCarry},
+ [ALEAL]= {LeftAddr | RightWrite},
[ALEAQ]= {LeftAddr | RightWrite},
[AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv},
@@ -167,6 +170,7 @@ static ProgInfo progtable[ALAST] = {
[AMOVSL]= {OK, DI|SI, DI|SI},
[AMOVSQ]= {OK, DI|SI, DI|SI},
[AMOVSW]= {OK, DI|SI, DI|SI},
+ [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX},
[AMOVSD]= {SizeD | LeftRead | RightWrite | Move},
[AMOVSS]= {SizeF | LeftRead | RightWrite | Move},
@@ -254,6 +258,7 @@ static ProgInfo progtable[ALAST] = {
[ASTOSL]= {OK, AX|DI, DI},
[ASTOSQ]= {OK, AX|DI, DI},
[ASTOSW]= {OK, AX|DI, DI},
+ [ADUFFZERO]= {OK, AX|DI, DI},
[ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry},
[ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry},
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 63fd0deca..f3b1e55de 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -55,30 +55,6 @@ rcmp(const void *a1, const void *a2)
}
static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(&ovar))
-//print("ovars = %Q\n", ovar);
-}
-
-static void
setaddrs(Bits bit)
{
int i, n;
@@ -138,6 +114,8 @@ static char* regname[] = {
static Node* regnodes[NREGVAR];
+static void walkvardef(Node *n, Reg *r, int active);
+
void
regopt(Prog *firstp)
{
@@ -145,7 +123,7 @@ regopt(Prog *firstp)
Prog *p;
Graph *g;
ProgInfo info;
- int i, z;
+ int i, z, active;
uint32 vreg;
Bits bit;
@@ -155,9 +133,8 @@ regopt(Prog *firstp)
first = 0;
}
- fixjmp(firstp);
mergetemp(firstp);
-
+
/*
* control flow is more complicated in generated go code
* than in generated c code. define pseudo-variables for
@@ -177,12 +154,10 @@ regopt(Prog *firstp)
params.b[z] = 0;
consts.b[z] = 0;
addrs.b[z] = 0;
+ ivar.b[z] = 0;
ovar.b[z] = 0;
}
- // build list of return variables
- setoutvar();
-
/*
* pass 1
* build aux data structure
@@ -190,12 +165,18 @@ regopt(Prog *firstp)
* find use and set of variables
*/
g = flowstart(firstp, sizeof(Reg));
- if(g == nil)
+ if(g == nil) {
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
return;
+ }
+
firstr = (Reg*)g->start;
for(r = firstr; r != R; r = (Reg*)r->f.link) {
p = r->f.prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
// Avoid making variables for direct-called functions.
@@ -256,6 +237,26 @@ regopt(Prog *firstp)
dumpit("pass2", &firstr->f, 1);
/*
+ * pass 2.5
+ * iterate propagating fat vardef covering forward
+ * r->act records vars with a VARDEF since the last CALL.
+ * (r->act will be reused in pass 5 for something else,
+ * but we'll be done with it by then.)
+ */
+ active = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ r->f.active = 0;
+ r->act = zbits;
+ }
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ p = r->f.prog;
+ if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+ active++;
+ walkvardef(p->to.node, r, active);
+ }
+ }
+
+ /*
* pass 3
* iterate propagating usage
* back until flow graph is complete
@@ -406,6 +407,8 @@ brk:
/*
* free aux structures. peep allocates new ones.
*/
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
flowend(g);
firstr = R;
@@ -454,6 +457,32 @@ brk:
}
}
+static void
+walkvardef(Node *n, Reg *r, int active)
+{
+ Reg *r1, *r2;
+ int bn;
+ Var *v;
+
+ for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
+ if(r1->f.active == active)
+ break;
+ r1->f.active = active;
+ if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
+ break;
+ for(v=n->opt; v!=nil; v=v->nextinnode) {
+ bn = v - var;
+ r1->act.b[bn/32] |= 1L << (bn%32);
+ }
+ if(r1->f.prog->as == ACALL)
+ break;
+ }
+
+ for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
+ if(r2->f.s2 != nil)
+ walkvardef(n, (Reg*)r2->f.s2, active);
+}
+
/*
* add mov b,rn
* just after r
@@ -467,7 +496,7 @@ addmove(Reg *r, int bn, int rn, int f)
p1 = mal(sizeof(*p1));
clearp(p1);
- p1->loc = 9999;
+ p1->pc = 9999;
p = r->f.prog;
p1->link = p->link;
@@ -481,12 +510,12 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->node = v->node;
- a->sym = v->node->sym;
+ a->sym = linksym(v->node->sym);
// need to clean this up with wptr and
// some of the defaults
p1->as = AMOVL;
- switch(v->etype) {
+ switch(simtype[(uchar)v->etype]) {
default:
fatal("unknown type %E", v->etype);
case TINT8:
@@ -500,7 +529,6 @@ addmove(Reg *r, int bn, int rn, int f)
break;
case TINT64:
case TUINT64:
- case TUINTPTR:
case TPTR64:
p1->as = AMOVQ;
break;
@@ -510,8 +538,6 @@ addmove(Reg *r, int bn, int rn, int f)
case TFLOAT64:
p1->as = AMOVSD;
break;
- case TINT:
- case TUINT:
case TINT32:
case TUINT32:
case TPTR32:
@@ -655,6 +681,16 @@ mkvar(Reg *r, Adr *a)
if(nvar >= NVAR) {
if(debug['w'] > 1 && node != N)
fatal("variable not optimized: %#N", node);
+
+ // If we're not tracking a word in a variable, mark the rest as
+ // having its address taken, so that we keep the whole thing
+ // live at all calls. otherwise we might optimize away part of
+ // a variable but not all of it.
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node)
+ v->addr = 1;
+ }
goto none;
}
@@ -667,11 +703,13 @@ mkvar(Reg *r, Adr *a)
v->width = w;
v->addr = flag; // funny punning
v->node = node;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-
- ostats.nvar++;
+
+ // node->opt is the head of a linked list
+ // of Vars within the given Node, so that
+ // we can start at a Var and find all the other
+ // Vars in the same Go variable.
+ v->nextinnode = node->opt;
+ node->opt = v;
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
@@ -681,6 +719,46 @@ mkvar(Reg *r, Adr *a)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
+ if(node->class == PPARAM)
+ for(z=0; z<BITS; z++)
+ ivar.b[z] |= bit.b[z];
+ if(node->class == PPARAMOUT)
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+
+ // Treat values with their address taken as live at calls,
+ // because the garbage collector's liveness analysis in ../gc/plive.c does.
+ // These must be consistent or else we will elide stores and the garbage
+ // collector will see uninitialized data.
+ // The typical case where our own analysis is out of sync is when the
+ // node appears to have its address taken but that code doesn't actually
+ // get generated and therefore doesn't show up as an address being
+ // taken when we analyze the instruction stream.
+ // One instance of this case is when a closure uses the same name as
+ // an outer variable for one of its own variables declared with :=.
+ // The parser flags the outer variable as possibly shared, and therefore
+ // sets addrtaken, even though it ends up not being actually shared.
+ // If we were better about _ elision, _ = &x would suffice too.
+ // The broader := in a closure problem is mentioned in a comment in
+ // closure.c:/^typecheckclosure and dcl.c:/^oldname.
+ if(node->addrtaken)
+ v->addr = 1;
+
+ // Disable registerization for globals, because:
+ // (1) we might panic at any time and we want the recovery code
+ // to see the latest values (issue 1304).
+ // (2) we don't know what pointers might point at them and we want
+ // loads via those pointers to see updated values and vice versa (issue 7995).
+ //
+ // Disable registerization for results if using defer, because the deferred func
+ // might recover and return, causing the current values to be used.
+ if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
+ v->addr = 1;
+
+ if(debug['R'])
+ print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ ostats.nvar++;
+
return bit;
none:
@@ -691,7 +769,8 @@ void
prop(Reg *r, Bits ref, Bits cal)
{
Reg *r1, *r2;
- int z;
+ int z, i, j;
+ Var *v, *v1;
for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
for(z=0; z<BITS; z++) {
@@ -710,10 +789,61 @@ prop(Reg *r, Bits ref, Bits cal)
case ACALL:
if(noreturn(r1->f.prog))
break;
+
+ // Mark all input variables (ivar) as used, because that's what the
+ // liveness bitmaps say. The liveness bitmaps say that so that a
+ // panic will not show stale values in the parameter dump.
+ // Mark variables with a recent VARDEF (r1->act) as used,
+ // so that the optimizer flushes initializations to memory,
+ // so that if a garbage collection happens during this CALL,
+ // the collector will see initialized memory. Again this is to
+ // match what the liveness bitmaps say.
for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
+ cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
ref.b[z] = 0;
}
+
+ // cal.b is the current approximation of what's live across the call.
+ // Every bit in cal.b is a single stack word. For each such word,
+ // find all the other tracked stack words in the same Go variable
+ // (struct/slice/string/interface) and mark them live too.
+ // This is necessary because the liveness analysis for the garbage
+ // collector works at variable granularity, not at word granularity.
+ // It is fundamental for slice/string/interface: the garbage collector
+ // needs the whole value, not just some of the words, in order to
+ // interpret the other bits correctly. Specifically, slice needs a consistent
+ // ptr and cap, string needs a consistent ptr and len, and interface
+ // needs a consistent type word and data word.
+ for(z=0; z<BITS; z++) {
+ if(cal.b[z] == 0)
+ continue;
+ for(i=0; i<32; i++) {
+ if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ continue;
+ v = var+z*32+i;
+ if(v->node->opt == nil) // v represents fixed register, not Go variable
+ continue;
+
+ // v->node->opt is the head of a linked list of Vars
+ // corresponding to tracked words from the Go variable v->node.
+ // Walk the list and set all the bits.
+ // For a large struct this could end up being quadratic:
+ // after the first setting, the outer loop (for z, i) would see a 1 bit
+ // for all of the remaining words in the struct, and for each such
+ // word would go through and turn on all the bits again.
+ // To avoid the quadratic behavior, we only turn on the bits if
+ // v is the head of the list or if the head's bit is not yet turned on.
+ // This will set the bits at most twice, keeping the overall loop linear.
+ v1 = v->node->opt;
+ j = v1 - var;
+ if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ for(; v1 != nil; v1 = v1->nextinnode) {
+ j = v1 - var;
+ cal.b[j/32] |= 1<<(j&31);
+ }
+ }
+ }
+ }
break;
case ATEXT:
@@ -729,17 +859,6 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
-
- default:
- // Work around for issue 1304:
- // flush modified globals before each instruction.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= externs.b[z];
- // issue 4066: flush modified return variables in case of panic
- if(hasdefer)
- cal.b[z] |= ovar.b[z];
- }
- break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -860,12 +979,11 @@ paint1(Reg *r, int bn)
for(;;) {
r->act.b[z] |= bb;
- if(r->use1.b[z] & bb) {
- change += CREF * r->f.loop;
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->f.loop;
+ if(r->f.prog->as != ANOP) { // don't give credit for NOPs
+ if(r->use1.b[z] & bb)
+ change += CREF * r->f.loop;
+ if((r->use2.b[z]|r->set.b[z]) & bb)
+ change += CREF * r->f.loop;
}
if(STORE(r) & r->regdiff.b[z] & bb) {
@@ -906,7 +1024,7 @@ regset(Reg *r, uint32 bb)
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
fatal("zero v.type for %#ux", b);
- c = copyu(r->f.prog, &v, A);
+ c = copyu(r->f.prog, &v, nil);
if(c == 3)
set |= b;
bb &= ~b;
@@ -925,7 +1043,7 @@ reguse(Reg *r, uint32 bb)
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, A);
+ c = copyu(r->f.prog, &v, nil);
if(c == 1 || c == 2 || c == 4)
set |= b;
bb &= ~b;
@@ -1067,8 +1185,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
void
addreg(Adr *a, int rn)
{
-
- a->sym = 0;
+ a->sym = nil;
a->offset = 0;
a->type = rn;
@@ -1088,6 +1205,8 @@ int
BtoR(int32 b)
{
b &= 0xffffL;
+ if(nacl)
+ b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
if(b == 0)
return 0;
return bitno(b) + D_AX;
@@ -1176,14 +1295,14 @@ dumpit(char *str, Flow *r0, int isreg)
if(r1 != nil) {
print(" pred:");
for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", r1->prog->loc);
+ print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
// r1 = r->s1;
// if(r1 != R) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
+// print(" %.4ud", (int)r1->prog->pc);
// print("\n");
// }
}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 5fa73a65b..1e2a1488f 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -762,6 +762,10 @@ enum as
AFUNCDATA,
APCDATA,
ACHECKNIL,
+ AVARDEF,
+ AVARKILL,
+ ADUFFCOPY,
+ ADUFFZERO,
ALAST
};
@@ -846,27 +850,21 @@ enum
D_DR = 95,
D_TR = 103,
- D_NONE = 111,
+ D_TLS = 111,
+ D_NONE = 112,
- D_BRANCH = 112,
- D_EXTERN = 113,
- D_STATIC = 114,
- D_AUTO = 115,
- D_PARAM = 116,
- D_CONST = 117,
- D_FCONST = 118,
- D_SCONST = 119,
- D_ADDR = 120,
-
- D_FILE,
- D_FILE1,
+ D_BRANCH = 113,
+ D_EXTERN = 114,
+ D_STATIC = 115,
+ D_AUTO = 116,
+ D_PARAM = 117,
+ D_CONST = 118,
+ D_FCONST = 119,
+ D_SCONST = 120,
+ D_ADDR = 121,
D_INDIR, /* additive */
- D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
- D_PCREL,
- D_TLS,
-
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
@@ -890,15 +888,3 @@ enum
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index a09cc9727..e251e32ca 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -44,49 +44,22 @@ char freebsddynld[] = "/libexec/ld-elf.so.1";
char openbsddynld[] = "/usr/libexec/ld.so";
char netbsddynld[] = "/libexec/ld.elf_so";
char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
+char solarisdynld[] = "/lib/amd64/ld.so.1";
char zeroes[32];
-vlong
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
-
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".elfload.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -97,24 +70,24 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
+static void addpltsym(LSym*);
+static void addgotsym(LSym*);
void
-adddynrela(Sym *rela, Sym *s, Reloc *r)
+adddynrela(LSym *rela, LSym *s, Reloc *r)
{
- addaddrplus(rela, s, r->off);
- adduint64(rela, R_X86_64_RELATIVE);
- addaddrplus(rela, r->sym, r->add); // Addend
+ addaddrplus(ctxt, rela, s, r->off);
+ adduint64(ctxt, rela, R_X86_64_RELATIVE);
+ addaddrplus(ctxt, rela, r->sym, r->add); // Addend
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rela, *got;
+ LSym *targ, *rela, *got;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -130,16 +103,16 @@ adddynrel(Sym *s, Reloc *r)
diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
return;
case 256 + R_X86_64_PLT32:
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@@ -150,7 +123,7 @@ adddynrel(Sym *s, Reloc *r)
if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
// turn MOVQ of GOT entry into LEAQ of symbol itself
s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
return;
}
@@ -158,8 +131,8 @@ adddynrel(Sym *s, Reloc *r)
// TODO: just needs relocation, no need to put in .dynsym
}
addgotsym(targ);
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->type = R_PCREL;
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
r->add += targ->got;
return;
@@ -167,7 +140,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_X86_64_64:
if(targ->type == SDYNIMPORT)
diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
- r->type = D_ADDR;
+ r->type = R_ADDR;
return;
// Handle relocations found in Mach-O object files.
@@ -175,7 +148,7 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these?
- r->type = D_ADDR;
+ r->type = R_ADDR;
if(targ->type == SDYNIMPORT)
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
@@ -183,9 +156,9 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
}
// fall through
@@ -194,7 +167,7 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
- r->type = D_PCREL;
+ r->type = R_PCREL;
if(targ->type == SDYNIMPORT)
diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
return;
@@ -208,7 +181,7 @@ adddynrel(Sym *s, Reloc *r)
return;
}
s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
}
// fall through
@@ -216,8 +189,8 @@ adddynrel(Sym *s, Reloc *r)
if(targ->type != SDYNIMPORT)
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ);
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->type = R_PCREL;
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
return;
}
@@ -227,24 +200,34 @@ adddynrel(Sym *s, Reloc *r)
return;
switch(r->type) {
- case D_PCREL:
+ case R_CALL:
+ case R_PCREL:
addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
- case D_ADDR:
+ case R_ADDR:
+ if(s->type == STEXT && iself) {
+ // The code is asking for the address of an external
+ // function. We provide it with the address of the
+ // correspondent GOT symbol.
+ addgotsym(targ);
+ r->sym = linklookup(ctxt, ".got", 0);
+ r->add += targ->got;
+ return;
+ }
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rela = lookup(".rela", 0);
- addaddrplus(rela, s, r->off);
+ adddynsym(ctxt, targ);
+ rela = linklookup(ctxt, ".rela", 0);
+ addaddrplus(ctxt, rela, s, r->off);
if(r->siz == 8)
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+ adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
else
- adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
- adduint64(rela, r->add);
+ adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+ adduint64(ctxt, rela, r->add);
r->type = 256; // ignore during relocsym
return;
}
@@ -259,22 +242,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
+ adddynsym(ctxt, targ);
+ got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
- adduint64(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ adduint64(ctxt, got, 0);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -290,7 +273,7 @@ elfreloc1(Reloc *r, vlong sectoff)
default:
return -1;
- case D_ADDR:
+ case R_ADDR:
if(r->siz == 4)
VPUT(R_X86_64_32 | (uint64)elfsym<<32);
else if(r->siz == 8)
@@ -299,14 +282,25 @@ elfreloc1(Reloc *r, vlong sectoff)
return -1;
break;
- case D_PCREL:
+ case R_TLS_LE:
if(r->siz == 4)
- VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+ VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
else
return -1;
break;
+
+ case R_CALL:
+ case R_PCREL:
+ if(r->siz == 4) {
+ if(r->xsym->type == SDYNIMPORT)
+ VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
+ else
+ VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+ } else
+ return -1;
+ break;
- case D_TLS:
+ case R_TLS:
if(r->siz == 4) {
if(flag_shared)
VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
@@ -325,7 +319,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
- Sym *rs;
+ LSym *rs;
rs = r->xsym;
@@ -347,10 +341,11 @@ machoreloc1(Reloc *r, vlong sectoff)
switch(r->type) {
default:
return -1;
- case D_ADDR:
+ case R_ADDR:
v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
break;
- case D_PCREL:
+ case R_CALL:
+ case R_PCREL:
v |= 1<<24; // pc-relative bit
v |= MACHO_X86_64_RELOC_BRANCH<<28;
break;
@@ -379,7 +374,7 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(r);
USED(s);
@@ -390,68 +385,68 @@ archreloc(Reloc *r, Sym *s, vlong *val)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// pushq got+8(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addpcrelplus(plt, got, 8);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x35);
+ addpcrelplus(ctxt, plt, got, 8);
// jmpq got+16(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, 16);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, got, 16);
// nopl 0(AX)
- adduint32(plt, 0x00401f0f);
+ adduint32(ctxt, plt, 0x00401f0f);
// assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint64(got, 0);
- adduint64(got, 0);
+ addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+ adduint64(ctxt, got, 0);
+ adduint64(ctxt, got, 0);
}
}
static void
-addpltsym(Sym *s)
+addpltsym(LSym *s)
{
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- Sym *plt, *got, *rela;
+ LSym *plt, *got, *rela;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rela = lookup(".rela.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rela = linklookup(ctxt, ".rela.plt", 0);
if(plt->size == 0)
elfsetupplt();
// jmpq *got+size(IP)
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, got, got->size);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
+ addaddrplus(ctxt, got, plt, plt->size);
// pushq $x
- adduint8(plt, 0x68);
- adduint32(plt, (got->size-24-8)/8);
+ adduint8(ctxt, plt, 0x68);
+ adduint32(ctxt, plt, (got->size-24-8)/8);
// jmpq .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
+ adduint8(ctxt, plt, 0xe9);
+ adduint32(ctxt, plt, -(plt->size+4));
// rela
- addaddrplus(rela, got, got->size-8);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
- adduint64(rela, 0);
+ addaddrplus(ctxt, rela, got, got->size-8);
+ adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+ adduint64(ctxt, rela, 0);
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
@@ -465,53 +460,53 @@ addpltsym(Sym *s)
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding.
- Sym *plt;
+ LSym *plt;
addgotsym(s);
- plt = lookup(".plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addpcrelplus(plt, lookup(".got", 0), s->got);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsym(Sym *s)
+addgotsym(LSym *s)
{
- Sym *got, *rela;
+ LSym *got, *rela;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint64(got, 0);
+ adduint64(ctxt, got, 0);
if(iself) {
- rela = lookup(".rela", 0);
- addaddrplus(rela, got, s->got);
- adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
- adduint64(rela, 0);
+ rela = linklookup(ctxt, ".rela", 0);
+ addaddrplus(ctxt, rela, got, s->got);
+ adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+ adduint64(ctxt, rela, 0);
} else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -521,24 +516,24 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
+ adduint8(ctxt, d, t);
/* reserved */
- adduint8(d, 0);
+ adduint8(ctxt, d, 0);
/* section where symbol is defined */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -555,21 +550,21 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
/* value */
if(s->type == SDYNIMPORT)
- adduint64(d, 0);
+ adduint64(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size of object */
- adduint64(d, s->size);
+ adduint64(ctxt, d, s->size);
if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
- addstring(lookup(".dynstr", 0), s->dynimplib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
+ addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@@ -583,16 +578,16 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else {
@@ -607,7 +602,7 @@ asmb(void)
int i;
vlong vl, symo, dwarfoff, machlink;
Section *sect;
- Sym *sym;
+ LSym *sym;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -662,8 +657,7 @@ asmb(void)
switch(HEADTYPE) {
default:
diag("unknown header type %d", HEADTYPE);
- case Hplan9x32:
- case Hplan9x64:
+ case Hplan9:
case Helf:
break;
case Hdarwin:
@@ -674,8 +668,10 @@ asmb(void)
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
+ case Hsolaris:
debug['8'] = 1; /* 64-bit addresses */
break;
+ case Hnacl:
case Hwindows:
break;
}
@@ -690,7 +686,7 @@ asmb(void)
Bflush(&bso);
switch(HEADTYPE) {
default:
- case Hplan9x64:
+ case Hplan9:
case Helf:
debug['s'] = 1;
symo = HEADR+segtext.len+segdata.filelen;
@@ -703,6 +699,8 @@ asmb(void)
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
+ case Hsolaris:
+ case Hnacl:
symo = rnd(HEADR+segtext.len, INITRND)+rnd(segrodata.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
@@ -729,11 +727,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x64:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -761,7 +759,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
- case Hplan9x64: /* plan9 */
+ case Hplan9: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
lputb(magic); /* magic */
@@ -775,17 +773,6 @@ asmb(void)
lputb(lcsize); /* line offsets */
vputb(vl); /* va of entry */
break;
- case Hplan9x32: /* plan9 */
- magic = 4*26*26+7;
- lputb(magic); /* magic */
- lputb(segtext.filelen); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb(entryvalue()); /* va of entry */
- lputb(spsize); /* sp offsets */
- lputb(lcsize); /* line offsets */
- break;
case Hdarwin:
asmbmacho();
break;
@@ -794,6 +781,8 @@ asmb(void)
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
+ case Hsolaris:
+ case Hnacl:
asmbelf(symo);
break;
case Hwindows:
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index ecab867e4..7303910a6 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "6.out.h"
#ifndef EXTERN
@@ -40,8 +41,6 @@
enum
{
thechar = '6',
- PtrSize = 8,
- IntSize = 8,
MaxAlign = 32, // max data alignment
// Loop alignment constants:
@@ -63,147 +62,13 @@ enum
FuncAlign = 16
};
-#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Movtab Movtab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- vlong u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- char index;
- char scale;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int32 type;
- int64 add;
- int64 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- vlong pc;
- int32 spadj;
- int32 line;
- short as;
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
-
- char width; /* fake for DATA */
- char mode; /* 16, 32, or 64 */
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 dynid;
- int32 sig;
- int32 plt;
- int32 got;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 args; // size of stack frame incoming arguments area
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in SSUB list
- Sym* outer; // container of sub
- Sym* reachparent;
- Sym* queue;
- vlong value;
- vlong size;
- Sym* gotype;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist; // for ATEXT
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[23];
-};
-struct Movtab
-{
- short as;
- uchar ft;
- uchar tt;
- uchar code;
- uchar op[4];
-};
+EXTERN int PtrSize;
+EXTERN int IntSize;
+EXTERN int RegSize;
+#define P ((Prog*)0)
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
MINSIZ = 8,
@@ -211,239 +76,42 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Ys32,
- Yi32,
- Yi64,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
- Ymr, Ymm,
- Yxr, Yxm,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Zlitm_r,
- Z_rp,
- Zbr,
- Zcall,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zibo_m_xm,
- Zil_,
- Zil_rp,
- Ziq_rp,
- Zilo_m,
- Ziqo_m,
- Zjmp,
- Zloop,
- Zo_iw,
- Zm_o,
- Zm_r,
- Zm2_r,
- Zm_r_xm,
- Zm_r_i_xm,
- Zm_r_3d,
- Zm_r_xm_nr,
- Zr_m_xm_nr,
- Zibm_r, /* mmx1,mmx2/mem64,imm8 */
- Zmb_r,
- Zaut_r,
- Zo_m,
- Zo_m64,
- Zpseudo,
- Zr_m,
- Zr_m_xm,
- Zr_m_i_xm,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zbyte,
- Zmax,
-
- Px = 0,
- P32 = 0x32, /* 32-bit only */
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escapes: 66 0f */
- Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1: f2 0f */
- Pf3 = 0xf3, /* xmm escape 2: f3 0f */
- Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
- Pw = 0x48, /* Rex.w */
- Py = 0x80, /* defaults to 64-bit mode */
-
- Rxf = 1<<9, /* internal flag for Rxr on from */
- Rxt = 1<<8, /* internal flag for Rxr on to */
- Rxw = 1<<3, /* =1, 64-bit operand size */
- Rxr = 1<<2, /* extend modrm reg */
- Rxx = 1<<1, /* extend sib index */
- Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
-
- Maxand = 10, /* in -a output width of the byte codes */
};
-#pragma varargck type "A" uint
-#pragma varargck type "D" Adr*
#pragma varargck type "I" uchar*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-#pragma varargck type "i" char*
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN int64 INITTEXT;
-EXTERN int64 INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
-EXTERN Sym* textp;
-EXTERN Sym* etextp;
-EXTERN char ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar* rexptr;
-EXTERN uchar and[30];
-EXTERN int reg[D_NONE];
-EXTERN int regrex[D_NONE+1];
EXTERN int32 lcsize;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN char* outfile;
-EXTERN vlong pc;
-EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN int32 spsize;
-EXTERN Sym* symlist;
+EXTERN LSym* symlist;
EXTERN int32 symsize;
-EXTERN int tlsoffset;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN char* paramspace;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
EXTERN vlong textstksiz;
EXTERN vlong textarg;
-extern Optab optab[];
-extern Optab* opindex[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-void addstackmark(void);
-Prog* appendp(Prog*);
+int Iconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rela, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-void asmelfsym(void);
-vlong atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void buildop(void);
-Prog* copyp(Prog*);
-double cputime(void);
-void datblk(int32, int32);
-void deadcode(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void domacho(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-vlong entryvalue(void);
-void follow(void);
-void gethunk(void);
-void gotypestrings(void);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void instinit(void);
-void main(int, char*[]);
-void* mysbrk(uint32);
-Prog* newtext(Prog*, Sym*);
-void nopout(Prog*);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-void parsetextconst(vlong);
-int relinv(int);
-vlong rnd(vlong, vlong);
-void span(void);
-void undef(void);
-vlong symaddr(Sym*);
-void vputb(uint64);
-void vputl(uint64);
-void wputb(uint16);
-void wputl(uint16);
-void xdefine(char*, int, vlong);
-
-void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
-void machsymseg(uint32, uint32);
-void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32);
-void machstack(vlong);
-void machdylink(void);
-uint32 machheadr(void);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
+void parsetextconst(vlong arg);
+vlong rnd(vlong v, vlong r);
/* Native is little-endian */
#define LPUT(a) lputl(a)
#define WPUT(a) wputl(a)
#define VPUT(a) vputl(a)
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "Z" char*
-#pragma varargck type "A" int
-#pragma varargck argpos diag 1
-
/* Used by ../ld/dwarf.c */
enum
{
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index 5040e4327..d960fcc91 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -33,371 +33,14 @@
#include "l.h"
#include "../ld/lib.h"
-static Prog* bigP;
-
void
listinit(void)
{
-
- fmtinstall('R', Rconv);
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('S', Sconv);
- fmtinstall('P', Pconv);
+ listinit6();
fmtinstall('I', Iconv);
}
int
-Pconv(Fmt *fp)
-{
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- switch(p->as) {
- case ATEXT:
- if(p->from.scale) {
- fmtprint(fp, "(%d) %A %D,%d,%lD",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- fmtprint(fp, "(%d) %A %D,%lD",
- p->line, p->as, &p->from, &p->to);
- break;
- default:
- fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
- break;
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- bigP = P;
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
-
- if(fp->flags & FmtLong) {
- if(i != D_CONST) {
- // ATEXT dst is not constant
- snprint(str, sizeof(str), "!!%D", a);
- goto brk;
- }
- parsetextconst(a->offset);
- if(textarg == 0) {
- snprint(str, sizeof(str), "$%lld", textstksiz);
- goto brk;
- }
- snprint(str, sizeof(str), "$%lld-%lld", textstksiz, textarg);
- goto brk;
- }
-
- if(i >= D_INDIR) {
- if(a->offset)
- snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- if(a->offset)
- snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
- else
- snprint(str, sizeof(str), "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- if(bigP != P && bigP->pcond != P)
- if(a->sym != S)
- snprint(str, sizeof(str), "%llux+%s", bigP->pcond->pc,
- a->sym->name);
- else
- snprint(str, sizeof(str), "%llux", bigP->pcond->pc);
- else
- snprint(str, sizeof(str), "%lld(PC)", a->offset);
- break;
-
- case D_EXTERN:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(SB)", a->sym->name, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(SB)", a->offset);
- break;
-
- case D_STATIC:
- if(a->sym) {
- snprint(str, sizeof(str), "%s<%d>+%lld(SB)", a->sym->name,
- a->sym->version, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!<999>+%lld(SB)", a->offset);
- break;
-
- case D_AUTO:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(SP)", a->sym->name, a->offset);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(SP)", a->offset);
- break;
-
- case D_PARAM:
- if(a->sym) {
- snprint(str, sizeof(str), "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
- break;
- }
- snprint(str, sizeof(str), "!!noname!!+%lld(%s)", a->offset, paramspace);
- break;
-
- case D_CONST:
- snprint(str, sizeof(str), "$%lld", a->offset);
- break;
-
- case D_FCONST:
- snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
- break;
-
- case D_SCONST:
- snprint(str, sizeof(str), "$\"%S\"", a->scon);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", a->index, a->scale);
- strcat(str, s);
- }
-conv:
- fmtstrcpy(fp, str);
-// if(a->gotype)
-// fmtprint(fp, "«%s»", a->gotype->name);
- return 0;
-
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "SPB",
- "BPB",
- "SIB",
- "DIB",
- "R8B",
- "R9B",
- "R10B",
- "R11B",
- "R12B",
- "R13B",
- "R14B",
- "R15B",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- "AH",
- "CH",
- "DH",
- "BH",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "M0",
- "M1",
- "M2",
- "M3",
- "M4",
- "M5",
- "M6",
- "M7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
- "X8",
- "X9",
- "X10",
- "X11",
- "X12",
- "X13",
- "X14",
- "X15",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
- "CR8",
- "CR9",
- "CR10",
- "CR11",
- "CR12",
- "CR13",
- "CR14",
- "CR15",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- snprint(str, sizeof(str), "%s", regstr[r-D_AL]);
- else
- snprint(str, sizeof(str), "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
-int
Iconv(Fmt *fp)
{
int i, n;
@@ -422,40 +65,3 @@ Iconv(Fmt *fp)
free(s);
return 0;
}
-
-void
-diag(char *fmt, ...)
-{
- char buf[1024], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
-
-void
-parsetextconst(vlong arg)
-{
- textstksiz = arg & 0xffffffffLL;
- if(textstksiz & 0x80000000LL)
- textstksiz = -(-textstksiz & 0xffffffffLL);
-
- textarg = (arg >> 32) & 0xffffffffLL;
- if(textarg & 0x80000000LL)
- textarg = 0;
- textarg = (textarg+7) & ~7LL;
-}
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index ae649a74b..3b8e8f4d7 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -30,7 +30,6 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -39,104 +38,22 @@
#include "../ld/pe.h"
#include <ar.h>
-char *noname = "<none>";
char* thestring = "amd64";
-char* paramspace = "FP";
-
-Header headers[] = {
- "plan9x32", Hplan9x32,
- "plan9", Hplan9x64,
- "elf", Helf,
- "darwin", Hdarwin,
- "dragonfly", Hdragonfly,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- "openbsd", Hopenbsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hplan9x32 -T4128 -R4096 is plan9 32-bit format
- * -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format
- * -Helf -T0x80110000 -R4096 is ELF32
- * -Hdarwin -Tx -Rx is apple MH-exec
- * -Hdragonfly -Tx -Rx is DragonFly elf-exec
- * -Hlinux -Tx -Rx is linux elf-exec
- * -Hfreebsd -Tx -Rx is FreeBSD elf-exec
- * -Hnetbsd -Tx -Rx is NetBSD elf-exec
- * -Hopenbsd -Tx -Rx is OpenBSD elf-exec
- * -Hwindows -Tx -Rx is MS Windows PE32+
- */
+LinkArch* thelinkarch = &linkamd64;
void
-main(int argc, char *argv[])
+linkarchinit(void)
{
- Binit(&bso, 1, OWRITE);
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = nil;
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagcount("8", "assume 64-bit addresses", &debug['8']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagint64("D", "addr: data address", &INITDAT);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("Q", "debug byte-register code gen", &debug['Q']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagcount("S", "check type signatures", &debug['S']);
- flagint64("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- mywhatsys(); // get goos
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
+ if(strcmp(getgoarch(), "amd64p32") == 0)
+ thelinkarch = &linkamd64p32;
+ PtrSize = thelinkarch->ptrsize;
+ IntSize = PtrSize;
+ RegSize = thelinkarch->regsize;
+}
+void
+archinit(void)
+{
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@@ -156,34 +73,18 @@ main(int argc, char *argv[])
case Hdragonfly:
case Hfreebsd:
case Hlinux:
+ case Hnacl:
case Hnetbsd:
case Hopenbsd:
+ case Hsolaris:
break;
}
- if(outfile == nil) {
- if(HEADTYPE == Hwindows)
- outfile = "6.out.exe";
- else
- outfile = "6.out";
- }
-
- libinit();
-
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hplan9x32: /* plan 9 */
- HEADR = 32L;
- if(INITTEXT == -1)
- INITTEXT = 4096+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
- case Hplan9x64: /* plan 9 */
+ case Hplan9: /* plan 9 */
HEADR = 32L + 8L;
if(INITTEXT == -1)
INITTEXT = 0x200000+HEADR;
@@ -202,11 +103,6 @@ main(int argc, char *argv[])
INITRND = 4096;
break;
case Hdarwin: /* apple MACH */
- /*
- * OS X system constant - offset from 0(GS) to our TLS.
- * Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c.
- */
- tlsoffset = 0x8a0;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITRND == -1)
@@ -221,13 +117,7 @@ main(int argc, char *argv[])
case Hnetbsd: /* netbsd */
case Hopenbsd: /* openbsd */
case Hdragonfly: /* dragonfly */
- /*
- * ELF uses TLS offset negative from FS.
- * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
- * Also known to ../../pkg/runtime/sys_linux_amd64.s
- * and ../../pkg/runtime/cgo/gcc_linux_amd64.c.
- */
- tlsoffset = -16;
+ case Hsolaris: /* solaris */
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -237,6 +127,18 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
+ case Hnacl:
+ elfinit();
+ debug['w']++; // disable dwarf, which gets confused and is useless anyway
+ HEADR = 0x10000;
+ funcalign = 32;
+ if(INITTEXT == -1)
+ INITTEXT = 0x20000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0x10000;
+ break;
case Hwindows: /* PE executable */
peinit();
HEADR = PEFILEHEADR;
@@ -248,555 +150,8 @@ main(int argc, char *argv[])
INITRND = PESECTALIGN;
break;
}
+
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
- instinit();
-
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
- zprg.mode = 64;
-
- pcstr = "%.6llux ";
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- dostkoff();
- dostkcheck();
- paramspace = "SP"; /* (FP) now (SP) on output */
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- if(HEADTYPE == Hwindows)
- dope();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = BGETC(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = BGETC(f);
- a->scale = BGETC(f);
- }
- a->offset = 0;
- if(t & T_OFFSET) {
- a->offset = BGETLE4(f);
- if(t & T_64) {
- a->offset &= 0xFFFFFFFFULL;
- a->offset |= (uvlong)BGETLE4(f) << 32;
- }
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- a->type = D_NONE;
- if(t & T_FCONST) {
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = BGETC(f);
- if(a->type < 0 || a->type >= D_SIZE)
- mangle(pn);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
- s = a->sym;
- t = a->type;
- if(t == D_INDIR+D_GS || a->index == D_GS)
- a->offset += tlsoffset;
- if(t != D_AUTO && t != D_PARAM) {
- if(s && adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- switch(t) {
- case D_FILE:
- case D_FILE1:
- case D_AUTO:
- case D_PARAM:
- if(s == S)
- mangle(pn);
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- vlong ipc;
- Prog *p;
- int v, o, r, skip, mode;
- Sym *h[NSYM], *s;
- uint32 sig;
- char *name, *x;
- int ntext;
- vlong eof;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
- mode = 64;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
- o |= BGETC(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .6 file\n");
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures "
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = BGETLE4(f);
- p->back = 2;
- p->mode = mode;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- if(p->from.sym == S)
- mangle(pn);
- break;
- }
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- else if(p->from.scale & NOPTR)
- s->type = SNOPTRBSS;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATYPE:
- if(skip)
- goto casdef;
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- if(fromgotype) {
- if(s->gotype && s->gotype != fromgotype)
- diag("%s: type mismatch for %s", pn, s->name);
- s->gotype = fromgotype;
- }
- s->type = STEXT;
- s->hist = gethist();
- s->value = pc;
- s->args = p->to.offset >> 32;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AMODE:
- if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
- switch((int)p->from.offset){
- case 16: case 32: case 64:
- mode = p->from.offset;
- break;
- }
- }
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AMOVSS:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AMOVSD:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(*p));
-
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- p->mode = q->mode;
- return p;
}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
deleted file mode 100644
index 46603ad45..000000000
--- a/src/cmd/6l/optab.c
+++ /dev/null
@@ -1,1369 +0,0 @@
-// Inferno utils/6l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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 "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi64, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,0,
- Ynone, Yiauto, Zpseudo,0,
- Ynone, Yml, Zpseudo,0,
- Ynone, Yrf, Zpseudo,0,
- Ynone, Yxr, Zpseudo,0,
- Yiauto, Ynone, Zpseudo,0,
- Yml, Ynone, Zpseudo,0,
- Yrf, Ynone, Zpseudo,0,
- Yxr, Ynone, Zpseudo,1,
- 0
-};
-uchar yfuncdata[] =
-{
- Yi32, Ym, Zpseudo, 0,
- 0
-};
-uchar ypcdata[] =
-{
- Yi32, Yi32, Zpseudo, 0,
- 0
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincw[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymbs[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar ybtl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar ymovw[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1,
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
- Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
- Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
- Yiauto, Yrl, Zaut_r, 2,
- 0
-};
-uchar yret[] =
-{
- Ynone, Ynone, Zo_iw, 1,
- Yi32, Ynone, Zo_iw, 1,
- 0
-};
-uchar ymovq[] =
-{
- Yrl, Yml, Zr_m, 1, // 0x89
- Yml, Yrl, Zm_r, 1, // 0x8b
- Yi0, Yrl, Zclr, 1, // 0x31
- Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
- Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
- Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
- Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
- Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
- Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
- Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
- Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
- Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2
- Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64
- Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
- Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
- Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zmb_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yxchg[] =
-{
- Yax, Yrl, Z_rp, 1,
- Yrl, Yax, Zrp_, 1,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- Yml, Yrl, Zm_r, 2,
- 0
-};
-uchar yimul3[] =
-{
- Yml, Yrl, Zibm_r, 2,
- 0
-};
-uchar ybyte[] =
-{
- Yi64, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar ybswap[] =
-{
- Ynone, Yrl, Z_rp, 2,
- 0,
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 0,
- Yi0, Ybr, Zbr, 0,
- Yi1, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m64, 0,
- Yrx, Yrx, Zo_m64, 2,
- Ynone, Ybr, Zcall, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m64, 2,
- Ynone, Ybr, Zjmp, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ymm[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxm[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvm1[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Yxm, Ymr, Zm_r_xm, 2,
- 0
-};
-uchar yxcvm2[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Ymm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxmq[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxr[] =
-{
- Yxr, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxr_ml[] =
-{
- Yxr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar ymr[] =
-{
- Ymr, Ymr, Zm_r, 1,
- 0
-};
-uchar ymr_ml[] =
-{
- Ymr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar yxcmp[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcmpi[] =
-{
- Yxm, Yxr, Zm_r_i_xm, 2,
- 0
-};
-uchar yxmov[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- Yxr, Yxm, Zr_m_xm, 1,
- 0
-};
-uchar yxcvfl[] =
-{
- Yxm, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxcvlf[] =
-{
- Yml, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvfq[] =
-{
- Yxm, Yrl, Zm_r_xm, 2,
- 0
-};
-uchar yxcvqf[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yps[] =
-{
- Ymm, Ymr, Zm_r_xm, 1,
- Yi8, Ymr, Zibo_m_xm, 2,
- Yxm, Yxr, Zm_r_xm, 2,
- Yi8, Yxr, Zibo_m_xm, 3,
- 0
-};
-uchar yxrrl[] =
-{
- Yxr, Yrl, Zm_r, 1,
- 0
-};
-uchar ymfp[] =
-{
- Ymm, Ymr, Zm_r_3d, 1,
- 0,
-};
-uchar ymrxr[] =
-{
- Ymr, Yxr, Zm_r, 1,
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar ymshuf[] =
-{
- Ymm, Ymr, Zibm_r, 2,
- 0
-};
-uchar ymshufb[] =
-{
- Yxm, Yxr, Zm2_r, 2,
- 0
-};
-uchar yxshuf[] =
-{
- Yxm, Yxr, Zibm_r, 2,
- 0
-};
-uchar yextrw[] =
-{
- Yxr, Yrl, Zibm_r, 2,
- 0
-};
-uchar yinsrw[] =
-{
- Yml, Yxr, Zibm_r, 2,
- 0
-};
-uchar yinsr[] =
-{
- Ymm, Yxr, Zibm_r, 3,
- 0
-};
-uchar ypsdq[] =
-{
- Yi8, Yxr, Zibo_m, 2,
- 0
-};
-uchar ymskb[] =
-{
- Yxr, Yrl, Zm_r_xm, 2,
- Ymr, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar ycrc32l[] =
-{
- Yml, Yrl, Zlitm_r, 0,
-};
-uchar yprefetch[] =
-{
- Ym, Ynone, Zm_o, 2,
- 0,
-};
-uchar yaes[] =
-{
- Yxm, Yxr, Zlitm_r, 2,
- 0
-};
-uchar yaes2[] =
-{
- Yxm, Yxr, Zibm_r, 2,
- 0
-};
-
-/*
- * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
- * and p->from and p->to as operands (Adr*). The linker scans optab to find
- * the entry with the given p->as and then looks through the ytable for that
- * instruction (the second field in the optab struct) for a line whose first
- * two values match the Ytypes of the p->from and p->to operands. The function
- * oclass in span.c computes the specific Ytype of an operand and then the set
- * of more general Ytypes that it satisfies is implied by the ycover table, set
- * up in instinit. For example, oclass distinguishes the constants 0 and 1
- * from the more general 8-bit constants, but instinit says
- *
- * ycover[Yi0*Ymax + Ys32] = 1;
- * ycover[Yi1*Ymax + Ys32] = 1;
- * ycover[Yi8*Ymax + Ys32] = 1;
- *
- * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
- * if that's what an instruction can handle.
- *
- * In parallel with the scan through the ytable for the appropriate line, there
- * is a z pointer that starts out pointing at the strange magic byte list in
- * the Optab struct. With each step past a non-matching ytable line, z
- * advances by the 4th entry in the line. When a matching line is found, that
- * z pointer has the extra data to use in laying down the instruction bytes.
- * The actual bytes laid down are a function of the 3rd entry in the line (that
- * is, the Ztype) and the z bytes.
- *
- * For example, let's look at AADDL. The optab line says:
- * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- *
- * and yaddl says
- * uchar yaddl[] =
- * {
- * Yi8, Yml, Zibo_m, 2,
- * Yi32, Yax, Zil_, 1,
- * Yi32, Yml, Zilo_m, 2,
- * Yrl, Yml, Zr_m, 1,
- * Yml, Yrl, Zm_r, 1,
- * 0
- * };
- *
- * so there are 5 possible types of ADDL instruction that can be laid down, and
- * possible states used to lay them down (Ztype and z pointer, assuming z
- * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
- *
- * Yi8, Yml -> Zibo_m, z (0x83, 00)
- * Yi32, Yax -> Zil_, z+2 (0x05)
- * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
- * Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
- * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
- *
- * The Pconstant in the optab line controls the prefix bytes to emit. That's
- * relatively straightforward as this program goes.
- *
- * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for
- * example, is an opcode byte (z[0]) then an asmando (which is some kind of
- * encoded addressing mode for the Yml arg), and then a single immediate byte.
- * Zilo_m is the same but a long (32-bit) immediate.
- */
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, P32, 0x37 },
- { AAAD, ynone, P32, 0xd5,0x0a },
- { AAAM, ynone, P32, 0xd4,0x0a },
- { AAAS, ynone, P32, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDPD, yxm, Pq, 0x58 },
- { AADDPS, yxm, Pm, 0x58 },
- { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDSD, yxm, Pf2, 0x58 },
- { AADDSS, yxm, Pf3, 0x58 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDNPD, yxm, Pq, 0x55 },
- { AANDNPS, yxm, Pm, 0x55 },
- { AANDPD, yxm, Pq, 0x54 },
- { AANDPS, yxm, Pq, 0x54 },
- { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, P32, 0x63 },
- { ABOUNDL, yrl_m, P32, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABSWAPL, ybswap, Px, 0x0f,0xc8 },
- { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 },
- { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
- { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
- { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
- { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
- { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
- { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
- { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
- { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
- { ABTSL, ybtl, Pm, 0xba,(05),0xab },
- { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
- { ABTSW, ybtl, Pq, 0xba,(05),0xab },
- { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xe8 },
- { ACDQ, ynone, Px, 0x99 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
- { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
- { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
- { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
- { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
- { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
- { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
- { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
- { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
- { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
- { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
- { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
- { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
- { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
- { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
- { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPPD, yxcmpi, Px, Pe,0xc2 },
- { ACMPPS, yxcmpi, Pm, 0xc2,0 },
- { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSQ, ynone, Pw, 0xa7 },
- { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACOMISD, yxcmp, Pe, 0x2f },
- { ACOMISS, yxcmp, Pm, 0x2f },
- { ACPUID, ynone, Pm, 0xa2 },
- { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
- { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
- { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
- { ACVTPD2PS, yxm, Pe, 0x5a },
- { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
- { ACVTPS2PD, yxm, Pm, 0x5a },
- { API2FW, ymfp, Px, 0x0c },
- { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
- { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
- { ACVTSD2SS, yxm, Pf2, 0x5a },
- { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
- { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
- { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
- { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
- { ACVTSS2SD, yxm, Pf3, 0x5a },
- { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
- { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
- { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
- { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
- { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
- { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
- { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
- { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
- { ACWD, ynone, Pe, 0x99 },
- { ACQO, ynone, Pw, 0x99 },
- { ADAA, ynone, P32, 0x27 },
- { ADAS, ynone, P32, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0xff,(01) },
- { ADECQ, yincl, Pw, 0xff,(01) },
- { ADECW, yincw, Pe, 0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVPD, yxm, Pe, 0x5e },
- { ADIVPS, yxm, Pm, 0x5e },
- { ADIVQ, ydivl, Pw, 0xf7,(06) },
- { ADIVSD, yxm, Pf2, 0x5e },
- { ADIVSS, yxm, Pf3, 0x5e },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AEMMS, ynone, Pm, 0x77 },
- { AENTER }, /* botch */
- { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
- { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
- { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
- { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVQ, ydivl, Pw, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
- { AIMUL3Q, yimul3, Pw, 0x6b,(00) },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0xff,(00) },
- { AINCQ, yincl, Pw, 0xff,(00) },
- { AINCW, yincw, Pe, 0xff,(00) },
- { AINL, yin, Px, 0xe5,0xed },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, P32, 0xce },
- { AINW, yin, Pe, 0xe5,0xed },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETQ, ynone, Pw, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZL, yloop, Px, 0xe3 },
- { AJCXZQ, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAQ, ym_rl, Pw, 0x8d },
- { ALEAVEL, ynone, P32, 0xc9 },
- { ALEAVEQ, ynone, Py, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSQ, ynone, Pw, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMASKMOVOU, yxr, Pe, 0xf7 },
- { AMASKMOVQ, ymr, Pm, 0xf7 },
- { AMAXPD, yxm, Pe, 0x5f },
- { AMAXPS, yxm, Pm, 0x5f },
- { AMAXSD, yxm, Pf2, 0x5f },
- { AMAXSS, yxm, Pf3, 0x5f },
- { AMINPD, yxm, Pe, 0x5d },
- { AMINPS, yxm, Pm, 0x5d },
- { AMINSD, yxm, Pf2, 0x5d },
- { AMINSS, yxm, Pf3, 0x5d },
- { AMOVAPD, yxmov, Pe, 0x28,0x29 },
- { AMOVAPS, yxmov, Pm, 0x28,0x29 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
- { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
- { AMOVHLPS, yxr, Pm, 0x12 },
- { AMOVHPD, yxmov, Pe, 0x16,0x17 },
- { AMOVHPS, yxmov, Pm, 0x16,0x17 },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 },
- { AMOVLHPS, yxr, Pm, 0x16 },
- { AMOVLPD, yxmov, Pe, 0x12,0x13 },
- { AMOVLPS, yxmov, Pm, 0x12,0x13 },
- { AMOVLQSX, yml_rl, Pw, 0x63 },
- { AMOVLQZX, yml_rl, Px, 0x8b },
- { AMOVMSKPD, yxrrl, Pq, 0x50 },
- { AMOVMSKPS, yxrrl, Pm, 0x50 },
- { AMOVNTO, yxr_ml, Pe, 0xe7 },
- { AMOVNTPD, yxr_ml, Pe, 0x2b },
- { AMOVNTPS, yxr_ml, Pm, 0x2b },
- { AMOVNTQ, ymr_ml, Pm, 0xe7 },
- { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 },
- { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSD, yxmov, Pf2, 0x10,0x11 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSQ, ynone, Pw, 0xa5 },
- { AMOVSS, yxmov, Pf3, 0x10,0x11 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMOVUPD, yxmov, Pe, 0x10,0x11 },
- { AMOVUPS, yxmov, Pm, 0x10,0x11 },
- { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
- { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULPD, yxm, Pe, 0x59 },
- { AMULPS, yxm, Ym, 0x59 },
- { AMULQ, ydivl, Pw, 0xf7,(04) },
- { AMULSD, yxm, Pf2, 0x59 },
- { AMULSS, yxm, Pf3, 0x59 },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Pb, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGQ, yscond, Pw, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px, 0,0 },
- { ANOTB, yscond, Pb, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTQ, yscond, Pw, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORPD, yxm, Pq, 0x56 },
- { AORPS, yxm, Pm, 0x56 },
- { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
- { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
- { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
- { APADDB, ymm, Py, 0xfc,Pe,0xfc },
- { APADDL, ymm, Py, 0xfe,Pe,0xfe },
- { APADDQ, yxm, Pe, 0xd4 },
- { APADDSB, ymm, Py, 0xec,Pe,0xec },
- { APADDSW, ymm, Py, 0xed,Pe,0xed },
- { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
- { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
- { APADDW, ymm, Py, 0xfd,Pe,0xfd },
- { APAND, ymm, Py, 0xdb,Pe,0xdb },
- { APANDN, ymm, Py, 0xdf,Pe,0xdf },
- { APAUSE, ynone, Px, 0xf3,0x90 },
- { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
- { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
- { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
- { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
- { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
- { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
- { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
- { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
- { APEXTRW, yextrw, Pq, 0xc5,(00) },
- { APF2IL, ymfp, Px, 0x1d },
- { APF2IW, ymfp, Px, 0x1c },
- { API2FL, ymfp, Px, 0x0d },
- { APFACC, ymfp, Px, 0xae },
- { APFADD, ymfp, Px, 0x9e },
- { APFCMPEQ, ymfp, Px, 0xb0 },
- { APFCMPGE, ymfp, Px, 0x90 },
- { APFCMPGT, ymfp, Px, 0xa0 },
- { APFMAX, ymfp, Px, 0xa4 },
- { APFMIN, ymfp, Px, 0x94 },
- { APFMUL, ymfp, Px, 0xb4 },
- { APFNACC, ymfp, Px, 0x8a },
- { APFPNACC, ymfp, Px, 0x8e },
- { APFRCP, ymfp, Px, 0x96 },
- { APFRCPIT1, ymfp, Px, 0xa6 },
- { APFRCPI2T, ymfp, Px, 0xb6 },
- { APFRSQIT1, ymfp, Px, 0xa7 },
- { APFRSQRT, ymfp, Px, 0x97 },
- { APFSUB, ymfp, Px, 0x9a },
- { APFSUBR, ymfp, Px, 0xaa },
- { APINSRW, yinsrw, Pq, 0xc4,(00) },
- { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) },
- { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) },
- { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
- { APMAXSW, yxm, Pe, 0xee },
- { APMAXUB, yxm, Pe, 0xde },
- { APMINSW, yxm, Pe, 0xea },
- { APMINUB, yxm, Pe, 0xda },
- { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
- { APMULHRW, ymfp, Px, 0xb7 },
- { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
- { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
- { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
- { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
- { APOPAL, ynone, P32, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, P32, 0x9d },
- { APOPFQ, ynone, Py, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, P32, 0x58,0x8f,(00) },
- { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pq, 0xf6 },
- { APSHUFHW, yxshuf, Pf3, 0x70,(00) },
- { APSHUFL, yxshuf, Pq, 0x70,(00) },
- { APSHUFLW, yxshuf, Pf2, 0x70,(00) },
- { APSHUFW, ymshuf, Pm, 0x70,(00) },
- { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
- { APSLLO, ypsdq, Pq, 0x73,(07) },
- { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
- { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
- { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
- { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
- { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
- { APSRLO, ypsdq, Pq, 0x73,(03) },
- { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
- { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
- { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
- { APSUBB, yxm, Pe, 0xf8 },
- { APSUBL, yxm, Pe, 0xfa },
- { APSUBQ, yxm, Pe, 0xfb },
- { APSUBSB, yxm, Pe, 0xe8 },
- { APSUBSW, yxm, Pe, 0xe9 },
- { APSUBUSB, yxm, Pe, 0xd8 },
- { APSUBUSW, yxm, Pe, 0xd9 },
- { APSUBW, yxm, Pe, 0xf9 },
- { APSWAPL, ymfp, Px, 0xbb },
- { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
- { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
- { APUNPCKHQDQ, yxm, Pe, 0x6d },
- { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
- { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
- { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
- { APUNPCKLQDQ, yxm, Pe, 0x6c },
- { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
- { APUSHAL, ynone, P32, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, P32, 0x9c },
- { APUSHFQ, ynone, Py, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { APXOR, ymm, Py, 0xef,Pe,0xef },
- { AQUAD, ybyte, Px, 8 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCPPS, yxm, Pm, 0x53 },
- { ARCPSS, yxm, Pf3, 0x53 },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { ARETFW, yret, Pe, 0xcb,0xca },
- { ARETFL, yret, Px, 0xcb,0xca },
- { ARETFQ, yret, Pw, 0xcb,0xca },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARSQRTPS, yxm, Pm, 0x52 },
- { ARSQRTSS, yxm, Pf3, 0x52 },
- { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASQ, ynone, Pw, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHUFPD, yxshuf, Pq, 0xc6,(00) },
- { ASHUFPS, yxshuf, Pm, 0xc6,(00) },
- { ASQRTPD, yxm, Pe, 0x51 },
- { ASQRTPS, yxm, Pm, 0x51 },
- { ASQRTSD, yxm, Pf2, 0x51 },
- { ASQRTSS, yxm, Pf3, 0x51 },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSQ, ynone, Pw, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBPD, yxm, Pe, 0x5c },
- { ASUBPS, yxm, Pm, 0x5c },
- { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBSD, yxm, Pf2, 0x5c },
- { ASUBSS, yxm, Pf3, 0x5c },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASWAPGS, ynone, Pm, 0x01,0xf8 },
- { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AUCOMISD, yxcmp, Pe, 0x2e },
- { AUCOMISS, yxcmp, Pm, 0x2e },
- { AUNPCKHPD, yxm, Pe, 0x15 },
- { AUNPCKHPS, yxm, Pm, 0x15 },
- { AUNPCKLPD, yxm, Pe, 0x14 },
- { AUNPCKLPS, yxm, Pm, 0x14 },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
- { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 },
- { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORPD, yxm, Pe, 0x57 },
- { AXORPS, yxm, Pm, 0x57 },
- { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
-
- { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
- { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
- { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
- { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
- { AINVD, ynone, Pm, 0x08 },
- { AINVLPG, ymbs, Pm, 0x01,(07) },
- { ALFENCE, ynone, Pm, 0xae,0xe8 },
- { AMFENCE, ynone, Pm, 0xae,0xf0 },
- { AMOVNTIL, yrl_ml, Pm, 0xc3 },
- { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
- { ARDMSR, ynone, Pm, 0x32 },
- { ARDPMC, ynone, Pm, 0x33 },
- { ARDTSC, ynone, Pm, 0x31 },
- { ARSM, ynone, Pm, 0xaa },
- { ASFENCE, ynone, Pm, 0xae,0xf8 },
- { ASYSRET, ynone, Pm, 0x07 },
- { AWBINVD, ynone, Pm, 0x09 },
- { AWRMSR, ynone, Pm, 0x30 },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
- { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 },
- { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 },
-
- { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
- { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
- { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
- { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
-
- { AMOVQL, yrl_ml, Px, 0x89 },
-
- { AUNDEF, ynone, Px, 0x0f, 0x0b },
-
- { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
- { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) },
- { AAESDEC, yaes, Pq, 0x38,0xde,(0) },
- { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) },
- { AAESIMC, yaes, Pq, 0x38,0xdb,(0) },
- { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) },
-
- { APSHUFD, yaes2, Pq, 0x70,(0) },
- { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
-
- { AUSEFIELD, ynop, Px, 0,0 },
- { AFUNCDATA, yfuncdata, Px, 0,0 },
- { APCDATA, ypcdata, Px, 0,0 },
-
- { AEND },
- 0
-};
-
-Optab* opindex[ALAST+1];
-
-/*
-AMOVD 0f 6e/r mmx,reg/mem32[mem64-rex?]
-AMOVD 0f 7e/r reg/mem32[64],mmx STORE
-AMOVQ 0f 6f/r mmx1,mmx2/mem64
-AMOVQ 0f 7f/r mmx1/mem64,mmx2
-*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
deleted file mode 100644
index 1be3c18fe..000000000
--- a/src/cmd/6l/pass.c
+++ /dev/null
@@ -1,991 +0,0 @@
-// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
- case AUNDEF:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- if((q = brchain(p->pcond)) != P)
- p->pcond = q;
- if((q = brchain(p->link)) != P)
- p->link = q;
- if(p->from.type == D_CONST) {
- if(p->from.offset == 1) {
- /*
- * expect conditional jump to be taken.
- * rewrite so that's the fall-through case.
- */
- p->as = relinv(a);
- q = p->link;
- p->link = p->pcond;
- p->pcond = q;
- }
- } else {
- q = p->link;
- if(q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- }
- xfol(p->link, last);
- if(p->pcond->mark)
- return;
- p = p->pcond;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-Prog*
-byteq(int v)
-{
- Prog *p;
-
- p = prg();
- p->as = ABYTE;
- p->from.type = D_CONST;
- p->from.offset = v&0xff;
- return p;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- errorexit();
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
- Sym *gmsym;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
-
- if(flag_shared) {
- s = lookup("init_array", 0);
- s->type = SINITARR;
- s->reachable = 1;
- s->hide = 1;
- addaddr(s, lookup(INITENTRY, 0));
- }
-
- gmsym = lookup("runtime.tlsgm", 0);
- if(linkmode != LinkExternal)
- gmsym->reachable = 0;
- s = lookup("exit", 0);
- vexit = s->value;
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Windows
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x28(GS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI
- && p->from.offset <= 8) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x28;
- }
- }
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
- || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
- // ELF uses FS instead of GS.
- if(p->from.type == D_INDIR+D_GS)
- p->from.type = D_INDIR+D_FS;
- if(p->to.type == D_INDIR+D_GS)
- p->to.type = D_INDIR+D_FS;
- if(p->from.index == D_GS)
- p->from.index = D_FS;
- if(p->to.index == D_GS)
- p->to.index = D_FS;
- }
- if(!flag_shared) {
- // Convert g() or m() accesses of the form
- // op n(reg)(GS*1), reg
- // to
- // op n(GS*1), reg
- if(p->from.index == D_FS || p->from.index == D_GS) {
- p->from.type = D_INDIR + p->from.index;
- p->from.index = D_NONE;
- }
- // Convert g() or m() accesses of the form
- // op reg, n(reg)(GS*1)
- // to
- // op reg, n(GS*1)
- if(p->to.index == D_FS || p->to.index == D_GS) {
- p->to.type = D_INDIR + p->to.index;
- p->to.index = D_NONE;
- }
- // Convert get_tls access of the form
- // op runtime.tlsgm(SB), reg
- // to
- // NOP
- if(gmsym != S && p->from.sym == gmsym) {
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
- p->from.sym = nil;
- p->to.sym = nil;
- continue;
- }
- } else {
- // Convert TLS reads of the form
- // op n(GS), reg
- // to
- // MOVQ $runtime.tlsgm(SB), reg
- // op n(reg)(GS*1), reg
- if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->to = p->to;
- q->as = p->as;
- q->from.type = D_INDIR+p->to.type;
- q->from.index = p->from.type - D_INDIR;
- q->from.scale = 1;
- q->from.offset = p->from.offset;
- p->as = AMOVQ;
- p->from.type = D_EXTERN;
- p->from.sym = gmsym;
- p->from.offset = 0;
- }
- }
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&SMASK) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-static char*
-morename[] =
-{
- "runtime.morestack00",
- "runtime.morestack10",
- "runtime.morestack01",
- "runtime.morestack11",
-
- "runtime.morestack8",
- "runtime.morestack16",
- "runtime.morestack24",
- "runtime.morestack32",
- "runtime.morestack40",
- "runtime.morestack48",
-};
-Prog* pmorestack[nelem(morename)];
-Sym* symmorestack[nelem(morename)];
-Sym* gmsym;
-
-static Prog* load_g_cx(Prog*);
-static Prog* stacksplit(Prog*, int32, Prog**);
-
-void
-dostkoff(void)
-{
- Prog *p, *q, *q1;
- int32 autoffset, deltasp;
- int a, pcsize;
- uint32 i;
-
- gmsym = lookup("runtime.tlsgm", 0);
- for(i=0; i<nelem(morename); i++) {
- symmorestack[i] = lookup(morename[i], 0);
- if(symmorestack[i]->type != STEXT)
- diag("morestack trampoline not defined - %s", morename[i]);
- pmorestack[i] = symmorestack[i]->text;
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
- for(q = p; q != P; q = q->link)
- if(q->as == ACALL)
- goto noleaf;
- p->from.scale |= NOSPLIT;
- noleaf:;
- }
-
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- q = P;
- if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
- p = appendp(p);
- p = load_g_cx(p); // load g into CX
- }
- if(!(cursym->text->from.scale & NOSPLIT))
- p = stacksplit(p, autoffset, &q); // emit split check
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- } else {
- // zero-byte stack adjustment.
- // Insert a fake non-zero adjustment so that stkcheck can
- // recognize the end of the stack-splitting prolog.
- p = appendp(p);
- p->as = ANOP;
- p->spadj = -PtrSize;
- p = appendp(p);
- p->as = ANOP;
- p->spadj = PtrSize;
- }
- if(q != P)
- q->pcond = p;
- deltasp = autoffset;
-
- if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + PtrSize;
- p = appendp(p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- }
-
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ASUBQ;
- p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
-
- if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
- // 6l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_SP;
- p->to.type = D_DI;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = autoffset/8;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = AREP;
-
- p = appendp(p);
- p->as = ASTOSQ;
- }
-
- for(; p != P; p = p->link) {
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- p->spadj = 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- p->spadj = -8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(p);
- p = appendp(p);
- // g->panicwrap -= autoffset + PtrSize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
- p->as = ARET;
- }
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- if(p->to.sym) // retjmp
- p->as = AJMP;
- }
- }
-}
-
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-static Prog*
-load_g_cx(Prog *p)
-{
- if(flag_shared) {
- // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
- p->as = AMOVQ;
- p->from.type = D_EXTERN;
- p->from.sym = gmsym;
- p->to.type = D_CX;
- p = appendp(p);
- }
- p->as = AMOVQ;
- if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
- || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly)
- // ELF uses FS
- p->from.type = D_INDIR+D_FS;
- else
- p->from.type = D_INDIR+D_GS;
- if(flag_shared) {
- // Add TLS offset stored in CX
- p->from.index = p->from.type - D_INDIR;
- p->from.type = D_INDIR + D_CX;
- }
- p->from.offset = tlsoffset+0;
- p->to.type = D_CX;
- if(HEADTYPE == Hwindows) {
- // movq %gs:0x28, %rcx
- // movq (%rcx), %rcx
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x28;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- }
- return p;
-}
-
-// Append code to p to check for stack split.
-// Appends to (does not overwrite) p.
-// Assumes g is in CX.
-// Returns last new instruction.
-// On return, *jmpok is the instruction that should jump
-// to the stack frame allocation if no split is needed.
-static Prog*
-stacksplit(Prog *p, int32 framesize, Prog **jmpok)
-{
- Prog *q, *q1;
- uint32 moreconst1, moreconst2, i;
-
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
-
- q = P;
- q1 = P;
- if(framesize <= StackSmall) {
- // small stack: SP <= stackguard
- // CMPQ SP, stackguard
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize <= stackguard-StackSmall
- // LEAQ -xxx(SP), AX
- // CMPQ AX, stackguard
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- } else {
- // Such a large stack we need to protect against wraparound.
- // If SP is close to zero:
- // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- //
- // Preemption sets stackguard to StackPreempt, a very large value.
- // That breaks the math above, so we have to check for that explicitly.
- // MOVQ stackguard, CX
- // CMPQ CX, $StackPreempt
- // JEQ label-of-call-to-morestack
- // LEAQ StackGuard(SP), AX
- // SUBQ CX, AX
- // CMPQ AX, $(framesize+(StackGuard-StackSmall))
-
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_SI;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SI;
- p->to.type = D_CONST;
- p->to.offset = StackPreempt;
-
- p = appendp(p);
- p->as = AJEQ;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = StackGuard;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ASUBQ;
- p->from.type = D_SI;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- q = p;
-
- // If we ask for more stack, we'll get a minimum of StackMin bytes.
- // We need a stack frame large enough to hold the top-of-stack data,
- // the function arguments+results, our caller's PC, our frame,
- // a word for the return PC of the next call, and then the StackLimit bytes
- // that must be available on entry to any function called from a function
- // that did a stack check. If StackMin is enough, don't ask for a specific
- // amount: then we can use the custom functions and save a few
- // instructions.
- moreconst1 = 0;
- if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
- moreconst1 = framesize;
- moreconst2 = textarg;
- if(moreconst2 == 1) // special marker
- moreconst2 = 0;
- if((moreconst2&7) != 0)
- diag("misaligned argument size in stack split");
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
- p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
- } else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
- }
-
- p = appendp(p);
- p->as = AJMP;
- p->to.type = D_BRANCH;
- p->pcond = cursym->text->link;
-
- if(q != P)
- q->pcond = p->link;
- if(q1 != P)
- q1->pcond = q->link;
-
- *jmpok = q;
- return p;
-}
-
-vlong
-atolwhex(char *s)
-{
- vlong n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
deleted file mode 100644
index 862ce080c..000000000
--- a/src/cmd/6l/prof.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
deleted file mode 100644
index 74f11d635..000000000
--- a/src/cmd/6l/span.c
+++ /dev/null
@@ -1,1846 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-
-static int rexflag;
-static int asmode;
-static vlong vaddr(Adr*, Reloc*);
-
-// single-instruction no-ops of various lengths.
-// constructed by hand and disassembled with gdb to verify.
-// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
-static uchar nop[][16] = {
- {0x90},
- {0x66, 0x90},
- {0x0F, 0x1F, 0x00},
- {0x0F, 0x1F, 0x40, 0x00},
- {0x0F, 0x1F, 0x44, 0x00, 0x00},
- {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
- {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
- {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-};
-
-static void
-fillnop(uchar *p, int n)
-{
- int m;
-
- while(n > 0) {
- m = n;
- if(m > nelem(nop))
- m = nelem(nop);
- memmove(p, nop[m-1], m);
- p += m;
- n -= m;
- }
-}
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- if(s->p != nil)
- return;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2)) {
- p->back |= 1; // backward jump
- q->back |= 4; // loop head
- }
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
- // pad with NOPs
- v = -c&(LoopAlign-1);
- if(v <= MaxLoopPad) {
- symgrow(s, c+v);
- fillnop(s->p+c, v);
- c += v;
- }
- }
-
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- if(q->as == AJCXZL)
- s->p[q->pc+2] = v;
- else
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->p != nil)
- continue;
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = p->mode != 64? AADDL: AADDQ;
- if(v < 0) {
- p->as = p->mode != 64? ASUBL: ASUBQ;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, vlong v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int c, i;
-
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- switch(a->index) {
- case D_CS:
- return 0x2e;
- case D_DS:
- return 0x3e;
- case D_ES:
- return 0x26;
- case D_FS:
- return 0x64;
- case D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- vlong v;
- int32 l;
-
- if(a->type >= D_INDIR || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- if(flag_shared)
- return Yiauto;
- else
- return Yi32; /* TO DO: Yi64 */
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
-/*
- case D_SPB:
-*/
- case D_BPB:
- case D_SIB:
- case D_DIB:
- case D_R8B:
- case D_R9B:
- case D_R10B:
- case D_R11B:
- case D_R12B:
- case D_R13B:
- case D_R14B:
- case D_R15B:
- if(asmode != 64)
- return Yxxx;
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CL:
- return Ycl;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_R8: /* not really Yrl */
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- return Yxxx;
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_M0+0:
- case D_M0+1:
- case D_M0+2:
- case D_M0+3:
- case D_M0+4:
- case D_M0+5:
- case D_M0+6:
- case D_M0+7:
- return Ymr;
-
- case D_X0+0:
- case D_X0+1:
- case D_X0+2:
- case D_X0+3:
- case D_X0+4:
- case D_X0+5:
- case D_X0+6:
- case D_X0+7:
- case D_X0+8:
- case D_X0+9:
- case D_X0+10:
- case D_X0+11:
- case D_X0+12:
- case D_X0+13:
- case D_X0+14:
- case D_X0+15:
- return Yxr;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
- case D_CR+8: return Ycr8;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- l = v;
- if((vlong)l == v)
- return Ys32; /* can sign extend */
- if((v>>32) == 0)
- return Yi32; /* unsigned */
- return Yi64;
- }
- return Yi32; /* TO DO: D_ADDR as Yi64 */
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_R8:
- case D_R9:
- case D_R10:
- case D_R11:
- case D_R12:
- case D_R13:
- case D_R14:
- case D_R15:
- if(asmode != 64)
- goto bad;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d/%d/%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-static void
-put8(vlong v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr[4] = v>>32;
- andptr[5] = v>>40;
- andptr[6] = v>>48;
- andptr[7] = v>>56;
- andptr += 8;
-}
-
-/*
-static void
-relput8(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- r = addrel(cursym);
- *r = rel;
- r->siz = 8;
- r->off = p->pc + andptr - and;
- }
- put8(v);
-}
-*/
-
-vlong
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static vlong
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- vlong v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->siz = 4; // TODO: 8 for external symbols
- r->off = -1; // caller must fill in
- r->sym = s;
- r->add = v;
- v = 0;
- if(flag_shared) {
- if(s->type == STLSBSS) {
- r->xadd = r->add - r->siz;
- r->type = D_TLS;
- r->xsym = s;
- } else
- r->type = D_PCREL;
- } else
- r->type = D_ADDR;
- }
- return v;
-}
-
-static void
-asmandsz(Adr *a, int r, int rex, int m64)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- USED(m64);
- rex &= (0x40 | Rxr);
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
- if(t < D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- if(flag_shared)
- goto bad;
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_X0+15) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- if(flag_shared && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || asmode != 64) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- goto putrelv;
- }
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- } else if(iself && linkmode == LinkExternal && a->type == D_INDIR+D_FS
- && HEADTYPE != Hopenbsd) {
- Reloc *r;
- Sym *s;
-
- r = addrel(cursym);
- r->off = curp->pc + andptr - and;
- r->add = a->offset-tlsoffset;
- r->xadd = r->add;
- r->siz = 4;
- r->type = D_TLS;
- s = lookup("runtime.tlsgm", 0);
- r->sym = s;
- r->xsym = s;
- v = 0;
- }
-
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-void
-asmand(Adr *a, Adr *ra)
-{
- asmandsz(a, reg[ra->type], regrex[ra->type], 0);
-}
-
-void
-asmando(Adr *a, int o)
-{
- asmandsz(a, o, 0, 0);
-}
-
-static void
-bytereg(Adr *a, char *t)
-{
- if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
- a->type = D_AL + (a->type-D_AX);
- *t = 0;
- }
-}
-
-#define E 0xff
-Movtab ymovtab[] =
-{
-/* push */
- {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
- {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
- {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
- {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
- {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
- {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
- {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
-
- {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
- {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
- {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
- {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
- {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
- {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
-
-/* pop */
- {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
- {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
- {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
- {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
- {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
- {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
-
- {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
- {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
- {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
- {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
- {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
-
-/* mov seg */
- {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
- {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
- {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
- {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
- {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
- {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
-
- {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
- {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
- {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
- {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
- {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
- {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
-
-/* mov cr */
- {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
- {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
- {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
- {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
- {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
- {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
-
- {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
- {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
- {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
- {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
- {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
- {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
-
-/* mov dr */
- {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
- {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
- {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
- {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
-
- {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
- {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
- {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
- {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
-
-/* mov tr */
- {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
- {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
-
- {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
- {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
-
-/* lgdt, sgdt, lidt, sidt */
- {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
- {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
- {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
- {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
- {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
-
-/* lldt, sldt */
- {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
- {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
-
-/* lmsw, smsw */
- {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
- {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
-
-/* ltr, str */
- {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
- {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
-
-/* load full pointer */
- {AMOVL, Yml, Ycol, 5, 0,0,0,0},
- {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
-
-/* double shift */
- {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
- {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
- {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
- {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
- {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
- {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
- 0
-};
-
-int
-isax(Adr *a)
-{
-
- switch(a->type) {
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- return 1;
- }
- if(a->index == D_AX)
- return 1;
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from)
- p->from.type = to;
- if(p->to.type == from)
- p->to.type = to;
-
- if(p->from.index == from)
- p->from.index = to;
- if(p->to.index == from)
- p->to.index = to;
-
- from += D_INDIR;
- if(p->from.type == from)
- p->from.type = to+D_INDIR;
- if(p->to.type == from)
- p->to.type = to+D_INDIR;
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-static int
-mediaop(Optab *o, int op, int osize, int z)
-{
- switch(op){
- case Pm:
- case Pe:
- case Pf2:
- case Pf3:
- if(osize != 1){
- if(op != Pm)
- *andptr++ = op;
- *andptr++ = Pm;
- op = o->op[++z];
- break;
- }
- default:
- if(andptr == and || andptr[-1] != Pm)
- *andptr++ = Pm;
- break;
- }
- *andptr++ = op;
- return z;
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- Movtab *mo;
- int z, op, ft, tt, xo, l, pre;
- vlong v;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- o = opindex[p->as];
- if(o == nil) {
- diag("asmins: missing op %P", p);
- return;
- }
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
-
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- xo = o->op[0] == 0x0f;
- for(z=0; *t; z+=t[3]+xo,t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
- case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pw;
- *andptr++ = Pm;
- break;
-
- case Pf2: /* xmm opcode escape */
- case Pf3:
- *andptr++ = o->prefix;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pw: /* 64-bit escape */
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- break;
-
- case Pb: /* botch */
- bytereg(&p->from, &p->ft);
- bytereg(&p->to, &p->tt);
- break;
-
- case P32: /* 32 bit but illegal if 64-bit mode */
- if(p->mode == 64)
- diag("asmins: illegal in 64-bit mode: %P", p);
- break;
-
- case Py: /* 64-bit only, no prefix */
- if(p->mode != 64)
- diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
- break;
- }
-
- if(z >= nelem(o->op))
- sysfatal("asmins bad table %P", p);
- op = o->op[z];
- if(op == 0x0f) {
- *andptr++ = op;
- op = o->op[++z];
- }
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zlitm_r:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- asmand(&p->from, &p->to);
- break;
-
- case Zmb_r:
- bytereg(&p->from, &p->ft);
- /* fall through */
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, &p->to);
- break;
- case Zm2_r:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- break;
-
- case Zm_r_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zm_r_3d:
- *andptr++ = 0x0f;
- *andptr++ = 0x0f;
- asmand(&p->from, &p->to);
- *andptr++ = op;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *andptr++ = op;
- asmand(&p->from, &p->to);
- *andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- asmand(&p->from, &p->to);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_xm_nr:
- rexflag = 0;
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- break;
-
- case Zr_m_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, &p->from);
- *andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- break;
-
- case Zo_m64:
- *andptr++ = op;
- asmandsz(&p->to, o->op[z+1], 0, 1);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmando(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zibo_m_xm:
- z = mediaop(o, op, t[3], z);
- asmando(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- *andptr++ = vaddr(a, nil);
- break;
-
- case Zib_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zo_iw:
- *andptr++ = op;
- if(p->from.type != D_NONE){
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- break;
-
- case Ziq_rp:
- v = vaddr(&p->from, &rel);
- l = v>>32;
- if(l == 0 && rel.siz != 8){
- //p->mark |= 0100;
- //print("zero: %llux %P\n", v, p);
- rexflag &= ~(0x40|Rxw);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = 0xb8 + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
- }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
- //p->mark |= 0100;
- //print("sign: %llux %P\n", v, p);
- *andptr ++ = 0xc7;
- asmando(&p->to, 0);
- put4(v);
- }else{ /* need all 8 */
- //print("all: %llux %P\n", v, p);
- rexflag |= regrex[p->to.type] & Rxb;
- *andptr++ = op + reg[p->to.type];
- if(rel.type != 0) {
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put8(v);
- }
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmando(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmando(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- rexflag |= regrex[p->to.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- rexflag |= regrex[p->from.type] & (Rxb|0x40);
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, &p->to);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- case Zloop:
- // TODO: jump across functions needs reloc
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch/loop without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- if(p->as == AJCXZL)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = v;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- if(p->as == AJCXZL)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = 0;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
-/*
- v = q->pc - p->pc - 2;
- if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
-*/
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- if(op > 4) {
- *andptr++ = v>>32;
- *andptr++ = v>>40;
- *andptr++ = v>>48;
- *andptr++ = v>>56;
- }
- }
- }
- break;
- }
- return;
-
-domov:
- for(mo=ymovtab; mo->as; mo++)
- if(p->as == mo->as)
- if(ycover[ft+mo->ft])
- if(ycover[tt+mo->tt]){
- t = mo->op;
- goto mfound;
- }
-bad:
- if(p->mode != 64){
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->to) || p->to.type == D_NONE) {
- // We certainly don't want to exchange
- // with AX if the op is MUL or DIV.
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmando(&p->from, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if(isax(&p->from)) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- subreg(&pp, z, D_BX);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmando(&p->to, reg[D_BX]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- }
- diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(mo->code) {
- default:
- diag("asmins: unknown mov %d %P", mo->code, p);
- break;
-
- case 0: /* lit */
- for(z=0; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[0];
- asmando(&p->to, t[1]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[0];
- asmando(&p->from, t[1]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->to, t[2]);
- rexflag |= regrex[p->from.type] & (Rxr|0x40);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[0];
- *andptr++ = t[1];
- asmando(&p->from, t[2]);
- rexflag |= regrex[p->to.type] & (Rxr|0x40);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[0])
- *andptr++ = t[0];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, &p->to);
- break;
-
- case 6: /* double shift */
- if(t[0] == Pw){
- if(p->mode != 64)
- diag("asmins: illegal 64: %P", p);
- rexflag |= Pw;
- t++;
- }else if(t[0] == Pe){
- *andptr++ = Pe;
- t++;
- }
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[0];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[1];
- asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
- break;
- }
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- int n, np, c;
- Reloc *r;
-
- rexflag = 0;
- andptr = and;
- asmode = p->mode;
- doasm(p);
- if(rexflag){
- /*
- * as befits the whole approach of the architecture,
- * the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
- * before the 0f opcode escape!), or it might be ignored.
- * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
- */
- if(p->mode != 64)
- diag("asmins: illegal in mode %d: %P", p->mode, p);
- n = andptr - and;
- for(np = 0; np < n; np++) {
- c = and[np];
- if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
- break;
- }
- memmove(and+np+1, and+np, n-np);
- and[np] = 0x40 | rexflag;
- andptr++;
- }
- n = andptr - and;
- for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
- if(r->off < p->pc)
- break;
- if(rexflag)
- r->off++;
- if(r->type == D_PCREL)
- r->add -= p->pc + n - (r->off + r->siz);
- }
-}
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index c5c22d7ba..adc388ca9 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -29,9 +29,9 @@
// THE SOFTWARE.
#include <bio.h>
+#include <link.h>
#include "../8l/8.out.h"
-
#ifndef EXTERN
#define EXTERN extern
#endif
@@ -45,10 +45,8 @@
typedef struct Sym Sym;
typedef struct Ref Ref;
-typedef struct Gen Gen;
typedef struct Io Io;
-typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Addr2 Addr2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -97,37 +95,11 @@ struct Io
};
#define I ((Io*)0)
-EXTERN struct
-{
- Sym* sym;
- short type;
-} h[NSYM];
-
-struct Gen
-{
- double dval;
- char sval[8];
- int32 offset;
- int32 offset2;
- Sym* sym;
- short type;
- short index;
- short scale;
-};
-struct Gen2
-{
- Gen from;
- Gen to;
-};
-
-struct Hist
+struct Addr2
{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
+ Addr from;
+ Addr to;
};
-#define H ((Hist*)0)
enum
{
@@ -137,14 +109,11 @@ enum
CPREPROC,
};
-
-EXTERN char debug[256];
+EXTERN int debug[256];
EXTERN Sym* hash[NHASH];
EXTERN char** Dlist;
EXTERN int nDlist;
-EXTERN Hist* ehist;
EXTERN int newflag;
-EXTERN Hist* hist;
EXTERN char* hunk;
EXTERN char** include;
EXTERN Io* iofree;
@@ -155,10 +124,9 @@ EXTERN int nerrors;
EXTERN int32 nhunk;
EXTERN int ninclude;
EXTERN int32 nsymb;
-EXTERN Gen nullgen;
+EXTERN Addr nullgen;
EXTERN char* outfile;
EXTERN int pass;
-EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
EXTERN int32 stmtline;
@@ -168,6 +136,8 @@ EXTERN int thechar;
EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
+EXTERN Link* ctxt;
+EXTERN Biobuf bstdout;
void* alloc(int32);
void* allocn(void*, int32, int32);
@@ -188,12 +158,9 @@ void cinit(void);
void checkscale(int);
void pinit(char*);
void cclean(void);
-int isreg(Gen*);
-void outcode(int, Gen2*);
+int isreg(Addr*);
+void outcode(int, Addr2*);
void outhist(void);
-void zaddr(Gen*, int);
-void zname(char*, int, int);
-void ieeedtod(Ieee*, double);
int filbuf(void);
Sym* getsym(void);
void domacro(void);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 13ccc985b..d7ff623da 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -44,8 +44,8 @@
} con2;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
+ Addr addr;
+ Addr2 addr2;
}
%left '|'
%left '^'
@@ -62,9 +62,9 @@
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset
%type <con2> con2
-%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
-%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
+%type <addr> mem imm imm2 reg nam rel rem rim rom omem nmem
+%type <addr2> nonnon nonrel nonrem rimnon rimrem remrim
+%type <addr2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
%%
prog:
| prog
@@ -366,14 +366,12 @@ rel:
if(pass == 2)
yyerror("undefined label: %s", $1->name);
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
- $$.sym = $1;
$$.offset = $1->value + $2;
}
@@ -431,31 +429,31 @@ imm:
{
$$ = nullgen;
$$.type = D_SCONST;
- memcpy($$.sval, $2, sizeof($$.sval));
+ memcpy($$.u.sval, $2, sizeof($$.u.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = $2;
+ $$.u.dval = $2;
}
| '$' '(' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = $3;
+ $$.u.dval = $3;
}
| '$' '(' '-' LFCONST ')'
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = -$4;
+ $$.u.dval = -$4;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
- $$.dval = -$3;
+ $$.u.dval = -$3;
}
imm2:
@@ -590,14 +588,14 @@ nam:
{
$$ = nullgen;
$$.type = $4;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 0);
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$ = nullgen;
$$.type = D_STATIC;
- $$.sym = $1;
+ $$.sym = linklookup(ctxt, $1->name, 1);
$$.offset = $4;
}
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index f2ccc3361..32c099b75 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -57,56 +57,75 @@ pathchar(void)
return '/';
}
+int
+Lconv(Fmt *fp)
+{
+ return linklinefmt(ctxt, fp);
+}
+
+void
+dodef(char *p)
+{
+ if(nDlist%8 == 0)
+ Dlist = allocn(Dlist, nDlist*sizeof(char *),
+ 8*sizeof(char *));
+ Dlist[nDlist++] = p;
+}
+
+void
+usage(void)
+{
+ print("usage: %ca [options] file.c...\n", thechar);
+ flagprint(1);
+ errorexit();
+}
void
main(int argc, char *argv[])
{
char *p;
- int c;
thechar = '8';
thestring = "386";
+ ctxt = linknew(&link386);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+ listinit8();
+ fmtinstall('L', Lconv);
+
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
cinit();
outfile = 0;
setinclude(".");
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c] = 1;
- break;
-
- case 'o':
- outfile = ARGF();
- break;
-
- case 'D':
- p = ARGF();
- if(p) {
- if (nDlist%8 == 0)
- Dlist = allocn(Dlist, nDlist*sizeof(char *),
- 8*sizeof(char *));
- Dlist[nDlist++] = p;
- }
- break;
-
- case 'I':
- p = ARGF();
- setinclude(p);
- break;
- } ARGEND
- if(*argv == 0) {
- print("usage: %ca [-options] file.s\n", thechar);
- errorexit();
- }
+
+ flagfn1("D", "name[=value]: add #define", dodef);
+ flagfn1("I", "dir: add dir to include path", setinclude);
+ flagcount("S", "print assembly and machine code", &debug['S']);
+ flagcount("m", "debug preprocessor macros", &debug['m']);
+ flagstr("o", "file: set output file", &outfile);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
+
+ flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
+
+ if(argc < 1)
+ usage();
if(argc > 1){
print("can't assemble multiple files\n");
errorexit();
}
+
if(assemble(argv[0]))
errorexit();
+ Bflush(&bstdout);
exits(0);
}
@@ -145,30 +164,22 @@ assemble(char *file)
errorexit();
}
Binit(&obuf, of, OWRITE);
-
- pass = 1;
- pinit(file);
-
- Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
-
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- if(nerrors) {
+ Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+ Bprint(&obuf, "!\n");
+
+ for(pass = 1; pass <= 2; pass++) {
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
cclean();
- return nerrors;
+ if(nerrors)
+ return nerrors;
}
- Bprint(&obuf, "\n!\n");
-
- pass = 2;
- outhist();
- pinit(file);
- for(i=0; i<nDlist; i++)
- dodefine(Dlist[i]);
- yyparse();
- cclean();
- return nerrors;
+ writeobj(ctxt, &obuf);
+ Bflush(&obuf);
+ return 0;
}
struct
@@ -225,6 +236,7 @@ struct
"ES", LSREG, D_ES,
"FS", LSREG, D_FS,
"GS", LSREG, D_GS,
+ "TLS", LSREG, D_TLS,
"GDTR", LBREG, D_GDTR,
"IDTR", LBREG, D_IDTR,
@@ -778,6 +790,7 @@ struct
"PSUBW", LTYPE3, APSUBW,
"PUNPCKHQDQ", LTYPE3, APUNPCKHQDQ,
"PUNPCKLQDQ", LTYPE3, APUNPCKLQDQ,
+ "PXOR", LTYPE3, APXOR,
"RCPPS", LTYPE3, ARCPPS,
"RCPSS", LTYPE3, ARCPSS,
"RSQRTPS", LTYPE3, ARSQRTPS,
@@ -810,15 +823,8 @@ cinit(void)
Sym *s;
int i;
- nullgen.sym = S;
- nullgen.offset = 0;
- if(FPCHIP)
- nullgen.dval = 0;
- for(i=0; i<sizeof(nullgen.sval); i++)
- nullgen.sval[i] = 0;
nullgen.type = D_NONE;
nullgen.index = D_NONE;
- nullgen.scale = 0;
nerrors = 0;
iostack = I;
@@ -834,13 +840,6 @@ cinit(void)
s->type = itab[i].type;
s->value = itab[i].value;
}
-
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
}
void
@@ -868,252 +867,43 @@ syminit(Sym *s)
void
cclean(void)
{
- Gen2 g2;
+ Addr2 g2;
g2.from = nullgen;
g2.to = nullgen;
outcode(AEND, &g2);
- Bflush(&obuf);
}
-void
-zname(char *n, int t, int s)
-{
-
- BPUTLE2(&obuf, ANAME); /* as(2) */
- BPUTC(&obuf, t); /* type */
- BPUTC(&obuf, s); /* sym */
- while(*n) {
- BPUTC(&obuf, *n);
- n++;
- }
- BPUTC(&obuf, 0);
-}
+static Prog *lastpc;
void
-zaddr(Gen *a, int s)
+outcode(int a, Addr2 *g2)
{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(a->offset != 0)
- t |= T_OFFSET;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_CONST2:
- t |= T_OFFSET|T_OFFSET2;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_NONE:
- break;
- }
- BPUTC(&obuf, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(&obuf, a->index);
- BPUTC(&obuf, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(&obuf, l);
- }
- if(t & T_OFFSET2) {
- l = a->offset2;
- BPUTLE4(&obuf, l);
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(&obuf, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- BPUTLE4(&obuf, e.l);
- BPUTLE4(&obuf, e.h);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(&obuf, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(&obuf, a->type);
-}
-
-void
-outcode(int a, Gen2 *g2)
-{
- int sf, st, t;
- Sym *s;
-
+ Prog *p;
+ Plist *pl;
+
if(pass == 1)
goto out;
-jackpot:
- sf = 0;
- s = g2->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = g2->from.type;
- if(t == D_ADDR)
- t = g2->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = g2->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = g2->to.type;
- if(t == D_ADDR)
- t = g2->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- zname(s->name, t, sym);
- s->sym = sym;
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- BPUTLE2(&obuf, a);
- BPUTLE4(&obuf, stmtline);
- zaddr(&g2->from, sf);
- zaddr(&g2->to, st);
+ p = malloc(sizeof *p);
+ memset(p, 0, sizeof *p);
+ p->as = a;
+ p->lineno = stmtline;
+ p->from = g2->from;
+ p->to = g2->to;
+ p->pc = pc;
+
+ if(lastpc == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastpc->link = p;
+ lastpc = p;
out:
if(a != AGLOBL && a != ADATA)
pc++;
}
-void
-outhist(void)
-{
- Gen g;
- Hist *h;
- char *p, *q, *op, c;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
-
- g = nullgen;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = strchr(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTLE2(&obuf, ANAME);
- BPUTC(&obuf, D_FILE); /* type */
- BPUTC(&obuf, 1); /* sym */
- BPUTC(&obuf, '<');
- Bwrite(&obuf, p, n);
- BPUTC(&obuf, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- g.offset = h->offset;
-
- BPUTLE2(&obuf, AHISTORY);
- BPUTLE4(&obuf, h->line);
- zaddr(&nullgen, 0);
- zaddr(&g, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
#include "../cc/lexbody"
#include "../cc/macbody"
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
index aec4856f6..f48c9fe1f 100644
--- a/src/cmd/8a/y.tab.c
+++ b/src/cmd/8a/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,51 +55,11 @@
/* Pure parsers. */
#define YYPURE 0
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
/* Using locations. */
#define YYLSP_NEEDED 0
-/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../pkg/runtime/funcdata.h"
-
-
-/* Line 268 of yacc.c */
-#line 80 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -176,13 +139,38 @@
+/* Copy the first part of user declarations. */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../pkg/runtime/funcdata.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 293 of yacc.c */
#line 38 "a.y"
-
+{
Sym *sym;
int32 lval;
struct {
@@ -191,25 +179,24 @@ typedef union YYSTYPE
} con2;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
-
-
-
-/* Line 293 of yacc.c */
-#line 201 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+ Addr addr;
+ Addr2 addr2;
+}
+/* Line 193 of yacc.c. */
+#line 187 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
+
/* Copy the second part of user declarations. */
-/* Line 343 of yacc.c */
-#line 213 "y.tab.c"
+/* Line 216 of yacc.c. */
+#line 200 "y.tab.c"
#ifdef short
# undef short
@@ -284,14 +271,14 @@ typedef short int yytype_int16;
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -312,11 +299,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -339,24 +326,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -372,9 +359,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -385,27 +372,6 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
@@ -423,7 +389,24 @@ union yyalloc
while (YYID (0))
# endif
# endif
-#endif /* !YYCOPY_NEEDED */
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
@@ -564,13 +547,13 @@ static const yytype_uint16 yyrline[] =
175, 180, 185, 192, 200, 205, 213, 218, 223, 232,
233, 236, 241, 251, 256, 266, 271, 276, 283, 288,
296, 304, 314, 323, 334, 335, 338, 339, 340, 344,
- 348, 349, 350, 353, 354, 357, 363, 372, 381, 386,
- 391, 396, 401, 406, 413, 419, 430, 436, 442, 448,
- 454, 462, 471, 476, 481, 486, 493, 494, 497, 503,
- 509, 515, 524, 533, 542, 547, 552, 558, 566, 576,
- 580, 589, 596, 605, 608, 612, 618, 619, 623, 626,
- 627, 631, 635, 639, 643, 649, 650, 654, 658, 662,
- 666, 670, 674, 678, 682, 686
+ 348, 349, 350, 353, 354, 357, 363, 371, 379, 384,
+ 389, 394, 399, 404, 411, 417, 428, 434, 440, 446,
+ 452, 460, 469, 474, 479, 484, 491, 492, 495, 501,
+ 507, 513, 522, 531, 540, 545, 550, 556, 564, 574,
+ 578, 587, 594, 603, 606, 610, 616, 617, 621, 624,
+ 625, 629, 633, 637, 641, 647, 648, 652, 656, 660,
+ 664, 668, 672, 676, 680, 684
};
#endif
@@ -585,12 +568,12 @@ static const char *const yytname[] =
"LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF",
"LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG",
"LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
- "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog",
- "$@1", "line", "$@2", "$@3", "inst", "nonnon", "rimrem", "remrim",
- "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4",
- "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11",
- "spec12", "rem", "rom", "rim", "rel", "reg", "imm", "imm2", "con2",
- "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "expr", 0
+ "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
+ "line", "@2", "@3", "inst", "nonnon", "rimrem", "remrim", "rimnon",
+ "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4", "spec5", "spec6",
+ "spec7", "spec8", "spec9", "spec10", "spec11", "spec12", "rem", "rom",
+ "rim", "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem", "nam",
+ "offset", "pointer", "con", "expr", 0
};
#endif
@@ -646,8 +629,8 @@ static const yytype_uint8 yyr2[] =
3, 4, 4, 3, 3, 3
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
@@ -738,7 +721,8 @@ static const yytype_int16 yypgoto[] =
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
- number is the opposite. If YYTABLE_NINF, syntax error. */
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
static const yytype_uint16 yytable[] =
{
@@ -799,12 +783,6 @@ static const yytype_uint16 yytable[] =
170, 171, 172, 173, 174, 175, 176
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-104))
-
-#define yytable_value_is_error(yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
10, 10, 10, 13, 0, 13, 8, 13, 11, 10,
@@ -910,18 +888,9 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -931,6 +900,7 @@ do \
{ \
yychar = (Token); \
yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK (1); \
goto yybackup; \
} \
@@ -972,10 +942,19 @@ while (YYID (0))
#endif
-/* This macro is provided for backward compatibility. */
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
@@ -1079,20 +1058,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1126,11 +1102,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1167,6 +1143,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1269,142 +1246,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
- about the unexpected token YYTOKEN for the state stack whose top is
- YYSSP.
-
- Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
- not large enough to hold the message. In that case, also set
- *YYMSG_ALLOC to the required number of bytes. Return 2 if the
- required number of bytes is too large to store. */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = 0;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yychar) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yychar.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (yytoken != YYEMPTY)
- {
- int yyn = yypact[*yyssp];
- yyarg[yycount++] = yytname[yytoken];
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yyx;
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
+ int yyn = yypact[yystate];
- switch (yycount)
- {
-# define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
- if (*yymsg_alloc < yysize)
- {
- *yymsg_alloc = 2 * yysize;
- if (! (yysize <= *yymsg_alloc
- && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
- *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
- return 1;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- {
- char *yyp = *yymsg;
- int yyi = 0;
- while ((*yyp = *yyformat) != '\0')
- if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyformat += 2;
- }
- else
- {
- yyp++;
- yyformat++;
- }
- }
- return 0;
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -1436,9 +1386,10 @@ yydestruct (yymsg, yytype, yyvaluep)
break;
}
}
-
+
/* Prevent warnings from -Wmissing-prototypes. */
+
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
@@ -1454,16 +1405,18 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-/* The lookahead symbol. */
+
+/* The look-ahead symbol. */
int yychar;
-/* The semantic value of the lookahead symbol. */
+/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -1490,37 +1443,14 @@ yyparse ()
#endif
#endif
{
- int yystate;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
+
+ int yystate;
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
@@ -1528,28 +1458,51 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
+
yyssp = yyss;
yyvsp = yyvs;
@@ -1579,6 +1532,7 @@ yyparse ()
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
+
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
@@ -1586,6 +1540,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -1608,8 +1563,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1620,6 +1576,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1629,9 +1586,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -1640,16 +1594,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -1675,22 +1629,26 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
*++yyvsp = yylval;
@@ -1730,8 +1688,6 @@ yyreduce:
switch (yyn)
{
case 3:
-
-/* Line 1806 of yacc.c */
#line 71 "a.y"
{
stmtline = lineno;
@@ -1739,8 +1695,6 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
#line 78 "a.y"
{
if((yyvsp[(1) - (2)].sym)->value != pc)
@@ -1750,8 +1704,6 @@ yyreduce:
break;
case 7:
-
-/* Line 1806 of yacc.c */
#line 85 "a.y"
{
(yyvsp[(1) - (2)].sym)->type = LLAB;
@@ -1760,8 +1712,6 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
#line 96 "a.y"
{
(yyvsp[(1) - (3)].sym)->type = LVAR;
@@ -1770,8 +1720,6 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
#line 101 "a.y"
{
if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
@@ -1781,586 +1729,462 @@ yyreduce:
break;
case 14:
-
-/* Line 1806 of yacc.c */
#line 106 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 15:
-
-/* Line 1806 of yacc.c */
#line 107 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 16:
-
-/* Line 1806 of yacc.c */
#line 108 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 17:
-
-/* Line 1806 of yacc.c */
#line 109 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 18:
-
-/* Line 1806 of yacc.c */
#line 110 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 19:
-
-/* Line 1806 of yacc.c */
#line 111 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 20:
-
-/* Line 1806 of yacc.c */
#line 112 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 21:
-
-/* Line 1806 of yacc.c */
#line 113 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 22:
-
-/* Line 1806 of yacc.c */
#line 114 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 23:
-
-/* Line 1806 of yacc.c */
#line 115 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 24:
-
-/* Line 1806 of yacc.c */
#line 116 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 25:
-
-/* Line 1806 of yacc.c */
#line 117 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 26:
-
-/* Line 1806 of yacc.c */
#line 118 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 27:
-
-/* Line 1806 of yacc.c */
#line 119 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 28:
-
-/* Line 1806 of yacc.c */
#line 120 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 29:
-
-/* Line 1806 of yacc.c */
#line 121 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 30:
-
-/* Line 1806 of yacc.c */
#line 122 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 31:
-
-/* Line 1806 of yacc.c */
#line 123 "a.y"
- { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
break;
case 32:
-
-/* Line 1806 of yacc.c */
#line 126 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = nullgen;
}
break;
case 33:
-
-/* Line 1806 of yacc.c */
#line 131 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = nullgen;
}
break;
case 34:
-
-/* Line 1806 of yacc.c */
#line 138 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 35:
-
-/* Line 1806 of yacc.c */
#line 145 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 36:
-
-/* Line 1806 of yacc.c */
#line 152 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 37:
-
-/* Line 1806 of yacc.c */
#line 157 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 38:
-
-/* Line 1806 of yacc.c */
#line 164 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 39:
-
-/* Line 1806 of yacc.c */
#line 169 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 40:
-
-/* Line 1806 of yacc.c */
#line 176 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 41:
-
-/* Line 1806 of yacc.c */
#line 181 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 42:
-
-/* Line 1806 of yacc.c */
#line 186 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 43:
-
-/* Line 1806 of yacc.c */
#line 193 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 44:
-
-/* Line 1806 of yacc.c */
#line 201 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 45:
-
-/* Line 1806 of yacc.c */
#line 206 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 46:
-
-/* Line 1806 of yacc.c */
#line 214 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
}
break;
case 47:
-
-/* Line 1806 of yacc.c */
#line 219 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(1) - (1)].addr);
}
break;
case 48:
-
-/* Line 1806 of yacc.c */
#line 224 "a.y"
{
- (yyval.gen2).from = nullgen;
- (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
- (yyval.gen2).to.index = (yyvsp[(2) - (2)].gen).type;
- (yyval.gen2).to.type = D_INDIR+D_ADDR;
+ (yyval.addr2).from = nullgen;
+ (yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+ (yyval.addr2).to.index = (yyvsp[(2) - (2)].addr).type;
+ (yyval.addr2).to.type = D_INDIR+D_ADDR;
}
break;
case 51:
-
-/* Line 1806 of yacc.c */
#line 237 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 52:
-
-/* Line 1806 of yacc.c */
#line 242 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- if((yyval.gen2).from.index != D_NONE)
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ if((yyval.addr2).from.index != D_NONE)
yyerror("dp shift with lhs index");
- (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
}
break;
case 53:
-
-/* Line 1806 of yacc.c */
#line 252 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 54:
-
-/* Line 1806 of yacc.c */
#line 257 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- if((yyval.gen2).to.index != D_NONE)
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ if((yyval.addr2).to.index != D_NONE)
yyerror("dp move with lhs index");
- (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
}
break;
case 55:
-
-/* Line 1806 of yacc.c */
#line 267 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 56:
-
-/* Line 1806 of yacc.c */
#line 272 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
- (yyval.gen2).to = nullgen;
+ (yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+ (yyval.addr2).to = nullgen;
}
break;
case 57:
-
-/* Line 1806 of yacc.c */
#line 277 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 58:
-
-/* Line 1806 of yacc.c */
#line 284 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 59:
-
-/* Line 1806 of yacc.c */
#line 289 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
}
break;
case 60:
-
-/* Line 1806 of yacc.c */
#line 297 "a.y"
{
- (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
- (yyval.gen2).to.offset = (yyvsp[(5) - (5)].lval);
+ (yyval.addr2).from = (yyvsp[(1) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (5)].addr);
+ (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
}
break;
case 61:
-
-/* Line 1806 of yacc.c */
#line 305 "a.y"
{
- (yyval.gen2).from = (yyvsp[(3) - (5)].gen);
- (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
- if((yyvsp[(1) - (5)].gen).type != D_CONST)
+ (yyval.addr2).from = (yyvsp[(3) - (5)].addr);
+ (yyval.addr2).to = (yyvsp[(5) - (5)].addr);
+ if((yyvsp[(1) - (5)].addr).type != D_CONST)
yyerror("illegal constant");
- (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset;
+ (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
}
break;
case 62:
-
-/* Line 1806 of yacc.c */
#line 315 "a.y"
{
- if((yyvsp[(1) - (3)].gen).type != D_CONST || (yyvsp[(3) - (3)].gen).type != D_CONST)
+ if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 63:
-
-/* Line 1806 of yacc.c */
#line 324 "a.y"
{
- if((yyvsp[(1) - (3)].gen).type != D_CONST)
+ if((yyvsp[(1) - (3)].addr).type != D_CONST)
yyerror("index for FUNCDATA must be integer constant");
- if((yyvsp[(3) - (3)].gen).type != D_EXTERN && (yyvsp[(3) - (3)].gen).type != D_STATIC)
+ if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
yyerror("value for FUNCDATA must be symbol reference");
- (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
- (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ (yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ (yyval.addr2).to = (yyvsp[(3) - (3)].addr);
}
break;
case 68:
-
-/* Line 1806 of yacc.c */
#line 341 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
case 69:
-
-/* Line 1806 of yacc.c */
#line 345 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
}
break;
case 75:
-
-/* Line 1806 of yacc.c */
#line 358 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
}
break;
case 76:
-
-/* Line 1806 of yacc.c */
#line 364 "a.y"
{
- (yyval.gen) = nullgen;
+ (yyval.addr) = nullgen;
if(pass == 2)
yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 77:
-
-/* Line 1806 of yacc.c */
-#line 373 "a.y"
+#line 372 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_BRANCH;
- (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
- (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_BRANCH;
+ (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
}
break;
case 78:
-
-/* Line 1806 of yacc.c */
-#line 382 "a.y"
+#line 380 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 387 "a.y"
+#line 385 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 80:
-
-/* Line 1806 of yacc.c */
-#line 392 "a.y"
+#line 390 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 81:
-
-/* Line 1806 of yacc.c */
-#line 397 "a.y"
+#line 395 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 82:
-
-/* Line 1806 of yacc.c */
-#line 402 "a.y"
+#line 400 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SP;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SP;
}
break;
case 83:
-
-/* Line 1806 of yacc.c */
-#line 407 "a.y"
+#line 405 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(1) - (1)].lval);
}
break;
case 84:
-
-/* Line 1806 of yacc.c */
-#line 414 "a.y"
+#line 412 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST;
- (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].lval);
}
break;
case 85:
-
-/* Line 1806 of yacc.c */
-#line 420 "a.y"
+#line 418 "a.y"
{
- (yyval.gen) = (yyvsp[(2) - (2)].gen);
- (yyval.gen).index = (yyvsp[(2) - (2)].gen).type;
- (yyval.gen).type = D_ADDR;
+ (yyval.addr) = (yyvsp[(2) - (2)].addr);
+ (yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
+ (yyval.addr).type = D_ADDR;
/*
if($2.type == D_AUTO || $2.type == D_PARAM)
yyerror("constant cannot be automatic: %s",
@@ -2370,76 +2194,62 @@ yyreduce:
break;
case 86:
-
-/* Line 1806 of yacc.c */
-#line 431 "a.y"
+#line 429 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_SCONST;
- memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_SCONST;
+ memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
}
break;
case 87:
-
-/* Line 1806 of yacc.c */
-#line 437 "a.y"
+#line 435 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
}
break;
case 88:
-
-/* Line 1806 of yacc.c */
-#line 443 "a.y"
+#line 441 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = (yyvsp[(3) - (4)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
}
break;
case 89:
-
-/* Line 1806 of yacc.c */
-#line 449 "a.y"
+#line 447 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = -(yyvsp[(4) - (5)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
}
break;
case 90:
-
-/* Line 1806 of yacc.c */
-#line 455 "a.y"
+#line 453 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_FCONST;
- (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_FCONST;
+ (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
}
break;
case 91:
-
-/* Line 1806 of yacc.c */
-#line 463 "a.y"
+#line 461 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_CONST2;
- (yyval.gen).offset = (yyvsp[(2) - (2)].con2).v1;
- (yyval.gen).offset2 = (yyvsp[(2) - (2)].con2).v2;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_CONST2;
+ (yyval.addr).offset = (yyvsp[(2) - (2)].con2).v1;
+ (yyval.addr).offset2 = (yyvsp[(2) - (2)].con2).v2;
}
break;
case 92:
-
-/* Line 1806 of yacc.c */
-#line 472 "a.y"
+#line 470 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
(yyval.con2).v2 = ArgsSizeUnknown;
@@ -2447,9 +2257,7 @@ yyreduce:
break;
case 93:
-
-/* Line 1806 of yacc.c */
-#line 477 "a.y"
+#line 475 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
(yyval.con2).v2 = ArgsSizeUnknown;
@@ -2457,9 +2265,7 @@ yyreduce:
break;
case 94:
-
-/* Line 1806 of yacc.c */
-#line 482 "a.y"
+#line 480 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
(yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
@@ -2467,9 +2273,7 @@ yyreduce:
break;
case 95:
-
-/* Line 1806 of yacc.c */
-#line 487 "a.y"
+#line 485 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
(yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
@@ -2477,370 +2281,290 @@ yyreduce:
break;
case 98:
-
-/* Line 1806 of yacc.c */
-#line 498 "a.y"
+#line 496 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).offset = (yyvsp[(1) - (1)].lval);
}
break;
case 99:
-
-/* Line 1806 of yacc.c */
-#line 504 "a.y"
+#line 502 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 100:
-
-/* Line 1806 of yacc.c */
-#line 510 "a.y"
+#line 508 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_SP;
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_SP;
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 101:
-
-/* Line 1806 of yacc.c */
-#line 516 "a.y"
+#line 514 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).offset = (yyvsp[(1) - (6)].lval);
- (yyval.gen).index = (yyvsp[(3) - (6)].lval);
- (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).offset = (yyvsp[(1) - (6)].lval);
+ (yyval.addr).index = (yyvsp[(3) - (6)].lval);
+ (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 102:
-
-/* Line 1806 of yacc.c */
-#line 525 "a.y"
+#line 523 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
- (yyval.gen).index = (yyvsp[(6) - (9)].lval);
- (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.addr).index = (yyvsp[(6) - (9)].lval);
+ (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 103:
-
-/* Line 1806 of yacc.c */
-#line 534 "a.y"
+#line 532 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
- (yyval.gen).index = (yyvsp[(6) - (9)].lval);
- (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.addr).index = (yyvsp[(6) - (9)].lval);
+ (yyval.addr).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 104:
-
-/* Line 1806 of yacc.c */
-#line 543 "a.y"
+#line 541 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
}
break;
case 105:
-
-/* Line 1806 of yacc.c */
-#line 548 "a.y"
+#line 546 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_SP;
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_SP;
}
break;
case 106:
-
-/* Line 1806 of yacc.c */
-#line 553 "a.y"
+#line 551 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
- (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.addr).offset = (yyvsp[(1) - (4)].lval);
}
break;
case 107:
-
-/* Line 1806 of yacc.c */
-#line 559 "a.y"
+#line 557 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+D_NONE;
- (yyval.gen).index = (yyvsp[(2) - (5)].lval);
- (yyval.gen).scale = (yyvsp[(4) - (5)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+D_NONE;
+ (yyval.addr).index = (yyvsp[(2) - (5)].lval);
+ (yyval.addr).scale = (yyvsp[(4) - (5)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 108:
-
-/* Line 1806 of yacc.c */
-#line 567 "a.y"
+#line 565 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
- (yyval.gen).index = (yyvsp[(5) - (8)].lval);
- (yyval.gen).scale = (yyvsp[(7) - (8)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+ (yyval.addr).index = (yyvsp[(5) - (8)].lval);
+ (yyval.addr).scale = (yyvsp[(7) - (8)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 109:
-
-/* Line 1806 of yacc.c */
-#line 577 "a.y"
+#line 575 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (1)].gen);
+ (yyval.addr) = (yyvsp[(1) - (1)].addr);
}
break;
case 110:
-
-/* Line 1806 of yacc.c */
-#line 581 "a.y"
+#line 579 "a.y"
{
- (yyval.gen) = (yyvsp[(1) - (6)].gen);
- (yyval.gen).index = (yyvsp[(3) - (6)].lval);
- (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
- checkscale((yyval.gen).scale);
+ (yyval.addr) = (yyvsp[(1) - (6)].addr);
+ (yyval.addr).index = (yyvsp[(3) - (6)].lval);
+ (yyval.addr).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.addr).scale);
}
break;
case 111:
-
-/* Line 1806 of yacc.c */
-#line 590 "a.y"
+#line 588 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = (yyvsp[(4) - (5)].lval);
- (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
- (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = (yyvsp[(4) - (5)].lval);
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
+ (yyval.addr).offset = (yyvsp[(2) - (5)].lval);
}
break;
case 112:
-
-/* Line 1806 of yacc.c */
-#line 597 "a.y"
+#line 595 "a.y"
{
- (yyval.gen) = nullgen;
- (yyval.gen).type = D_STATIC;
- (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
- (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ (yyval.addr) = nullgen;
+ (yyval.addr).type = D_STATIC;
+ (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
+ (yyval.addr).offset = (yyvsp[(4) - (7)].lval);
}
break;
case 113:
-
-/* Line 1806 of yacc.c */
-#line 605 "a.y"
+#line 603 "a.y"
{
(yyval.lval) = 0;
}
break;
case 114:
-
-/* Line 1806 of yacc.c */
-#line 609 "a.y"
+#line 607 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 115:
-
-/* Line 1806 of yacc.c */
-#line 613 "a.y"
+#line 611 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 117:
-
-/* Line 1806 of yacc.c */
-#line 620 "a.y"
+#line 618 "a.y"
{
(yyval.lval) = D_AUTO;
}
break;
case 120:
-
-/* Line 1806 of yacc.c */
-#line 628 "a.y"
+#line 626 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
case 121:
-
-/* Line 1806 of yacc.c */
-#line 632 "a.y"
+#line 630 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 122:
-
-/* Line 1806 of yacc.c */
-#line 636 "a.y"
+#line 634 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 123:
-
-/* Line 1806 of yacc.c */
-#line 640 "a.y"
+#line 638 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
case 124:
-
-/* Line 1806 of yacc.c */
-#line 644 "a.y"
+#line 642 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
case 126:
-
-/* Line 1806 of yacc.c */
-#line 651 "a.y"
+#line 649 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
case 127:
-
-/* Line 1806 of yacc.c */
-#line 655 "a.y"
+#line 653 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
case 128:
-
-/* Line 1806 of yacc.c */
-#line 659 "a.y"
+#line 657 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
case 129:
-
-/* Line 1806 of yacc.c */
-#line 663 "a.y"
+#line 661 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
case 130:
-
-/* Line 1806 of yacc.c */
-#line 667 "a.y"
+#line 665 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
case 131:
-
-/* Line 1806 of yacc.c */
-#line 671 "a.y"
+#line 669 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
case 132:
-
-/* Line 1806 of yacc.c */
-#line 675 "a.y"
+#line 673 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
case 133:
-
-/* Line 1806 of yacc.c */
-#line 679 "a.y"
+#line 677 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
case 134:
-
-/* Line 1806 of yacc.c */
-#line 683 "a.y"
+#line 681 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
case 135:
-
-/* Line 1806 of yacc.c */
-#line 687 "a.y"
+#line 685 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
break;
-
-/* Line 1806 of yacc.c */
-#line 2831 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 2566 "y.tab.c"
default: break;
}
- /* User semantic actions sometimes alter yychar, and that requires
- that yytoken be updated with the new translation. We take the
- approach of translating immediately before every use of yytoken.
- One alternative is translating here after every semantic action,
- but that translation would be missed if the semantic action invokes
- YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
- if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
- incorrect destructor might then be invoked immediately. In the
- case of YYERROR or YYBACKUP, subsequent parser actions might lead
- to an incorrect destructor call or verbose syntax error message
- before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -2849,6 +2573,7 @@ yyreduce:
*++yyvsp = yyval;
+
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -2868,10 +2593,6 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -2879,36 +2600,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char const *yymsgp = YY_("syntax error");
- int yysyntax_error_status;
- yysyntax_error_status = YYSYNTAX_ERROR;
- if (yysyntax_error_status == 0)
- yymsgp = yymsg;
- else if (yysyntax_error_status == 1)
- {
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
- if (!yymsg)
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- yysyntax_error_status = 2;
- }
- else
- {
- yysyntax_error_status = YYSYNTAX_ERROR;
- yymsgp = yymsg;
- }
- }
- yyerror (yymsgp);
- if (yysyntax_error_status == 2)
- goto yyexhaustedlab;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -2916,7 +2638,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -2933,7 +2655,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -2967,7 +2689,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -2990,6 +2712,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
@@ -3014,7 +2739,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -3025,14 +2750,9 @@ yyexhaustedlab:
#endif
yyreturn:
- if (yychar != YYEMPTY)
- {
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = YYTRANSLATE (yychar);
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
index 14637cb33..d19145548 100644
--- a/src/cmd/8a/y.tab.h
+++ b/src/cmd/8a/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,11 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -112,11 +114,8 @@
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 2068 of yacc.c */
#line 38 "a.y"
-
+{
Sym *sym;
int32 lval;
struct {
@@ -125,19 +124,16 @@ typedef union YYSTYPE
} con2;
double dval;
char sval[8];
- Gen gen;
- Gen2 gen2;
-
-
-
-/* Line 2068 of yacc.c */
-#line 135 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+ Addr addr;
+ Addr2 addr2;
+}
+/* Line 1529 of yacc.c. */
+#line 132 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
index b668b4c63..87b8e22bc 100644
--- a/src/cmd/8c/gc.h
+++ b/src/cmd/8c/gc.h
@@ -46,11 +46,8 @@
#define SZ_DOUBLE 8
#define FNX 100
-typedef struct Adr Adr;
-typedef struct Prog Prog;
typedef struct Case Case;
typedef struct C1 C1;
-typedef struct Var Var;
typedef struct Reg Reg;
typedef struct Rgn Rgn;
typedef struct Renv Renv;
@@ -64,30 +61,10 @@ EXTERN struct
short ptr;
} idx;
-struct Adr
-{
- int32 offset;
- int32 offset2;
- double dval;
- char sval[NSNAME];
-
- Sym* sym;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Adr*)0)
+#define A ((Addr*)0)
#define INDEXED 9
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* link;
- int32 lineno;
- short as;
-};
+
#define P ((Prog*)0)
struct Case
@@ -106,14 +83,6 @@ struct C1
int32 label;
};
-struct Var
-{
- int32 offset;
- Sym* sym;
- char name;
- char etype;
-};
-
struct Reg
{
int32 pc;
@@ -171,7 +140,6 @@ EXTERN Node fconstnode;
EXTERN int32 continpc;
EXTERN int32 curarg;
EXTERN int32 cursafe;
-EXTERN Prog* firstp;
EXTERN Prog* lastp;
EXTERN int32 maxargsafe;
EXTERN int mnstring;
@@ -226,7 +194,6 @@ EXTERN Reg* firstr;
EXTERN Reg* lastr;
EXTERN Reg zreg;
EXTERN Reg* freer;
-EXTERN Var var[NVAR];
EXTERN int32* idom;
EXTERN Reg** rpo2r;
EXTERN int32 maxnr;
@@ -287,7 +254,7 @@ void regaalloc1(Node*, Node*);
void regaalloc(Node*, Node*);
void regind(Node*, Node*);
void gprep(Node*, Node*);
-void naddr(Node*, Adr*);
+void naddr(Node*, Addr*);
void gmove(Node*, Node*);
void gins(int a, Node*, Node*);
void fgopcode(int, Node*, Node*, int, int);
@@ -315,19 +282,11 @@ void nullwarn(Node*, Node*);
void sextern(Sym*, Node*, int32, int32);
void gextern(Sym*, Node*, int32, int32);
void outcode(void);
-void ieeedtod(Ieee*, double);
/*
* list
*/
void listinit(void);
-int Pconv(Fmt*);
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Sconv(Fmt*);
-int Rconv(Fmt*);
-int Xconv(Fmt*);
-int Bconv(Fmt*);
/*
* reg.c
@@ -336,7 +295,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
+Bits mkvar(Reg*, Addr*);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
@@ -344,7 +303,7 @@ uint32 allreg(uint32, Rgn*);
void paint1(Reg*, int);
uint32 paint2(Reg*, int);
void paint3(Reg*, int, int32, int);
-void addreg(Adr*, int);
+void addreg(Addr*, int);
/*
* peep.c
@@ -353,17 +312,17 @@ void peep(void);
void excise(Reg*);
Reg* uniqp(Reg*);
Reg* uniqs(Reg*);
-int regtyp(Adr*);
-int anyvar(Adr*);
+int regtyp(Addr*);
+int anyvar(Addr*);
int subprop(Reg*);
int copyprop(Reg*);
-int copy1(Adr*, Adr*, Reg*, int);
-int copyu(Prog*, Adr*, Adr*);
+int copy1(Addr*, Addr*, Reg*, int);
+int copyu(Prog*, Addr*, Addr*);
-int copyas(Adr*, Adr*);
-int copyau(Adr*, Adr*);
-int copysub(Adr*, Adr*, Adr*, int);
-int copysub1(Prog*, Adr*, Adr*, int);
+int copyas(Addr*, Addr*);
+int copyau(Addr*, Addr*);
+int copysub(Addr*, Addr*, Addr*, int);
+int copysub1(Prog*, Addr*, Addr*, int);
int32 RtoB(int);
int32 FtoB(int);
@@ -401,14 +360,6 @@ void mulgen(Type*, Node*, Node*);
void genmuladd(Node*, Node*, int, Node*);
void shiftit(Type*, Node*, Node*);
-#pragma varargck type "A" int
-#pragma varargck type "B" Bits
-#pragma varargck type "D" Adr*
-#pragma varargck type "lD" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-
/* wrecklessly steal a field */
#define rplink label
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
index 8506e08ef..1730eccd0 100644
--- a/src/cmd/8c/list.c
+++ b/src/cmd/8c/list.c
@@ -34,319 +34,5 @@
void
listinit(void)
{
-
- fmtinstall('A', Aconv);
- fmtinstall('B', Bconv);
- fmtinstall('P', Pconv);
- fmtinstall('S', Sconv);
- fmtinstall('D', Dconv);
- fmtinstall('R', Rconv);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char str[STRINGSZ], ss[STRINGSZ], *s;
- Bits bits;
- int i;
-
- str[0] = 0;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(str[0])
- strcat(str, " ");
- if(var[i].sym == S) {
- sprint(ss, "$%d", var[i].offset);
- s = ss;
- } else
- s = var[i].sym->name;
- if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
- break;
- strcat(str, s);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Pconv(Fmt *fp)
-{
- char str[STRINGSZ];
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- switch(p->as) {
- case ADATA:
- sprint(str, "(%L) %A %D/%d,%D",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
-
- case ATEXT:
- if(p->from.scale) {
- sprint(str, "(%L) %A %D,%d,%lD",
- p->lineno, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- sprint(str, "(%L) %A %D,%lD",
- p->lineno, p->as, &p->from, &p->to);
- break;
-
- default:
- sprint(str, "(%L) %A %D,%D",
- p->lineno, p->as, &p->from, &p->to);
- break;
- }
- return fmtstrcpy(fp, str);
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
-
- if(fp->flags & FmtLong) {
- if(i == D_CONST2)
- sprint(str, "$%d-%d", a->offset, a->offset2);
- else {
- // ATEXT dst is not constant
- sprint(str, "!!%D", a);
- }
- goto brk;
- }
-
- if(i >= D_INDIR) {
- if(a->offset)
- sprint(str, "%d(%R)", a->offset, i-D_INDIR);
- else
- sprint(str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
- default:
- if(a->offset)
- sprint(str, "$%d,%R", a->offset, i);
- else
- sprint(str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- sprint(str, "%d", a->offset);
- break;
-
- case D_EXTERN:
- sprint(str, "%s+%d(SB)", a->sym->name, a->offset);
- break;
-
- case D_STATIC:
- sprint(str, "%s<>+%d(SB)", a->sym->name, a->offset);
- break;
-
- case D_AUTO:
- if(a->sym)
- sprint(str, "%s+%d(SP)", a->sym->name, a->offset);
- else
- sprint(str, "%d(SP)", a->offset);
- break;
-
- case D_PARAM:
- if(a->sym)
- sprint(str, "%s+%d(FP)", a->sym->name, a->offset);
- else
- sprint(str, "%d(FP)", a->offset);
- break;
-
- case D_CONST:
- sprint(str, "$%d", a->offset);
- break;
-
- case D_CONST2:
- if(!(fp->flags & FmtLong)) {
- // D_CONST2 outside of ATEXT should not happen
- sprint(str, "!!$%d-%d", a->offset, a->offset2);
- }
- break;
-
- case D_FCONST:
- sprint(str, "$(%.17e)", a->dval);
- break;
-
- case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- sprint(str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
- strcat(str, s);
- }
-conv:
- return fmtstrcpy(fp, str);
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "AH",
- "CH",
- "DH",
- "BH",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "X0", /* [D_X0] */
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
+ listinit8();
}
diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c
index da0127d11..4f58fc05c 100644
--- a/src/cmd/8c/peep.c
+++ b/src/cmd/8c/peep.c
@@ -217,7 +217,7 @@ uniqs(Reg *r)
}
int
-regtyp(Adr *a)
+regtyp(Addr *a)
{
int t;
@@ -245,7 +245,7 @@ int
subprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
int t;
@@ -365,7 +365,7 @@ int
copyprop(Reg *r0)
{
Prog *p;
- Adr *v1, *v2;
+ Addr *v1, *v2;
Reg *r;
p = r0->prog;
@@ -379,7 +379,7 @@ copyprop(Reg *r0)
}
int
-copy1(Adr *v1, Adr *v2, Reg *r, int f)
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
{
int t;
Prog *p;
@@ -464,7 +464,7 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f)
* 0 otherwise (not touched)
*/
int
-copyu(Prog *p, Adr *v, Adr *s)
+copyu(Prog *p, Addr *v, Addr *s)
{
switch(p->as) {
@@ -740,7 +740,7 @@ copyu(Prog *p, Adr *v, Adr *s)
* semantics
*/
int
-copyas(Adr *a, Adr *v)
+copyas(Addr *a, Addr *v)
{
if(a->type != v->type)
return 0;
@@ -756,7 +756,7 @@ copyas(Adr *a, Adr *v)
* either direct or indirect
*/
int
-copyau(Adr *a, Adr *v)
+copyau(Addr *a, Addr *v)
{
if(copyas(a, v))
@@ -775,7 +775,7 @@ copyau(Adr *a, Adr *v)
* return failure to substitute
*/
int
-copysub(Adr *a, Adr *v, Adr *s, int f)
+copysub(Addr *a, Addr *v, Addr *s, int f)
{
int t;
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
index a3d5d6115..e6ba8bcb3 100644
--- a/src/cmd/8c/reg.c
+++ b/src/cmd/8c/reg.c
@@ -558,7 +558,7 @@ brk:
if(debug['R'] && debug['v']) {
print("after pass 7 (peep)\n");
for(r=firstr; r; r=r->link)
- print("%04d %P\n", r->pc, r->prog);
+ print("%04d %P\n", (int)r->pc, r->prog);
print("\n");
}
@@ -602,8 +602,10 @@ brk:
r1 = 0; /* set */
for(r = firstr; r != R; r = r->link) {
p = r->prog;
- if(p->to.type == D_BRANCH)
+ if(p->to.type == D_BRANCH) {
p->to.offset = r->s2->pc;
+ p->to.u.branch = r->s2->prog;
+ }
r1 = r;
}
@@ -638,7 +640,7 @@ void
addmove(Reg *r, int bn, int rn, int f)
{
Prog *p, *p1;
- Adr *a;
+ Addr *a;
Var *v;
p1 = alloc(sizeof(*p1));
@@ -697,13 +699,13 @@ doregbits(int r)
}
Bits
-mkvar(Reg *r, Adr *a)
+mkvar(Reg *r, Addr *a)
{
Var *v;
int i, t, n, et, z;
int32 o;
Bits bit;
- Sym *s;
+ LSym *s;
/*
* mark registers used
@@ -730,7 +732,7 @@ mkvar(Reg *r, Adr *a)
break;
}
s = a->sym;
- if(s == S)
+ if(s == nil)
goto none;
if(s->name[0] == '.')
goto none;
@@ -1121,7 +1123,7 @@ uint32
regset(Reg *r, uint32 bb)
{
uint32 b, set;
- Adr v;
+ Addr v;
int c;
set = 0;
@@ -1140,7 +1142,7 @@ uint32
reguse(Reg *r, uint32 bb)
{
uint32 b, set;
- Adr v;
+ Addr v;
int c;
set = 0;
@@ -1287,7 +1289,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
}
void
-addreg(Adr *a, int rn)
+addreg(Addr *a, int rn)
{
a->sym = 0;
@@ -1373,10 +1375,11 @@ fixjmp(Reg *firstr)
for(r=firstr; r; r=r->link) {
p = r->prog;
if(debug['R'] && debug['v'])
- print("%04d %P\n", r->pc, p);
+ print("%04d %P\n", (int)r->pc, p);
if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
r->s2 = chasejmp(r->s2, &jmploop);
p->to.offset = r->s2->pc;
+ p->to.u.branch = r->s2->prog;
if(debug['R'] && debug['v'])
print("->%P\n", p);
}
@@ -1397,7 +1400,7 @@ fixjmp(Reg *firstr)
// Let it stay.
} else {
if(debug['R'] && debug['v'])
- print("del %04d %P\n", r->pc, p);
+ print("del %04d %P\n", (int)r->pc, p);
p->as = ANOP;
}
}
@@ -1410,7 +1413,7 @@ fixjmp(Reg *firstr)
p = r->prog;
if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
if(debug['R'] && debug['v'])
- print("del %04d %P\n", r->pc, p);
+ print("del %04d %P\n", (int)r->pc, p);
p->as = ANOP;
}
}
@@ -1431,7 +1434,7 @@ fixjmp(Reg *firstr)
if(debug['R'] && debug['v']) {
print("\n");
for(r=firstr; r; r=r->link)
- print("%04d %P\n", r->pc, r->prog);
+ print("%04d %P\n", (int)r->pc, r->prog);
print("\n");
}
}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index b68197447..ae36f84ea 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -169,7 +169,7 @@ outstring(char *s, int32 n)
p->from.offset += nstring - NSNAME;
p->from.scale = NSNAME;
p->to.type = D_SCONST;
- memmove(p->to.sval, string, NSNAME);
+ memmove(p->to.u.sval, string, NSNAME);
mnstring = 0;
}
n--;
@@ -190,7 +190,7 @@ sextern(Sym *s, Node *a, int32 o, int32 w)
p->from.offset += o+e;
p->from.scale = lw;
p->to.type = D_SCONST;
- memmove(p->to.sval, a->cstring+e, lw);
+ memmove(p->to.u.sval, a->cstring+e, lw);
}
}
@@ -220,29 +220,12 @@ gextern(Sym *s, Node *a, int32 o, int32 w)
}
}
-void zname(Biobuf*, Sym*, int);
-void zaddr(Biobuf*, Adr*, int);
-void outhist(Biobuf*);
-
void
outcode(void)
{
- struct { Sym *sym; short type; } h[NSYM];
- Prog *p;
- Sym *s;
- int f, sf, st, t, sym;
+ int f;
Biobuf b;
- if(debug['S']) {
- for(p = firstp; p != P; p = p->link)
- if(p->as != ADATA && p->as != AGLOBL)
- pc--;
- for(p = firstp; p != P; p = p->link) {
- print("%P\n", p);
- if(p->as != ADATA && p->as != AGLOBL)
- pc++;
- }
- }
f = open(outfile, OWRITE);
if(f < 0) {
diag(Z, "cannot open %s", outfile);
@@ -250,7 +233,7 @@ outcode(void)
}
Binit(&b, f, OWRITE);
- Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
if(pragcgobuf.to > pragcgobuf.start) {
Bprint(&b, "\n");
Bprint(&b, "$$ // exports\n\n");
@@ -261,258 +244,12 @@ outcode(void)
}
Bprint(&b, "!\n");
- outhist(&b);
- for(sym=0; sym<NSYM; sym++) {
- h[sym].sym = S;
- h[sym].type = 0;
- }
- sym = 1;
- for(p = firstp; p != P; p = p->link) {
- jackpot:
- sf = 0;
- s = p->from.sym;
- while(s != S) {
- sf = s->sym;
- if(sf < 0 || sf >= NSYM)
- sf = 0;
- t = p->from.type;
- if(t == D_ADDR)
- t = p->from.index;
- if(h[sf].type == t)
- if(h[sf].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- sf = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- break;
- }
- st = 0;
- s = p->to.sym;
- while(s != S) {
- st = s->sym;
- if(st < 0 || st >= NSYM)
- st = 0;
- t = p->to.type;
- if(t == D_ADDR)
- t = p->to.index;
- if(h[st].type == t)
- if(h[st].sym == s)
- break;
- s->sym = sym;
- zname(&b, s, t);
- h[sym].sym = s;
- h[sym].type = t;
- st = sym;
- sym++;
- if(sym >= NSYM)
- sym = 1;
- if(st == sf)
- goto jackpot;
- break;
- }
- BPUTLE2(&b, p->as);
- BPUTLE4(&b, p->lineno);
- zaddr(&b, &p->from, sf);
- zaddr(&b, &p->to, st);
- }
+ writeobj(ctxt, &b);
Bterm(&b);
close(f);
- firstp = P;
lastp = P;
}
-void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, *q, *op, c;
- Prog pg;
- int n;
- char *tofree;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- pg = zprog;
- pg.as = AHISTORY;
- c = pathchar();
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p != nil && goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- op = 0;
- if(systemtype(Windows) && p && p[1] == ':'){
- c = p[2];
- } else if(p && p[0] != c && h->offset == 0 && pathname){
- if(systemtype(Windows) && pathname[1] == ':') {
- op = p;
- p = pathname;
- c = p[2];
- } else if(pathname[0] == c){
- op = p;
- p = pathname;
- }
- }
- while(p) {
- q = utfrune(p, c);
- if(q) {
- n = q-p;
- if(n == 0){
- n = 1; /* leading "/" */
- *p = '/'; /* don't emit "\" on windows */
- }
- q++;
- } else {
- n = strlen(p);
- q = 0;
- }
- if(n) {
- BPUTLE2(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
- }
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
- }
- }
- pg.lineno = h->line;
- pg.to.type = zprog.to.type;
- pg.to.offset = h->offset;
- if(h->offset)
- pg.to.type = D_CONST;
-
- BPUTLE2(b, pg.as);
- BPUTLE4(b, pg.lineno);
- zaddr(b, &pg.from, 0);
- zaddr(b, &pg.to, 0);
-
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- char *n;
- uint32 sig;
-
- if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
- sig = sign(s);
- BPUTLE2(b, ASIGNAME);
- BPUTLE4(b, sig);
- s->sig = SIGDONE;
- }
- else{
- BPUTLE2(b, ANAME); /* as */
- }
- BPUTC(b, t); /* type */
- BPUTC(b, s->sym); /* sym */
- n = s->name;
- while(*n) {
- BPUTC(b, *n);
- n++;
- }
- BPUTC(b, 0);
-}
-
-void
-zaddr(Biobuf *b, Adr *a, int s)
-{
- int32 l;
- int i, t;
- char *n;
- Ieee e;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
-
- switch(a->type) {
- default:
- t |= T_TYPE;
- case D_NONE:
- if(a->offset != 0)
- t |= T_OFFSET;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- case D_CONST2:
- t |= T_OFFSET|T_OFFSET2;
- break;
- }
- BPUTC(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(b, a->index);
- BPUTC(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(b, l);
- }
- if(t & T_OFFSET2) { /* implies offset2 */
- l = a->offset2;
- BPUTLE4(b, l);
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->dval);
- BPUTLE4(b, e.l);
- BPUTLE4(b, e.h);
- return;
- }
- if(t & T_SCONST) {
- n = a->sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(b, a->type);
-}
-
int32
align(int32 i, Type *t, int op, int32 *maxalign)
{
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 5c486af38..25082de05 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -30,14 +30,23 @@
#include "gc.h"
+
+int thechar = '8';
+char *thestring = "386";
+
+LinkArch *thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
+
void
ginit(void)
{
int i;
Type *t;
- thechar = '8';
- thestring = "386";
exregoffset = 0;
exfregoffset = 0;
listinit();
@@ -48,7 +57,6 @@ ginit(void)
breakpc = -1;
continpc = -1;
cases = C;
- firstp = P;
lastp = P;
tfield = types[TLONG];
@@ -156,17 +164,18 @@ gclean(void)
void
nextpc(void)
{
+ Plist *pl;
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
+ p->pc = pc;
pc++;
- if(firstp == P) {
- firstp = p;
- lastp = p;
- return;
- }
- lastp->link = p;
+ if(lastp == nil) {
+ pl = linknewplist(ctxt);
+ pl->firstpc = p;
+ } else
+ lastp->link = p;
lastp = p;
}
@@ -188,7 +197,8 @@ gargs(Node *n, Node *tn1, Node *tn2)
cursafe = regs;
}
-int nareg(void)
+int
+nareg(void)
{
int i, n;
@@ -435,7 +445,7 @@ regind(Node *n, Node *nn)
}
void
-naddr(Node *n, Adr *a)
+naddr(Node *n, Addr *a)
{
int32 v;
@@ -450,11 +460,11 @@ naddr(Node *n, Adr *a)
case OREGISTER:
a->type = n->reg;
- a->sym = S;
+ a->sym = nil;
break;
case OEXREG:
- a->type = D_INDIR + D_GS;
+ a->type = D_INDIR + D_TLS;
a->offset = n->reg - 1;
break;
@@ -495,14 +505,14 @@ naddr(Node *n, Adr *a)
case OINDREG:
a->type = n->reg+D_INDIR;
- a->sym = S;
+ a->sym = nil;
a->offset = n->xoffset;
break;
case ONAME:
a->etype = n->etype;
a->type = D_STATIC;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
@@ -523,10 +533,10 @@ naddr(Node *n, Adr *a)
case OCONST:
if(typefd[n->type->etype]) {
a->type = D_FCONST;
- a->dval = n->fconst;
+ a->u.dval = n->fconst;
break;
}
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = n->vconst;
break;
@@ -1366,9 +1376,10 @@ gbranch(int o)
void
patch(Prog *op, int32 pc)
{
-
op->to.offset = pc;
op->to.type = D_BRANCH;
+ op->to.u.branch = nil;
+ op->pcond = nil;
}
void
@@ -1378,7 +1389,7 @@ gpseudo(int a, Sym *s, Node *n)
nextpc();
p->as = a;
p->from.type = D_EXTERN;
- p->from.sym = s;
+ p->from.sym = linksym(s);
switch(a) {
case ATEXT:
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index cc28a3145..d626c2eb0 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -242,6 +242,7 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
+ case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
@@ -522,6 +523,7 @@ agen(Node *n, Node *res)
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
+ gvardef(&n1);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(ALEAL, &n1, &n2);
@@ -934,6 +936,13 @@ bgen(Node *n, int true, int likely, Prog *to)
patch(gins(AEND, N, N), to);
return;
}
+
+ while(n->op == OCONVNOP) {
+ n = n->left;
+ if(n->ninit != nil)
+ genlist(n->ninit);
+ }
+
nl = n->left;
nr = N;
@@ -1203,6 +1212,8 @@ sgen(Node *n, Node *res, int64 w)
{
Node dst, src, tdst, tsrc;
int32 c, q, odst, osrc;
+ NodeList *l;
+ Prog *p;
if(debug['g']) {
print("\nsgen w=%lld\n", w);
@@ -1223,6 +1234,13 @@ sgen(Node *n, Node *res, int64 w)
return;
}
+ // If copying .args, that's all the results, so record definition sites
+ // for them for the liveness analysis.
+ if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
+ for(l = curfn->dcl; l != nil; l = l->next)
+ if(l->n->class == PPARAMOUT)
+ gvardef(l->n);
+
// Avoid taking the address for simple enough types.
if(componentgen(n, res))
return;
@@ -1255,6 +1273,10 @@ sgen(Node *n, Node *res, int64 w)
agen(n, &src);
else
gmove(&tsrc, &src);
+
+ if(res->op == ONAME)
+ gvardef(res);
+
if(res->addable)
agen(res, &dst);
else
@@ -1294,10 +1316,16 @@ sgen(Node *n, Node *res, int64 w)
} else {
gins(ACLD, N, N); // paranoia. TODO(rsc): remove?
// normal direction
- if(q >= 4) {
+ if(q > 128 || (q >= 4 && nacl)) {
gconreg(AMOVL, q, D_CX);
gins(AREP, N, N); // repeat
gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
+ } else if(q >= 4) {
+ p = gins(ADUFFCOPY, N, N);
+ p->to.type = D_ADDR;
+ p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
+ // 10 and 128 = magic constants: see ../../pkg/runtime/asm_386.s
+ p->to.offset = 10*(128-q);
} else
while(q > 0) {
gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
@@ -1369,8 +1397,17 @@ componentgen(Node *nr, Node *nl)
}
}
+ // nl and nr are 'cadable' which basically means they are names (variables) now.
+ // If they are the same variable, don't generate any code, because the
+ // VARDEF we generate will mark the old value as dead incorrectly.
+ // (And also the assignments are useless.)
+ if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
+ goto yes;
+
switch(nl->type->etype) {
case TARRAY:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(nl->type->type);
@@ -1404,6 +1441,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TSTRING:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
@@ -1427,6 +1466,8 @@ componentgen(Node *nr, Node *nl)
goto yes;
case TINTER:
+ if(nl->op == ONAME)
+ gvardef(nl);
nodl.xoffset += Array_array;
nodl.type = ptrto(types[TUINT8]);
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 2c8aaa0a4..fbd2e9ad3 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -8,6 +8,12 @@
int thechar = '8';
char* thestring = "386";
+LinkArch* thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
vlong MAXWIDTH = (1LL<<32) - 1;
@@ -28,6 +34,7 @@ betypeinit(void)
{
widthptr = 4;
widthint = 4;
+ widthreg = 4;
zprog.link = P;
zprog.as = AGOK;
@@ -36,5 +43,5 @@ betypeinit(void)
zprog.from.scale = 0;
zprog.to = zprog.from;
- listinit();
+ listinit8();
}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 55fdded0b..bdefa93b5 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -9,42 +9,6 @@
#include "../gc/go.h"
#include "../8l/8.out.h"
-typedef struct Addr Addr;
-
-struct Addr
-{
- int32 offset;
- int32 offset2;
-
- union {
- double dval;
- vlong vval;
- Prog* branch;
- char sval[NSNAME];
- } u;
-
- Sym* gotype;
- Sym* sym;
- Node* node;
- int width;
- uchar type;
- uchar index;
- uchar etype;
- uchar scale; /* doubles as width in DATA op */
-};
-#define A ((Addr*)0)
-
-struct Prog
-{
- short as; // opcode
- uint32 loc; // pc offset in this func
- uint32 lineno; // source line that generated this
- Addr from; // src address
- Addr to; // dst address
- Prog* link; // next instruction in this func
- void* opt; // for optimizer passes
-};
-
#define TEXTFLAG from.scale
// foptoas flags
@@ -59,15 +23,14 @@ EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
-extern char* anames[];
EXTERN Prog zprog;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
+EXTERN Node* panicdiv;
EXTERN Node* throwreturn;
-EXTERN int maxstksize;
extern uint32 unmappedzero;
@@ -168,14 +131,6 @@ void datagostring(Strlit*, Addr*);
/*
* list.c
*/
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Yconv(Fmt*);
void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
-
-#pragma varargck type "D" Addr*
-#pragma varargck type "lD" Addr*
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index fa5ed00dd..2285a04e6 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -9,61 +9,100 @@
#include "gg.h"
#include "opt.h"
-static Prog* appendp(Prog*, int, int, int32, int, int32);
+static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
+static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
void
-defframe(Prog *ptxt, Bvec *bv)
+defframe(Prog *ptxt)
{
- uint32 frame;
+ uint32 frame, ax;
Prog *p;
- int i, j;
+ vlong lo, hi;
+ NodeList *l;
+ Node *n;
// fill in argument size
ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
- if(stksize > maxstksize)
- maxstksize = stksize;
- frame = rnd(maxstksize+maxarg, widthptr);
+ frame = rnd(stksize+maxarg, widthptr);
ptxt->to.offset = frame;
- maxstksize = 0;
-
- // insert code to clear pointered part of the frame,
- // so that garbage collector only sees initialized values
+
+ // insert code to zero ambiguously live variables
+ // so that the garbage collector only sees initialized values
// when it looks for pointers.
p = ptxt;
- if(stkzerosize >= 8*widthptr) {
- p = appendp(p, AMOVL, D_CONST, 0, D_AX, 0);
- p = appendp(p, AMOVL, D_CONST, stkzerosize/widthptr, D_CX, 0);
- p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0);
- p = appendp(p, AREP, D_NONE, 0, D_NONE, 0);
- appendp(p, ASTOSL, D_NONE, 0, D_NONE, 0);
- } else {
- j = (stkptrsize - stkzerosize)/widthptr * 2;
- for(i=0; i<stkzerosize; i+=widthptr) {
- if(bvget(bv, j) || bvget(bv, j+1))
- p = appendp(p, AMOVL, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
- j += 2;
+ hi = 0;
+ lo = hi;
+ ax = 0;
+ for(l=curfn->dcl; l != nil; l = l->next) {
+ n = l->n;
+ if(!n->needzero)
+ continue;
+ if(n->class != PAUTO)
+ fatal("needzero class %d", n->class);
+ if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
+ fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
+ if(lo != hi && n->xoffset + n->type->width == lo - 2*widthptr) {
+ // merge with range we already have
+ lo = n->xoffset;
+ continue;
}
+ // zero old range
+ p = zerorange(p, frame, lo, hi, &ax);
+
+ // set new range
+ hi = n->xoffset + n->type->width;
+ lo = n->xoffset;
}
+ // zero final range
+ zerorange(p, frame, lo, hi, &ax);
}
static Prog*
-appendp(Prog *p, int as, int ftype, int32 foffset, int ttype, int32 toffset)
+zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
+{
+ vlong cnt, i;
+
+ cnt = hi - lo;
+ if(cnt == 0)
+ return p;
+ if(*ax == 0) {
+ p = appendpp(p, AMOVL, D_CONST, 0, D_AX, 0);
+ *ax = 1;
+ }
+ if(cnt <= 4*widthreg) {
+ for(i = 0; i < cnt; i += widthreg) {
+ p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
+ }
+ } else if(!nacl && cnt <= 128*widthreg) {
+ p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 1*(128-cnt/widthreg));
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ } else {
+ p = appendpp(p, AMOVL, D_CONST, cnt/widthreg, D_CX, 0);
+ p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
+ p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
+ p = appendpp(p, ASTOSL, D_NONE, 0, D_NONE, 0);
+ }
+ return p;
+}
+
+static Prog*
+appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)
{
Prog *q;
-
- q = mal(sizeof(*q));
- clearp(q);
- q->as = as;
- q->lineno = p->lineno;
- q->from.type = ftype;
- q->from.offset = foffset;
- q->to.type = ttype;
- q->to.offset = toffset;
- q->link = p->link;
- p->link = q;
- return q;
+ q = mal(sizeof(*q));
+ clearp(q);
+ q->as = as;
+ q->lineno = p->lineno;
+ q->from.type = ftype;
+ q->from.offset = foffset;
+ q->to.type = ttype;
+ q->to.offset = toffset;
+ q->link = p->link;
+ p->link = q;
+ return q;
}
// Sweep the prog list to mark any used nodes.
@@ -71,13 +110,13 @@ void
markautoused(Prog* p)
{
for (; p; p = p->link) {
- if (p->as == ATYPE)
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
continue;
- if (p->from.type == D_AUTO && p->from.node)
+ if (p->from.node)
p->from.node->used = 1;
- if (p->to.type == D_AUTO && p->to.node)
+ if (p->to.node)
p->to.node->used = 1;
}
}
@@ -93,6 +132,16 @@ fixautoused(Prog* p)
*lp = p->link;
continue;
}
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.node->used) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ p->to.type = D_NONE;
+ p->to.node = N;
+ p->as = ANOP;
+ continue;
+ }
if (p->from.type == D_AUTO && p->from.node)
p->from.offset += p->from.node->stkdelta;
@@ -109,6 +158,7 @@ clearfat(Node *nl)
{
uint32 w, c, q;
Node n1;
+ Prog *p;
/* clear a fat object */
if(debug['g'])
@@ -126,21 +176,22 @@ clearfat(Node *nl)
agen(nl, &n1);
gconreg(AMOVL, 0, D_AX);
- if(q >= 4) {
+ if(q > 128 || (q >= 4 && nacl)) {
gconreg(AMOVL, q, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSL, N, N); // STOL AL,*(DI)+
+ } else if(q >= 4) {
+ p = gins(ADUFFZERO, N, N);
+ p->to.type = D_ADDR;
+ p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+ // 1 and 128 = magic constants: see ../../pkg/runtime/asm_386.s
+ p->to.offset = 1*(128-q);
} else
while(q > 0) {
gins(ASTOSL, N, N); // STOL AL,*(DI)+
q--;
}
- if(c >= 4) {
- gconreg(AMOVL, c, D_CX);
- gins(AREP, N, N); // repeat
- gins(ASTOSB, N, N); // STOB AL,*(DI)+
- } else
while(c > 0) {
gins(ASTOSB, N, N); // STOB AL,*(DI)+
c--;
@@ -236,7 +287,9 @@ ginscall(Node *f, int proc)
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTL, &reg, &reg);
- patch(gbranch(AJNE, T, -1), retpc);
+ p = gbranch(AJEQ, T, +1);
+ cgen_ret(N);
+ patch(p, pc);
}
break;
}
@@ -437,15 +490,15 @@ cgen_ret(Node *n)
{
Prog *p;
- genlist(n->list); // copy out args
- if(retpc) {
- gjmp(retpc);
- return;
- }
+ if(n != N)
+ genlist(n->list); // copy out args
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ genlist(curfn->exit);
p = gins(ARET, N, N);
- if(n->op == ORETJMP) {
+ if(n != N && n->op == ORETJMP) {
p->to.type = D_EXTERN;
- p->to.sym = n->left->sym;
+ p->to.sym = linksym(n->left->sym);
}
}
@@ -663,6 +716,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
gmove(&t2, &n1);
gmove(&t1, ax);
p2 = P;
+ if(nacl) {
+ // Native Client does not relay the divide-by-zero trap
+ // to the executing program, so we must insert a check
+ // for ourselves.
+ nodconst(&n4, t, 0);
+ gins(optoas(OCMP, t), &n1, &n4);
+ p1 = gbranch(optoas(ONE, t), T, +1);
+ if(panicdiv == N)
+ panicdiv = sysfunc("panicdivide");
+ ginscall(panicdiv, -1);
+ patch(p1, pc);
+ }
if(check) {
nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n1, &n4);
@@ -1246,8 +1311,8 @@ expandchecks(Prog *firstp)
p->link = p1;
p1->lineno = p->lineno;
p2->lineno = p->lineno;
- p1->loc = 9999;
- p2->loc = 9999;
+ p1->pc = 9999;
+ p2->pc = 9999;
p->as = ACMPL;
p->to.type = D_CONST;
p->to.offset = 0;
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index 0517824e0..fa0605e6c 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -32,229 +32,6 @@
#include <libc.h>
#include "gg.h"
-void
-zname(Biobuf *b, Sym *s, int t)
-{
- BPUTLE2(b, ANAME); /* as */
- BPUTC(b, t); /* type */
- BPUTC(b, s->sym); /* sym */
-
- Bputname(b, s);
-}
-
-void
-zfile(Biobuf *b, char *p, int n)
-{
- BPUTLE2(b, ANAME);
- BPUTC(b, D_FILE);
- BPUTC(b, 1);
- BPUTC(b, '<');
- Bwrite(b, p, n);
- BPUTC(b, 0);
-}
-
-void
-zhist(Biobuf *b, int line, vlong offset)
-{
- Addr a;
-
- BPUTLE2(b, AHISTORY);
- BPUTLE4(b, line);
- zaddr(b, &zprog.from, 0, 0);
- a = zprog.to;
- if(offset != 0) {
- a.offset = offset;
- a.type = D_CONST;
- }
- zaddr(b, &a, 0, 0);
-}
-
-void
-zaddr(Biobuf *b, Addr *a, int s, int gotype)
-{
- int32 l;
- uint64 e;
- int i, t;
- char *n;
-
- t = 0;
- if(a->index != D_NONE || a->scale != 0)
- t |= T_INDEX;
- if(s != 0)
- t |= T_SYM;
- if(gotype != 0)
- t |= T_GOTYPE;
-
- switch(a->type) {
-
- case D_BRANCH:
- if(a->u.branch == nil)
- fatal("unpatched branch");
- a->offset = a->u.branch->loc;
-
- default:
- t |= T_TYPE;
-
- case D_NONE:
- if(a->offset != 0)
- t |= T_OFFSET;
- if(a->offset2 != 0)
- t |= T_OFFSET2;
- break;
- case D_FCONST:
- t |= T_FCONST;
- break;
- case D_SCONST:
- t |= T_SCONST;
- break;
- }
- BPUTC(b, t);
-
- if(t & T_INDEX) { /* implies index, scale */
- BPUTC(b, a->index);
- BPUTC(b, a->scale);
- }
- if(t & T_OFFSET) { /* implies offset */
- l = a->offset;
- BPUTLE4(b, l);
- }
- if(t & T_OFFSET2) { /* implies offset */
- l = a->offset2;
- BPUTLE4(b, l);
- }
- if(t & T_SYM) /* implies sym */
- BPUTC(b, s);
- if(t & T_FCONST) {
- ieeedtod(&e, a->u.dval);
- BPUTLE4(b, e);
- BPUTLE4(b, e >> 32);
- return;
- }
- if(t & T_SCONST) {
- n = a->u.sval;
- for(i=0; i<NSNAME; i++) {
- BPUTC(b, *n);
- n++;
- }
- return;
- }
- if(t & T_TYPE)
- BPUTC(b, a->type);
- if(t & T_GOTYPE)
- BPUTC(b, gotype);
-}
-
-static struct {
- struct { Sym *sym; short type; } h[NSYM];
- int sym;
-} z;
-
-static void
-zsymreset(void)
-{
- for(z.sym=0; z.sym<NSYM; z.sym++) {
- z.h[z.sym].sym = S;
- z.h[z.sym].type = 0;
- }
- z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
- int i;
-
- *new = 0;
- if(s == S)
- return 0;
-
- i = s->sym;
- if(i < 0 || i >= NSYM)
- i = 0;
- if(z.h[i].type == t && z.h[i].sym == s)
- return i;
- i = z.sym;
- s->sym = i;
- zname(bout, s, t);
- z.h[i].sym = s;
- z.h[i].type = t;
- if(++z.sym >= NSYM)
- z.sym = 1;
- *new = 1;
- return i;
-}
-
-static int
-zsymaddr(Addr *a, int *new)
-{
- int t;
-
- t = a->type;
- if(t == D_ADDR)
- t = a->index;
- return zsym(a->sym, t, new);
-}
-
-void
-dumpfuncs(void)
-{
- Plist *pl;
- int sf, st, gf, gt, new;
- Sym *s;
- Prog *p;
-
- zsymreset();
-
- // fix up pc
- pcloc = 0;
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
- for(p=pl->firstpc; p!=P; p=p->link) {
- p->loc = pcloc;
- if(p->as != ADATA && p->as != AGLOBL)
- pcloc++;
- }
- }
-
- // put out functions
- for(pl=plist; pl!=nil; pl=pl->link) {
- if(isblank(pl->name))
- continue;
-
- // -S prints code; -SS prints code and data
- if(debug['S'] && (pl->name || debug['S']>1)) {
- s = S;
- if(pl->name != N)
- s = pl->name->sym;
- print("\n--- prog list \"%S\" ---\n", s);
- for(p=pl->firstpc; p!=P; p=p->link)
- print("%P\n", p);
- }
-
- for(p=pl->firstpc; p!=P; p=p->link) {
- for(;;) {
- sf = zsymaddr(&p->from, &new);
- gf = zsym(p->from.gotype, D_EXTERN, &new);
- if(new && sf == gf)
- continue;
- st = zsymaddr(&p->to, &new);
- if(new && (st == sf || st == gf))
- continue;
- gt = zsym(p->to.gotype, D_EXTERN, &new);
- if(new && (gt == sf || gt == gf || gt == st))
- continue;
- break;
- }
-
- BPUTLE2(bout, p->as);
- BPUTLE4(bout, p->lineno);
- zaddr(bout, &p->from, sf, gf);
- zaddr(bout, &p->to, st, gt);
- }
- }
-}
-
int
dsname(Sym *s, int off, char *t, int n)
{
@@ -265,7 +42,7 @@ dsname(Sym *s, int off, char *t, int n)
p->from.index = D_NONE;
p->from.offset = off;
p->from.scale = n;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->to.type = D_SCONST;
p->to.index = D_NONE;
@@ -284,7 +61,7 @@ datastring(char *s, int len, Addr *a)
sym = stringsym(s, len);
a->type = D_EXTERN;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
a->offset = widthptr+4; // skip header
a->etype = TINT32;
@@ -301,7 +78,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_EXTERN;
- a->sym = sym;
+ a->sym = linksym(sym);
a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
@@ -386,7 +163,7 @@ dstringptr(Sym *s, int off, char *str)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
@@ -411,7 +188,7 @@ dgostrlitptr(Sym *s, int off, Strlit *lit)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
datagostring(lit, &p->to);
@@ -439,28 +216,6 @@ dgostringptr(Sym *s, int off, char *str)
return dgostrlitptr(s, off, lit);
}
-
-int
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
- Prog *p;
-
- off = rnd(off, wid);
-
- p = gins(ADATA, N, N);
- p->from.type = D_EXTERN;
- p->from.index = D_NONE;
- p->from.sym = s;
- p->from.offset = off;
- p->from.scale = wid;
- p->to.type = D_CONST;
- p->to.index = D_NONE;
- p->to.offset = v;
- off += wid;
-
- return off;
-}
-
int
dsymptr(Sym *s, int off, Sym *x, int xoff)
{
@@ -471,12 +226,12 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->from.offset = off;
p->from.scale = widthptr;
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
- p->to.sym = x;
+ p->to.sym = linksym(x);
p->to.offset = xoff;
off += widthptr;
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 34703ba6e..2f3cb28c8 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -48,7 +48,7 @@ clearp(Prog *p)
p->from.index = D_NONE;
p->to.type = D_NONE;
p->to.index = D_NONE;
- p->loc = pcloc;
+ p->pc = pcloc;
pcloc++;
}
@@ -137,7 +137,7 @@ patch(Prog *p, Prog *to)
if(p->to.type != D_BRANCH)
fatal("patch: not a branch");
p->to.u.branch = to;
- p->to.offset = to->loc;
+ p->to.offset = to->pc;
}
Prog*
@@ -161,13 +161,8 @@ newplist(void)
{
Plist *pl;
- pl = mal(sizeof(*pl));
- if(plist == nil)
- plist = pl;
- else
- plast->link = pl;
- plast = pl;
-
+ pl = linknewplist(ctxt);
+
pc = mal(sizeof(*pc));
clearp(pc);
pl->firstpc = pc;
@@ -199,8 +194,8 @@ ggloblnod(Node *nam)
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
- p->from.gotype = ngotype(nam);
- p->to.sym = S;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
p->to.type = D_CONST;
p->to.offset = nam->type->width;
if(nam->readonly)
@@ -227,7 +222,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata)
p = gins(AGLOBL, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
p->to.type = D_CONST;
p->to.index = D_NONE;
p->to.offset = width;
@@ -245,7 +240,7 @@ gtrack(Sym *s)
p = gins(AUSEFIELD, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
- p->from.sym = s;
+ p->from.sym = linksym(s);
}
int
@@ -273,7 +268,7 @@ afunclit(Addr *a, Node *n)
if(a->type == D_ADDR && a->index == D_EXTERN) {
a->type = D_EXTERN;
a->index = D_NONE;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
}
}
@@ -437,6 +432,7 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
+ case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
@@ -1048,6 +1044,7 @@ Node*
nodarg(Type *t, int fp)
{
Node *n;
+ NodeList *l;
Type *first;
Iter savet;
@@ -1072,6 +1069,14 @@ nodarg(Type *t, int fp)
break;
case TFIELD:
+ if(fp == 1 && t->sym != S && !isblanksym(t->sym)) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym)
+ return n;
+ }
+ }
+
n = nod(ONAME, N, N);
n->type = t->type;
n->sym = t->sym;
@@ -1692,7 +1697,6 @@ floatmove(Node *f, Node *t)
gins(ACMPL, &thi, ncon(0));
p1 = gbranch(AJLT, T, 0);
// native
- t1.type = types[TINT64];
nodreg(&r1, types[tt], D_F0);
gins(AFMOVV, &t1, &r1);
if(tt == TFLOAT32)
@@ -2178,10 +2182,12 @@ gins(int as, Node *f, Node *t)
void
naddr(Node *n, Addr *a, int canemitcode)
{
+ Sym *s;
+
a->scale = 0;
a->index = D_NONE;
a->type = D_NONE;
- a->gotype = S;
+ a->gotype = nil;
a->node = N;
if(n == N)
return;
@@ -2193,12 +2199,12 @@ naddr(Node *n, Addr *a, int canemitcode)
case OREGISTER:
a->type = n->val.u.reg;
- a->sym = S;
+ a->sym = nil;
break;
case OINDREG:
a->type = n->val.u.reg+D_INDIR;
- a->sym = n->sym;
+ a->sym = linksym(n->sym);
a->offset = n->xoffset;
break;
@@ -2208,20 +2214,22 @@ naddr(Node *n, Addr *a, int canemitcode)
a->etype = n->left->type->etype;
a->width = n->left->type->width;
a->offset = n->xoffset;
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
a->type = D_PARAM;
a->node = n->left->orig;
break;
case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
a->type = D_DX+D_INDIR;
a->offset = n->xoffset;
- a->sym = S;
+ a->sym = nil;
break;
case OCFUNC:
naddr(n->left, a, canemitcode);
- a->sym = n->left->sym;
+ a->sym = linksym(n->left->sym);
break;
case ONAME:
@@ -2233,17 +2241,17 @@ naddr(Node *n, Addr *a, int canemitcode)
a->width = n->type->width;
}
a->offset = n->xoffset;
- a->sym = n->sym;
+ s = n->sym;
a->node = n->orig;
//if(a->node >= (Node*)&n)
// fatal("stack node");
- if(a->sym == S)
- a->sym = lookup(".noname");
+ if(s == S)
+ s = lookup(".noname");
if(n->method) {
if(n->type != T)
if(n->type->sym != S)
if(n->type->sym->pkg != nil)
- a->sym = pkglookup(a->sym->name, n->type->sym->pkg);
+ s = pkglookup(s->name, n->type->sym->pkg);
}
switch(n->class) {
@@ -2262,9 +2270,10 @@ naddr(Node *n, Addr *a, int canemitcode)
case PFUNC:
a->index = D_EXTERN;
a->type = D_ADDR;
- a->sym = funcsym(a->sym);
+ s = funcsym(s);
break;
}
+ a->sym = linksym(s);
break;
case OLITERAL:
@@ -2278,7 +2287,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case CTINT:
case CTRUNE:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
break;
@@ -2286,12 +2295,12 @@ naddr(Node *n, Addr *a, int canemitcode)
datagostring(n->val.u.sval, a);
break;
case CTBOOL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = n->val.u.bval;
break;
case CTNIL:
- a->sym = S;
+ a->sym = nil;
a->type = D_CONST;
a->offset = 0;
break;
@@ -2327,7 +2336,7 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // ptr(nil)
- a->etype = simtype[TUINTPTR];
+ a->etype = simtype[tptr];
a->offset += Array_array;
a->width = widthptr;
break;
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
index 0d99bdb97..77a69e13a 100644
--- a/src/cmd/8g/opt.h
+++ b/src/cmd/8g/opt.h
@@ -109,6 +109,7 @@ EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
EXTERN Bits addrs;
+EXTERN Bits ivar;
EXTERN Bits ovar;
EXTERN int change;
EXTERN int32 maxnr;
@@ -155,8 +156,6 @@ int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
-#pragma varargck type "D" Adr*
-
/*
* prog.c
*/
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index 966c0421b..a4e516dd3 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -107,7 +107,7 @@ peep(Prog *firstp)
switch(p->as) {
case ALEAL:
if(regtyp(&p->to))
- if(p->from.sym != S)
+ if(p->from.sym != nil)
if(p->from.index == D_NONE || p->from.index == D_CONST)
conprop(r);
break;
@@ -387,6 +387,8 @@ subprop(Flow *r0)
if(uniqs(r) == nil)
break;
p = r->prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
if(info.flags & Call)
return 0;
@@ -478,7 +480,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
if(debug['P'])
print("; merge; f=%d", f);
}
- t = copyu(p, v2, A);
+ t = copyu(p, v2, nil);
switch(t) {
case 2: /* rar, can't split */
if(debug['P'])
@@ -516,7 +518,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
break;
}
if(!f) {
- t = copyu(p, v1, A);
+ t = copyu(p, v1, nil);
if(!f && (t == 2 || t == 3 || t == 4)) {
f = 1;
if(debug['P'])
@@ -547,7 +549,7 @@ copyu(Prog *p, Adr *v, Adr *s)
switch(p->as) {
case AJMP:
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -557,7 +559,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case ARET:
- if(s != A)
+ if(s != nil)
return 1;
return 3;
@@ -569,7 +571,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(v->type == p->from.type)
return 2;
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->to, v, s, 1))
return 1;
return 0;
@@ -584,6 +586,8 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
}
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ return 0;
proginfo(&info, p);
if((info.reguse|info.regset) & RtoB(v->type))
@@ -599,7 +603,7 @@ copyu(Prog *p, Adr *v, Adr *s)
if(info.flags & RightWrite) {
if(copyas(&p->to, v)) {
- if(s != A)
+ if(s != nil)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
@@ -608,7 +612,7 @@ copyu(Prog *p, Adr *v, Adr *s)
}
if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
- if(s != A) {
+ if(s != nil) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
@@ -727,7 +731,7 @@ loop:
return;
p = r->prog;
- t = copyu(p, v0, A);
+ t = copyu(p, v0, nil);
switch(t) {
case 0: // miss
case 1: // use
@@ -743,7 +747,7 @@ loop:
if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
- if(p->from.u.vval == p0->from.u.vval)
+ if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
if(p->from.index == p0->from.index) {
excise(r);
goto loop;
diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c
index 14f197b6a..8eed67f6d 100644
--- a/src/cmd/8g/prog.c
+++ b/src/cmd/8g/prog.c
@@ -38,9 +38,11 @@ static ProgInfo progtable[ALAST] = {
[ATEXT]= {Pseudo},
[AFUNCDATA]= {Pseudo},
[APCDATA]= {Pseudo},
- [AUNDEF]= {OK},
+ [AUNDEF]= {Break},
[AUSEFIELD]= {OK},
[ACHECKNIL]= {LeftRead},
+ [AVARDEF]= {Pseudo | RightWrite},
+ [AVARKILL]= {Pseudo | RightWrite},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Intel opcode.
@@ -136,11 +138,16 @@ static ProgInfo progtable[ALAST] = {
[AFMOVW]= {SizeW | LeftAddr | RightWrite},
[AFMOVV]= {SizeQ | LeftAddr | RightWrite},
- [AFMOVDP]= {SizeD | LeftRead | RightAddr},
- [AFMOVFP]= {SizeF | LeftRead | RightAddr},
- [AFMOVLP]= {SizeL | LeftRead | RightAddr},
- [AFMOVWP]= {SizeW | LeftRead | RightAddr},
- [AFMOVVP]= {SizeQ | LeftRead | RightAddr},
+ // These instructions are marked as RightAddr
+ // so that the register optimizer does not try to replace the
+ // memory references with integer register references.
+ // But they do not use the previous value at the address, so
+ // we also mark them RightWrite.
+ [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr},
+ [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr},
+ [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr},
+ [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr},
+ [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr},
[AFMULD]= {SizeD | LeftAddr | RightRdwr},
[AFMULDP]= {SizeD | LeftAddr | RightRdwr},
@@ -193,6 +200,7 @@ static ProgInfo progtable[ALAST] = {
[AMOVSB]= {OK, DI|SI, DI|SI},
[AMOVSL]= {OK, DI|SI, DI|SI},
[AMOVSW]= {OK, DI|SI, DI|SI},
+ [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX},
[AMOVSD]= {SizeD | LeftRead | RightWrite | Move},
[AMOVSS]= {SizeF | LeftRead | RightWrite | Move},
@@ -285,6 +293,7 @@ static ProgInfo progtable[ALAST] = {
[ASTOSB]= {OK, AX|DI, DI},
[ASTOSL]= {OK, AX|DI, DI},
[ASTOSW]= {OK, AX|DI, DI},
+ [ADUFFZERO]= {OK, AX|DI, DI},
[ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry},
[ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry},
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index a85c6608a..fd610f87a 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -55,30 +55,6 @@ rcmp(const void *a1, const void *a2)
}
static void
-setoutvar(void)
-{
- Type *t;
- Node *n;
- Addr a;
- Iter save;
- Bits bit;
- int z;
-
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- n = nodarg(t, 1);
- a = zprog.from;
- naddr(n, &a, 0);
- bit = mkvar(R, &a);
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
- t = structnext(&save);
- }
-//if(bany(ovar))
-//print("ovars = %Q\n", ovar);
-}
-
-static void
setaddrs(Bits bit)
{
int i, n;
@@ -108,6 +84,8 @@ static char* regname[] = {
static Node* regnodes[NREGVAR];
+static void walkvardef(Node *n, Reg *r, int active);
+
void
regopt(Prog *firstp)
{
@@ -115,7 +93,7 @@ regopt(Prog *firstp)
Prog *p;
Graph *g;
ProgInfo info;
- int i, z;
+ int i, z, active;
uint32 vreg;
Bits bit;
@@ -124,8 +102,7 @@ regopt(Prog *firstp)
exregoffset = D_DI; // no externals
first = 0;
}
-
- fixjmp(firstp);
+
mergetemp(firstp);
/*
@@ -147,12 +124,10 @@ regopt(Prog *firstp)
params.b[z] = 0;
consts.b[z] = 0;
addrs.b[z] = 0;
+ ivar.b[z] = 0;
ovar.b[z] = 0;
}
- // build list of return variables
- setoutvar();
-
/*
* pass 1
* build aux data structure
@@ -160,12 +135,18 @@ regopt(Prog *firstp)
* find use and set of variables
*/
g = flowstart(firstp, sizeof(Reg));
- if(g == nil)
+ if(g == nil) {
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
return;
+ }
+
firstr = (Reg*)g->start;
for(r = firstr; r != R; r = (Reg*)r->f.link) {
p = r->f.prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
proginfo(&info, p);
// Avoid making variables for direct-called functions.
@@ -228,6 +209,26 @@ regopt(Prog *firstp)
dumpit("pass2", &firstr->f, 1);
/*
+ * pass 2.5
+ * iterate propagating fat vardef covering forward
+ * r->act records vars with a VARDEF since the last CALL.
+ * (r->act will be reused in pass 5 for something else,
+ * but we'll be done with it by then.)
+ */
+ active = 0;
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ r->f.active = 0;
+ r->act = zbits;
+ }
+ for(r = firstr; r != R; r = (Reg*)r->f.link) {
+ p = r->f.prog;
+ if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+ active++;
+ walkvardef(p->to.node, r, active);
+ }
+ }
+
+ /*
* pass 3
* iterate propagating usage
* back until flow graph is complete
@@ -367,6 +368,8 @@ brk:
/*
* free aux structures. peep allocates new ones.
*/
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
flowend(g);
firstr = R;
@@ -423,6 +426,32 @@ brk:
}
}
+static void
+walkvardef(Node *n, Reg *r, int active)
+{
+ Reg *r1, *r2;
+ int bn;
+ Var *v;
+
+ for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
+ if(r1->f.active == active)
+ break;
+ r1->f.active = active;
+ if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
+ break;
+ for(v=n->opt; v!=nil; v=v->nextinnode) {
+ bn = v - var;
+ r1->act.b[bn/32] |= 1L << (bn%32);
+ }
+ if(r1->f.prog->as == ACALL)
+ break;
+ }
+
+ for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
+ if(r2->f.s2 != nil)
+ walkvardef(n, (Reg*)r2->f.s2, active);
+}
+
/*
* add mov b,rn
* just after r
@@ -436,7 +465,7 @@ addmove(Reg *r, int bn, int rn, int f)
p1 = mal(sizeof(*p1));
clearp(p1);
- p1->loc = 9999;
+ p1->pc = 9999;
p = r->f.prog;
p1->link = p->link;
@@ -450,7 +479,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->node = v->node;
- a->sym = v->node->sym;
+ a->sym = linksym(v->node->sym);
// need to clean this up with wptr and
// some of the defaults
@@ -618,6 +647,16 @@ mkvar(Reg *r, Adr *a)
if(nvar >= NVAR) {
if(debug['w'] > 1 && node != N)
fatal("variable not optimized: %D", a);
+
+ // If we're not tracking a word in a variable, mark the rest as
+ // having its address taken, so that we keep the whole thing
+ // live at all calls. otherwise we might optimize away part of
+ // a variable but not all of it.
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node)
+ v->addr = 1;
+ }
goto none;
}
@@ -630,10 +669,13 @@ mkvar(Reg *r, Adr *a)
v->width = w;
v->addr = flag; // funny punning
v->node = node;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
- ostats.nvar++;
+
+ // node->opt is the head of a linked list
+ // of Vars within the given Node, so that
+ // we can start at a Var and find all the other
+ // Vars in the same Go variable.
+ v->nextinnode = node->opt;
+ node->opt = v;
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
@@ -642,6 +684,46 @@ mkvar(Reg *r, Adr *a)
if(n == D_PARAM)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
+
+ if(node->class == PPARAM)
+ for(z=0; z<BITS; z++)
+ ivar.b[z] |= bit.b[z];
+ if(node->class == PPARAMOUT)
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+
+ // Treat values with their address taken as live at calls,
+ // because the garbage collector's liveness analysis in ../gc/plive.c does.
+ // These must be consistent or else we will elide stores and the garbage
+ // collector will see uninitialized data.
+ // The typical case where our own analysis is out of sync is when the
+ // node appears to have its address taken but that code doesn't actually
+ // get generated and therefore doesn't show up as an address being
+ // taken when we analyze the instruction stream.
+ // One instance of this case is when a closure uses the same name as
+ // an outer variable for one of its own variables declared with :=.
+ // The parser flags the outer variable as possibly shared, and therefore
+ // sets addrtaken, even though it ends up not being actually shared.
+ // If we were better about _ elision, _ = &x would suffice too.
+ // The broader := in a closure problem is mentioned in a comment in
+ // closure.c:/^typecheckclosure and dcl.c:/^oldname.
+ if(node->addrtaken)
+ v->addr = 1;
+
+ // Disable registerization for globals, because:
+ // (1) we might panic at any time and we want the recovery code
+ // to see the latest values (issue 1304).
+ // (2) we don't know what pointers might point at them and we want
+ // loads via those pointers to see updated values and vice versa (issue 7995).
+ //
+ // Disable registerization for results if using defer, because the deferred func
+ // might recover and return, causing the current values to be used.
+ if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
+ v->addr = 1;
+
+ if(debug['R'])
+ print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ ostats.nvar++;
return bit;
@@ -653,7 +735,8 @@ void
prop(Reg *r, Bits ref, Bits cal)
{
Reg *r1, *r2;
- int z;
+ int z, i, j;
+ Var *v, *v1;
for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
for(z=0; z<BITS; z++) {
@@ -672,10 +755,61 @@ prop(Reg *r, Bits ref, Bits cal)
case ACALL:
if(noreturn(r1->f.prog))
break;
+
+ // Mark all input variables (ivar) as used, because that's what the
+ // liveness bitmaps say. The liveness bitmaps say that so that a
+ // panic will not show stale values in the parameter dump.
+ // Mark variables with a recent VARDEF (r1->act) as used,
+ // so that the optimizer flushes initializations to memory,
+ // so that if a garbage collection happens during this CALL,
+ // the collector will see initialized memory. Again this is to
+ // match what the liveness bitmaps say.
for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z];
+ cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
ref.b[z] = 0;
}
+
+ // cal.b is the current approximation of what's live across the call.
+ // Every bit in cal.b is a single stack word. For each such word,
+ // find all the other tracked stack words in the same Go variable
+ // (struct/slice/string/interface) and mark them live too.
+ // This is necessary because the liveness analysis for the garbage
+ // collector works at variable granularity, not at word granularity.
+ // It is fundamental for slice/string/interface: the garbage collector
+ // needs the whole value, not just some of the words, in order to
+ // interpret the other bits correctly. Specifically, slice needs a consistent
+ // ptr and cap, string needs a consistent ptr and len, and interface
+ // needs a consistent type word and data word.
+ for(z=0; z<BITS; z++) {
+ if(cal.b[z] == 0)
+ continue;
+ for(i=0; i<32; i++) {
+ if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ continue;
+ v = var+z*32+i;
+ if(v->node->opt == nil) // v represents fixed register, not Go variable
+ continue;
+
+ // v->node->opt is the head of a linked list of Vars
+ // corresponding to tracked words from the Go variable v->node.
+ // Walk the list and set all the bits.
+ // For a large struct this could end up being quadratic:
+ // after the first setting, the outer loop (for z, i) would see a 1 bit
+ // for all of the remaining words in the struct, and for each such
+ // word would go through and turn on all the bits again.
+ // To avoid the quadratic behavior, we only turn on the bits if
+ // v is the head of the list or if the head's bit is not yet turned on.
+ // This will set the bits at most twice, keeping the overall loop linear.
+ v1 = v->node->opt;
+ j = v1 - var;
+ if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
+ for(; v1 != nil; v1 = v1->nextinnode) {
+ j = v1 - var;
+ cal.b[j/32] |= 1<<(j&31);
+ }
+ }
+ }
+ }
break;
case ATEXT:
@@ -691,17 +825,6 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
-
- default:
- // Work around for issue 1304:
- // flush modified globals before each instruction.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= externs.b[z];
- // issue 4066: flush modified return variables in case of panic
- if(hasdefer)
- cal.b[z] |= ovar.b[z];
- }
- break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -824,18 +947,19 @@ paint1(Reg *r, int bn)
r->act.b[z] |= bb;
p = r->f.prog;
- if(r->use1.b[z] & bb) {
- change += CREF * r->f.loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != D_F0)
- change = -CINF;
- }
-
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->f.loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != D_F0)
- change = -CINF;
+ if(r->f.prog->as != ANOP) { // don't give credit for NOPs
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->f.loop;
+ if(p->as == AFMOVL || p->as == AFMOVW)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->f.loop;
+ if(p->as == AFMOVL || p->as == AFMOVW)
+ if(BtoR(bb) != D_F0)
+ change = -CINF;
+ }
}
if(STORE(r) & r->regdiff.b[z] & bb) {
@@ -877,7 +1001,7 @@ regset(Reg *r, uint32 bb)
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFF ? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, A);
+ c = copyu(r->f.prog, &v, nil);
if(c == 3)
set |= b;
bb &= ~b;
@@ -896,7 +1020,7 @@ reguse(Reg *r, uint32 bb)
v = zprog.from;
while(b = bb & ~(bb-1)) {
v.type = b & 0xFF ? BtoR(b): BtoF(b);
- c = copyu(r->f.prog, &v, A);
+ c = copyu(r->f.prog, &v, nil);
if(c == 1 || c == 2 || c == 4)
set |= b;
bb &= ~b;
@@ -1038,8 +1162,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
void
addreg(Adr *a, int rn)
{
-
- a->sym = 0;
+ a->sym = nil;
a->offset = 0;
a->type = rn;
@@ -1140,15 +1263,15 @@ dumpit(char *str, Flow *r0, int isreg)
r1 = r->p2;
if(r1 != nil) {
print(" pred:");
- for(; r1 != nil; r1 = r->p2link)
- print(" %.4ud", r1->prog->loc);
+ for(; r1 != nil; r1 = r1->p2link)
+ print(" %.4ud", (int)r1->prog->pc);
print("\n");
}
// r1 = r->s1;
// if(r1 != nil) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4ud", r1->prog->loc);
+// print(" %.4ud", (int)r1->prog->pc);
// print("\n");
// }
}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index 988e50f3e..8e642d390 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -547,6 +547,7 @@ enum as
APSUBW,
APUNPCKHQDQ,
APUNPCKLQDQ,
+ APXOR,
ARCPPS,
ARCPSS,
ARSQRTPS,
@@ -578,6 +579,10 @@ enum as
AFUNCDATA,
APCDATA,
ACHECKNIL,
+ AVARDEF,
+ AVARKILL,
+ ADUFFCOPY,
+ ADUFFZERO,
ALAST
};
@@ -631,30 +636,23 @@ enum
D_X5,
D_X6,
D_X7,
-
- D_NONE = 67,
-
- D_BRANCH = 68,
- D_EXTERN = 69,
- D_STATIC = 70,
- D_AUTO = 71,
- D_PARAM = 72,
- D_CONST = 73,
- D_FCONST = 74,
- D_SCONST = 75,
- D_ADDR = 76,
-
- D_FILE,
- D_FILE1,
+
+ D_TLS = 67,
+ D_NONE = 68,
+
+ D_BRANCH = 69,
+ D_EXTERN = 70,
+ D_STATIC = 71,
+ D_AUTO = 72,
+ D_PARAM = 73,
+ D_CONST = 74,
+ D_FCONST = 75,
+ D_SCONST = 76,
+ D_ADDR = 77,
D_INDIR, /* additive */
D_CONST2 = D_INDIR+D_INDIR,
- D_SIZE, /* 8l internal */
- D_PCREL,
- D_GOTOFF,
- D_GOTREL,
- D_TLS,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
@@ -676,15 +674,3 @@ enum
* this is the ranlib header
*/
#define SYMDEF "__.GOSYMDEF"
-
-/*
- * this is the simulated IEEE floating point
- */
-typedef struct ieee Ieee;
-struct ieee
-{
- int32 l; /* contains ls-man 0xffffffff */
- int32 h; /* contains sign 0x80000000
- exp 0x7ff00000
- ms-man 0x000fffff */
-};
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 3be37ea22..114a3eb5d 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -42,47 +42,20 @@ char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
char openbsddynld[] = "/usr/libexec/ld.so";
char netbsddynld[] = "/usr/libexec/ld.elf_so";
char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-
-int32
-entryvalue(void)
-{
- char *a;
- Sym *s;
-
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return atolwhex(a);
- s = lookup(a, 0);
- if(s->type == 0)
- return INITTEXT;
- if(s->type != STEXT)
- diag("entry not text: %s", s->name);
- return s->value;
-}
-
-vlong
-datoff(vlong addr)
-{
- if(addr >= segdata.vaddr)
- return addr - segdata.vaddr + segdata.fileoff;
- if(addr >= segtext.vaddr)
- return addr - segtext.vaddr + segtext.fileoff;
- diag("datoff %#llx", addr);
- return 0;
-}
+char solarisdynld[] = "/lib/ld.so.1";
static int
needlib(char *name)
{
char *p;
- Sym *s;
+ LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
- s = lookup(p, 0);
+ s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@@ -93,11 +66,11 @@ needlib(char *name)
int nelfsym = 1;
-static void addpltsym(Sym*);
-static void addgotsym(Sym*);
+static void addpltsym(Link*, LSym*);
+static void addgotsym(Link*, LSym*);
void
-adddynrela(Sym *rela, Sym *s, Reloc *r)
+adddynrela(LSym *rela, LSym *s, Reloc *r)
{
USED(rela);
USED(s);
@@ -106,12 +79,12 @@ adddynrela(Sym *rela, Sym *s, Reloc *r)
}
void
-adddynrel(Sym *s, Reloc *r)
+adddynrel(LSym *s, Reloc *r)
{
- Sym *targ, *rel, *got;
+ LSym *targ, *rel, *got;
targ = r->sym;
- cursym = s;
+ ctxt->cursym = s;
switch(r->type) {
default:
@@ -127,16 +100,16 @@ adddynrel(Sym *s, Reloc *r)
diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
return;
case 256 + R_386_PLT32:
- r->type = D_PCREL;
+ r->type = R_PCREL;
r->add += 4;
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@@ -150,46 +123,46 @@ adddynrel(Sym *s, Reloc *r)
return;
}
s->p[r->off-2] = 0x8d;
- r->type = D_GOTOFF;
+ r->type = R_GOTOFF;
return;
}
- addgotsym(targ);
- r->type = D_CONST; // write r->add during relocsym
+ addgotsym(ctxt, targ);
+ r->type = R_CONST; // write r->add during relocsym
r->sym = S;
r->add += targ->got;
return;
case 256 + R_386_GOTOFF:
- r->type = D_GOTOFF;
+ r->type = R_GOTOFF;
return;
case 256 + R_386_GOTPC:
- r->type = D_PCREL;
- r->sym = lookup(".got", 0);
+ r->type = R_PCREL;
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
return;
case 256 + R_386_32:
if(targ->type == SDYNIMPORT)
diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
- r->type = D_ADDR;
+ r->type = R_ADDR;
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
- r->type = D_ADDR;
+ r->type = R_ADDR;
if(targ->type == SDYNIMPORT)
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if(targ->type == SDYNIMPORT) {
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
}
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
case 512 + MACHO_FAKE_GOTPCREL:
@@ -201,13 +174,13 @@ adddynrel(Sym *s, Reloc *r)
return;
}
s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
}
- addgotsym(targ);
- r->sym = lookup(".got", 0);
+ addgotsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
- r->type = D_PCREL;
+ r->type = R_PCREL;
return;
}
@@ -216,21 +189,22 @@ adddynrel(Sym *s, Reloc *r)
return;
switch(r->type) {
- case D_PCREL:
- addpltsym(targ);
- r->sym = lookup(".plt", 0);
+ case R_CALL:
+ case R_PCREL:
+ addpltsym(ctxt, targ);
+ r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
- case D_ADDR:
+ case R_ADDR:
if(s->type != SDATA)
break;
if(iself) {
- adddynsym(targ);
- rel = lookup(".rel", 0);
- addaddrplus(rel, s, r->off);
- adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
- r->type = D_CONST; // write r->add during relocsym
+ adddynsym(ctxt, targ);
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, s, r->off);
+ adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
+ r->type = R_CONST; // write r->add during relocsym
r->sym = S;
return;
}
@@ -245,22 +219,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- adddynsym(targ);
- got = lookup(".got", 0);
+ adddynsym(ctxt, targ);
+ got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
- adduint32(got, 0);
- adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
- cursym = s;
+ ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@@ -276,21 +250,23 @@ elfreloc1(Reloc *r, vlong sectoff)
default:
return -1;
- case D_ADDR:
+ case R_ADDR:
if(r->siz == 4)
LPUT(R_386_32 | elfsym<<8);
else
return -1;
break;
- case D_PCREL:
+ case R_CALL:
+ case R_PCREL:
if(r->siz == 4)
LPUT(R_386_PC32 | elfsym<<8);
else
return -1;
break;
- case D_TLS:
+ case R_TLS_LE:
+ case R_TLS_IE:
if(r->siz == 4)
LPUT(R_386_TLS_LE | elfsym<<8);
else
@@ -304,7 +280,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
- Sym *rs;
+ LSym *rs;
rs = r->xsym;
@@ -326,10 +302,11 @@ machoreloc1(Reloc *r, vlong sectoff)
switch(r->type) {
default:
return -1;
- case D_ADDR:
+ case R_ADDR:
v |= MACHO_GENERIC_RELOC_VANILLA<<28;
break;
- case D_PCREL:
+ case R_CALL:
+ case R_PCREL:
v |= 1<<24; // pc-relative bit
v |= MACHO_GENERIC_RELOC_VANILLA<<28;
break;
@@ -358,17 +335,17 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
-archreloc(Reloc *r, Sym *s, vlong *val)
+archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(s);
if(linkmode == LinkExternal)
return -1;
switch(r->type) {
- case D_CONST:
+ case R_CONST:
*val = r->add;
return 0;
- case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ case R_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
}
return -1;
@@ -377,119 +354,119 @@ archreloc(Reloc *r, Sym *s, vlong *val)
void
elfsetupplt(void)
{
- Sym *plt, *got;
+ LSym *plt, *got;
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
if(plt->size == 0) {
// pushl got+4
- adduint8(plt, 0xff);
- adduint8(plt, 0x35);
- addaddrplus(plt, got, 4);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x35);
+ addaddrplus(ctxt, plt, got, 4);
// jmp *got+8
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, 8);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, got, 8);
// zero pad
- adduint32(plt, 0);
+ adduint32(ctxt, plt, 0);
// assume got->size == 0 too
- addaddrplus(got, lookup(".dynamic", 0), 0);
- adduint32(got, 0);
- adduint32(got, 0);
+ addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+ adduint32(ctxt, got, 0);
+ adduint32(ctxt, got, 0);
}
}
static void
-addpltsym(Sym *s)
+addpltsym(Link *ctxt, LSym *s)
{
- Sym *plt, *got, *rel;
+ LSym *plt, *got, *rel;
if(s->plt >= 0)
return;
- adddynsym(s);
+ adddynsym(ctxt, s);
if(iself) {
- plt = lookup(".plt", 0);
- got = lookup(".got.plt", 0);
- rel = lookup(".rel.plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
+ got = linklookup(ctxt, ".got.plt", 0);
+ rel = linklookup(ctxt, ".rel.plt", 0);
if(plt->size == 0)
elfsetupplt();
// jmpq *got+size
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, got, got->size);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
- addaddrplus(got, plt, plt->size);
+ addaddrplus(ctxt, got, plt, plt->size);
// pushl $x
- adduint8(plt, 0x68);
- adduint32(plt, rel->size);
+ adduint8(ctxt, plt, 0x68);
+ adduint32(ctxt, plt, rel->size);
// jmp .plt
- adduint8(plt, 0xe9);
- adduint32(plt, -(plt->size+4));
+ adduint8(ctxt, plt, 0xe9);
+ adduint32(ctxt, plt, -(plt->size+4));
// rel
- addaddrplus(rel, got, got->size-4);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+ addaddrplus(ctxt, rel, got, got->size-4);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
// Same laziness as in 6l.
- Sym *plt;
+ LSym *plt;
- plt = lookup(".plt", 0);
+ plt = linklookup(ctxt, ".plt", 0);
- addgotsym(s);
+ addgotsym(ctxt, s);
- adduint32(lookup(".linkedit.plt", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
- adduint8(plt, 0xff);
- adduint8(plt, 0x25);
- addaddrplus(plt, lookup(".got", 0), s->got);
+ adduint8(ctxt, plt, 0xff);
+ adduint8(ctxt, plt, 0x25);
+ addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
-addgotsym(Sym *s)
+addgotsym(Link *ctxt, LSym *s)
{
- Sym *got, *rel;
+ LSym *got, *rel;
if(s->got >= 0)
return;
- adddynsym(s);
- got = lookup(".got", 0);
+ adddynsym(ctxt, s);
+ got = linklookup(ctxt, ".got", 0);
s->got = got->size;
- adduint32(got, 0);
+ adduint32(ctxt, got, 0);
if(iself) {
- rel = lookup(".rel", 0);
- addaddrplus(rel, got, s->got);
- adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+ rel = linklookup(ctxt, ".rel", 0);
+ addaddrplus(ctxt, rel, got, s->got);
+ adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
} else if(HEADTYPE == Hdarwin) {
- adduint32(lookup(".linkedit.got", 0), s->dynid);
+ adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
-adddynsym(Sym *s)
+adddynsym(Link *ctxt, LSym *s)
{
- Sym *d;
+ LSym *d;
int t;
char *name;
@@ -499,20 +476,20 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
- d = lookup(".dynsym", 0);
+ d = linklookup(ctxt, ".dynsym", 0);
/* name */
name = s->extname;
- adduint32(d, addstring(lookup(".dynstr", 0), name));
+ adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* value */
if(s->type == SDYNIMPORT)
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
else
- addaddr(d, s);
+ addaddr(ctxt, d, s);
/* size */
- adduint32(d, 0);
+ adduint32(ctxt, d, 0);
/* type */
t = STB_GLOBAL << 4;
@@ -520,12 +497,12 @@ adddynsym(Sym *s)
t |= STT_FUNC;
else
t |= STT_OBJECT;
- adduint8(d, t);
- adduint8(d, 0);
+ adduint8(ctxt, d, t);
+ adduint8(ctxt, d, 0);
/* shndx */
if(s->type == SDYNIMPORT)
- adduint16(d, SHN_UNDEF);
+ adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@@ -542,7 +519,7 @@ adddynsym(Sym *s)
t = 14;
break;
}
- adduint16(d, t);
+ adduint16(ctxt, d, t);
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@@ -556,16 +533,16 @@ adddynsym(Sym *s)
void
adddynlib(char *lib)
{
- Sym *s;
+ LSym *s;
if(!needlib(lib))
return;
if(iself) {
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
if(s->size == 0)
addstring(s, "");
- elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else if(HEADTYPE != Hwindows) {
@@ -576,10 +553,10 @@ adddynlib(char *lib)
void
asmb(void)
{
- int32 v, magic;
+ int32 magic;
uint32 symo, dwarfoff, machlink;
Section *sect;
- Sym *sym;
+ LSym *sym;
int i;
if(debug['v'])
@@ -641,18 +618,7 @@ asmb(void)
default:
if(iself)
goto Elfsym;
- case Hgarbunix:
- symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
- break;
- case Hunixcoff:
- symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- break;
- case Hplan9x32:
- symo = HEADR+segtext.filelen+segdata.filelen;
- break;
- case Hmsdoscom:
- case Hmsdosexe:
- debug['s'] = 1;
+ case Hplan9:
symo = HEADR+segtext.filelen+segdata.filelen;
break;
case Hdarwin:
@@ -685,11 +651,11 @@ asmb(void)
elfemitreloc();
}
break;
- case Hplan9x32:
+ case Hplan9:
asmplan9sym();
cflush();
- sym = lookup("pclntab", 0);
+ sym = linklookup(ctxt, "pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
for(i=0; i < lcsize; i++)
@@ -715,96 +681,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
- case Hgarbunix: /* garbage */
- lputb(0x160L<<16); /* magic and sections */
- lputb(0L); /* time and date */
- lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
- lputb(symsize); /* nsyms */
- lputb((0x38L<<16)|7L); /* size of optional hdr and flags */
- lputb((0413<<16)|0437L); /* magic and version */
- lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
- lputb(segdata.filelen);
- lputb(segdata.len - segdata.filelen);
- lputb(entryvalue()); /* va of entry */
- lputb(INITTEXT-HEADR); /* va of base of text */
- lputb(segdata.vaddr); /* va of base of data */
- lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */
- lputb(~0L); /* gp reg mask */
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(0L);
- lputb(~0L); /* gp value ?? */
- break;
- case Hunixcoff: /* unix coff */
- /*
- * file header
- */
- lputl(0x0004014c); /* 4 sections, magic */
- lputl(0); /* unix time stamp */
- lputl(0); /* symbol table */
- lputl(0); /* nsyms */
- lputl(0x0003001c); /* flags, sizeof a.out header */
- /*
- * a.out header
- */
- lputl(0x10b); /* magic, version stamp */
- lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
- lputl(segdata.filelen); /* data sizes */
- lputl(segdata.len - segdata.filelen); /* bss sizes */
- lputb(entryvalue()); /* va of entry */
- lputl(INITTEXT); /* text start */
- lputl(segdata.vaddr); /* data start */
- /*
- * text section header
- */
- s8put(".text");
- lputl(HEADR); /* pa */
- lputl(HEADR); /* va */
- lputl(segtext.filelen); /* text size */
- lputl(HEADR); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x20); /* flags text only */
- /*
- * data section header
- */
- s8put(".data");
- lputl(segdata.vaddr); /* pa */
- lputl(segdata.vaddr); /* va */
- lputl(segdata.filelen); /* data size */
- lputl(HEADR+segtext.filelen); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x40); /* flags data only */
- /*
- * bss section header
- */
- s8put(".bss");
- lputl(segdata.vaddr+segdata.filelen); /* pa */
- lputl(segdata.vaddr+segdata.filelen); /* va */
- lputl(segdata.len - segdata.filelen); /* bss size */
- lputl(0); /* file offset */
- lputl(0); /* relocation */
- lputl(0); /* line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x80); /* flags bss only */
- /*
- * comment section header
- */
- s8put(".comment");
- lputl(0); /* pa */
- lputl(0); /* va */
- lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
- lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
- lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
- lputl(0); /* relocation, line numbers */
- lputl(0x200); /* flags comment only */
- break;
- case Hplan9x32: /* plan9 */
+ case Hplan9: /* plan9 */
magic = 4*11*11+7;
lputb(magic); /* magic */
lputb(segtext.filelen); /* sizes */
@@ -815,31 +692,6 @@ asmb(void)
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
- case Hmsdoscom:
- /* MS-DOS .COM */
- break;
- case Hmsdosexe:
- /* fake MS-DOS .EXE */
- v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
- wputl(0x5A4D); /* 'MZ' */
- wputl(v % 512); /* bytes in last page */
- wputl(rnd(v, 512)/512); /* total number of pages */
- wputl(0x0000); /* number of reloc items */
- v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
- wputl(v/16); /* size of header */
- wputl(0x0000); /* minimum allocation */
- wputl(0xFFFF); /* maximum allocation */
- wputl(0x0000); /* initial ss value */
- wputl(0x0100); /* initial sp value */
- wputl(0x0000); /* complemented checksum */
- v = entryvalue();
- wputl(v); /* initial ip value (!) */
- wputl(0x0000); /* initial cs value */
- wputl(0x0000);
- wputl(0x0000);
- wputl(0x003E); /* reloc table offset */
- wputl(0x0000); /* overlay number */
- break;
case Hdarwin:
asmbmacho();
break;
@@ -848,6 +700,7 @@ asmb(void)
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
+ case Hnacl:
asmbelf(symo);
break;
case Hwindows:
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 814aa1458..c9695ade0 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
+#include <link.h>
#include "8.out.h"
#ifndef EXTERN
@@ -42,141 +43,14 @@ enum
thechar = '8',
PtrSize = 4,
IntSize = 4,
+ RegSize = 4,
MaxAlign = 32, // max data alignment
FuncAlign = 16
};
#define P ((Prog*)0)
-#define S ((Sym*)0)
-#define TNAME (cursym?cursym->name:noname)
-
-typedef struct Adr Adr;
-typedef struct Prog Prog;
-typedef struct Sym Sym;
-typedef struct Auto Auto;
-typedef struct Optab Optab;
-typedef struct Reloc Reloc;
-
-struct Adr
-{
- union
- {
- int32 u0offset;
- char u0scon[8];
- Prog *u0cond; /* not used, but should be D_BRANCH */
- Ieee u0ieee;
- char *u0sbig;
- } u0;
- Sym* sym;
- short type;
- uchar index;
- char scale;
- int32 offset2;
-};
-
-#define offset u0.u0offset
-#define scon u0.u0scon
-#define cond u0.u0cond
-#define ieee u0.u0ieee
-#define sbig u0.u0sbig
-
-struct Reloc
-{
- int32 off;
- uchar siz;
- uchar done;
- int32 type;
- int32 add;
- int32 xadd;
- Sym* sym;
- Sym* xsym;
-};
-
-struct Prog
-{
- Adr from;
- Adr to;
- Prog* forwd;
- Prog* comefrom;
- Prog* link;
- Prog* pcond; /* work on this */
- int32 pc;
- int32 spadj;
- int32 line;
- short as;
- char width; /* fake for DATA */
- char ft; /* oclass cache */
- char tt;
- uchar mark; /* work on these */
- uchar back;
- uchar bigjmp;
-};
-#define datasize from.scale
-#define textflag from.scale
-#define iscall(p) ((p)->as == ACALL)
-
-struct Auto
-{
- Sym* asym;
- Auto* link;
- int32 aoffset;
- short type;
- Sym* gotype;
-};
-struct Sym
-{
- char* name;
- char* extname; // name used in external object files
- short type;
- short version;
- uchar dupok;
- uchar reachable;
- uchar cgoexport;
- uchar special;
- uchar stkcheck;
- uchar hide;
- int32 value;
- int32 size;
- int32 sig;
- int32 dynid;
- int32 plt;
- int32 got;
- int32 align; // if non-zero, required alignment in bytes
- int32 elfsym;
- int32 args; // size of stack frame incoming arguments area
- Sym* hash; // in hash table
- Sym* allsym; // in all symbol list
- Sym* next; // in text or data list
- Sym* sub; // in sub list
- Sym* outer; // container of sub
- Sym* gotype;
- Sym* reachparent;
- Sym* queue;
- char* file;
- char* dynimplib;
- char* dynimpvers;
- struct Section* sect;
- struct Hist* hist; // for ATEXT
-
- // STEXT
- Auto* autom;
- Prog* text;
-
- // SDATA, SBSS
- uchar* p;
- int32 np;
- int32 maxp;
- Reloc* r;
- int32 nr;
- int32 maxr;
-};
-struct Optab
-{
- short as;
- uchar* ytab;
- uchar prefix;
- uchar op[13];
-};
+#define S ((LSym*)0)
+#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
@@ -185,202 +59,36 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
-
- Yxxx = 0,
- Ynone,
- Yi0,
- Yi1,
- Yi8,
- Yi32,
- Yiauto,
- Yal,
- Ycl,
- Yax,
- Ycx,
- Yrb,
- Yrl,
- Yrf,
- Yf0,
- Yrx,
- Ymb,
- Yml,
- Ym,
- Ybr,
- Ycol,
-
- Ycs, Yss, Yds, Yes, Yfs, Ygs,
- Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
- Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
- Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
- Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
- Ymr, Ymm,
- Yxr, Yxm,
- Ymax,
-
- Zxxx = 0,
-
- Zlit,
- Zlitm_r,
- Z_rp,
- Zbr,
- Zcall,
- Zcallcon,
- Zcallind,
- Zib_,
- Zib_rp,
- Zibo_m,
- Zil_,
- Zil_rp,
- Zilo_m,
- Zjmp,
- Zjmpcon,
- Zloop,
- Zm_o,
- Zm_r,
- Zm2_r,
- Zm_r_xm,
- Zm_r_i_xm,
- Zaut_r,
- Zo_m,
- Zpseudo,
- Zr_m,
- Zr_m_xm,
- Zr_m_i_xm,
- Zrp_,
- Z_ib,
- Z_il,
- Zm_ibo,
- Zm_ilo,
- Zib_rr,
- Zil_rr,
- Zclr,
- Zibm_r, /* mmx1,mmx2/mem64,imm8 */
- Zbyte,
- Zmov,
- Zmax,
-
- Px = 0,
- Pe = 0x66, /* operand escape */
- Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escape */
- Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1 */
- Pf3 = 0xf3, /* xmm escape 2 */
};
-#pragma varargck type "A" int
-#pragma varargck type "D" Adr*
#pragma varargck type "I" uchar*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "S" char*
-#pragma varargck type "Y" Sym*
-#pragma varargck type "Z" char*
-#pragma varargck type "i" char*
-EXTERN int32 HEADR;
-EXTERN int32 HEADTYPE;
-EXTERN int32 INITRND;
-EXTERN int32 INITTEXT;
-EXTERN int32 INITDAT;
-EXTERN char* INITENTRY; /* entry point */
-EXTERN char* pcstr;
-EXTERN Auto* curauto;
-EXTERN Auto* curhist;
-EXTERN Prog* curp;
-EXTERN Sym* cursym;
-EXTERN Sym* datap;
+EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
-EXTERN Sym* etextp;
EXTERN Prog* firstp;
-EXTERN uchar ycover[Ymax*Ymax];
-EXTERN uchar* andptr;
-EXTERN uchar and[100];
-EXTERN char reg[D_NONE];
EXTERN int32 lcsize;
-EXTERN int maxop;
-EXTERN int nerrors;
-EXTERN char* noname;
-EXTERN int32 pc;
EXTERN char* rpath;
EXTERN int32 spsize;
-EXTERN Sym* symlist;
+EXTERN LSym* symlist;
EXTERN int32 symsize;
-EXTERN Sym* textp;
EXTERN int32 textsize;
-EXTERN Prog zprg;
-EXTERN int dtype;
-EXTERN int tlsoffset;
-EXTERN Sym* adrgotype; // type symbol on last Adr read
-EXTERN Sym* fromgotype; // type symbol on last p->from read
-extern Optab optab[];
-extern char* anames[];
-
-int Aconv(Fmt*);
-int Dconv(Fmt*);
-int Iconv(Fmt*);
-int Pconv(Fmt*);
-int Rconv(Fmt*);
-int Sconv(Fmt*);
-void addhist(int32, int);
-Prog* appendp(Prog*);
+int Iconv(Fmt *fp);
+void adddynlib(char *lib);
+void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rela, LSym *s, Reloc *r);
+void adddynsym(Link *ctxt, LSym *s);
+int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
-void asmdyn(void);
-void asmins(Prog*);
-void asmsym(void);
-int32 atolwhex(char*);
-Prog* brchain(Prog*);
-Prog* brloop(Prog*);
-void cflush(void);
-Prog* copyp(Prog*);
-vlong cpos(void);
-double cputime(void);
-void diag(char*, ...);
-void dodata(void);
-void doelf(void);
-void doprof1(void);
-void doprof2(void);
-void dostkoff(void);
-int32 entryvalue(void);
-void follow(void);
-void instinit(void);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
void listinit(void);
-Sym* lookup(char*, int);
-void lputb(int32);
-void lputl(int32);
-void vputl(uint64);
-void strnput(char*, int);
-void main(int, char*[]);
-void* mal(uint32);
-int opsize(Prog*);
-void patch(void);
-Prog* prg(void);
-int relinv(int);
-int32 rnd(int32, int32);
-void s8put(char*);
-void span(void);
-void undef(void);
-int32 symaddr(Sym*);
-void wput(ushort);
-void wputl(ushort);
-void xdefine(char*, int, int32);
-
-uint32 machheadr(void);
-vlong addaddr(Sym *s, Sym *t);
-vlong addsize(Sym *s, Sym *t);
-vlong addstring(Sym *s, char *str);
-vlong adduint16(Sym *s, uint16 v);
-vlong adduint32(Sym *s, uint32 v);
-vlong adduint64(Sym *s, uint64 v);
-vlong adduint8(Sym *s, uint8 v);
-vlong adduintxx(Sym *s, uint64 v, int wid);
-
-/*
- * go.c
- */
-void deadcode(void);
+int machoreloc1(Reloc *r, vlong sectoff);
+void main(int argc, char *argv[]);
+int32 rnd(int32 v, int32 r);
+void s8put(char *n);
+char* xsymname(LSym *s);
/* Native is little-endian */
#define LPUT(a) lputl(a)
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index e2a2ec5ed..0a7534060 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -36,297 +36,10 @@
void
listinit(void)
{
-
- fmtinstall('R', Rconv);
- fmtinstall('A', Aconv);
- fmtinstall('D', Dconv);
- fmtinstall('S', Sconv);
- fmtinstall('P', Pconv);
+ listinit8();
fmtinstall('I', Iconv);
}
-static Prog *bigP;
-
-int
-Pconv(Fmt *fp)
-{
- Prog *p;
-
- p = va_arg(fp->args, Prog*);
- bigP = p;
- switch(p->as) {
- case ATEXT:
- if(p->from.scale) {
- fmtprint(fp, "(%d) %A %D,%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- default:
- fmtprint(fp, "(%d) %A %D,%D",
- p->line, p->as, &p->from, &p->to);
- break;
- case ADATA:
- case AINIT_:
- case ADYNT_:
- fmtprint(fp, "(%d) %A %D/%d,%D",
- p->line, p->as, &p->from, p->from.scale, &p->to);
- break;
- }
- bigP = P;
- return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
-}
-
-char*
-xsymname(Sym *s)
-{
- if(s == nil)
- return "!!noname!!";
- return s->name;
-}
-
-int
-Dconv(Fmt *fp)
-{
- char str[STRINGSZ], s[STRINGSZ];
- Adr *a;
- int i;
-
- a = va_arg(fp->args, Adr*);
- i = a->type;
- if(i >= D_INDIR && i < 2*D_INDIR) {
- if(a->offset)
- snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
- else
- snprint(str, sizeof str, "(%R)", i-D_INDIR);
- goto brk;
- }
- switch(i) {
-
- default:
- snprint(str, sizeof str, "%R", i);
- break;
-
- case D_NONE:
- str[0] = 0;
- break;
-
- case D_BRANCH:
- if(bigP != P && bigP->pcond != P)
- if(a->sym != S)
- snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
- a->sym->name);
- else
- snprint(str, sizeof str, "%ux", bigP->pcond->pc);
- else
- snprint(str, sizeof str, "%d(PC)", a->offset);
- break;
-
- case D_EXTERN:
- snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
- break;
-
- case D_STATIC:
- snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
- a->sym->version, a->offset);
- break;
-
- case D_AUTO:
- snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
- break;
-
- case D_PARAM:
- if(a->sym)
- snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
- else
- snprint(str, sizeof str, "%d(FP)", a->offset);
- break;
-
- case D_CONST:
- snprint(str, sizeof str, "$%d", a->offset);
- break;
-
- case D_CONST2:
- snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
- break;
-
- case D_FCONST:
- snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
- break;
-
- case D_SCONST:
- snprint(str, sizeof str, "$\"%S\"", a->scon);
- break;
-
- case D_ADDR:
- a->type = a->index;
- a->index = D_NONE;
- snprint(str, sizeof str, "$%D", a);
- a->index = a->type;
- a->type = D_ADDR;
- goto conv;
- }
-brk:
- if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", (int)a->index, a->scale);
- strcat(str, s);
- }
-conv:
- fmtstrcpy(fp, str);
-// if(a->gotype)
-// fmtprint(fp, "«%s»", a->gotype->name);
- return 0;
-}
-
-char* regstr[] =
-{
- "AL", /* [D_AL] */
- "CL",
- "DL",
- "BL",
- "AH",
- "CH",
- "DH",
- "BH",
-
- "AX", /* [D_AX] */
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
-
- "F0", /* [D_F0] */
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
-
- "CS", /* [D_CS] */
- "SS",
- "DS",
- "ES",
- "FS",
- "GS",
-
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
-
- "CR0", /* [D_CR] */
- "CR1",
- "CR2",
- "CR3",
- "CR4",
- "CR5",
- "CR6",
- "CR7",
-
- "DR0", /* [D_DR] */
- "DR1",
- "DR2",
- "DR3",
- "DR4",
- "DR5",
- "DR6",
- "DR7",
-
- "TR0", /* [D_TR] */
- "TR1",
- "TR2",
- "TR3",
- "TR4",
- "TR5",
- "TR6",
- "TR7",
-
- "X0",
- "X1",
- "X2",
- "X3",
- "X4",
- "X5",
- "X6",
- "X7",
-
- "NONE", /* [D_NONE] */
-};
-
-int
-Rconv(Fmt *fp)
-{
- char str[STRINGSZ];
- int r;
-
- r = va_arg(fp->args, int);
- if(r >= D_AL && r <= D_NONE)
- sprint(str, "%s", regstr[r-D_AL]);
- else
- sprint(str, "gok(%d)", r);
-
- return fmtstrcpy(fp, str);
-}
-
-int
-Sconv(Fmt *fp)
-{
- int i, c;
- char str[STRINGSZ], *p, *a;
-
- a = va_arg(fp->args, char*);
- p = str;
- for(i=0; i<sizeof(double); i++) {
- c = a[i] & 0xff;
- if(c >= 'a' && c <= 'z' ||
- c >= 'A' && c <= 'Z' ||
- c >= '0' && c <= '9') {
- *p++ = c;
- continue;
- }
- *p++ = '\\';
- switch(c) {
- default:
- if(c < 040 || c >= 0177)
- break; /* not portable */
- p[-1] = c;
- continue;
- case 0:
- *p++ = 'z';
- continue;
- case '\\':
- case '"':
- *p++ = c;
- continue;
- case '\n':
- *p++ = 'n';
- continue;
- case '\t':
- *p++ = 't';
- continue;
- }
- *p++ = (c>>6) + '0';
- *p++ = ((c>>3) & 7) + '0';
- *p++ = (c & 7) + '0';
- }
- *p = 0;
- return fmtstrcpy(fp, str);
-}
-
int
Iconv(Fmt *fp)
{
@@ -352,27 +65,3 @@ Iconv(Fmt *fp)
free(s);
return 0;
}
-
-void
-diag(char *fmt, ...)
-{
- char buf[1024], *tn, *sep;
- va_list arg;
-
- tn = "";
- sep = "";
- if(cursym != S) {
- tn = cursym->name;
- sep = ": ";
- }
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- print("%s%s%s\n", tn, sep, buf);
-
- nerrors++;
- if(nerrors > 20) {
- print("too many errors\n");
- errorexit();
- }
-}
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 3fdc41381..1b65c5eb9 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -30,7 +30,6 @@
// Reading object files.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -39,110 +38,17 @@
#include "../ld/pe.h"
#include <ar.h>
-#ifndef DEFAULT
-#define DEFAULT '9'
-#endif
-
-char *noname = "<none>";
-char *thestring = "386";
-
-Header headers[] = {
- "garbunix", Hgarbunix,
- "unixcoff", Hunixcoff,
- "plan9", Hplan9x32,
- "msdoscom", Hmsdoscom,
- "msdosexe", Hmsdosexe,
- "darwin", Hdarwin,
- "dragonfly", Hdragonfly,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "netbsd", Hnetbsd,
- "openbsd", Hopenbsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
-};
-
-/*
- * -Hgarbunix -T0x40004C -D0x10000000 is garbage unix
- * -Hunixcoff -T0xd0 -R4 is unix coff
- * -Hplan9 -T4128 -R4096 is plan9 format
- * -Hmsdoscom -Tx -Rx is MS-DOS .COM
- * -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
- * -Hdarwin -Tx -Rx is Apple Mach-O
- * -Hdragonfly -Tx -Rx is DragonFly ELF32
- * -Hlinux -Tx -Rx is Linux ELF32
- * -Hfreebsd -Tx -Rx is FreeBSD ELF32
- * -Hnetbsd -Tx -Rx is NetBSD ELF32
- * -Hopenbsd -Tx -Rx is OpenBSD ELF32
- * -Hwindows -Tx -Rx is MS Windows PE32
- */
+char* thestring = "386";
+LinkArch* thelinkarch = &link386;
void
-main(int argc, char *argv[])
+linkarchinit(void)
{
- Binit(&bso, 1, OWRITE);
- listinit();
- memset(debug, 0, sizeof(debug));
- nerrors = 0;
- outfile = nil;
- HEADTYPE = -1;
- INITTEXT = -1;
- INITDAT = -1;
- INITRND = -1;
- INITENTRY = 0;
- linkmode = LinkAuto;
- nuxiinit();
-
- flagcount("1", "use alternate profiling code", &debug['1']);
- flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
- flagstr("E", "sym: entry symbol", &INITENTRY);
- flagint32("D", "addr: data address", &INITDAT);
- flagfn1("I", "interp: set ELF interp", setinterp);
- flagfn1("L", "dir: add dir to library path", Lflag);
- flagfn1("H", "head: header type", setheadtype);
- flagcount("K", "add stack underflow checks", &debug['K']);
- flagcount("O", "print pc-line tables", &debug['O']);
- flagcount("Q", "debug byte-register code gen", &debug['Q']);
- flagint32("R", "rnd: address rounding", &INITRND);
- flagcount("S", "check type signatures", &debug['S']);
- flagint32("T", "addr: text address", &INITTEXT);
- flagfn0("V", "print version and exit", doversion);
- flagcount("W", "disassemble input", &debug['W']);
- flagfn2("X", "name value: define string data", addstrdata);
- flagcount("Z", "clear stack frame on entry", &debug['Z']);
- flagcount("a", "disassemble output", &debug['a']);
- flagcount("c", "dump call graph", &debug['c']);
- flagcount("d", "disable dynamic executable", &debug['d']);
- flagstr("extld", "linker to run in external mode", &extld);
- flagstr("extldflags", "flags for external linker", &extldflags);
- flagcount("f", "ignore version mismatch", &debug['f']);
- flagcount("g", "disable go package data checks", &debug['g']);
- flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
- flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
- flagstr("k", "sym: set field tracking symbol", &tracksym);
- flagstr("o", "outfile: set output file", &outfile);
- flagcount("p", "insert profiling code", &debug['p']);
- flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
- flagcount("race", "enable race detector", &flag_race);
- flagcount("s", "disable symbol table", &debug['s']);
- flagcount("n", "dump symbol table", &debug['n']);
- flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
- flagcount("u", "reject unsafe packages", &debug['u']);
- flagcount("v", "print link trace", &debug['v']);
- flagcount("w", "disable DWARF generation", &debug['w']);
- // TODO: link mode flag
-
- flagparse(&argc, &argv, usage);
-
- if(argc != 1)
- usage();
-
- mywhatsys(); // get goos
-
- if(HEADTYPE == -1)
- HEADTYPE = headtype(goos);
+}
+void
+archinit(void)
+{
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@@ -164,40 +70,12 @@ main(int argc, char *argv[])
break;
}
- if(outfile == nil) {
- if(HEADTYPE == Hwindows)
- outfile = "8.out.exe";
- else
- outfile = "8.out";
- }
-
- libinit();
-
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
- case Hgarbunix: /* this is garbage */
- HEADR = 20L+56L;
- if(INITTEXT == -1)
- INITTEXT = 0x40004CL;
- if(INITDAT == -1)
- INITDAT = 0x10000000L;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hunixcoff: /* is unix coff */
- HEADR = 0xd0L;
- if(INITTEXT == -1)
- INITTEXT = 0xd0;
- if(INITDAT == -1)
- INITDAT = 0x400000;
- if(INITRND == -1)
- INITRND = 0;
- break;
- case Hplan9x32: /* plan 9 */
- tlsoffset = -8;
+ case Hplan9: /* plan 9 */
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+32;
@@ -206,33 +84,7 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case Hmsdoscom: /* MS-DOS .COM */
- HEADR = 0;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- break;
- case Hmsdosexe: /* fake MS-DOS .EXE */
- HEADR = 0x200;
- if(INITTEXT == -1)
- INITTEXT = 0x0100;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4;
- HEADR += (INITTEXT & 0xFFFF);
- if(debug['v'])
- Bprint(&bso, "HEADR = 0x%d\n", HEADR);
- break;
case Hdarwin: /* apple MACH */
- /*
- * OS X system constant - offset from %gs to our TLS.
- * Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c.
- */
- tlsoffset = 0x468;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITTEXT == -1)
@@ -247,13 +99,6 @@ main(int argc, char *argv[])
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
- /*
- * ELF uses TLS offsets negative from %gs.
- * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
- * Also known to ../../pkg/runtime/sys_linux_386.s
- * and ../../pkg/runtime/cgo/gcc_linux_386.c.
- */
- tlsoffset = -8;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -263,6 +108,19 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
+
+ case Hnacl:
+ elfinit();
+ HEADR = 0x10000;
+ funcalign = 32;
+ if(INITTEXT == -1)
+ INITTEXT = 0x20000;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0x10000;
+ break;
+
case Hwindows: /* PE executable */
peinit();
HEADR = PEFILEHEADR;
@@ -275,518 +133,6 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%ux is ignored because of -R0x%ux\n",
+ print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
- if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
- HEADTYPE, INITTEXT, INITDAT, INITRND);
- Bflush(&bso);
-
- instinit();
- zprg.link = P;
- zprg.pcond = P;
- zprg.back = 2;
- zprg.as = AGOK;
- zprg.from.type = D_NONE;
- zprg.from.index = D_NONE;
- zprg.from.scale = 1;
- zprg.to = zprg.from;
-
- pcstr = "%.6ux ";
- histgen = 0;
- pc = 0;
- dtype = 4;
- version = 0;
- cbp = buf.cbuf;
- cbc = sizeof(buf.cbuf);
-
- addlibpath("command line", "command line", argv[0], "main");
- loadlib();
- deadcode();
- patch();
- follow();
- doelf();
- if(HEADTYPE == Hdarwin)
- domacho();
- if(HEADTYPE == Hwindows)
- dope();
- dostkoff();
- dostkcheck();
- if(debug['p'])
- if(debug['1'])
- doprof1();
- else
- doprof2();
- span();
- addexport();
- textaddress();
- pclntab();
- symtab();
- dodata();
- address();
- doweak();
- reloc();
- asmb();
- undef();
- hostlink();
-
- if(debug['v']) {
- Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%d symbols\n", nsymbol);
- Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
- Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
- }
- Bflush(&bso);
-
- errorexit();
-}
-
-static Sym*
-zsym(char *pn, Biobuf *f, Sym *h[])
-{
- int o;
-
- o = BGETC(f);
- if(o < 0 || o >= NSYM || h[o] == nil)
- mangle(pn);
- return h[o];
-}
-
-static void
-zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
-{
- int t;
- int32 l;
- Sym *s;
- Auto *u;
-
- t = BGETC(f);
- a->index = D_NONE;
- a->scale = 0;
- if(t & T_INDEX) {
- a->index = BGETC(f);
- a->scale = BGETC(f);
- }
- a->type = D_NONE;
- a->offset = 0;
- if(t & T_OFFSET)
- a->offset = BGETLE4(f);
- a->offset2 = 0;
- if(t & T_OFFSET2) {
- a->offset2 = BGETLE4(f);
- a->type = D_CONST2;
- }
- a->sym = S;
- if(t & T_SYM)
- a->sym = zsym(pn, f, h);
- if(t & T_FCONST) {
- a->ieee.l = BGETLE4(f);
- a->ieee.h = BGETLE4(f);
- a->type = D_FCONST;
- } else
- if(t & T_SCONST) {
- Bread(f, a->scon, NSNAME);
- a->type = D_SCONST;
- }
- if(t & T_TYPE)
- a->type = BGETC(f);
- adrgotype = S;
- if(t & T_GOTYPE)
- adrgotype = zsym(pn, f, h);
-
- t = a->type;
- if(t == D_INDIR+D_GS)
- a->offset += tlsoffset;
-
- s = a->sym;
- if(s == S)
- return;
- if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
- s->gotype = adrgotype;
- return;
- }
- l = a->offset;
- for(u=curauto; u; u=u->link) {
- if(u->asym == s)
- if(u->type == t) {
- if(u->aoffset > l)
- u->aoffset = l;
- if(adrgotype)
- u->gotype = adrgotype;
- return;
- }
- }
-
- u = mal(sizeof(*u));
- u->link = curauto;
- curauto = u;
- u->asym = s;
- u->aoffset = l;
- u->type = t;
- u->gotype = adrgotype;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = D_NONE;
- p->to.type = D_NONE;
-}
-
-void
-ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
-{
- int32 ipc;
- Prog *p;
- int v, o, r, skip;
- Sym *h[NSYM], *s;
- uint32 sig;
- int ntext;
- int32 eof;
- char *name, *x;
- char src[1024];
- Prog *lastp;
-
- lastp = nil;
- ntext = 0;
- eof = Boffset(f) + len;
- src[0] = 0;
- pn = estrdup(pn); // we keep it in Sym* references
-
-newloop:
- memset(h, 0, sizeof(h));
- version++;
- histfrogp = 0;
- ipc = pc;
- skip = 0;
-
-loop:
- if(f->state == Bracteof || Boffset(f) >= eof)
- goto eof;
- o = BGETC(f);
- if(o == Beof)
- goto eof;
- o |= BGETC(f) << 8;
- if(o <= AXXX || o >= ALAST) {
- if(o < 0)
- goto eof;
- diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
- print(" probably not a .%c file\n", thechar);
- errorexit();
- }
-
- if(o == ANAME || o == ASIGNAME) {
- sig = 0;
- if(o == ASIGNAME)
- sig = BGETLE4(f);
- v = BGETC(f); /* type */
- o = BGETC(f); /* sym */
- r = 0;
- if(v == D_STATIC)
- r = version;
- name = Brdline(f, '\0');
- if(name == nil) {
- if(Blinelen(f) > 0) {
- fprint(2, "%s: name too long\n", pn);
- errorexit();
- }
- goto eof;
- }
- x = expandpkg(name, pkg);
- s = lookup(x, r);
- if(x != name)
- free(x);
-
- if(debug['S'] && r == 0)
- sig = 1729;
- if(sig != 0){
- if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures "
- "%ux(%s) and %ux(%s) for %s",
- s->sig, s->file, sig, pn, s->name);
- s->sig = sig;
- s->file = pn;
- }
-
- if(debug['W'])
- print(" ANAME %s\n", s->name);
- if(o < 0 || o >= nelem(h))
- mangle(pn);
- h[o] = s;
- if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
- s->type = SXREF;
- if(v == D_FILE) {
- if(s->type != SFILE) {
- histgen++;
- s->type = SFILE;
- s->value = histgen;
- }
- if(histfrogp < MAXHIST) {
- histfrog[histfrogp] = s;
- histfrogp++;
- } else
- collapsefrog(s);
- dwarfaddfrag(s->value, s->name);
- }
- goto loop;
- }
-
- p = mal(sizeof(*p));
- p->as = o;
- p->line = BGETLE4(f);
- p->back = 2;
- zaddr(pn, f, &p->from, h);
- fromgotype = adrgotype;
- zaddr(pn, f, &p->to, h);
-
- if(debug['W'])
- print("%P\n", p);
-
- switch(p->as) {
- case AHISTORY:
- if(p->to.offset == -1) {
- addlib(src, pn);
- histfrogp = 0;
- goto loop;
- }
- if(src[0] == '\0')
- copyhistfrog(src, sizeof src);
- addhist(p->line, D_FILE); /* 'z' */
- if(p->to.offset)
- addhist(p->to.offset, D_FILE1); /* 'Z' */
- savehist(p->line, p->to.offset);
- histfrogp = 0;
- goto loop;
-
- case AEND:
- histtoauto();
- if(cursym != nil && cursym->text)
- cursym->autom = curauto;
- curauto = 0;
- cursym = nil;
- if(Boffset(f) == eof)
- return;
- goto newloop;
-
- case AGLOBL:
- s = p->from.sym;
- if(s->type == 0 || s->type == SXREF) {
- s->type = SBSS;
- s->size = 0;
- }
- if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
- diag("%s: redefinition: %s in %s",
- pn, s->name, TNAME);
- s->type = SBSS;
- s->size = 0;
- }
- if(p->to.offset > s->size)
- s->size = p->to.offset;
- if(p->from.scale & DUPOK)
- s->dupok = 1;
- if(p->from.scale & RODATA)
- s->type = SRODATA;
- else if(p->from.scale & NOPTR)
- s->type = SNOPTRBSS;
- goto loop;
-
- case ADATA:
- // Assume that AGLOBL comes after ADATA.
- // If we've seen an AGLOBL that said this sym was DUPOK,
- // ignore any more ADATA we see, which must be
- // redefinitions.
- s = p->from.sym;
- if(s->dupok) {
-// if(debug['v'])
-// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
- goto loop;
- }
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
- savedata(s, p, pn);
- unmal(p, sizeof *p);
- goto loop;
-
- case AGOK:
- diag("%s: GOK opcode in %s", pn, TNAME);
- pc++;
- goto loop;
-
- case ATYPE:
- if(skip)
- goto casdef;
- pc++;
- goto loop;
-
- case ATEXT:
- s = p->from.sym;
- if(s->text != nil) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: %s: redefinition", pn, s->name);
- return;
- }
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- diag("skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- if(cursym != nil && cursym->text) {
- histtoauto();
- cursym->autom = curauto;
- curauto = 0;
- }
- skip = 0;
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- s->text = p;
- cursym = s;
- if(s->type != 0 && s->type != SXREF) {
- if(p->from.scale & DUPOK) {
- skip = 1;
- goto casdef;
- }
- diag("%s: redefinition: %s\n%P", pn, s->name, p);
- }
- s->type = STEXT;
- s->hist = gethist();
- s->value = pc;
- s->args = p->to.offset2;
- lastp = p;
- p->pc = pc++;
- goto loop;
-
- case AFMOVF:
- case AFADDF:
- case AFSUBF:
- case AFSUBRF:
- case AFMULF:
- case AFDIVF:
- case AFDIVRF:
- case AFCOMF:
- case AFCOMFP:
- case AMOVSS:
- case AADDSS:
- case ASUBSS:
- case AMULSS:
- case ADIVSS:
- case ACOMISS:
- case AUCOMISS:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 9 max */
- sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, ieeedtof(&p->from.ieee));
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- case AFMOVD:
- case AFADDD:
- case AFSUBD:
- case AFSUBRD:
- case AFMULD:
- case AFDIVD:
- case AFDIVRD:
- case AFCOMD:
- case AFCOMDP:
- case AMOVSD:
- case AADDSD:
- case ASUBSD:
- case AMULSD:
- case ADIVSD:
- case ACOMISD:
- case AUCOMISD:
- if(skip)
- goto casdef;
- if(p->from.type == D_FCONST) {
- /* size sb 18 max */
- sprint(literal, "$%ux.%ux",
- p->from.ieee.l, p->from.ieee.h);
- s = lookup(literal, 0);
- if(s->type == 0) {
- s->type = SRODATA;
- adduint32(s, p->from.ieee.l);
- adduint32(s, p->from.ieee.h);
- s->reachable = 0;
- }
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->from.offset = 0;
- }
- goto casdef;
-
- casdef:
- default:
- if(skip)
- nopout(p);
- p->pc = pc;
- pc++;
-
- if(p->to.type == D_BRANCH)
- p->to.offset += ipc;
- if(lastp == nil) {
- if(p->as != ANOP)
- diag("unexpected instruction: %P", p);
- goto loop;
- }
- lastp->link = p;
- lastp = p;
- goto loop;
- }
-
-eof:
- diag("truncated object file: %s", pn);
-}
-
-Prog*
-prg(void)
-{
- Prog *p;
-
- p = mal(sizeof(Prog));
- *p = zprg;
- return p;
-}
-
-Prog*
-copyp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- *p = *q;
- return p;
-}
-
-Prog*
-appendp(Prog *q)
-{
- Prog *p;
-
- p = prg();
- p->link = q->link;
- q->link = p;
- p->line = q->line;
- return p;
}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
deleted file mode 100644
index a4c40e8e3..000000000
--- a/src/cmd/8l/optab.c
+++ /dev/null
@@ -1,1030 +0,0 @@
-// Inferno utils/8l/optab.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/optab.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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 "l.h"
-
-uchar ynone[] =
-{
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar ytext[] =
-{
- Ymb, Yi32, Zpseudo,1,
- 0
-};
-uchar ynop[] =
-{
- Ynone, Ynone, Zpseudo,1,
- Ynone, Yml, Zpseudo,1,
- Ynone, Yrf, Zpseudo,1,
- Yml, Ynone, Zpseudo,1,
- Yrf, Ynone, Zpseudo,1,
- 0
-};
-uchar yfuncdata[] =
-{
- Yi32, Ym, Zpseudo, 0,
- 0
-};
-uchar ypcdata[] =
-{
- Yi32, Yi32, Zpseudo, 0,
- 0,
-};
-uchar yxorb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxorl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yaddl[] =
-{
- Yi8, Yml, Zibo_m, 2,
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yincb[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yincl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Yml, Zo_m, 2,
- 0
-};
-uchar ycmpb[] =
-{
- Yal, Yi32, Z_ib, 1,
- Ymb, Yi32, Zm_ibo, 2,
- Ymb, Yrb, Zm_r, 1,
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar ycmpl[] =
-{
- Yml, Yi8, Zm_ibo, 2,
- Yax, Yi32, Z_il, 1,
- Yml, Yi32, Zm_ilo, 2,
- Yml, Yrl, Zm_r, 1,
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yshb[] =
-{
- Yi1, Ymb, Zo_m, 2,
- Yi32, Ymb, Zibo_m, 2,
- Ycx, Ymb, Zo_m, 2,
- 0
-};
-uchar yshl[] =
-{
- Yi1, Yml, Zo_m, 2,
- Yi32, Yml, Zibo_m, 2,
- Ycl, Yml, Zo_m, 2,
- Ycx, Yml, Zo_m, 2,
- 0
-};
-uchar ytestb[] =
-{
- Yi32, Yal, Zib_, 1,
- Yi32, Ymb, Zibo_m, 2,
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar ytestl[] =
-{
- Yi32, Yax, Zil_, 1,
- Yi32, Yml, Zilo_m, 2,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ymovb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- Yi32, Yrb, Zib_rp, 1,
- Yi32, Ymb, Zibo_m, 2,
- 0
-};
-uchar ymovw[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1+2,
-// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yiauto, Yrl, Zaut_r, 1,
- 0
-};
-uchar ymovl[] =
-{
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- Yi0, Yrl, Zclr, 1+2,
-// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
- Yi32, Yrl, Zil_rp, 1,
- Yi32, Yml, Zilo_m, 2,
- Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
- Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
- Yiauto, Yrl, Zaut_r, 1,
- 0
-};
-uchar ymovq[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar ym_rl[] =
-{
- Ym, Yrl, Zm_r, 1,
- 0
-};
-uchar yrl_m[] =
-{
- Yrl, Ym, Zr_m, 1,
- 0
-};
-uchar ymb_rl[] =
-{
- Ymb, Yrl, Zm_r, 1,
- 0
-};
-uchar yml_rl[] =
-{
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar yrb_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- 0
-};
-uchar yrl_ml[] =
-{
- Yrl, Yml, Zr_m, 1,
- 0
-};
-uchar yml_mb[] =
-{
- Yrb, Ymb, Zr_m, 1,
- Ymb, Yrb, Zm_r, 1,
- 0
-};
-uchar yxchg[] =
-{
- Yax, Yrl, Z_rp, 1,
- Yrl, Yax, Zrp_, 1,
- Yrl, Yml, Zr_m, 1,
- Yml, Yrl, Zm_r, 1,
- 0
-};
-uchar ydivl[] =
-{
- Yml, Ynone, Zm_o, 2,
- 0
-};
-uchar ydivb[] =
-{
- Ymb, Ynone, Zm_o, 2,
- 0
-};
-uchar yimul[] =
-{
- Yml, Ynone, Zm_o, 2,
- Yi8, Yrl, Zib_rr, 1,
- Yi32, Yrl, Zil_rr, 1,
- 0
-};
-uchar ybyte[] =
-{
- Yi32, Ynone, Zbyte, 1,
- 0
-};
-uchar yin[] =
-{
- Yi32, Ynone, Zib_, 1,
- Ynone, Ynone, Zlit, 1,
- 0
-};
-uchar yint[] =
-{
- Yi32, Ynone, Zib_, 1,
- 0
-};
-uchar ypushl[] =
-{
- Yrl, Ynone, Zrp_, 1,
- Ym, Ynone, Zm_o, 2,
- Yi8, Ynone, Zib_, 1,
- Yi32, Ynone, Zil_, 1,
- 0
-};
-uchar ypopl[] =
-{
- Ynone, Yrl, Z_rp, 1,
- Ynone, Ym, Zo_m, 2,
- 0
-};
-uchar ybswap[] =
-{
- Ynone, Yrl, Z_rp, 1,
- 0,
-};
-uchar yscond[] =
-{
- Ynone, Ymb, Zo_m, 2,
- 0
-};
-uchar yjcond[] =
-{
- Ynone, Ybr, Zbr, 0,
- Yi0, Ybr, Zbr, 0,
- Yi1, Ybr, Zbr, 1,
- 0
-};
-uchar yloop[] =
-{
- Ynone, Ybr, Zloop, 1,
- 0
-};
-uchar ycall[] =
-{
- Ynone, Yml, Zo_m, 0,
- Yrx, Yrx, Zo_m, 2,
- Ynone, Ycol, Zcallind, 2,
- Ynone, Ybr, Zcall, 0,
- Ynone, Yi32, Zcallcon, 1,
- 0
-};
-uchar yjmp[] =
-{
- Ynone, Yml, Zo_m, 2,
- Ynone, Ybr, Zjmp, 0,
- Ynone, Yi32, Zjmpcon, 1,
- 0
-};
-
-uchar yfmvd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvdp[] =
-{
- Yf0, Ym, Zo_m, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfmvf[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfmvx[] =
-{
- Ym, Yf0, Zm_o, 2,
- 0
-};
-uchar yfmvp[] =
-{
- Yf0, Ym, Zo_m, 2,
- 0
-};
-uchar yfcmv[] =
-{
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar yfadd[] =
-{
- Ym, Yf0, Zm_o, 2,
- Yrf, Yf0, Zm_o, 2,
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfaddp[] =
-{
- Yf0, Yrf, Zo_m, 2,
- 0
-};
-uchar yfxch[] =
-{
- Yf0, Yrf, Zo_m, 2,
- Yrf, Yf0, Zm_o, 2,
- 0
-};
-uchar ycompp[] =
-{
- Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
- 0
-};
-uchar ystsw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ynone, Yax, Zlit, 1,
- 0
-};
-uchar ystcw[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ysvrs[] =
-{
- Ynone, Ym, Zo_m, 2,
- Ym, Ynone, Zm_o, 2,
- 0
-};
-uchar ymskb[] =
-{
- Yxr, Yrl, Zm_r_xm, 2,
- Ymr, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxm[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvm1[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Yxm, Ymr, Zm_r_xm, 2,
- 0
-};
-uchar yxcvm2[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- Ymm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxmq[] =
-{
- Yxm, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxr[] =
-{
- Yxr, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxr_ml[] =
-{
- Yxr, Yml, Zr_m_xm, 1,
- 0
-};
-uchar yxcmp[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcmpi[] =
-{
- Yxm, Yxr, Zm_r_i_xm, 2,
- 0
-};
-uchar yxmov[] =
-{
- Yxm, Yxr, Zm_r_xm, 1,
- Yxr, Yxm, Zr_m_xm, 1,
- 0
-};
-uchar yxcvfl[] =
-{
- Yxm, Yrl, Zm_r_xm, 1,
- 0
-};
-uchar yxcvlf[] =
-{
- Yml, Yxr, Zm_r_xm, 1,
- 0
-};
-uchar yxcvfq[] =
-{
- Yxm, Yrl, Zm_r_xm, 2,
- 0
-};
-uchar yxcvqf[] =
-{
- Yml, Yxr, Zm_r_xm, 2,
- 0
-};
-uchar yxrrl[] =
-{
- Yxr, Yrl, Zm_r, 1,
- 0
-};
-uchar yprefetch[] =
-{
- Ym, Ynone, Zm_o, 2,
- 0,
-};
-uchar yaes[] =
-{
- Yxm, Yxr, Zlitm_r, 2,
- 0
-};
-uchar yinsrd[] =
-{
- Yml, Yxr, Zibm_r, 2,
- 0
-};
-uchar ymshufb[] =
-{
- Yxm, Yxr, Zm2_r, 2,
- 0
-};
-
-Optab optab[] =
-/* as, ytab, andproto, opcode */
-{
- { AXXX },
- { AAAA, ynone, Px, 0x37 },
- { AAAD, ynone, Px, 0xd5,0x0a },
- { AAAM, ynone, Px, 0xd4,0x0a },
- { AAAS, ynone, Px, 0x3f },
- { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
- { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
- { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
- { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- { AADJSP },
- { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
- { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
- { AARPL, yrl_ml, Px, 0x63 },
- { ABOUNDL, yrl_m, Px, 0x62 },
- { ABOUNDW, yrl_m, Pe, 0x62 },
- { ABSFL, yml_rl, Pm, 0xbc },
- { ABSFW, yml_rl, Pq, 0xbc },
- { ABSRL, yml_rl, Pm, 0xbd },
- { ABSRW, yml_rl, Pq, 0xbd },
- { ABTL, yml_rl, Pm, 0xa3 },
- { ABTW, yml_rl, Pq, 0xa3 },
- { ABTCL, yml_rl, Pm, 0xbb },
- { ABTCW, yml_rl, Pq, 0xbb },
- { ABTRL, yml_rl, Pm, 0xb3 },
- { ABTRW, yml_rl, Pq, 0xb3 },
- { ABTSL, yml_rl, Pm, 0xab },
- { ABTSW, yml_rl, Pq, 0xab },
- { ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 },
- { ACLC, ynone, Px, 0xf8 },
- { ACLD, ynone, Px, 0xfc },
- { ACLI, ynone, Px, 0xfa },
- { ACLTS, ynone, Pm, 0x06 },
- { ACMC, ynone, Px, 0xf5 },
- { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
- { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
- { ACMPSB, ynone, Pb, 0xa6 },
- { ACMPSL, ynone, Px, 0xa7 },
- { ACMPSW, ynone, Pe, 0xa7 },
- { ADAA, ynone, Px, 0x27 },
- { ADAS, ynone, Px, 0x2f },
- { ADATA },
- { ADECB, yincb, Pb, 0xfe,(01) },
- { ADECL, yincl, Px, 0x48,0xff,(01) },
- { ADECW, yincl, Pe, 0x48,0xff,(01) },
- { ADIVB, ydivb, Pb, 0xf6,(06) },
- { ADIVL, ydivl, Px, 0xf7,(06) },
- { ADIVW, ydivl, Pe, 0xf7,(06) },
- { AENTER }, /* botch */
- { AGLOBL },
- { AGOK },
- { AHISTORY },
- { AHLT, ynone, Px, 0xf4 },
- { AIDIVB, ydivb, Pb, 0xf6,(07) },
- { AIDIVL, ydivl, Px, 0xf7,(07) },
- { AIDIVW, ydivl, Pe, 0xf7,(07) },
- { AIMULB, ydivb, Pb, 0xf6,(05) },
- { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
- { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
- { AINB, yin, Pb, 0xe4,0xec },
- { AINL, yin, Px, 0xe5,0xed },
- { AINW, yin, Pe, 0xe5,0xed },
- { AINCB, yincb, Pb, 0xfe,(00) },
- { AINCL, yincl, Px, 0x40,0xff,(00) },
- { AINCW, yincl, Pe, 0x40,0xff,(00) },
- { AINSB, ynone, Pb, 0x6c },
- { AINSL, ynone, Px, 0x6d },
- { AINSW, ynone, Pe, 0x6d },
- { AINT, yint, Px, 0xcd },
- { AINTO, ynone, Px, 0xce },
- { AIRETL, ynone, Px, 0xcf },
- { AIRETW, ynone, Pe, 0xcf },
- { AJCC, yjcond, Px, 0x73,0x83,(00) },
- { AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZL, yloop, Px, 0xe3 },
- { AJCXZW, yloop, Px, 0xe3 },
- { AJEQ, yjcond, Px, 0x74,0x84 },
- { AJGE, yjcond, Px, 0x7d,0x8d },
- { AJGT, yjcond, Px, 0x7f,0x8f },
- { AJHI, yjcond, Px, 0x77,0x87 },
- { AJLE, yjcond, Px, 0x7e,0x8e },
- { AJLS, yjcond, Px, 0x76,0x86 },
- { AJLT, yjcond, Px, 0x7c,0x8c },
- { AJMI, yjcond, Px, 0x78,0x88 },
- { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
- { AJNE, yjcond, Px, 0x75,0x85 },
- { AJOC, yjcond, Px, 0x71,0x81,(00) },
- { AJOS, yjcond, Px, 0x70,0x80,(00) },
- { AJPC, yjcond, Px, 0x7b,0x8b },
- { AJPL, yjcond, Px, 0x79,0x89 },
- { AJPS, yjcond, Px, 0x7a,0x8a },
- { ALAHF, ynone, Px, 0x9f },
- { ALARL, yml_rl, Pm, 0x02 },
- { ALARW, yml_rl, Pq, 0x02 },
- { ALEAL, ym_rl, Px, 0x8d },
- { ALEAW, ym_rl, Pe, 0x8d },
- { ALEAVEL, ynone, Px, 0xc9 },
- { ALEAVEW, ynone, Pe, 0xc9 },
- { ALOCK, ynone, Px, 0xf0 },
- { ALODSB, ynone, Pb, 0xac },
- { ALODSL, ynone, Px, 0xad },
- { ALODSW, ynone, Pe, 0xad },
- { ALONG, ybyte, Px, 4 },
- { ALOOP, yloop, Px, 0xe2 },
- { ALOOPEQ, yloop, Px, 0xe1 },
- { ALOOPNE, yloop, Px, 0xe0 },
- { ALSLL, yml_rl, Pm, 0x03 },
- { ALSLW, yml_rl, Pq, 0x03 },
- { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0 },
- { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 },
- { AMOVQ, ymovq, Pf3, 0x7e },
- { AMOVBLSX, ymb_rl, Pm, 0xbe },
- { AMOVBLZX, ymb_rl, Pm, 0xb6 },
- { AMOVBWSX, ymb_rl, Pq, 0xbe },
- { AMOVBWZX, ymb_rl, Pq, 0xb6 },
- { AMOVWLSX, yml_rl, Pm, 0xbf },
- { AMOVWLZX, yml_rl, Pm, 0xb7 },
- { AMOVSB, ynone, Pb, 0xa4 },
- { AMOVSL, ynone, Px, 0xa5 },
- { AMOVSW, ynone, Pe, 0xa5 },
- { AMULB, ydivb, Pb, 0xf6,(04) },
- { AMULL, ydivl, Px, 0xf7,(04) },
- { AMULW, ydivl, Pe, 0xf7,(04) },
- { ANAME },
- { ANEGB, yscond, Px, 0xf6,(03) },
- { ANEGL, yscond, Px, 0xf7,(03) },
- { ANEGW, yscond, Pe, 0xf7,(03) },
- { ANOP, ynop, Px,0,0 },
- { ANOTB, yscond, Px, 0xf6,(02) },
- { ANOTL, yscond, Px, 0xf7,(02) },
- { ANOTW, yscond, Pe, 0xf7,(02) },
- { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
- { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
- { AOUTB, yin, Pb, 0xe6,0xee },
- { AOUTL, yin, Px, 0xe7,0xef },
- { AOUTW, yin, Pe, 0xe7,0xef },
- { AOUTSB, ynone, Pb, 0x6e },
- { AOUTSL, ynone, Px, 0x6f },
- { AOUTSW, ynone, Pe, 0x6f },
- { APAUSE, ynone, Px, 0xf3,0x90 },
- { APOPAL, ynone, Px, 0x61 },
- { APOPAW, ynone, Pe, 0x61 },
- { APOPFL, ynone, Px, 0x9d },
- { APOPFW, ynone, Pe, 0x9d },
- { APOPL, ypopl, Px, 0x58,0x8f,(00) },
- { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
- { APUSHAL, ynone, Px, 0x60 },
- { APUSHAW, ynone, Pe, 0x60 },
- { APUSHFL, ynone, Px, 0x9c },
- { APUSHFW, ynone, Pe, 0x9c },
- { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
- { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
- { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
- { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
- { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
- { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
- { AREP, ynone, Px, 0xf3 },
- { AREPN, ynone, Px, 0xf2 },
- { ARET, ynone, Px, 0xc3 },
- { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
- { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
- { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
- { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
- { ASAHF, ynone, Px, 0x9e },
- { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
- { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
- { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
- { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
- { ASCASB, ynone, Pb, 0xae },
- { ASCASL, ynone, Px, 0xaf },
- { ASCASW, ynone, Pe, 0xaf },
- { ASETCC, yscond, Pm, 0x93,(00) },
- { ASETCS, yscond, Pm, 0x92,(00) },
- { ASETEQ, yscond, Pm, 0x94,(00) },
- { ASETGE, yscond, Pm, 0x9d,(00) },
- { ASETGT, yscond, Pm, 0x9f,(00) },
- { ASETHI, yscond, Pm, 0x97,(00) },
- { ASETLE, yscond, Pm, 0x9e,(00) },
- { ASETLS, yscond, Pm, 0x96,(00) },
- { ASETLT, yscond, Pm, 0x9c,(00) },
- { ASETMI, yscond, Pm, 0x98,(00) },
- { ASETNE, yscond, Pm, 0x95,(00) },
- { ASETOC, yscond, Pm, 0x91,(00) },
- { ASETOS, yscond, Pm, 0x90,(00) },
- { ASETPC, yscond, Pm, 0x96,(00) },
- { ASETPL, yscond, Pm, 0x99,(00) },
- { ASETPS, yscond, Pm, 0x9a,(00) },
- { ACDQ, ynone, Px, 0x99 },
- { ACWD, ynone, Pe, 0x99 },
- { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
- { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
- { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
- { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
- { ASTC, ynone, Px, 0xf9 },
- { ASTD, ynone, Px, 0xfd },
- { ASTI, ynone, Px, 0xfb },
- { ASTOSB, ynone, Pb, 0xaa },
- { ASTOSL, ynone, Px, 0xab },
- { ASTOSW, ynone, Pe, 0xab },
- { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
- { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
- { ASYSCALL, ynone, Px, 0xcd,100 },
- { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
- { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
- { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
- { ATEXT, ytext, Px },
- { AVERR, ydivl, Pm, 0x00,(04) },
- { AVERW, ydivl, Pm, 0x00,(05) },
- { AWAIT, ynone, Px, 0x9b },
- { AWORD, ybyte, Px, 2 },
- { AXCHGB, yml_mb, Pb, 0x86,0x86 },
- { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
- { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
- { AXLAT, ynone, Px, 0xd7 },
- { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
- { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
- { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
-
- { AFMOVB, yfmvx, Px, 0xdf,(04) },
- { AFMOVBP, yfmvp, Px, 0xdf,(06) },
- { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
- { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
- { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
- { AFMOVFP, yfmvp, Px, 0xd9,(03) },
- { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
- { AFMOVLP, yfmvp, Px, 0xdb,(03) },
- { AFMOVV, yfmvx, Px, 0xdf,(05) },
- { AFMOVVP, yfmvp, Px, 0xdf,(07) },
- { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
- { AFMOVWP, yfmvp, Px, 0xdf,(03) },
- { AFMOVX, yfmvx, Px, 0xdb,(05) },
- { AFMOVXP, yfmvp, Px, 0xdb,(07) },
-
- { AFCOMB },
- { AFCOMBP },
- { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
- { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
- { AFCOMDPP, ycompp, Px, 0xde,(03) },
- { AFCOMF, yfmvx, Px, 0xd8,(02) },
- { AFCOMFP, yfmvx, Px, 0xd8,(03) },
- { AFCOMI, yfmvx, Px, 0xdb,(06) },
- { AFCOMIP, yfmvx, Px, 0xdf,(06) },
- { AFCOML, yfmvx, Px, 0xda,(02) },
- { AFCOMLP, yfmvx, Px, 0xda,(03) },
- { AFCOMW, yfmvx, Px, 0xde,(02) },
- { AFCOMWP, yfmvx, Px, 0xde,(03) },
-
- { AFUCOM, ycompp, Px, 0xdd,(04) },
- { AFUCOMI, ycompp, Px, 0xdb,(05) },
- { AFUCOMIP, ycompp, Px, 0xdf,(05) },
- { AFUCOMP, ycompp, Px, 0xdd,(05) },
- { AFUCOMPP, ycompp, Px, 0xda,(13) },
-
- { AFADDDP, yfaddp, Px, 0xde,(00) },
- { AFADDW, yfmvx, Px, 0xde,(00) },
- { AFADDL, yfmvx, Px, 0xda,(00) },
- { AFADDF, yfmvx, Px, 0xd8,(00) },
- { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
-
- { AFMULDP, yfaddp, Px, 0xde,(01) },
- { AFMULW, yfmvx, Px, 0xde,(01) },
- { AFMULL, yfmvx, Px, 0xda,(01) },
- { AFMULF, yfmvx, Px, 0xd8,(01) },
- { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
-
- { AFSUBDP, yfaddp, Px, 0xde,(05) },
- { AFSUBW, yfmvx, Px, 0xde,(04) },
- { AFSUBL, yfmvx, Px, 0xda,(04) },
- { AFSUBF, yfmvx, Px, 0xd8,(04) },
- { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
-
- { AFSUBRDP, yfaddp, Px, 0xde,(04) },
- { AFSUBRW, yfmvx, Px, 0xde,(05) },
- { AFSUBRL, yfmvx, Px, 0xda,(05) },
- { AFSUBRF, yfmvx, Px, 0xd8,(05) },
- { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
-
- { AFDIVDP, yfaddp, Px, 0xde,(07) },
- { AFDIVW, yfmvx, Px, 0xde,(06) },
- { AFDIVL, yfmvx, Px, 0xda,(06) },
- { AFDIVF, yfmvx, Px, 0xd8,(06) },
- { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
-
- { AFDIVRDP, yfaddp, Px, 0xde,(06) },
- { AFDIVRW, yfmvx, Px, 0xde,(07) },
- { AFDIVRL, yfmvx, Px, 0xda,(07) },
- { AFDIVRF, yfmvx, Px, 0xd8,(07) },
- { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
-
- { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
- { AFFREE },
- { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
- { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
- { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
- { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
- { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
- { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
- { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
- { AF2XM1, ynone, Px, 0xd9, 0xf0 },
- { AFABS, ynone, Px, 0xd9, 0xe1 },
- { AFCHS, ynone, Px, 0xd9, 0xe0 },
- { AFCLEX, ynone, Px, 0xdb, 0xe2 },
- { AFCOS, ynone, Px, 0xd9, 0xff },
- { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
- { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
- { AFINIT, ynone, Px, 0xdb, 0xe3 },
- { AFLD1, ynone, Px, 0xd9, 0xe8 },
- { AFLDL2E, ynone, Px, 0xd9, 0xea },
- { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
- { AFLDLG2, ynone, Px, 0xd9, 0xec },
- { AFLDLN2, ynone, Px, 0xd9, 0xed },
- { AFLDPI, ynone, Px, 0xd9, 0xeb },
- { AFLDZ, ynone, Px, 0xd9, 0xee },
- { AFNOP, ynone, Px, 0xd9, 0xd0 },
- { AFPATAN, ynone, Px, 0xd9, 0xf3 },
- { AFPREM, ynone, Px, 0xd9, 0xf8 },
- { AFPREM1, ynone, Px, 0xd9, 0xf5 },
- { AFPTAN, ynone, Px, 0xd9, 0xf2 },
- { AFRNDINT, ynone, Px, 0xd9, 0xfc },
- { AFSCALE, ynone, Px, 0xd9, 0xfd },
- { AFSIN, ynone, Px, 0xd9, 0xfe },
- { AFSINCOS, ynone, Px, 0xd9, 0xfb },
- { AFSQRT, ynone, Px, 0xd9, 0xfa },
- { AFTST, ynone, Px, 0xd9, 0xe4 },
- { AFXAM, ynone, Px, 0xd9, 0xe5 },
- { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
- { AFYL2X, ynone, Px, 0xd9, 0xf1 },
- { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
- { AEND },
- { ADYNT_ },
- { AINIT_ },
- { ASIGNAME },
- { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
- { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
- { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
- { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
-
- { ACPUID, ynone, Pm, 0xa2 },
- { ARDTSC, ynone, Pm, 0x31 },
-
- { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
- { AXADDL, yrl_ml, Pm, 0xc1 },
- { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
-
- { ACMOVLCC, yml_rl, Pm, 0x43 },
- { ACMOVLCS, yml_rl, Pm, 0x42 },
- { ACMOVLEQ, yml_rl, Pm, 0x44 },
- { ACMOVLGE, yml_rl, Pm, 0x4d },
- { ACMOVLGT, yml_rl, Pm, 0x4f },
- { ACMOVLHI, yml_rl, Pm, 0x47 },
- { ACMOVLLE, yml_rl, Pm, 0x4e },
- { ACMOVLLS, yml_rl, Pm, 0x46 },
- { ACMOVLLT, yml_rl, Pm, 0x4c },
- { ACMOVLMI, yml_rl, Pm, 0x48 },
- { ACMOVLNE, yml_rl, Pm, 0x45 },
- { ACMOVLOC, yml_rl, Pm, 0x41 },
- { ACMOVLOS, yml_rl, Pm, 0x40 },
- { ACMOVLPC, yml_rl, Pm, 0x4b },
- { ACMOVLPL, yml_rl, Pm, 0x49 },
- { ACMOVLPS, yml_rl, Pm, 0x4a },
- { ACMOVWCC, yml_rl, Pq, 0x43 },
- { ACMOVWCS, yml_rl, Pq, 0x42 },
- { ACMOVWEQ, yml_rl, Pq, 0x44 },
- { ACMOVWGE, yml_rl, Pq, 0x4d },
- { ACMOVWGT, yml_rl, Pq, 0x4f },
- { ACMOVWHI, yml_rl, Pq, 0x47 },
- { ACMOVWLE, yml_rl, Pq, 0x4e },
- { ACMOVWLS, yml_rl, Pq, 0x46 },
- { ACMOVWLT, yml_rl, Pq, 0x4c },
- { ACMOVWMI, yml_rl, Pq, 0x48 },
- { ACMOVWNE, yml_rl, Pq, 0x45 },
- { ACMOVWOC, yml_rl, Pq, 0x41 },
- { ACMOVWOS, yml_rl, Pq, 0x40 },
- { ACMOVWPC, yml_rl, Pq, 0x4b },
- { ACMOVWPL, yml_rl, Pq, 0x49 },
- { ACMOVWPS, yml_rl, Pq, 0x4a },
-
- { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
- { AFCMOVCS, yfcmv, Px, 0xda,(00) },
- { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
- { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
- { AFCMOVLS, yfcmv, Px, 0xda,(02) },
- { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
- { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
- { AFCMOVUN, yfcmv, Px, 0xda,(03) },
-
- { ALFENCE, ynone, Pm, 0xae,0xe8 },
- { AMFENCE, ynone, Pm, 0xae,0xf0 },
- { ASFENCE, ynone, Pm, 0xae,0xf8 },
-
- { AEMMS, ynone, Pm, 0x77 },
-
- { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
- { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
- { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
- { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
-
- { ABSWAPL, ybswap, Pm, 0xc8 },
-
- { AUNDEF, ynone, Px, 0x0f, 0x0b },
-
- { AADDPD, yxm, Pq, 0x58 },
- { AADDPS, yxm, Pm, 0x58 },
- { AADDSD, yxm, Pf2, 0x58 },
- { AADDSS, yxm, Pf3, 0x58 },
- { AANDNPD, yxm, Pq, 0x55 },
- { AANDNPS, yxm, Pm, 0x55 },
- { AANDPD, yxm, Pq, 0x54 },
- { AANDPS, yxm, Pq, 0x54 },
- { ACMPPD, yxcmpi, Px, Pe,0xc2 },
- { ACMPPS, yxcmpi, Pm, 0xc2,0 },
- { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
- { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
- { ACOMISD, yxcmp, Pe, 0x2f },
- { ACOMISS, yxcmp, Pm, 0x2f },
- { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
- { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
- { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
- { ACVTPD2PS, yxm, Pe, 0x5a },
- { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
- { ACVTPS2PD, yxm, Pm, 0x5a },
- { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
- { ACVTSD2SS, yxm, Pf2, 0x5a },
- { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
- { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
- { ACVTSS2SD, yxm, Pf3, 0x5a },
- { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
- { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
- { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
- { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
- { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
- { ADIVPD, yxm, Pe, 0x5e },
- { ADIVPS, yxm, Pm, 0x5e },
- { ADIVSD, yxm, Pf2, 0x5e },
- { ADIVSS, yxm, Pf3, 0x5e },
- { AMASKMOVOU, yxr, Pe, 0xf7 },
- { AMAXPD, yxm, Pe, 0x5f },
- { AMAXPS, yxm, Pm, 0x5f },
- { AMAXSD, yxm, Pf2, 0x5f },
- { AMAXSS, yxm, Pf3, 0x5f },
- { AMINPD, yxm, Pe, 0x5d },
- { AMINPS, yxm, Pm, 0x5d },
- { AMINSD, yxm, Pf2, 0x5d },
- { AMINSS, yxm, Pf3, 0x5d },
- { AMOVAPD, yxmov, Pe, 0x28,0x29 },
- { AMOVAPS, yxmov, Pm, 0x28,0x29 },
- { AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
- { AMOVHLPS, yxr, Pm, 0x12 },
- { AMOVHPD, yxmov, Pe, 0x16,0x17 },
- { AMOVHPS, yxmov, Pm, 0x16,0x17 },
- { AMOVLHPS, yxr, Pm, 0x16 },
- { AMOVLPD, yxmov, Pe, 0x12,0x13 },
- { AMOVLPS, yxmov, Pm, 0x12,0x13 },
- { AMOVMSKPD, yxrrl, Pq, 0x50 },
- { AMOVMSKPS, yxrrl, Pm, 0x50 },
- { AMOVNTO, yxr_ml, Pe, 0xe7 },
- { AMOVNTPD, yxr_ml, Pe, 0x2b },
- { AMOVNTPS, yxr_ml, Pm, 0x2b },
- { AMOVSD, yxmov, Pf2, 0x10,0x11 },
- { AMOVSS, yxmov, Pf3, 0x10,0x11 },
- { AMOVUPD, yxmov, Pe, 0x10,0x11 },
- { AMOVUPS, yxmov, Pm, 0x10,0x11 },
- { AMULPD, yxm, Pe, 0x59 },
- { AMULPS, yxm, Ym, 0x59 },
- { AMULSD, yxm, Pf2, 0x59 },
- { AMULSS, yxm, Pf3, 0x59 },
- { AORPD, yxm, Pq, 0x56 },
- { AORPS, yxm, Pm, 0x56 },
- { APADDQ, yxm, Pe, 0xd4 },
- { APAND, yxm, Pe, 0xdb },
- { APCMPEQB, yxmq, Pe ,0x74 },
- { APMAXSW, yxm, Pe, 0xee },
- { APMAXUB, yxm, Pe, 0xde },
- { APMINSW, yxm, Pe, 0xea },
- { APMINUB, yxm, Pe, 0xda },
- { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
- { APSADBW, yxm, Pq, 0xf6 },
- { APSUBB, yxm, Pe, 0xf8 },
- { APSUBL, yxm, Pe, 0xfa },
- { APSUBQ, yxm, Pe, 0xfb },
- { APSUBSB, yxm, Pe, 0xe8 },
- { APSUBSW, yxm, Pe, 0xe9 },
- { APSUBUSB, yxm, Pe, 0xd8 },
- { APSUBUSW, yxm, Pe, 0xd9 },
- { APSUBW, yxm, Pe, 0xf9 },
- { APUNPCKHQDQ, yxm, Pe, 0x6d },
- { APUNPCKLQDQ, yxm, Pe, 0x6c },
- { ARCPPS, yxm, Pm, 0x53 },
- { ARCPSS, yxm, Pf3, 0x53 },
- { ARSQRTPS, yxm, Pm, 0x52 },
- { ARSQRTSS, yxm, Pf3, 0x52 },
- { ASQRTPD, yxm, Pe, 0x51 },
- { ASQRTPS, yxm, Pm, 0x51 },
- { ASQRTSD, yxm, Pf2, 0x51 },
- { ASQRTSS, yxm, Pf3, 0x51 },
- { ASUBPD, yxm, Pe, 0x5c },
- { ASUBPS, yxm, Pm, 0x5c },
- { ASUBSD, yxm, Pf2, 0x5c },
- { ASUBSS, yxm, Pf3, 0x5c },
- { AUCOMISD, yxcmp, Pe, 0x2e },
- { AUCOMISS, yxcmp, Pm, 0x2e },
- { AUNPCKHPD, yxm, Pe, 0x15 },
- { AUNPCKHPS, yxm, Pm, 0x15 },
- { AUNPCKLPD, yxm, Pe, 0x14 },
- { AUNPCKLPS, yxm, Pm, 0x14 },
- { AXORPD, yxm, Pe, 0x57 },
- { AXORPS, yxm, Pm, 0x57 },
-
- { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
- { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) },
- { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
-
- { AUSEFIELD, ynop, Px, 0,0 },
- { ATYPE },
- { AFUNCDATA, yfuncdata, Px, 0,0 },
- { APCDATA, ypcdata, Px, 0,0 },
-
- 0
-};
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
deleted file mode 100644
index 1eaf78fe0..000000000
--- a/src/cmd/8l/pass.c
+++ /dev/null
@@ -1,858 +0,0 @@
-// Inferno utils/8l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Code and data passes.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../../pkg/runtime/stack.h"
-
-static void xfol(Prog*, Prog**);
-
-Prog*
-brchain(Prog *p)
-{
- int i;
-
- for(i=0; i<20; i++) {
- if(p == P || p->as != AJMP)
- return p;
- p = p->pcond;
- }
- return P;
-}
-
-void
-follow(void)
-{
- Prog *firstp, *lastp;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f follow\n", cputime());
- Bflush(&bso);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- firstp = prg();
- lastp = firstp;
- xfol(cursym->text, &lastp);
- lastp->link = nil;
- cursym->text = firstp->link;
- }
-}
-
-static int
-nofollow(int a)
-{
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETW:
- case AUNDEF:
- return 1;
- }
- return 0;
-}
-
-static int
-pushpop(int a)
-{
- switch(a) {
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- return 1;
- }
- return 0;
-}
-
-static void
-xfol(Prog *p, Prog **last)
-{
- Prog *q;
- int i;
- enum as a;
-
-loop:
- if(p == P)
- return;
- if(p->as == AJMP)
- if((q = p->pcond) != P && q->as != ATEXT) {
- /* mark instruction as done and continue layout at target of jump */
- p->mark = 1;
- p = q;
- if(p->mark == 0)
- goto loop;
- }
- if(p->mark) {
- /*
- * p goes here, but already used it elsewhere.
- * copy up to 4 instructions or else branch to other copy.
- */
- for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == P)
- break;
- if(q == *last)
- break;
- a = q->as;
- if(a == ANOP) {
- i--;
- continue;
- }
- if(nofollow(a) || pushpop(a))
- break; // NOTE(rsc): arm does goto copy
- if(q->pcond == P || q->pcond->mark)
- continue;
- if(a == ACALL || a == ALOOP)
- continue;
- for(;;) {
- if(p->as == ANOP) {
- p = p->link;
- continue;
- }
- q = copyp(p);
- p = p->link;
- q->mark = 1;
- (*last)->link = q;
- *last = q;
- if(q->as != a || q->pcond == P || q->pcond->mark)
- continue;
-
- q->as = relinv(q->as);
- p = q->pcond;
- q->pcond = q->link;
- q->link = p;
- xfol(q->link, last);
- p = q->link;
- if(p->mark)
- return;
- goto loop;
- }
- } /* */
- q = prg();
- q->as = AJMP;
- q->line = p->line;
- q->to.type = D_BRANCH;
- q->to.offset = p->pc;
- q->pcond = p;
- p = q;
- }
-
- /* emit p */
- p->mark = 1;
- (*last)->link = p;
- *last = p;
- a = p->as;
-
- /* continue loop with what comes after p */
- if(nofollow(a))
- return;
- if(p->pcond != P && a != ACALL) {
- /*
- * some kind of conditional branch.
- * recurse to follow one path.
- * continue loop on the other.
- */
- if((q = brchain(p->pcond)) != P)
- p->pcond = q;
- if((q = brchain(p->link)) != P)
- p->link = q;
- if(p->from.type == D_CONST) {
- if(p->from.offset == 1) {
- /*
- * expect conditional jump to be taken.
- * rewrite so that's the fall-through case.
- */
- p->as = relinv(a);
- q = p->link;
- p->link = p->pcond;
- p->pcond = q;
- }
- } else {
- q = p->link;
- if(q->mark)
- if(a != ALOOP) {
- p->as = relinv(a);
- p->link = p->pcond;
- p->pcond = q;
- }
- }
- xfol(p->link, last);
- if(p->pcond->mark)
- return;
- p = p->pcond;
- goto loop;
- }
- p = p->link;
- goto loop;
-}
-
-int
-relinv(int a)
-{
-
- switch(a) {
- case AJEQ: return AJNE;
- case AJNE: return AJEQ;
- case AJLE: return AJGT;
- case AJLS: return AJHI;
- case AJLT: return AJGE;
- case AJMI: return AJPL;
- case AJGE: return AJLT;
- case AJPL: return AJMI;
- case AJGT: return AJLE;
- case AJHI: return AJLS;
- case AJCS: return AJCC;
- case AJCC: return AJCS;
- case AJPS: return AJPC;
- case AJPC: return AJPS;
- case AJOS: return AJOC;
- case AJOC: return AJOS;
- }
- diag("unknown relation: %s in %s", anames[a], TNAME);
- return a;
-}
-
-void
-patch(void)
-{
- int32 c;
- Prog *p, *q;
- Sym *s;
- int32 vexit;
- Sym *plan9_tos;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f mkfwd\n", cputime());
- Bflush(&bso);
- mkfwd();
- if(debug['v'])
- Bprint(&bso, "%5.2f patch\n", cputime());
- Bflush(&bso);
- s = lookup("exit", 0);
- vexit = s->value;
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(HEADTYPE == Hwindows) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x14(FS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x14;
- }
- }
- if(HEADTYPE == Hlinux) {
- // Running binaries under Xen requires using
- // MOVL 0(GS), reg
- // and then off(reg) instead of saying off(GS) directly
- // when the offset is negative.
- // In external mode we just produce a reloc.
- if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- if(linkmode != LinkExternal) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- } else {
- // Add signals to relocate.
- p->from.index = D_GS;
- p->from.scale = 1;
- }
- }
- }
- if(HEADTYPE == Hplan9x32) {
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->from.offset = 0;
- }
- }
- if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
- s = p->to.sym;
- if(p->to.type == D_INDIR+D_ADDR) {
- /* skip check if this is an indirect call (CALL *symbol(SB)) */
- continue;
- } else if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- if((s->type&SMASK) != STEXT) {
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- }
- if(s->text == nil)
- continue;
- p->to.type = D_BRANCH;
- p->to.offset = s->text->pc;
- p->pcond = s->text;
- continue;
- }
- }
- if(p->to.type != D_BRANCH)
- continue;
- c = p->to.offset;
- for(q = cursym->text; q != P;) {
- if(c == q->pc)
- break;
- if(q->forwd != P && c >= q->forwd->pc)
- q = q->forwd;
- else
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s (%#ux)\n%P [%s]",
- TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
- p->to.type = D_NONE;
- }
- p->pcond = q;
- }
- }
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->p != nil)
- continue;
-
- for(p = cursym->text; p != P; p = p->link) {
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
- }
-}
-
-Prog*
-brloop(Prog *p)
-{
- int c;
- Prog *q;
-
- c = 0;
- for(q = p; q != P; q = q->pcond) {
- if(q->as != AJMP)
- break;
- c++;
- if(c >= 5000)
- return P;
- }
- return q;
-}
-
-static Prog* load_g_cx(Prog*);
-static Prog* stacksplit(Prog*, int32, Prog**);
-
-static Sym *plan9_tos;
-static Prog *pmorestack;
-static Sym *symmorestack;
-
-void
-dostkoff(void)
-{
- Prog *p, *q;
- int32 autoffset, deltasp;
- int a;
-
- pmorestack = P;
- symmorestack = lookup("runtime.morestack", 0);
-
- if(symmorestack->type != STEXT)
- diag("runtime.morestack not defined");
- else {
- pmorestack = symmorestack->text;
- symmorestack->text->from.scale |= NOSPLIT;
- }
-
- plan9_tos = S;
- if(HEADTYPE == Hplan9x32)
- plan9_tos = lookup("_tos", 0);
-
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- p = cursym->text;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
-
- if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
- p = appendp(p);
- p = load_g_cx(p); // load g into CX
- }
- if(!(cursym->text->from.scale & NOSPLIT))
- p = stacksplit(p, autoffset, &q); // emit split check
-
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- p->spadj = autoffset;
- } else {
- // zero-byte stack adjustment.
- // Insert a fake non-zero adjustment so that stkcheck can
- // recognize the end of the stack-splitting prolog.
- p = appendp(p);
- p->as = ANOP;
- p->spadj = -PtrSize;
- p = appendp(p);
- p->as = ANOP;
- p->spadj = PtrSize;
- }
- if(q != P)
- q->pcond = p;
- deltasp = autoffset;
-
- if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + PtrSize;
- p = appendp(p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- }
-
- if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
- // 8l -Z means zero the stack frame on entry.
- // This slows down function calls but can help avoid
- // false positives in garbage collection.
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_SP;
- p->to.type = D_DI;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = autoffset/4;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = AREP;
-
- p = appendp(p);
- p->as = ASTOSL;
- }
-
- for(; p != P; p = p->link) {
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- p->spadj = 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- p->spadj = 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- p->spadj = -4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- p->spadj = -2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
-
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(p);
- p = appendp(p);
- // g->panicwrap -= autoffset + PtrSize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + PtrSize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*PtrSize;
- p = appendp(p);
- p->as = ARET;
- }
-
- if(autoffset) {
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = -autoffset;
- p->spadj = -autoffset;
- p = appendp(p);
- p->as = ARET;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so undo
- // the cleanup.
- p->spadj = +autoffset;
- }
- if(p->to.sym) // retjmp
- p->as = AJMP;
- }
- }
-}
-
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-static Prog*
-load_g_cx(Prog *p)
-{
- switch(HEADTYPE) {
- case Hwindows:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x14;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- break;
-
- case Hlinux:
- if(linkmode != LinkExternal) {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- } else {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- p->from.index = D_GS;
- p->from.scale = 1;
- }
- break;
-
- case Hplan9x32:
- p->as = AMOVL;
- p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
- p->to.type = D_CX;
-
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- break;
-
- default:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
- return p;
-}
-
-// Append code to p to check for stack split.
-// Appends to (does not overwrite) p.
-// Assumes g is in CX.
-// Returns last new instruction.
-// On return, *jmpok is the instruction that should jump
-// to the stack frame allocation if no split is needed.
-static Prog*
-stacksplit(Prog *p, int32 framesize, Prog **jmpok)
-{
- Prog *q, *q1;
- int arg;
-
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
-
- p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- }
- q1 = P;
-
- if(framesize <= StackSmall) {
- // small stack: SP <= stackguard
- // CMPL SP, stackguard
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- } else if(framesize <= StackBig) {
- // large stack: SP-framesize <= stackguard-StackSmall
- // LEAL -(framesize-StackSmall)(SP), AX
- // CMPL AX, stackguard
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(framesize-StackSmall);
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- } else {
- // Such a large stack we need to protect against wraparound
- // if SP is close to zero.
- // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- //
- // Preemption sets stackguard to StackPreempt, a very large value.
- // That breaks the math above, so we have to check for that explicitly.
- // MOVL stackguard, CX
- // CMPL CX, $StackPreempt
- // JEQ label-of-call-to-morestack
- // LEAL StackGuard(SP), AX
- // SUBL stackguard, AX
- // CMPL AX, $(framesize+(StackGuard-StackSmall))
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_SI;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SI;
- p->to.type = D_CONST;
- p->to.offset = (uint32)StackPreempt;
-
- p = appendp(p);
- p->as = AJEQ;
- p->to.type = D_BRANCH;
- q1 = p;
-
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = StackGuard;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ASUBL;
- p->from.type = D_SI;
- p->from.offset = 0;
- p->to.type = D_AX;
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_CONST;
- p->to.offset = framesize+(StackGuard-StackSmall);
- }
-
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
-
- p = appendp(p); // save frame size in DI
- p->as = AMOVL;
- p->to.type = D_DI;
- p->from.type = D_CONST;
-
- // If we ask for more stack, we'll get a minimum of StackMin bytes.
- // We need a stack frame large enough to hold the top-of-stack data,
- // the function arguments+results, our caller's PC, our frame,
- // a word for the return PC of the next call, and then the StackLimit bytes
- // that must be available on entry to any function called from a function
- // that did a stack check. If StackMin is enough, don't ask for a specific
- // amount: then we can use the custom functions and save a few
- // instructions.
- if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
- p->from.offset = (framesize+7) & ~7LL;
-
- arg = cursym->text->to.offset2;
- if(arg == 1) // special marker for known 0
- arg = 0;
- if(arg&3)
- diag("misaligned argument size in stack split");
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = arg;
-
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
- p = appendp(p);
- p->as = AJMP;
- p->to.type = D_BRANCH;
- p->pcond = cursym->text->link;
-
- if(q != P)
- q->pcond = p->link;
- if(q1 != P)
- q1->pcond = q->link;
-
- *jmpok = q;
- return p;
-}
-
-int32
-atolwhex(char *s)
-{
- int32 n;
- int f;
-
- n = 0;
- f = 0;
- while(*s == ' ' || *s == '\t')
- s++;
- if(*s == '-' || *s == '+') {
- if(*s++ == '-')
- f = 1;
- while(*s == ' ' || *s == '\t')
- s++;
- }
- if(s[0]=='0' && s[1]){
- if(s[1]=='x' || s[1]=='X'){
- s += 2;
- for(;;){
- if(*s >= '0' && *s <= '9')
- n = n*16 + *s++ - '0';
- else if(*s >= 'a' && *s <= 'f')
- n = n*16 + *s++ - 'a' + 10;
- else if(*s >= 'A' && *s <= 'F')
- n = n*16 + *s++ - 'A' + 10;
- else
- break;
- }
- } else
- while(*s >= '0' && *s <= '7')
- n = n*8 + *s++ - '0';
- } else
- while(*s >= '0' && *s <= '9')
- n = n*10 + *s++ - '0';
- if(f)
- n = -n;
- return n;
-}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
deleted file mode 100644
index d99c5e408..000000000
--- a/src/cmd/8l/prof.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Profiling.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-doprof1(void)
-{
-#ifdef NOTDEF // TODO(rsc)
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->size = n*4;
-#endif
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
-
- if(p->from.scale & NOPROF) /* dont profile */
- continue;
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- for(; p; p=p->link) {
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
- }
- }
- }
-}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
deleted file mode 100644
index acf973cab..000000000
--- a/src/cmd/8l/span.c
+++ /dev/null
@@ -1,1507 +0,0 @@
-// Inferno utils/8l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-// Instruction layout.
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-
-static int32 vaddr(Adr*, Reloc*);
-
-void
-span1(Sym *s)
-{
- Prog *p, *q;
- int32 c, v, loop;
- uchar *bp;
- int n, m, i;
-
- cursym = s;
-
- for(p = s->text; p != P; p = p->link) {
- p->back = 2; // use short branches first time through
- if((q = p->pcond) != P && (q->back & 2))
- p->back |= 1; // backward jump
-
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
-
- n = 0;
- do {
- loop = 0;
- memset(s->r, 0, s->nr*sizeof s->r[0]);
- s->nr = 0;
- s->np = 0;
- c = 0;
- for(p = s->text; p != P; p = p->link) {
- p->pc = c;
-
- // process forward jumps to p
- for(q = p->comefrom; q != P; q = q->forwd) {
- v = p->pc - (q->pc + q->mark);
- if(q->back & 2) { // short
- if(v > 127) {
- loop++;
- q->back ^= 2;
- }
- if(q->as == AJCXZW)
- s->p[q->pc+2] = v;
- else
- s->p[q->pc+1] = v;
- } else {
- bp = s->p + q->pc + q->mark - 4;
- *bp++ = v;
- *bp++ = v>>8;
- *bp++ = v>>16;
- *bp = v>>24;
- }
- }
- p->comefrom = P;
-
- asmins(p);
- p->pc = c;
- m = andptr-and;
- symgrow(s, p->pc+m);
- memmove(s->p+p->pc, and, m);
- p->mark = m;
- c += m;
- }
- if(++n > 20) {
- diag("span must be looping");
- errorexit();
- }
- } while(loop);
- s->size = c;
-
- if(debug['a'] > 1) {
- print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
- for(i=0; i<s->np; i++) {
- print(" %.2ux", s->p[i]);
- if(i%16 == 15)
- print("\n %.6ux", i+1);
- }
- if(i%16)
- print("\n");
-
- for(i=0; i<s->nr; i++) {
- Reloc *r;
-
- r = &s->r[i];
- print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
- }
- }
-}
-
-void
-span(void)
-{
- Prog *p, *q;
- int32 v;
- int n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
-
- // NOTE(rsc): If we get rid of the globals we should
- // be able to parallelize these iterations.
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- if(cursym->text == nil || cursym->text->link == nil)
- continue;
-
- // TODO: move into span1
- for(p = cursym->text; p != P; p = p->link) {
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
- if(p->as == AADJSP) {
- p->to.type = D_SP;
- v = -p->from.offset;
- p->from.offset = v;
- p->as = AADDL;
- if(v < 0) {
- p->as = ASUBL;
- v = -v;
- p->from.offset = v;
- }
- if(v == 0)
- p->as = ANOP;
- }
- }
- span1(cursym);
- }
-}
-
-void
-xdefine(char *p, int t, int32 v)
-{
- Sym *s;
-
- s = lookup(p, 0);
- s->type = t;
- s->value = v;
- s->reachable = 1;
- s->special = 1;
-}
-
-void
-instinit(void)
-{
- int i;
-
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: at %A found %A", i, optab[i].as);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_X0 && i <= D_X0+7)
- reg[i] = (i-D_X0) & 7;
- }
-}
-
-int
-prefixof(Adr *a)
-{
- switch(a->type) {
- case D_INDIR+D_CS:
- return 0x2e;
- case D_INDIR+D_DS:
- return 0x3e;
- case D_INDIR+D_ES:
- return 0x26;
- case D_INDIR+D_FS:
- return 0x64;
- case D_INDIR+D_GS:
- return 0x65;
- }
- return 0;
-}
-
-int
-oclass(Adr *a)
-{
- int32 v;
-
- if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
- if(a->index != D_NONE && a->scale == 0) {
- if(a->type == D_ADDR) {
- switch(a->index) {
- case D_EXTERN:
- case D_STATIC:
- return Yi32;
- case D_AUTO:
- case D_PARAM:
- return Yiauto;
- }
- return Yxxx;
- }
- //if(a->type == D_INDIR+D_ADDR)
- // print("*Ycol\n");
- return Ycol;
- }
- return Ym;
- }
- switch(a->type)
- {
- case D_AL:
- return Yal;
-
- case D_AX:
- return Yax;
-
- case D_CL:
- case D_DL:
- case D_BL:
- case D_AH:
- case D_CH:
- case D_DH:
- case D_BH:
- return Yrb;
-
- case D_CX:
- return Ycx;
-
- case D_DX:
- case D_BX:
- return Yrx;
-
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- return Yrl;
-
- case D_F0+0:
- return Yf0;
-
- case D_F0+1:
- case D_F0+2:
- case D_F0+3:
- case D_F0+4:
- case D_F0+5:
- case D_F0+6:
- case D_F0+7:
- return Yrf;
-
- case D_X0+0:
- case D_X0+1:
- case D_X0+2:
- case D_X0+3:
- case D_X0+4:
- case D_X0+5:
- case D_X0+6:
- case D_X0+7:
- return Yxr;
-
- case D_NONE:
- return Ynone;
-
- case D_CS: return Ycs;
- case D_SS: return Yss;
- case D_DS: return Yds;
- case D_ES: return Yes;
- case D_FS: return Yfs;
- case D_GS: return Ygs;
-
- case D_GDTR: return Ygdtr;
- case D_IDTR: return Yidtr;
- case D_LDTR: return Yldtr;
- case D_MSW: return Ymsw;
- case D_TASK: return Ytask;
-
- case D_CR+0: return Ycr0;
- case D_CR+1: return Ycr1;
- case D_CR+2: return Ycr2;
- case D_CR+3: return Ycr3;
- case D_CR+4: return Ycr4;
- case D_CR+5: return Ycr5;
- case D_CR+6: return Ycr6;
- case D_CR+7: return Ycr7;
-
- case D_DR+0: return Ydr0;
- case D_DR+1: return Ydr1;
- case D_DR+2: return Ydr2;
- case D_DR+3: return Ydr3;
- case D_DR+4: return Ydr4;
- case D_DR+5: return Ydr5;
- case D_DR+6: return Ydr6;
- case D_DR+7: return Ydr7;
-
- case D_TR+0: return Ytr0;
- case D_TR+1: return Ytr1;
- case D_TR+2: return Ytr2;
- case D_TR+3: return Ytr3;
- case D_TR+4: return Ytr4;
- case D_TR+5: return Ytr5;
- case D_TR+6: return Ytr6;
- case D_TR+7: return Ytr7;
-
- case D_EXTERN:
- case D_STATIC:
- case D_AUTO:
- case D_PARAM:
- return Ym;
-
- case D_CONST:
- case D_CONST2:
- case D_ADDR:
- if(a->sym == S) {
- v = a->offset;
- if(v == 0)
- return Yi0;
- if(v == 1)
- return Yi1;
- if(v >= -128 && v <= 127)
- return Yi8;
- }
- return Yi32;
-
- case D_BRANCH:
- return Ybr;
- }
- return Yxxx;
-}
-
-void
-asmidx(int scale, int index, int base)
-{
- int i;
-
- switch(index) {
- default:
- goto bad;
-
- case D_NONE:
- i = 4 << 3;
- goto bas;
-
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_BP:
- case D_SI:
- case D_DI:
- i = reg[index] << 3;
- break;
- }
- switch(scale) {
- default:
- goto bad;
- case 1:
- break;
- case 2:
- i |= (1<<6);
- break;
- case 4:
- i |= (2<<6);
- break;
- case 8:
- i |= (3<<6);
- break;
- }
-bas:
- switch(base) {
- default:
- goto bad;
- case D_NONE: /* must be mod=00 */
- i |= 5;
- break;
- case D_AX:
- case D_CX:
- case D_DX:
- case D_BX:
- case D_SP:
- case D_BP:
- case D_SI:
- case D_DI:
- i |= reg[base];
- break;
- }
- *andptr++ = i;
- return;
-bad:
- diag("asmidx: bad address %d,%d,%d", scale, index, base);
- *andptr++ = 0;
- return;
-}
-
-static void
-put4(int32 v)
-{
- andptr[0] = v;
- andptr[1] = v>>8;
- andptr[2] = v>>16;
- andptr[3] = v>>24;
- andptr += 4;
-}
-
-static void
-relput4(Prog *p, Adr *a)
-{
- vlong v;
- Reloc rel, *r;
-
- v = vaddr(a, &rel);
- if(rel.siz != 0) {
- if(rel.siz != 4)
- diag("bad reloc");
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- put4(v);
-}
-
-int32
-symaddr(Sym *s)
-{
- if(!s->reachable)
- diag("unreachable symbol in symaddr - %s", s->name);
- return s->value;
-}
-
-static int32
-vaddr(Adr *a, Reloc *r)
-{
- int t;
- int32 v;
- Sym *s;
-
- if(r != nil)
- memset(r, 0, sizeof *r);
-
- t = a->type;
- v = a->offset;
- if(t == D_ADDR)
- t = a->index;
- switch(t) {
- case D_STATIC:
- case D_EXTERN:
- s = a->sym;
- if(s != nil) {
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- if(r == nil) {
- diag("need reloc for %D", a);
- errorexit();
- }
- r->type = D_ADDR;
- r->siz = 4;
- r->off = -1;
- r->sym = s;
- r->add = v;
- v = 0;
- }
- }
- return v;
-}
-
-static int
-istls(Adr *a)
-{
- if(HEADTYPE == Hlinux)
- return a->index == D_GS;
- return a->type == D_INDIR+D_GS;
-}
-
-void
-asmand(Adr *a, int r)
-{
- int32 v;
- int t, scale;
- Reloc rel;
-
- v = a->offset;
- t = a->type;
- rel.siz = 0;
- if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- } else
- t -= D_INDIR;
-
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a->scale, a->index, t);
- goto putrelv;
- }
- if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
-
- scale = a->scale;
- if(t < D_INDIR || t >= 2*D_INDIR) {
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- t = D_NONE;
- v = vaddr(a, &rel);
- break;
- case D_AUTO:
- case D_PARAM:
- t = D_SP;
- break;
- }
- scale = 1;
- } else
- t -= D_INDIR;
-
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- goto putrelv;
- }
- if(t == D_SP) {
- if(v == 0 && rel.siz == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(scale, D_NONE, t);
- goto putrelv;
- }
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && rel.siz == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- goto putrelv;
- }
- goto bad;
-
-putrelv:
- if(rel.siz != 0) {
- Reloc *r;
-
- if(rel.siz != 4) {
- diag("bad rel");
- goto bad;
- }
- r = addrel(cursym);
- *r = rel;
- r->off = curp->pc + andptr - and;
- } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) {
- Reloc *r;
- Sym *s;
-
- r = addrel(cursym);
- r->off = curp->pc + andptr - and;
- r->add = a->offset-tlsoffset;
- r->xadd = r->add;
- r->siz = 4;
- r->type = D_TLS;
- s = lookup("runtime.tlsgm", 0);
- r->sym = s;
- r->xsym = s;
- v = 0;
- }
-
- put4(v);
- return;
-
-bad:
- diag("asmand: bad address %D", a);
- return;
-}
-
-#define E 0xff
-uchar ymovtab[] =
-{
-/* push */
- APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
- APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
- APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
- APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
- APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
- APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
-
- APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
- APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
- APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
- APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
- APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
- APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
-
-/* pop */
- APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
- APOPL, Ynone, Yes, 0, 0x07,E,0,0,
- APOPL, Ynone, Yss, 0, 0x17,E,0,0,
- APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
- APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
-
- APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
- APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
- APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
- APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
- APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
-
-/* mov seg */
- AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
- AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
- AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
- AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
- AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
- AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
-
- AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
- AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
- AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
- AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
- AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
- AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
-
-/* mov cr */
- AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
- AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
- AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
- AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
-
- AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
- AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
- AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
- AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
-
-/* mov dr */
- AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
- AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
- AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
-
- AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
- AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
- AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
-
-/* mov tr */
- AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
- AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
-
- AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
- AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
-
-/* lgdt, sgdt, lidt, sidt */
- AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
- AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
- AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
- AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
-
-/* lldt, sldt */
- AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
- AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
-
-/* lmsw, smsw */
- AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
- AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
-
-/* ltr, str */
- AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
- AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
-
-/* load full pointer */
- AMOVL, Yml, Ycol, 5, 0,0,0,0,
- AMOVW, Yml, Ycol, 5, Pe,0,0,0,
-
-/* double shift */
- ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
- ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
-
-/* extra imul */
- AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
- AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
- 0
-};
-
-// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
-// which is not referenced in a->type.
-// If a is empty, it returns BX to account for MULB-like instructions
-// that might use DX and AX.
-int
-byteswapreg(Adr *a)
-{
- int cana, canb, canc, cand;
-
- cana = canb = canc = cand = 1;
-
- switch(a->type) {
- case D_NONE:
- cana = cand = 0;
- break;
- case D_AX:
- case D_AL:
- case D_AH:
- case D_INDIR+D_AX:
- cana = 0;
- break;
- case D_BX:
- case D_BL:
- case D_BH:
- case D_INDIR+D_BX:
- canb = 0;
- break;
- case D_CX:
- case D_CL:
- case D_CH:
- case D_INDIR+D_CX:
- canc = 0;
- break;
- case D_DX:
- case D_DL:
- case D_DH:
- case D_INDIR+D_DX:
- cand = 0;
- break;
- }
- switch(a->index) {
- case D_AX:
- cana = 0;
- break;
- case D_BX:
- canb = 0;
- break;
- case D_CX:
- canc = 0;
- break;
- case D_DX:
- cand = 0;
- break;
- }
- if(cana)
- return D_AX;
- if(canb)
- return D_BX;
- if(canc)
- return D_CX;
- if(cand)
- return D_DX;
-
- diag("impossible byte register");
- errorexit();
- return 0;
-}
-
-void
-subreg(Prog *p, int from, int to)
-{
-
- if(debug['Q'])
- print("\n%P s/%R/%R/\n", p, from, to);
-
- if(p->from.type == from) {
- p->from.type = to;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to;
- p->tt = 0;
- }
-
- if(p->from.index == from) {
- p->from.index = to;
- p->ft = 0;
- }
- if(p->to.index == from) {
- p->to.index = to;
- p->tt = 0;
- }
-
- from += D_INDIR;
- if(p->from.type == from) {
- p->from.type = to+D_INDIR;
- p->ft = 0;
- }
- if(p->to.type == from) {
- p->to.type = to+D_INDIR;
- p->tt = 0;
- }
-
- if(debug['Q'])
- print("%P\n", p);
-}
-
-static int
-mediaop(Optab *o, int op, int osize, int z)
-{
- switch(op){
- case Pm:
- case Pe:
- case Pf2:
- case Pf3:
- if(osize != 1){
- if(op != Pm)
- *andptr++ = op;
- *andptr++ = Pm;
- op = o->op[++z];
- break;
- }
- default:
- if(andptr == and || andptr[-1] != Pm)
- *andptr++ = Pm;
- break;
- }
- *andptr++ = op;
- return z;
-}
-
-void
-doasm(Prog *p)
-{
- Optab *o;
- Prog *q, pp;
- uchar *t;
- int z, op, ft, tt, breg;
- int32 v, pre;
- Reloc rel, *r;
- Adr *a;
-
- curp = p; // TODO
-
- pre = prefixof(&p->from);
- if(pre)
- *andptr++ = pre;
- pre = prefixof(&p->to);
- if(pre)
- *andptr++ = pre;
-
- if(p->ft == 0)
- p->ft = oclass(&p->from);
- if(p->tt == 0)
- p->tt = oclass(&p->to);
-
- ft = p->ft * Ymax;
- tt = p->tt * Ymax;
- o = &optab[p->as];
- t = o->ytab;
- if(t == 0) {
- diag("asmins: noproto %P", p);
- return;
- }
- for(z=0; *t; z+=t[3],t+=4)
- if(ycover[ft+t[0]])
- if(ycover[tt+t[1]])
- goto found;
- goto domov;
-
-found:
- switch(o->prefix) {
- case Pq: /* 16 bit escape and opcode escape */
- *andptr++ = Pe;
- *andptr++ = Pm;
- break;
-
- case Pf2: /* xmm opcode escape */
- case Pf3:
- *andptr++ = o->prefix;
- *andptr++ = Pm;
- break;
-
- case Pm: /* opcode escape */
- *andptr++ = Pm;
- break;
-
- case Pe: /* 16 bit escape */
- *andptr++ = Pe;
- break;
-
- case Pb: /* botch */
- break;
- }
-
- op = o->op[z];
- switch(t[2]) {
- default:
- diag("asmins: unknown z %d %P", t[2], p);
- return;
-
- case Zpseudo:
- break;
-
- case Zlit:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- break;
-
- case Zlitm_r:
- for(; op = o->op[z]; z++)
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r:
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm2_r:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case Zm_r_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->from, reg[p->to.type]);
- *andptr++ = p->to.offset;
- break;
-
- case Zibm_r:
- while ((op = o->op[z++]) != 0)
- *andptr++ = op;
- asmand(&p->from, reg[p->to.type]);
- *andptr++ = p->to.offset;
- break;
-
- case Zaut_r:
- *andptr++ = 0x8d; /* leal */
- if(p->from.type != D_ADDR)
- diag("asmins: Zaut sb type ADDR");
- p->from.type = p->from.index;
- p->from.index = D_NONE;
- p->ft = 0;
- asmand(&p->from, reg[p->to.type]);
- p->from.index = p->from.type;
- p->from.type = D_ADDR;
- p->ft = 0;
- break;
-
- case Zm_o:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- break;
-
- case Zr_m:
- *andptr++ = op;
- asmand(&p->to, reg[p->from.type]);
- break;
-
- case Zr_m_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, reg[p->from.type]);
- break;
-
- case Zr_m_i_xm:
- mediaop(o, op, t[3], z);
- asmand(&p->to, reg[p->from.type]);
- *andptr++ = p->from.offset;
- break;
-
- case Zo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- break;
-
- case Zm_ibo:
- *andptr++ = op;
- asmand(&p->from, o->op[z+1]);
- *andptr++ = vaddr(&p->to, nil);
- break;
-
- case Zibo_m:
- *andptr++ = op;
- asmand(&p->to, o->op[z+1]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_ib:
- case Zib_:
- if(t[2] == Zib_)
- a = &p->from;
- else
- a = &p->to;
- v = vaddr(a, nil);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
- case Zib_rp:
- *andptr++ = op + reg[p->to.type];
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Zil_rp:
- *andptr++ = op + reg[p->to.type];
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Zib_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- *andptr++ = vaddr(&p->from, nil);
- break;
-
- case Z_il:
- case Zil_:
- if(t[2] == Zil_)
- a = &p->from;
- else
- a = &p->to;
- *andptr++ = op;
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zm_ilo:
- case Zilo_m:
- *andptr++ = op;
- if(t[2] == Zilo_m) {
- a = &p->from;
- asmand(&p->to, o->op[z+1]);
- } else {
- a = &p->to;
- asmand(&p->from, o->op[z+1]);
- }
- if(o->prefix == Pe) {
- v = vaddr(a, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, a);
- break;
-
- case Zil_rr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- if(o->prefix == Pe) {
- v = vaddr(&p->from, nil);
- *andptr++ = v;
- *andptr++ = v>>8;
- }
- else
- relput4(p, &p->from);
- break;
-
- case Z_rp:
- *andptr++ = op + reg[p->to.type];
- break;
-
- case Zrp_:
- *andptr++ = op + reg[p->from.type];
- break;
-
- case Zclr:
- *andptr++ = op;
- asmand(&p->to, reg[p->to.type]);
- break;
-
- case Zcall:
- q = p->pcond;
- if(q == nil) {
- diag("call without target");
- errorexit();
- }
- if(q->as != ATEXT) {
- // Could handle this case by making D_PCREL
- // record the Prog* instead of the Sym*, but let's
- // wait until the need arises.
- diag("call of non-TEXT %P", q);
- errorexit();
- }
- *andptr++ = op;
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->sym = q->from.sym;
- put4(0);
- break;
-
- case Zbr:
- case Zjmp:
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("jmp/branch/loop without target");
- errorexit();
- }
- if(q->as == ATEXT) {
- // jump out of function
- if(t[2] == Zbr) {
- diag("branch to ATEXT");
- errorexit();
- }
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->sym = q->from.sym;
- r->type = D_PCREL;
- r->siz = 4;
- put4(0);
- break;
- }
-
- // Assumes q is in this function.
- // TODO: Check in input, preserve in brchain.
-
- // Fill in backward jump now.
- if(p->back & 1) {
- v = q->pc - (p->pc + 2);
- if(v >= -128) {
- if(p->as == AJCXZW)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = v;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- v -= 5-2;
- if(t[2] == Zbr) {
- *andptr++ = 0x0f;
- v--;
- }
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- break;
- }
-
- // Annotate target; will fill in later.
- p->forwd = q->comefrom;
- q->comefrom = p;
- if(p->back & 2) { // short
- if(p->as == AJCXZW)
- *andptr++ = 0x67;
- *andptr++ = op;
- *andptr++ = 0;
- } else if(t[2] == Zloop) {
- diag("loop too far: %P", p);
- } else {
- if(t[2] == Zbr)
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- *andptr++ = 0;
- }
- break;
-
- case Zcallcon:
- case Zjmpcon:
- if(t[2] == Zcallcon)
- *andptr++ = op;
- else
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_PCREL;
- r->siz = 4;
- r->add = p->to.offset;
- put4(0);
- break;
-
- case Zcallind:
- *andptr++ = op;
- *andptr++ = o->op[z+1];
- r = addrel(cursym);
- r->off = p->pc + andptr - and;
- r->type = D_ADDR;
- r->siz = 4;
- r->add = p->to.offset;
- r->sym = p->to.sym;
- put4(0);
- break;
-
- case Zbyte:
- v = vaddr(&p->from, &rel);
- if(rel.siz != 0) {
- rel.siz = op;
- r = addrel(cursym);
- *r = rel;
- r->off = p->pc + andptr - and;
- }
- *andptr++ = v;
- if(op > 1) {
- *andptr++ = v>>8;
- if(op > 2) {
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
- case Zmov:
- goto domov;
- }
- return;
-
-domov:
- for(t=ymovtab; *t; t+=8)
- if(p->as == t[0])
- if(ycover[ft+t[1]])
- if(ycover[tt+t[2]])
- goto mfound;
-bad:
- /*
- * here, the assembly has failed.
- * if its a byte instruction that has
- * unaddressable registers, try to
- * exchange registers and reissue the
- * instruction with the operands renamed.
- */
- pp = *p;
- z = p->from.type;
- if(z >= D_BP && z <= D_DI) {
- if((breg = byteswapreg(&p->to)) != D_AX) {
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[breg]);
- subreg(&pp, z, breg);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg lhs,bx */
- asmand(&p->from, reg[breg]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
- }
- return;
- }
- z = p->to.type;
- if(z >= D_BP && z <= D_DI) {
- if((breg = byteswapreg(&p->from)) != D_AX) {
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[breg]);
- subreg(&pp, z, breg);
- doasm(&pp);
- *andptr++ = 0x87; /* xchg rhs,bx */
- asmand(&p->to, reg[breg]);
- } else {
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- subreg(&pp, z, D_AX);
- doasm(&pp);
- *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
- }
- return;
- }
- diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
- return;
-
-mfound:
- switch(t[3]) {
- default:
- diag("asmins: unknown mov %d %P", t[3], p);
- break;
-
- case 0: /* lit */
- for(z=4; t[z]!=E; z++)
- *andptr++ = t[z];
- break;
-
- case 1: /* r,m */
- *andptr++ = t[4];
- asmand(&p->to, t[5]);
- break;
-
- case 2: /* m,r */
- *andptr++ = t[4];
- asmand(&p->from, t[5]);
- break;
-
- case 3: /* r,m - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->to, t[6]);
- break;
-
- case 4: /* m,r - 2op */
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, t[6]);
- break;
-
- case 5: /* load full pointer, trash heap */
- if(t[4])
- *andptr++ = t[4];
- switch(p->to.index) {
- default:
- goto bad;
- case D_DS:
- *andptr++ = 0xc5;
- break;
- case D_SS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb2;
- break;
- case D_ES:
- *andptr++ = 0xc4;
- break;
- case D_FS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb4;
- break;
- case D_GS:
- *andptr++ = 0x0f;
- *andptr++ = 0xb5;
- break;
- }
- asmand(&p->from, reg[p->to.type]);
- break;
-
- case 6: /* double shift */
- z = p->from.type;
- switch(z) {
- default:
- goto bad;
- case D_CONST:
- *andptr++ = 0x0f;
- *andptr++ = t[4];
- asmand(&p->to, reg[p->from.index]);
- *andptr++ = p->from.offset;
- break;
- case D_CL:
- case D_CX:
- *andptr++ = 0x0f;
- *andptr++ = t[5];
- asmand(&p->to, reg[p->from.index]);
- break;
- }
- break;
-
- case 7: /* imul rm,r */
- if(t[4] == Pq) {
- *andptr++ = Pe;
- *andptr++ = Pm;
- } else
- *andptr++ = t[4];
- *andptr++ = t[5];
- asmand(&p->from, reg[p->to.type]);
- break;
- }
-}
-
-void
-asmins(Prog *p)
-{
- andptr = and;
- doasm(p);
- if(andptr > and+sizeof and) {
- print("and[] is too short - %ld byte instruction\n", andptr - and);
- errorexit();
- }
-}
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
new file mode 100644
index 000000000..b278d08ce
--- /dev/null
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -0,0 +1,115 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func loadSyms(t *testing.T) map[string]string {
+ cmd := exec.Command("go", "tool", "nm", os.Args[0])
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
+ }
+ syms := make(map[string]string)
+ scanner := bufio.NewScanner(bytes.NewReader(out))
+ for scanner.Scan() {
+ f := strings.Fields(scanner.Text())
+ if len(f) < 3 {
+ continue
+ }
+ syms[f[2]] = f[0]
+ }
+ if err := scanner.Err(); err != nil {
+ t.Fatalf("error reading symbols: %v", err)
+ }
+ return syms
+}
+
+func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno string) {
+ cmd := exec.Command(exepath, os.Args[0])
+ cmd.Stdin = strings.NewReader(addr)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out))
+ }
+ f := strings.Split(string(out), "\n")
+ if len(f) < 3 && f[2] == "" {
+ t.Fatal("addr2line output must have 2 lines")
+ }
+ funcname = f[0]
+ pathAndLineNo := f[1]
+ f = strings.Split(pathAndLineNo, ":")
+ if runtime.GOOS == "windows" {
+ switch len(f) {
+ case 2:
+ return funcname, f[0], f[1]
+ case 3:
+ return funcname, f[0] + ":" + f[1], f[2]
+ default:
+ t.Fatalf("no line number found in %q", pathAndLineNo)
+ }
+ }
+ if len(f) != 2 {
+ t.Fatalf("no line number found in %q", pathAndLineNo)
+ }
+ return funcname, f[0], f[1]
+}
+
+const symName = "cmd/addr2line.TestAddr2Line"
+
+func testAddr2Line(t *testing.T, exepath, addr string) {
+ funcName, srcPath, srcLineNo := runAddr2Line(t, exepath, addr)
+ if symName != funcName {
+ t.Fatalf("expected function name %v; got %v", symName, funcName)
+ }
+ fi1, err := os.Stat("addr2line_test.go")
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ fi2, err := os.Stat(srcPath)
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ if !os.SameFile(fi1, fi2) {
+ t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
+ }
+ if srcLineNo != "94" {
+ t.Fatalf("line number = %v; want 94", srcLineNo)
+ }
+}
+
+// This is line 93. The test depends on that.
+func TestAddr2Line(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ syms := loadSyms(t)
+
+ tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ exepath := filepath.Join(tmpDir, "testaddr2line.exe")
+ out, err := exec.Command("go", "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
+ if err != nil {
+ t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
+ }
+
+ testAddr2Line(t, exepath, syms[symName])
+ testAddr2Line(t, exepath, "0x"+syms[symName])
+}
diff --git a/src/cmd/addr2line/main.c b/src/cmd/addr2line/main.c
deleted file mode 100644
index 54c4d90b5..000000000
--- a/src/cmd/addr2line/main.c
+++ /dev/null
@@ -1,90 +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.
-
-/*
- * addr2line simulation - only enough to make pprof work on Macs
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-void
-printusage(int fd)
-{
- fprint(fd, "usage: addr2line binary\n");
- fprint(fd, "reads addresses from standard input and writes two lines for each:\n");
- fprint(fd, "\tfunction name\n");
- fprint(fd, "\tfile:line\n");
-}
-
-void
-usage(void)
-{
- printusage(2);
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd;
- char *p, *q;
- uvlong pc;
- Symbol s;
- Fhdr fhdr;
- Biobuf bin, bout;
- char file[1024];
-
- if(argc > 1 && strcmp(argv[1], "--help") == 0) {
- printusage(1);
- exits(0);
- }
-
- ARGBEGIN{
- default:
- usage();
- }ARGEND
-
- if(argc != 1)
- usage();
-
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
-
- Binit(&bin, 0, OREAD);
- Binit(&bout, 1, OWRITE);
- for(;;) {
- p = Brdline(&bin, '\n');
- if(p == nil)
- break;
- p[Blinelen(&bin)-1] = '\0';
- q = strchr(p, ':');
- if(q != nil) {
- // reverse: translate file:line to pc
- *q++ = '\0';
- pc = file2pc(p, atoi(q));
- if(pc == ~(uvlong)0)
- Bprint(&bout, "!%r\n");
- else
- Bprint(&bout, "0x%llux\n", pc);
- continue;
- }
- pc = strtoull(p, 0, 16);
- if(!findsym(pc, CTEXT, &s))
- s.name = "??";
- if(!fileline(file, sizeof file, pc))
- strcpy(file, "??:0");
- Bprint(&bout, "%s\n%s\n", s.name, file);
- }
- Bflush(&bout);
- exits(0);
-}
diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go
new file mode 100644
index 000000000..b94ba12ef
--- /dev/null
+++ b/src/cmd/addr2line/main.go
@@ -0,0 +1,253 @@
+// 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.
+
+// Addr2line is a minimal simulation of the GNU addr2line tool,
+// just enough to support pprof.
+//
+// Usage:
+// go tool addr2line binary
+//
+// Addr2line reads hexadecimal addresses, one per line and with optional 0x prefix,
+// from standard input. For each input address, addr2line prints two output lines,
+// first the name of the function containing the address and second the file:line
+// of the source code corresponding to that address.
+//
+// This tool is intended for use only by pprof; its interface may change or
+// it may be deleted entirely in future releases.
+package main
+
+import (
+ "bufio"
+ "debug/elf"
+ "debug/gosym"
+ "debug/macho"
+ "debug/pe"
+ "debug/plan9obj"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func printUsage(w *os.File) {
+ fmt.Fprintf(w, "usage: addr2line binary\n")
+ fmt.Fprintf(w, "reads addresses from standard input and writes two lines for each:\n")
+ fmt.Fprintf(w, "\tfunction name\n")
+ fmt.Fprintf(w, "\tfile:line\n")
+}
+
+func usage() {
+ printUsage(os.Stderr)
+ os.Exit(2)
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("addr2line: ")
+
+ // pprof expects this behavior when checking for addr2line
+ if len(os.Args) > 1 && os.Args[1] == "--help" {
+ printUsage(os.Stdout)
+ os.Exit(0)
+ }
+
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 1 {
+ usage()
+ }
+
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ textStart, symtab, pclntab, err := loadTables(f)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ pcln := gosym.NewLineTable(pclntab, textStart)
+ tab, err := gosym.NewTable(symtab, pcln)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ stdin := bufio.NewScanner(os.Stdin)
+ stdout := bufio.NewWriter(os.Stdout)
+
+ for stdin.Scan() {
+ p := stdin.Text()
+ if strings.Contains(p, ":") {
+ // Reverse translate file:line to pc.
+ // This was an extension in the old C version of 'go tool addr2line'
+ // and is probably not used by anyone, but recognize the syntax.
+ // We don't have an implementation.
+ fmt.Fprintf(stdout, "!reverse translation not implemented\n")
+ continue
+ }
+ pc, _ := strconv.ParseUint(strings.TrimPrefix(p, "0x"), 16, 64)
+ file, line, fn := tab.PCToLine(pc)
+ name := "?"
+ if fn != nil {
+ name = fn.Name
+ } else {
+ file = "?"
+ line = 0
+ }
+ fmt.Fprintf(stdout, "%s\n%s:%d\n", name, file, line)
+ }
+ stdout.Flush()
+}
+
+func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) {
+ if obj, err := elf.NewFile(f); err == nil {
+ if sect := obj.Section(".text"); sect != nil {
+ textStart = sect.Addr
+ }
+ if sect := obj.Section(".gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if sect := obj.Section(".gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
+ }
+
+ if obj, err := macho.NewFile(f); err == nil {
+ if sect := obj.Section("__text"); sect != nil {
+ textStart = sect.Addr
+ }
+ if sect := obj.Section("__gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if sect := obj.Section("__gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
+ }
+
+ if obj, err := pe.NewFile(f); err == nil {
+ var imageBase uint64
+ switch oh := obj.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ default:
+ return 0, nil, nil, fmt.Errorf("pe file format not recognized")
+ }
+ if sect := obj.Section(".text"); sect != nil {
+ textStart = imageBase + uint64(sect.VirtualAddress)
+ }
+ if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
+ return 0, nil, nil, err
+ }
+ if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
+ return 0, nil, nil, err
+ }
+ return textStart, symtab, pclntab, nil
+ }
+
+ if obj, err := plan9obj.NewFile(f); err == nil {
+ sym, err := findPlan9Symbol(obj, "text")
+ if err != nil {
+ return 0, nil, nil, err
+ }
+ textStart = sym.Value
+ if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
+ return 0, nil, nil, err
+ }
+ if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
+ return 0, nil, nil, err
+ }
+ return textStart, symtab, pclntab, nil
+ }
+
+ return 0, nil, nil, fmt.Errorf("unrecognized binary format")
+}
+
+func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
+ for _, s := range f.Symbols {
+ if s.Name != name {
+ continue
+ }
+ if s.SectionNumber <= 0 {
+ return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
+ }
+ if len(f.Sections) < int(s.SectionNumber) {
+ return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
+ }
+ return s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPESymbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPESymbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ if ssym.SectionNumber != esym.SectionNumber {
+ return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
+ }
+ sect := f.Sections[ssym.SectionNumber-1]
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ return data[ssym.Value:esym.Value], nil
+}
+
+func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
+ syms, err := f.Symbols()
+ if err != nil {
+ return nil, err
+ }
+ for _, s := range syms {
+ if s.Name != name {
+ continue
+ }
+ return &s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPlan9Symbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPlan9Symbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ text, err := findPlan9Symbol(f, "text")
+ if err != nil {
+ return nil, err
+ }
+ sect := f.Section("text")
+ if sect == nil {
+ return nil, err
+ }
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ return data[ssym.Value-text.Value : esym.Value-text.Value], nil
+}
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index a62c87421..4bde794a1 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -817,7 +817,7 @@ func (w *Walker) emitFunc(f *types.Func) {
func (w *Walker) emitMethod(m *types.Selection) {
sig := m.Type().(*types.Signature)
recv := sig.Recv().Type()
- // report exported methods with unexported reveiver base type
+ // report exported methods with unexported receiver base type
if true {
base := recv
if p, _ := recv.(*types.Pointer); p != nil {
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index 1e10dc600..896b2b4a1 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -46,14 +46,14 @@ func main() {
gopath := prepGoPath()
cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
- cmd.Env = append([]string{"GOPATH=" + gopath}, filterOut(os.Environ(), "GOARCH")...)
+ cmd.Env = append(filterOut(os.Environ(), "GOARCH", "GOPATH"), "GOPATH="+gopath)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
}
out, err = exec.Command("go", "tool", "api",
- "-c", file("go1", "go1.1", "go1.2"),
+ "-c", file("go1", "go1.1", "go1.2", "go1.3"),
"-next", file("next"),
"-except", file("except")).CombinedOutput()
if err != nil {
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index af2339c97..c8aac1253 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -30,6 +30,7 @@
#include <libc.h>
#include <bio.h>
+#include <link.h>
#ifndef EXTERN
#define EXTERN extern
@@ -48,13 +49,13 @@ typedef struct Type Type;
typedef struct Funct Funct;
typedef struct Decl Decl;
typedef struct Io Io;
-typedef struct Hist Hist;
typedef struct Term Term;
typedef struct Init Init;
typedef struct Bits Bits;
typedef struct Bvec Bvec;
typedef struct Dynimp Dynimp;
typedef struct Dynexp Dynexp;
+typedef struct Var Var;
typedef Rune TRune; /* target system type */
@@ -83,6 +84,14 @@ struct Bvec
uint32 b[];
};
+struct Var
+{
+ vlong offset;
+ LSym* sym;
+ char name;
+ char etype;
+};
+
struct Node
{
Node* left;
@@ -114,6 +123,7 @@ struct Node
struct Sym
{
Sym* link;
+ LSym* lsym;
Type* type;
Type* suetag;
Type* tenum;
@@ -200,16 +210,6 @@ struct Io
};
#define I ((Io*)0)
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-EXTERN Hist* hist;
-
struct Term
{
vlong mult;
@@ -469,7 +469,6 @@ EXTERN int32 autoffset;
EXTERN int blockno;
EXTERN Decl* dclstack;
EXTERN int debug[256];
-EXTERN Hist* ehist;
EXTERN int32 firstbit;
EXTERN Sym* firstarg;
EXTERN Type* firstargtype;
@@ -498,7 +497,6 @@ EXTERN int32 nsymb;
EXTERN Biobuf outbuf;
EXTERN Biobuf diagbuf;
EXTERN char* outfile;
-EXTERN char* pathname;
EXTERN int peekc;
EXTERN int32 stkoff;
EXTERN Type* strf;
@@ -508,8 +506,9 @@ EXTERN Sym* symstring;
EXTERN int taggen;
EXTERN Type* tfield;
EXTERN Type* tufield;
-EXTERN int thechar;
-EXTERN char* thestring;
+extern int thechar;
+extern char* thestring;
+extern LinkArch* thelinkarch;
EXTERN Type* thisfn;
EXTERN int32 thunk;
EXTERN Type* types[NALLTYPES];
@@ -525,8 +524,11 @@ EXTERN int flag_largemodel;
EXTERN int ncontin;
EXTERN int canreach;
EXTERN int warnreach;
+EXTERN int nacl;
EXTERN Bits zbits;
EXTERN Fmt pragcgobuf;
+EXTERN Biobuf bstdout;
+EXTERN Var var[NVAR];
extern char *onames[], *tnames[], *gnames[];
extern char *cnames[], *qnames[], *bnames[];
@@ -556,6 +558,7 @@ extern uchar typechlpfd[];
EXTERN uchar* typeword;
EXTERN uchar* typecmplx;
+EXTERN Link* ctxt;
extern uint32 thash1;
extern uint32 thash2;
@@ -603,6 +606,7 @@ int FNconv(Fmt*);
int Oconv(Fmt*);
int Qconv(Fmt*);
int VBconv(Fmt*);
+int Bconv(Fmt*);
void setinclude(char*);
/*
@@ -612,7 +616,6 @@ void dodefine(char*);
void domacro(void);
Sym* getsym(void);
int32 getnsn(void);
-void linehist(char*, int);
void macdef(void);
void macprag(void);
void macend(void);
@@ -731,6 +734,7 @@ void diag(Node*, char*, ...);
void warn(Node*, char*, ...);
void yyerror(char*, ...);
void fatal(Node*, char*, ...);
+LSym* linksym(Sym*);
/*
* acid.c
@@ -791,6 +795,7 @@ int32 exreg(Type*);
int32 align(int32, Type*, int, int32*);
int32 maxround(int32, int32);
int hasdotdotdot(void);
+void linkarchinit(void);
extern schar ewidth[];
@@ -814,6 +819,7 @@ int machcap(Node*);
#pragma varargck argpos diag 2
#pragma varargck argpos yyerror 1
+#pragma varargck type "B" Bits
#pragma varargck type "F" Node*
#pragma varargck type "L" int32
#pragma varargck type "Q" int32
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index 049dc5196..424843764 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -117,8 +117,28 @@ void
main(int argc, char *argv[])
{
int c;
+ char *p;
+
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+ if(strcmp(p, "amd64p32") == 0) // must be before cinit
+ ewidth[TIND] = 4;
+
+ nacl = strcmp(getgoos(), "nacl") == 0;
+ if(nacl)
+ flag_largemodel = 1;
quotefmtinstall(); // before cinit, which overrides %Q
+
+ linkarchinit();
+ ctxt = linknew(thelinkarch);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+
ensuresymb(NSYMB);
memset(debug, 0, sizeof(debug));
tinit();
@@ -175,12 +195,14 @@ main(int argc, char *argv[])
flagcount("q", "print Go definitions", &debug['q']);
flagcount("s", "print #define assembly offsets", &debug['s']);
flagcount("t", "debug code generation", &debug['t']);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
flagcount("w", "enable warnings", &debug['w']);
flagcount("v", "increase debug verbosity", &debug['v']);
if(thechar == '6')
flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
if(argc < 1 && outfile == 0)
usage();
@@ -195,6 +217,7 @@ main(int argc, char *argv[])
else
c = compile(argv[0], defs, ndef);
+ Bflush(&bstdout);
if(c)
errorexit();
exits(0);
@@ -331,6 +354,7 @@ compile(char *file, char **defs, int ndef)
void
errorexit(void)
{
+ Bflush(&bstdout);
if(outfile)
remove(outfile);
exits("error");
@@ -390,7 +414,7 @@ newfile(char *s, int f)
errorexit();
}
fi.c = 0;
- linehist(s, 0);
+ linklinehist(ctxt, lineno, s, 0);
}
Sym*
@@ -1300,13 +1324,6 @@ cinit(void)
nodproto = new(OPROTO, Z, Z);
dclstack = D;
- pathname = allocn(pathname, 0, 100);
- if(getwd(pathname, 99) == 0) {
- pathname = allocn(pathname, 100, 900);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
- }
-
fmtinstall('O', Oconv);
fmtinstall('T', Tconv);
fmtinstall('F', FNconv);
@@ -1314,6 +1331,7 @@ cinit(void)
fmtinstall('Q', Qconv);
fmtinstall('|', VBconv);
fmtinstall('U', Uconv);
+ fmtinstall('B', Bconv);
}
int
@@ -1330,7 +1348,7 @@ loop:
fi.c = read(i->f, i->b, BUFSIZ) - 1;
if(fi.c < 0) {
close(i->f);
- linehist(0, 0);
+ linklinehist(ctxt, lineno, nil, 0);
goto pop;
}
fi.p = i->b + 1;
@@ -1365,70 +1383,7 @@ Oconv(Fmt *fp)
int
Lconv(Fmt *fp)
{
- char str[STRINGSZ], s[STRINGSZ];
- Hist *h;
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 l, d;
- int i, n;
-
- l = va_arg(fp->args, int32);
- n = 0;
- for(h = hist; h != H; h = h->link) {
- if(l < h->line)
- break;
- if(h->name) {
- if(h->offset != 0) { /* #line directive, not #pragma */
- if(n > 0 && n < HISTSZ && h->offset >= 0) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- if(n < HISTSZ) { /* beginning of file */
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
- if(n > HISTSZ)
- n = HISTSZ;
- str[0] = 0;
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
- break;
- strcat(str, " ");
- }
- if(a[i].line)
- snprint(s, STRINGSZ, "%s:%d[%s:%d]",
- a[i].line->name, l-a[i].ldel+1,
- a[i].incl->name, l-a[i].idel+1);
- else
- snprint(s, STRINGSZ, "%s:%d",
- a[i].incl->name, l-a[i].idel+1);
- if(strlen(s)+strlen(str) >= STRINGSZ-10)
- break;
- strcat(str, s);
- l = a[i].incl->line - 1; /* now print out start of this file */
- }
- if(n == 0)
- strcat(str, "<eof>");
- return fmtstrcpy(fp, str);
+ return linklinefmt(ctxt, fp);
}
int
@@ -1548,6 +1503,32 @@ VBconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == nil) {
+ sprint(ss, "$%lld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
void
setinclude(char *p)
{
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index 9d293b089..e24db1bc0 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -152,7 +152,7 @@ setinclude(char *p)
void
errorexit(void)
{
-
+ Bflush(&bstdout);
if(outfile)
remove(outfile);
exits("error");
@@ -209,7 +209,7 @@ newfile(char *s, int f)
errorexit();
}
fi.c = 0;
- linehist(s, 0);
+ linklinehist(ctxt, lineno, s, 0);
}
Sym*
@@ -477,7 +477,7 @@ l1:
return LCONST;
case '"':
- memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+ memcpy(yylval.sval, nullgen.u.sval, sizeof(yylval.sval));
cp = yylval.sval;
c1 = 0;
for(;;) {
@@ -638,10 +638,6 @@ pinit(char *f)
pc = 0;
peekc = IGN;
sym = 1;
- for(i=0; i<NSYM; i++) {
- h[i].type = 0;
- h[i].sym = S;
- }
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
s->macro = 0;
@@ -661,7 +657,7 @@ loop:
fi.c = read(i->f, i->b, BUFSIZ) - 1;
if(fi.c < 0) {
close(i->f);
- linehist(0, 0);
+ linklinehist(ctxt, lineno, 0, 0);
goto pop;
}
fi.p = i->b + 1;
@@ -709,67 +705,5 @@ yyerror(char *a, ...)
void
prfile(int32 l)
{
- int i, n;
- Hist a[HISTSZ], *h;
- int32 d;
-
- n = 0;
- for(h = hist; h != H; h = h->link) {
- if(l < h->line)
- break;
- if(h->name) {
- if(h->offset == 0) {
- if(n >= 0 && n < HISTSZ)
- a[n] = *h;
- n++;
- continue;
- }
- if(n > 0 && n < HISTSZ)
- if(a[n-1].offset == 0) {
- a[n] = *h;
- n++;
- } else
- a[n-1] = *h;
- continue;
- }
- n--;
- if(n >= 0 && n < HISTSZ) {
- d = h->line - a[n].line;
- for(i=0; i<n; i++)
- a[i].line += d;
- }
- }
- if(n > HISTSZ)
- n = HISTSZ;
- for(i=0; i<n; i++)
- print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
-}
-
-void
-ieeedtod(Ieee *ieee, double native)
-{
- double fr, ho, f;
- int exp;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- ieee->h |= 0x80000000L;
- return;
- }
- if(native == 0) {
- ieee->l = 0;
- ieee->h = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldn't use fp constants here */
- fr = modf(fr*f, &ho);
- ieee->h = ho;
- ieee->h &= 0xfffffL;
- ieee->h |= (exp+1022L) << 20;
- f = 65536L;
- fr = modf(fr*f, &ho);
- ieee->l = ho;
- ieee->l = (uint32)ieee->l << 16;
- ieee->l |= (int32)(fr*f);
+ linkprfile(ctxt, l);
}
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index f0a507669..f6927b2f6 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -642,7 +642,7 @@ nn:
c = strlen(symb) + 1;
cp = alloc(c);
memcpy(cp, symb, c);
- linehist(cp, n);
+ linklinehist(ctxt, lineno, cp, n);
return;
bad:
@@ -713,7 +713,6 @@ macprag(void)
Sym *s;
int c0, c;
char *hp;
- Hist *h;
s = getsym();
@@ -779,18 +778,7 @@ praglib:
hp = alloc(c);
memcpy(hp, symb, c);
- h = alloc(sizeof(Hist));
- h->name = hp;
- h->line = lineno;
- h->offset = -1;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
+ linklinehist(ctxt, lineno, hp, -1);
return;
bad:
@@ -810,43 +798,3 @@ macend(void)
return;
}
}
-
-void
-linehist(char *f, int offset)
-{
- Hist *h;
-
- /*
- * overwrite the last #line directive if
- * no alloc has happened since the last one
- */
- if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
- if(f && ehist->name && strcmp(f, ehist->name) == 0) {
- ehist->line = lineno;
- ehist->offset = offset;
- return;
- }
-
- if(debug['f'])
- if(f) {
- if(offset)
- print("%4d: %s (#line %d)\n", lineno, f, offset);
- else
- print("%4d: %s\n", lineno, f);
- } else
- print("%4d: <pop>\n", lineno);
- newflag = 0;
-
- h = alloc(sizeof(Hist));
- h->name = f;
- h->line = lineno;
- h->offset = offset;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
-}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index b82872bc5..10bebc196 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -35,6 +35,26 @@ enum { BitsPerPointer = 2 };
static void dumpgcargs(Type *fn, Sym *sym);
+static Sym*
+makefuncdatasym(char *namefmt, int64 funcdatakind)
+{
+ Node nod;
+ Sym *sym;
+ static int32 nsym;
+ static char namebuf[40];
+
+ snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
+ sym = slookup(namebuf);
+ sym->class = CSTATIC;
+ memset(&nod, 0, sizeof nod);
+ nod.op = ONAME;
+ nod.sym = sym;
+ nod.class = CSTATIC;
+ gins(AFUNCDATA, nodconst(funcdatakind), &nod);
+ linksym(sym)->type = SRODATA;
+ return sym;
+}
+
int
hasdotdotdot(void)
{
@@ -80,10 +100,10 @@ void
codgen(Node *n, Node *nn)
{
Prog *sp;
- Node *n1, nod, nod1, nod2;
- Sym *gcsym, *gclocalssym;
- static int ngcsym, ngclocalssym;
- static char namebuf[40];
+ Node *n1, nod, nod1;
+ Sym *gcargs;
+ Sym *gclocals;
+ int isvarargs;
cursafe = 0;
curarg = 0;
@@ -109,25 +129,11 @@ codgen(Node *n, Node *nn)
* generate funcdata symbol for this function.
* data is filled in at the end of codgen().
*/
- snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
- gcsym = slookup(namebuf);
- gcsym->class = CSTATIC;
-
- memset(&nod, 0, sizeof nod);
- nod.op = ONAME;
- nod.sym = gcsym;
- nod.class = CSTATIC;
- gins(AFUNCDATA, nodconst(FUNCDATA_GCArgs), &nod);
-
- snprint(namebuf, sizeof(namebuf), "gclocalssym·%d", ngclocalssym++);
- gclocalssym = slookup(namebuf);
- gclocalssym->class = CSTATIC;
-
- memset(&nod2, 0, sizeof(nod2));
- nod2.op = ONAME;
- nod2.sym = gclocalssym;
- nod2.class = CSTATIC;
- gins(AFUNCDATA, nodconst(FUNCDATA_GCLocals), &nod2);
+ isvarargs = hasdotdotdot();
+ gcargs = nil;
+ if(!isvarargs)
+ gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
+ gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
/*
* isolate first argument
@@ -166,7 +172,8 @@ codgen(Node *n, Node *nn)
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
- dumpgcargs(thisfn, gcsym);
+ if(!isvarargs)
+ dumpgcargs(thisfn, gcargs);
// TODO(rsc): "stkoff" is not right. It does not account for
// the possibility of data stored in .safe variables.
@@ -177,9 +184,9 @@ codgen(Node *n, Node *nn)
// area its own section.
// That said, we've been using stkoff for months
// and nothing too terrible has happened.
- gextern(gclocalssym, nodconst(-stkoff), 0, 4); // locals
- gclocalssym->type = typ(0, T);
- gclocalssym->type->width = 4;
+ gextern(gclocals, nodconst(-stkoff), 0, 4); // locals
+ gclocals->type = typ(0, T);
+ gclocals->type->width = 4;
}
void
@@ -655,7 +662,9 @@ walktype1(Type *t, int32 offset, Bvec *bv, int param)
{
Type *t1;
int32 o;
+ int32 widthptr;
+ widthptr = ewidth[TIND];
switch(t->etype) {
case TCHAR:
case TUCHAR:
@@ -670,14 +679,16 @@ walktype1(Type *t, int32 offset, Bvec *bv, int param)
case TFLOAT:
case TDOUBLE:
// non-pointer types
+ for(o = 0; o < t->width; o++)
+ bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar
break;
case TIND:
pointer:
// pointer types
- if((offset + t->offset) % ewidth[TIND] != 0)
+ if((offset + t->offset) % widthptr != 0)
yyerror("unaligned pointer");
- bvset(bv, ((offset + t->offset) / ewidth[TIND])*BitsPerPointer);
+ bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr
break;
case TARRAY:
@@ -715,39 +726,39 @@ dumpgcargs(Type *fn, Sym *sym)
int32 argbytes;
int32 symoffset, argoffset;
- if(hasdotdotdot()) {
- // give up for C vararg functions.
- // TODO: maybe make a map just for the args we do know?
- gextern(sym, nodconst(0), 0, 4); // nptrs=0
- symoffset = 4;
- } else {
- argbytes = (argsize() + ewidth[TIND] - 1);
- bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
- argoffset = align(0, fn->link, Aarg0, nil);
- if(argoffset > 0) {
- // The C calling convention returns structs by
- // copying them to a location pointed to by a
- // hidden first argument. This first argument
- // is a pointer.
- if(argoffset != ewidth[TIND])
- yyerror("passbyptr arg not the right size");
- bvset(bv, 0);
- }
- for(t = fn->down; t != T; t = t->down) {
- if(t->etype == TVOID)
- continue;
- argoffset = align(argoffset, t, Aarg1, nil);
- walktype1(t, argoffset, bv, 1);
- argoffset = align(argoffset, t, Aarg2, nil);
- }
- gextern(sym, nodconst(bv->n), 0, 4);
- symoffset = 4;
- for(i = 0; i < bv->n; i += 32) {
- gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
- symoffset += 4;
- }
- free(bv);
+ // Dump the length of the bitmap array. This value is always one for
+ // functions written in C.
+ symoffset = 0;
+ gextern(sym, nodconst(1), symoffset, 4);
+ symoffset += 4;
+ argbytes = (argsize() + ewidth[TIND] - 1);
+ bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
+ argoffset = align(0, fn->link, Aarg0, nil);
+ if(argoffset > 0) {
+ // The C calling convention returns structs by copying them to a
+ // location pointed to by a hidden first argument. This first
+ // argument is a pointer.
+ if(argoffset != ewidth[TIND])
+ yyerror("passbyptr arg not the right size");
+ bvset(bv, 1); // 2 = live ptr
+ }
+ for(t = fn->down; t != T; t = t->down) {
+ if(t->etype == TVOID)
+ continue;
+ argoffset = align(argoffset, t, Aarg1, nil);
+ walktype1(t, argoffset, bv, 1);
+ argoffset = align(argoffset, t, Aarg2, nil);
+ }
+ // Dump the length of the bitmap.
+ gextern(sym, nodconst(bv->n), symoffset, 4);
+ symoffset += 4;
+ // Dump the words of the bitmap.
+ for(i = 0; i < bv->n; i += 32) {
+ gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
+ symoffset += 4;
}
+ free(bv);
+ // Finalize the gc symbol.
sym->type = typ(0, T);
sym->type->width = symoffset;
}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
index cc9c22763..bae57c64d 100644
--- a/src/cmd/cc/pswt.c
+++ b/src/cmd/cc/pswt.c
@@ -138,32 +138,3 @@ nullwarn(Node *l, Node *r)
if(r != Z)
cgen(r, Z);
}
-
-void
-ieeedtod(Ieee *ieee, double native)
-{
- double fr, ho, f;
- int exp;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- ieee->h |= 0x80000000L;
- return;
- }
- if(native == 0) {
- ieee->l = 0;
- ieee->h = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldn't use fp constants here */
- fr = modf(fr*f, &ho);
- ieee->h = ho;
- ieee->h &= 0xfffffL;
- ieee->h |= (exp+1022L) << 20;
- f = 65536L;
- fr = modf(fr*f, &ho);
- ieee->l = ho;
- ieee->l <<= 16;
- ieee->l |= (int32)(fr*f);
-}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
index bed989102..94c11d021 100644
--- a/src/cmd/cc/sub.c
+++ b/src/cmd/cc/sub.c
@@ -2056,3 +2056,13 @@ mixedasop(Type *l, Type *r)
{
return !typefd[l->etype] && typefd[r->etype];
}
+
+LSym*
+linksym(Sym *s)
+{
+ if(s == nil)
+ return nil;
+ if(s->lsym != nil)
+ return s->lsym;
+ return linklookup(ctxt, s->name, s->class == CSTATIC);
+}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 605bab6d2..69c7ce893 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -52,6 +52,14 @@ these directives. Package-specific flags should be set using the
directives, not the environment variables, so that builds work in
unmodified environments.
+All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
+used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
+directives in a package are concatenated and used to compile C++ files in that
+package. All the LDFLAGS directives in any package in the program are
+concatenated and used at link time. All the pkg-config directives are
+concatenated and sent to pkg-config simultaneously to add to each appropriate
+set of command-line flags.
+
When the Go tool sees that one or more Go files use the special import
"C", it will look for other non-Go files in the directory and compile
them as part of the Go package. Any .c, .s, or .S files will be
@@ -63,11 +71,26 @@ compilers may be changed by the CC and CXX environment variables,
respectively; those environment variables may include command line
options.
+To enable cgo during cross compiling builds, set the CGO_ENABLED
+environment variable to 1 when building the Go tools with make.bash.
+Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will
+be used for compiling for the host.
+
+After the Go tools are built, when running the go command, CC_FOR_TARGET is
+ignored. The value of CC_FOR_TARGET when running make.bash is the default
+compiler. However, you can set the environment variable CC, not CC_FOR_TARGET,
+to control the compiler when running the go tool.
+
+CXX_FOR_TARGET works in a similar way for C++ code.
+
Go references to C
Within the Go file, C's struct field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
+C struct fields that cannot be expressed in Go, such as bit fields
+or misaligned data, are omitted in the Go struct, replaced by
+appropriate padding to reach the next field or the end of the struct.
The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
@@ -84,6 +107,11 @@ C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
+Cgo translates C types into equivalent unexported Go types.
+Because the translations are unexported, a Go package should not
+expose C types in its exported API: a C type used in one Go package
+is different from the same C type used in another.
+
Any C function (even void functions) may be called in a multiple
assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 3e1837ebf..7a802102d 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1197,12 +1197,12 @@ 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
+ if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
+ break
+ }
if tag == "" {
tag = "__" + strconv.Itoa(tagGen)
tagGen++
@@ -1212,6 +1212,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
t.Go = name // publish before recursive calls
goIdent[name.Name] = name
+ if dt.ByteSize < 0 {
+ // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown),
+ // so execute the basic things that the struct case would do
+ // other than try to determine a Go representation.
+ tt := *t
+ tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
+ tt.Go = c.Ident("struct{}")
+ typedef[name.Name] = &tt
+ break
+ }
switch dt.Kind {
case "class", "union":
t.Go = c.Opaque(t.Size)
@@ -1259,13 +1269,33 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
sub := c.Type(dt.Type, pos)
t.Size = sub.Size
t.Align = sub.Align
- if _, ok := typedef[name.Name]; !ok {
+ oldType := typedef[name.Name]
+ if oldType == nil {
tt := *t
tt.Go = sub.Go
typedef[name.Name] = &tt
}
- if *godefs || *cdefs {
+
+ // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
+ // use that as the Go form for this typedef too, so that the typedef will be interchangeable
+ // with the base type.
+ // In -godefs and -cdefs mode, do this for all typedefs.
+ if isStructUnionClass(sub.Go) || *godefs || *cdefs {
t.Go = sub.Go
+
+ if isStructUnionClass(sub.Go) {
+ // Use the typedef name for C code.
+ typedef[sub.Go.(*ast.Ident).Name].C = t.C
+ }
+
+ // If we've seen this typedef before, and it
+ // was an anonymous struct/union/class before
+ // too, use the old definition.
+ // TODO: it would be safer to only do this if
+ // we verify that the types are the same.
+ if oldType != nil && isStructUnionClass(oldType.Go) {
+ t.Go = oldType.Go
+ }
}
case *dwarf.UcharType:
@@ -1327,9 +1357,21 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// 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
+ // Unsized types are [0]byte, unless they're typedefs of other types
+ // or structs with tags.
+ // if so, use the name we've already defined.
t.Size = 0
- t.Go = c.Opaque(0)
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ // ok
+ case *dwarf.StructType:
+ if dt.StructName != "" {
+ break
+ }
+ t.Go = c.Opaque(0)
+ default:
+ t.Go = c.Opaque(0)
+ }
if t.C.Empty() {
t.C.Set("void")
}
@@ -1344,6 +1386,19 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
+// isStructUnionClass reports whether the type described by the Go syntax x
+// is a struct, union, or class with a tag.
+func isStructUnionClass(x ast.Expr) bool {
+ id, ok := x.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ name := id.Name
+ return strings.HasPrefix(name, "_Ctype_struct_") ||
+ strings.HasPrefix(name, "_Ctype_union_") ||
+ strings.HasPrefix(name, "_Ctype_class_")
+}
+
// FuncArg returns a Go type with the same memory layout as
// dtype when used as the type of a C function argument.
func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
@@ -1496,7 +1551,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
t := c.Type(f.Type, pos)
tgo := t.Go
size := t.Size
-
+ talign := t.Align
if f.BitSize > 0 {
if f.BitSize%8 != 0 {
continue
@@ -1509,8 +1564,17 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
name = "uint"
}
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
+ talign = size
}
+ if talign > 0 && f.ByteOffset%talign != 0 {
+ // Drop misaligned fields, the same way we drop integer bit fields.
+ // The goal is to make available what can be made available.
+ // Otherwise one bad and unneeded field in an otherwise okay struct
+ // makes the whole program not compile. Much of the time these
+ // structs are in system headers that cannot be corrected.
+ continue
+ }
n := len(fld)
fld = fld[0 : n+1]
name := f.Name
@@ -1525,8 +1589,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
buf.WriteString(" ")
buf.WriteString(name)
buf.WriteString("; ")
- if t.Align > align {
- align = t.Align
+ if talign > align {
+ align = talign
}
}
if off < dt.ByteSize {
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 83ab95251..76c7247af 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -485,7 +485,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
fgcc.Close()
}
-// fixGo convers the internal Name.Go field into the name we should show
+// fixGo converts the internal Name.Go field into the name we should show
// to users in error messages. There's only one for now: on input we rewrite
// C.malloc into C._CMalloc, so change it back here.
func fixGo(name string) string {
@@ -529,15 +529,8 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
// We're trying to write a gcc struct that matches 6c/8c/5c's layout.
// Use packed attribute to force no padding in this struct in case
- // gcc has different packing requirements. For example,
- // on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
- // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
- // and http://golang.org/issue/5603.
- extraAttr := ""
- if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
- extraAttr = ", __gcc_struct__"
- }
- fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__%v)) *a = v;\n", ctype, extraAttr)
+ // gcc has different packing requirements.
+ fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "a->r = ")
@@ -618,6 +611,19 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "\n")
}
+// packedAttribute returns host compiler struct attribute that will be
+// used to match 6c/8c/5c's struct layout. For example, on 386 Windows,
+// gcc wants to 8-align int64s, but 8c does not.
+// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
+// and http://golang.org/issue/5603.
+func (p *Package) packedAttribute() string {
+ s := "__attribute__((__packed__"
+ if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
+ s += ", __gcc_struct__"
+ }
+ return s + "))"
+}
+
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
@@ -727,7 +733,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
+ fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
@@ -874,10 +880,24 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
fmt.Fprintf(cdeclBuf, ")")
cParams := cdeclBuf.String()
+ // We need to use a name that will be exported by the
+ // Go code; otherwise gccgo will make it static and we
+ // will not be able to link against it from the C
+ // code.
goName := "Cgoexp_" + exp.ExpName
fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
fmt.Fprint(fgcch, "\n")
+ // Use a #define so that the C code that includes
+ // cgo_export.h will be able to refer to the Go
+ // function using the expected name.
+ fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
+
+ // Use a #undef in _cgo_export.c so that we ignore the
+ // #define from cgo_export.h, since here we are
+ // defining the real function.
+ fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
+
fmt.Fprint(fgcc, "\n")
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
fmt.Fprint(fgcc, "\t")
@@ -1219,7 +1239,10 @@ struct __go_string __go_byte_array_to_string(const void* p, intgo len);
struct __go_open_array __go_string_to_byte_array (struct __go_string str);
const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
- return strndup((const char*)s.__data, s.__length);
+ char *p = malloc(s.__length+1);
+ memmove(p, s.__data, s.__length);
+ p[s.__length] = 0;
+ return p;
}
struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
index 9de93180f..6222e5060 100644
--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -75,7 +75,8 @@ extern char *goroot_final;
extern char *goextlinkenabled;
extern char *goversion;
extern char *defaultcc;
-extern char *defaultcxx;
+extern char *defaultcxxtarget;
+extern char *defaultcctarget;
extern char *workdir;
extern char *tooldir;
extern char *slash;
@@ -93,7 +94,7 @@ void cmdversion(int, char**);
// buildgc.c
void gcopnames(char*, char*);
-void mkenam(char*, char*);
+void mkanames(char*, char*);
// buildruntime.c
void mkzasm(char*, char*);
diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c
index dafc5c1c2..52a621c5d 100644
--- a/src/cmd/dist/arm.c
+++ b/src/cmd/dist/arm.c
@@ -17,16 +17,8 @@ static void useVFPv1(void);
char *
xgetgoarm(void)
{
-#if defined(__NetBSD__) || defined(__FreeBSD__)
- // NetBSD has buggy support for VFPv2 (incorrect inexact,
- // denormial, and NaN handling). When GOARM=6, some of our
- // math tests fails on Raspberry Pi.
- // Thus we return "5" here for safety, the user is free
- // to override.
- // Note: using GOARM=6 with cgo can trigger a kernel assertion
- // failure and crash NetBSD/evbarm kernel.
- // FreeBSD also have broken VFP support, so disable VFP also
- // on FreeBSD.
+#if defined(__FreeBSD__)
+ // FreeBSD has broken VFP support
return "5";
#endif
if(xtryexecfunc(useVFPv3))
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index e6e5f0cf7..6884e0aae 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -27,22 +27,27 @@ char *gochar;
char *goversion;
char *slash; // / for unix, \ for windows
char *defaultcc;
-char *defaultcxx;
+char *defaultcflags;
+char *defaultldflags;
+char *defaultcxxtarget;
+char *defaultcctarget;
bool rebuildall;
bool defaultclang;
static bool shouldbuild(char*, char*);
static void copy(char*, char*, int);
+static void dopack(char*, char*, char**, int);
static char *findgoversion(void);
// The known architecture letters.
-static char *gochars = "568";
+static char *gochars = "5668";
// The known architectures.
static char *okgoarch[] = {
// same order as gochars
"arm",
"amd64",
+ "amd64p32",
"386",
};
@@ -51,7 +56,9 @@ static char *okgoos[] = {
"darwin",
"dragonfly",
"linux",
+ "solaris",
"freebsd",
+ "nacl",
"netbsd",
"openbsd",
"plan9",
@@ -164,14 +171,29 @@ init(void)
}
defaultcc = btake(&b);
- xgetenv(&b, "CXX");
+ xgetenv(&b, "CFLAGS");
+ defaultcflags = btake(&b);
+
+ xgetenv(&b, "LDFLAGS");
+ defaultldflags = btake(&b);
+
+ xgetenv(&b, "CC_FOR_TARGET");
if(b.len == 0) {
- if(defaultclang)
- bprintf(&b, "clang++");
- else
- bprintf(&b, "g++");
+ bprintf(&b, defaultcc);
}
- defaultcxx = btake(&b);
+ defaultcctarget = btake(&b);
+
+ xgetenv(&b, "CXX_FOR_TARGET");
+ if(b.len == 0) {
+ xgetenv(&b, "CXX");
+ if(b.len == 0) {
+ if(defaultclang)
+ bprintf(&b, "clang++");
+ else
+ bprintf(&b, "g++");
+ }
+ }
+ defaultcxxtarget = btake(&b);
xsetenv("GOROOT", goroot);
xsetenv("GOARCH", goarch);
@@ -268,9 +290,8 @@ findgoversion(void)
p = tags.p[i];
if(streq(p, "+"))
nrev++;
- // NOTE: Can reenable the /* */ code when we want to
- // start reporting versions named 'weekly' again.
- if(/*hasprefix(p, "weekly.") ||*/ hasprefix(p, "go")) {
+ // Only show the beta tag for the exact revision.
+ if(hasprefix(p, "go") && (!contains(p, "beta") || nrev == 0)) {
tag = xstrdup(p);
// If this tag matches the current checkout
// exactly (no "+" yet), don't show extra
@@ -344,7 +365,8 @@ static char *oldtool[] = {
// Unreleased directories (relative to $GOROOT) that should
// not be in release branches.
static char *unreleased[] = {
- "src/cmd/prof",
+ "src/cmd/link",
+ "src/pkg/debug/goobj",
"src/pkg/old",
};
@@ -414,7 +436,7 @@ setup(void)
}
// For release, make sure excluded things are excluded.
- if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) {
+ if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
for(i=0; i<nelem(unreleased); i++)
if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
fatal("%s should not exist in release build", bstr(&b));
@@ -435,7 +457,6 @@ static char *proto_gccargs[] = {
"-Wstrict-prototypes",
"-Wextra",
"-Wunused",
- "-Wuninitialized",
"-Wno-sign-compare",
"-Wno-missing-braces",
"-Wno-parentheses",
@@ -447,6 +468,15 @@ static char *proto_gccargs[] = {
"-fno-common",
"-ggdb",
"-pipe",
+};
+
+// gccargs2 is the second part of gccargs.
+// it is used if the environment isn't defining CFLAGS.
+static char *proto_gccargs2[] = {
+ // on older versions of GCC, -Wuninitialized is not supported
+ // without -O, so put it here together with -O settings in case
+ // the user's $CFLAGS doesn't include -O.
+ "-Wuninitialized",
#if defined(__NetBSD__) && defined(__arm__)
// GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
// Fix available at http://patchwork.ozlabs.org/patch/64562/.
@@ -456,7 +486,7 @@ static char *proto_gccargs[] = {
#endif
};
-static Vec gccargs;
+static Vec gccargs, ldargs;
// deptab lists changes to the default dependencies for a given prefix.
// deps ending in /* read the whole directory; deps beginning with -
@@ -480,18 +510,17 @@ static struct {
"$GOROOT/include/libc.h",
"$GOROOT/include/bio.h",
}},
- {"libmach", {
+ {"liblink", {
"$GOROOT/include/u.h",
"$GOROOT/include/utf.h",
"$GOROOT/include/fmt.h",
"$GOROOT/include/libc.h",
"$GOROOT/include/bio.h",
"$GOROOT/include/ar.h",
- "$GOROOT/include/bootexec.h",
- "$GOROOT/include/mach.h",
- "$GOROOT/include/ureg_amd64.h",
- "$GOROOT/include/ureg_arm.h",
- "$GOROOT/include/ureg_x86.h",
+ "$GOROOT/include/link.h",
+ "anames5.c",
+ "anames6.c",
+ "anames8.c",
}},
{"cmd/cc", {
"-pgen.c",
@@ -500,6 +529,7 @@ static struct {
{"cmd/gc", {
"-cplx.c",
"-pgen.c",
+ "-plive.c",
"-popt.c",
"-y1.tab.c", // makefile dreg
"opnames.h",
@@ -507,64 +537,58 @@ static struct {
{"cmd/5c", {
"../cc/pgen.c",
"../cc/pswt.c",
- "../5l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/6c", {
"../cc/pgen.c",
"../cc/pswt.c",
- "../6l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/8c", {
"../cc/pgen.c",
"../cc/pswt.c",
- "../8l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/5g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
- "../5l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/6g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
- "../6l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/8g", {
"../gc/cplx.c",
"../gc/pgen.c",
+ "../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
- "../8l/enam.c",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/5l", {
"../ld/*",
- "enam.c",
}},
{"cmd/6l", {
"../ld/*",
- "enam.c",
}},
{"cmd/8l", {
"../ld/*",
- "enam.c",
}},
{"cmd/go", {
"zdefaultcc.go",
}},
{"cmd/", {
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libmach.a",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libbio.a",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/lib9.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
+ "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
}},
{"pkg/runtime", {
"zaexperiment.h", // must sort above zasm
@@ -592,7 +616,9 @@ static struct {
void (*gen)(char*, char*);
} gentab[] = {
{"opnames.h", gcopnames},
- {"enam.c", mkenam},
+ {"anames5.c", mkanames},
+ {"anames6.c", mkanames},
+ {"anames8.c", mkanames},
{"zasm_", mkzasm},
{"zdefaultcc.go", mkzdefaultcc},
{"zsys_", mkzsys},
@@ -601,6 +627,9 @@ static struct {
{"zruntime_defs_", mkzruntimedefs},
{"zversion.go", mkzversion},
{"zaexperiment.h", mkzexperiment},
+
+ // not generated anymore, but delete the file if we see it
+ {"enam.c", nil},
};
// install installs the library, package, or binary associated with dir,
@@ -609,11 +638,11 @@ static void
install(char *dir)
{
char *name, *p, *elem, *prefix, *exe;
- bool islib, ispkg, isgo, stale;
+ bool islib, ispkg, isgo, stale, ispackcmd;
Buf b, b1, path;
Vec compile, files, link, go, missing, clean, lib, extra;
Time ttarg, t;
- int i, j, k, n, doclean, targ, usecpp;
+ int i, j, k, n, doclean, targ;
if(vflag) {
if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
@@ -646,30 +675,33 @@ install(char *dir)
goto out;
}
- // For release, cmd/prof is not included.
- if((streq(dir, "cmd/prof")) && !isdir(bstr(&path))) {
- if(vflag > 1)
- errprintf("skipping %s - does not exist\n", dir);
- goto out;
- }
-
// set up gcc command line on first run.
if(gccargs.len == 0) {
- bprintf(&b, "%s", defaultcc);
+ bprintf(&b, "%s %s", defaultcc, defaultcflags);
splitfields(&gccargs, bstr(&b));
for(i=0; i<nelem(proto_gccargs); i++)
vadd(&gccargs, proto_gccargs[i]);
+ if(defaultcflags[0] == '\0') {
+ for(i=0; i<nelem(proto_gccargs2); i++)
+ vadd(&gccargs, proto_gccargs2[i]);
+ }
if(contains(gccargs.p[0], "clang")) {
// disable ASCII art in clang errors, if possible
vadd(&gccargs, "-fno-caret-diagnostics");
// clang is too smart about unused command-line arguments
vadd(&gccargs, "-Qunused-arguments");
}
+ // disable word wrapping in error messages
+ vadd(&gccargs, "-fmessage-length=0");
if(streq(gohostos, "darwin")) {
// golang.org/issue/5261
vadd(&gccargs, "-mmacosx-version-min=10.6");
}
}
+ if(ldargs.len == 0 && defaultldflags[0] != '\0') {
+ bprintf(&b, "%s", defaultldflags);
+ splitfields(&ldargs, bstr(&b));
+ }
islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
ispkg = hasprefix(dir, "pkg");
@@ -681,6 +713,7 @@ install(char *dir)
// Start final link command line.
// Note: code below knows that link.p[targ] is the target.
+ ispackcmd = 0;
if(islib) {
// C library.
vadd(&link, "ar");
@@ -695,8 +728,8 @@ install(char *dir)
vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
} else if(ispkg) {
// Go library (package).
- vadd(&link, bpathf(&b, "%s/pack", tooldir));
- vadd(&link, "grc");
+ ispackcmd = 1;
+ vadd(&link, "pack"); // program name - unused here, but all the other cases record one
p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
*xstrrchr(p, '/') = '\0';
xmkdirall(p);
@@ -712,7 +745,7 @@ install(char *dir)
targ = link.len;
vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
} else {
- // C command. Use gccargs.
+ // C command. Use gccargs and ldargs.
if(streq(gohostos, "plan9")) {
vadd(&link, bprintf(&b, "%sl", gohostchar));
vadd(&link, "-o");
@@ -720,6 +753,7 @@ install(char *dir)
vadd(&link, bpathf(&b, "%s/%s", tooldir, name));
} else {
vcopy(&link, gccargs.p, gccargs.len);
+ vcopy(&link, ldargs.p, ldargs.len);
if(sflag)
vadd(&link, "-static");
vadd(&link, "-o");
@@ -754,17 +788,18 @@ install(char *dir)
files.len = n;
for(i=0; i<nelem(deptab); i++) {
- if(hasprefix(dir, deptab[i].prefix)) {
+ if(streq(dir, deptab[i].prefix) ||
+ (hassuffix(deptab[i].prefix, "/") && hasprefix(dir, deptab[i].prefix))) {
for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
breset(&b1);
bwritestr(&b1, p);
bsubst(&b1, "$GOROOT", goroot);
bsubst(&b1, "$GOOS", goos);
bsubst(&b1, "$GOARCH", goarch);
+ bsubst(&b1, "$GOHOSTOS", gohostos);
+ bsubst(&b1, "$GOHOSTARCH", gohostarch);
p = bstr(&b1);
if(hassuffix(p, ".a")) {
- if(streq(gohostos, "plan9") && hassuffix(p, "libbio.a"))
- continue;
vadd(&lib, bpathf(&b, "%s", p));
continue;
}
@@ -865,6 +900,8 @@ install(char *dir)
p = files.p[i];
elem = lastelem(p);
for(j=0; j<nelem(gentab); j++) {
+ if(gentab[j].gen == nil)
+ continue;
if(hasprefix(elem, gentab[j].nameprefix)) {
if(vflag > 1)
errprintf("generate %s\n", p);
@@ -916,20 +953,6 @@ install(char *dir)
goto nobuild;
}
- // The files generated by GNU Bison use macros that aren't
- // supported by the Plan 9 compilers so we have to use the
- // external preprocessor when compiling.
- usecpp = 0;
- if(streq(gohostos, "plan9")) {
- for(i=0; i<files.len; i++) {
- p = files.p[i];
- if(hassuffix(p, "y.tab.c") || hassuffix(p, "y.tab.h")){
- usecpp = 1;
- break;
- }
- }
- }
-
// Compile the files.
for(i=0; i<files.len; i++) {
if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
@@ -941,13 +964,12 @@ install(char *dir)
// C library or tool.
if(streq(gohostos, "plan9")) {
vadd(&compile, bprintf(&b, "%sc", gohostchar));
- vadd(&compile, "-FTVw");
- if(usecpp)
- vadd(&compile, "-Bp+");
+ vadd(&compile, "-FTVwp");
+ vadd(&compile, "-DPLAN9");
+ vadd(&compile, "-D__STDC__=1");
+ vadd(&compile, "-D__SIZE_TYPE__=ulong"); // for GNU Bison
vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot));
vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch));
- // Work around Plan 9 C compiler's handling of #include with .. path.
- vadd(&compile, bpathf(&b, "-I%s/src/cmd/ld", goroot));
} else {
vcopy(&compile, gccargs.p, gccargs.len);
vadd(&compile, "-c");
@@ -955,13 +977,15 @@ install(char *dir)
vadd(&compile, "-m64");
else if(streq(gohostarch, "386"))
vadd(&compile, "-m32");
- if(streq(dir, "lib9"))
- vadd(&compile, "-DPLAN9PORT");
vadd(&compile, "-I");
vadd(&compile, bpathf(&b, "%s/include", goroot));
}
+ if(streq(dir, "lib9"))
+ vadd(&compile, "-DPLAN9PORT");
+
+
vadd(&compile, "-I");
vadd(&compile, bstr(&path));
@@ -1048,11 +1072,13 @@ install(char *dir)
vreset(&compile);
vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
- bpathf(&b, "%s/_go_.%s", workdir, gochar);
+ bpathf(&b, "%s/_go_.a", workdir);
+ vadd(&compile, "-pack");
vadd(&compile, "-o");
vadd(&compile, bstr(&b));
vadd(&clean, bstr(&b));
- vadd(&link, bstr(&b));
+ if(!ispackcmd)
+ vadd(&link, bstr(&b));
vadd(&compile, "-p");
if(hasprefix(dir, "pkg/"))
@@ -1066,6 +1092,12 @@ install(char *dir)
vcopy(&compile, go.p, go.len);
runv(nil, bstr(&path), CheckExit, &compile);
+
+ if(ispackcmd) {
+ xremove(link.p[targ]);
+ dopack(link.p[targ], bstr(&b), &link.p[targ+1], link.len - (targ+1));
+ goto nobuild;
+ }
}
if(!islib && !isgo) {
@@ -1138,21 +1170,6 @@ shouldbuild(char *file, char *dir)
int i, j, ret;
Buf b;
Vec lines, fields;
-
- // On Plan 9, most of the libraries are already present.
- // The main exception is libmach which has been modified
- // in various places to support Go object files.
- if(streq(gohostos, "plan9")) {
- if(streq(dir, "lib9")) {
- name = lastelem(file);
- if(streq(name, "goos.c") || streq(name, "flag.c"))
- return 1;
- if(!contains(name, "plan9"))
- return 0;
- }
- if(streq(dir, "libbio"))
- return 0;
- }
// Check file name for GOOS or GOARCH.
name = lastelem(file);
@@ -1238,20 +1255,56 @@ copy(char *dst, char *src, int exec)
bfree(&b);
}
+// dopack copies the package src to dst,
+// appending the files listed in extra.
+// The archive format is the traditional Unix ar format.
+static void
+dopack(char *dst, char *src, char **extra, int nextra)
+{
+ int i;
+ char c, *p, *q;
+ Buf b, bdst;
+
+ binit(&b);
+ binit(&bdst);
+
+ readfile(&bdst, src);
+ for(i=0; i<nextra; i++) {
+ readfile(&b, extra[i]);
+ // find last path element for archive member name
+ p = xstrrchr(extra[i], '/');
+ if(p)
+ p++;
+ q = xstrrchr(extra[i], '\\');
+ if(q) {
+ q++;
+ if(p == nil || q > p)
+ p = q;
+ }
+ if(p == nil)
+ p = extra[i];
+ bwritef(&bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", p, 0, 0, 0, 0644, b.len);
+ bwriteb(&bdst, &b);
+ if(b.len&1) {
+ c = 0;
+ bwrite(&bdst, &c, 1);
+ }
+ }
+
+ writefile(&bdst, dst, 0);
+
+ bfree(&b);
+ bfree(&bdst);
+}
+
// buildorder records the order of builds for the 'go bootstrap' command.
static char *buildorder[] = {
"lib9",
"libbio",
- "libmach",
+ "liblink",
"misc/pprof",
- "cmd/addr2line",
- "cmd/nm",
- "cmd/objdump",
- "cmd/pack",
- "cmd/prof",
-
"cmd/cc", // must be before c
"cmd/gc", // must be before g
"cmd/%sl", // must be before a, c, g
@@ -1323,17 +1376,12 @@ static char *cleantab[] = {
"cmd/8c",
"cmd/8g",
"cmd/8l",
- "cmd/addr2line",
"cmd/cc",
"cmd/gc",
- "cmd/go",
- "cmd/nm",
- "cmd/objdump",
- "cmd/pack",
- "cmd/prof",
+ "cmd/go",
"lib9",
"libbio",
- "libmach",
+ "liblink",
"pkg/bufio",
"pkg/bytes",
"pkg/container/heap",
@@ -1388,8 +1436,6 @@ clean(void)
vinit(&dir);
for(i=0; i<nelem(cleantab); i++) {
- if((streq(cleantab[i], "cmd/prof")) && !isdir(cleantab[i]))
- continue;
bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
xreaddir(&dir, bstr(&path));
// Remove generated files.
@@ -1488,6 +1534,7 @@ cmdenv(int argc, char **argv)
usage();
xprintf(format, "CC", defaultcc);
+ xprintf(format, "CC_FOR_TARGET", defaultcctarget);
xprintf(format, "GOROOT", goroot);
xprintf(format, "GOBIN", gobin);
xprintf(format, "GOARCH", goarch);
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
index 03a797f2c..1f0625daa 100644
--- a/src/cmd/dist/buildgc.c
+++ b/src/cmd/dist/buildgc.c
@@ -63,10 +63,10 @@ gcopnames(char *dir, char *file)
vfree(&fields);
}
-// mkenam reads [568].out.h and writes enam.c
+// mkanames reads [568].out.h and writes anames[568].c
// The format is much the same as the Go opcodes above.
void
-mkenam(char *dir, char *file)
+mkanames(char *dir, char *file)
{
int i, ch;
Buf in, b, out;
@@ -78,11 +78,11 @@ mkenam(char *dir, char *file)
binit(&out);
vinit(&lines);
- ch = dir[xstrlen(dir)-2];
- bprintf(&b, "%s/../%cl/%c.out.h", dir, ch, ch);
+ ch = file[xstrlen(file)-3];
+ bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
readfile(&in, bstr(&b));
splitlines(&lines, bstr(&in));
- bwritestr(&out, "char* anames[] = {\n");
+ bprintf(&out, "char* anames%c[] = {\n", ch);
for(i=0; i<lines.len; i++) {
if(hasprefix(lines.p[i], "\tA")) {
p = xstrstr(lines.p[i], ",");
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
index a340252bc..41208fac5 100644
--- a/src/cmd/dist/buildgo.c
+++ b/src/cmd/dist/buildgo.c
@@ -31,7 +31,7 @@ mkzdefaultcc(char *dir, char *file)
"\n"
"const defaultCC = `%s`\n"
"const defaultCXX = `%s`\n",
- defaultcc, defaultcxx);
+ defaultcctarget, defaultcxxtarget);
writefile(&out, file, 0);
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index e6e309d92..ba5993b2f 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -127,83 +127,22 @@ static struct {
char *goos;
char *hdr;
} zasmhdr[] = {
- {"386", "windows",
- "#define get_tls(r) MOVL 0x14(FS), r\n"
- "#define g(r) 0(r)\n"
- "#define m(r) 4(r)\n"
- },
- {"386", "plan9",
- "// Plan 9 does not have per-process segment descriptors with\n"
- "// which to do thread-local storage. Instead, we will use a\n"
- "// fixed offset from the per-process TOS struct address for\n"
- "// the local storage. Since the process ID is contained in the\n"
- "// TOS struct, we specify an offset for that here as well.\n"
- "#define get_tls(r) MOVL _tos(SB), r \n"
- "#define g(r) -8(r)\n"
- "#define m(r) -4(r)\n"
- "#define procid(r) 48(r)\n"
- },
- {"386", "linux",
- "// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n"
- "// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n"
- "// what the machine sees as opposed to 8l input).\n"
- "// 8l rewrites 0(GS) and 4(GS) into these.\n"
- "//\n"
- "// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n"
- "// directly. Instead, we have to store %gs:0 into a temporary\n"
- "// register and then use -8(%reg) and -4(%reg). This kind\n"
- "// of addressing is correct even when not running Xen.\n"
- "//\n"
- "// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n"
- "// of mov instructions, using CX as the intermediate register\n"
- "// (safe because CX is about to be written to anyway).\n"
- "// But 8l cannot handle other instructions, like storing into 0(GS),\n"
- "// which is where these macros come into play.\n"
- "// get_tls sets up the temporary and then g and r use it.\n"
- "//\n"
- "// Another wrinkle is that get_tls needs to read from %gs:0,\n"
- "// but in 8l input it's called 8(GS), because 8l is going to\n"
- "// subtract 8 from all the offsets, as described above.\n"
- "//\n"
- "// The final wrinkle is that when generating an ELF .o file for\n"
- "// external linking mode, we need to be able to relocate the\n"
- "// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n"
- "// that is ignored by the linker except for that identification.\n"
- "#define get_tls(r) MOVL 8(GS), r\n"
- "#define g(r) -8(r)(GS*1)\n"
- "#define m(r) -4(r)(GS*1)\n"
- },
{"386", "",
- "#define get_tls(r)\n"
- "#define g(r) 0(GS)\n"
- "#define m(r) 4(GS)\n"
- },
-
- {"amd64", "windows",
- "#define get_tls(r) MOVQ 0x28(GS), r\n"
- "#define g(r) 0(r)\n"
- "#define m(r) 8(r)\n"
+ "#define get_tls(r) MOVL TLS, r\n"
+ "#define g(r) 0(r)(TLS*1)\n"
+ "#define m(r) 4(r)(TLS*1)\n"
},
- {"amd64", "plan9",
- "#define get_tls(r)\n"
- "#define g(r) 0(GS)\n"
- "#define m(r) 8(GS)\n"
- "#define procid(r) 16(GS)\n"
- },
- // The TLS accessors here are defined here to use initial exec model.
- // If the linker is not outputting a shared library, it will reduce
- // the TLS accessors to the local exec model, effectively removing
- // get_tls().
- {"amd64", "linux",
- "#define get_tls(r) MOVQ runtime·tlsgm(SB), r\n"
- "#define g(r) 0(r)(GS*1)\n"
- "#define m(r) 8(r)(GS*1)\n"
+ {"amd64p32", "",
+ "#define get_tls(r) MOVL TLS, r\n"
+ "#define g(r) 0(r)(TLS*1)\n"
+ "#define m(r) 4(r)(TLS*1)\n"
},
{"amd64", "",
- "#define get_tls(r)\n"
- "#define g(r) 0(GS)\n"
- "#define m(r) 8(GS)\n"
+ "#define get_tls(r) MOVQ TLS, r\n"
+ "#define g(r) 0(r)(TLS*1)\n"
+ "#define m(r) 8(r)(TLS*1)\n"
},
+
{"arm", "",
"#define LR R14\n"
},
@@ -243,7 +182,8 @@ mkzasm(char *dir, char *file)
ok:
// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
- // to get acid [sic] output.
+ // to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
+ // report compilation failures (the -o redirects all messages, unfortunately).
vreset(&argv);
vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
vadd(&argv, "-D");
@@ -252,8 +192,8 @@ ok:
vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
vadd(&argv, "-I");
vadd(&argv, bprintf(&b, "%s", workdir));
- vadd(&argv, "-a");
vadd(&argv, "-n");
+ vadd(&argv, "-a");
vadd(&argv, "-o");
vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
vadd(&argv, "proc.c");
@@ -284,8 +224,8 @@ ok:
aggr = "p";
else if(streq(fields.p[1], "Gobuf"))
aggr = "gobuf";
- else if(streq(fields.p[1], "WinCall"))
- aggr = "wincall";
+ else if(streq(fields.p[1], "LibCall"))
+ aggr = "libcall";
else if(streq(fields.p[1], "WinCallbackContext"))
aggr = "cbctxt";
else if(streq(fields.p[1], "SEH"))
@@ -329,7 +269,7 @@ ok:
vfree(&fields);
}
-// mkzsys writes zsys_$GOOS_$GOARCH.h,
+// mkzsys writes zsys_$GOOS_$GOARCH.s,
// which contains arch or os specific asm code.
//
void
@@ -365,10 +305,8 @@ mkzsys(char *dir, char *file)
}
static char *runtimedefs[] = {
+ "defs.c",
"proc.c",
- "iface.c",
- "hashmap.c",
- "chan.c",
"parfor.c",
};
diff --git a/src/cmd/dist/goc2c.c b/src/cmd/dist/goc2c.c
index f0fa04335..38627657e 100644
--- a/src/cmd/dist/goc2c.c
+++ b/src/cmd/dist/goc2c.c
@@ -85,11 +85,15 @@ enum {
String,
Slice,
Eface,
+ Complex128,
+ Float32,
+ Float64,
};
static struct {
char *name;
int size;
+ int rnd; // alignment
} type_table[] = {
/*
* variable sized first, for easy replacement.
@@ -105,6 +109,7 @@ static struct {
{"String", 8},
{"Slice", 12},
{"Eface", 8},
+ {"Complex128", 16},
/* fixed size */
{"float32", 4},
@@ -130,7 +135,7 @@ int structround = 4;
static void
bad_eof(void)
{
- fatal("%s:%ud: unexpected EOF\n", file, lineno);
+ fatal("%s:%d: unexpected EOF\n", file, lineno);
}
/* Free a list of parameters. */
@@ -295,9 +300,9 @@ read_package(void)
token = read_token_no_eof();
if (token == nil)
- fatal("%s:%ud: no token\n", file, lineno);
+ fatal("%s:%d: no token\n", file, lineno);
if (!streq(token, "package")) {
- fatal("%s:%ud: expected \"package\", got \"%s\"\n",
+ fatal("%s:%d: expected \"package\", got \"%s\"\n",
file, lineno, token);
}
return read_token_no_eof();
@@ -307,6 +312,9 @@ read_package(void)
static void
read_preprocessor_lines(void)
{
+ int first;
+
+ first = 1;
while (1) {
int c;
@@ -317,6 +325,10 @@ read_preprocessor_lines(void)
xungetc();
break;
}
+ if(first) {
+ first = 0;
+ xputchar('\n');
+ }
xputchar(c);
do {
c = getchar_update_lineno();
@@ -365,17 +377,24 @@ read_type(void)
/* Return the size of the given type. */
static int
-type_size(char *p)
+type_size(char *p, int *rnd)
{
int i;
- if(p[xstrlen(p)-1] == '*')
+ if(p[xstrlen(p)-1] == '*') {
+ *rnd = type_table[Uintptr].rnd;
return type_table[Uintptr].size;
+ }
+
+ if(streq(p, "Iface"))
+ p = "Eface";
for(i=0; type_table[i].name; i++)
- if(streq(type_table[i].name, p))
+ if(streq(type_table[i].name, p)) {
+ *rnd = type_table[i].rnd;
return type_table[i].size;
- fatal("%s:%ud: unknown type %s\n", file, lineno, p);
+ }
+ fatal("%s:%d: unknown type %s\n", file, lineno, p);
return 0;
}
@@ -398,18 +417,22 @@ read_params(int *poffset)
while (1) {
p = xmalloc(sizeof(struct params));
p->name = token;
- p->type = read_type();
p->next = nil;
*pp = p;
pp = &p->next;
- size = type_size(p->type);
- rnd = size;
- if(rnd > structround)
- rnd = structround;
- if(offset%rnd)
- offset += rnd - offset%rnd;
- offset += size;
+ if(streq(token, "...")) {
+ p->type = xstrdup("");
+ } else {
+ p->type = read_type();
+ rnd = 0;
+ size = type_size(p->type, &rnd);
+ if(rnd > structround)
+ rnd = structround;
+ if(offset%rnd)
+ offset += rnd - offset%rnd;
+ offset += size;
+ }
token = read_token_no_eof();
if (!streq(token, ","))
@@ -418,7 +441,7 @@ read_params(int *poffset)
}
}
if (!streq(token, ")")) {
- fatal("%s:%ud: expected '('\n",
+ fatal("%s:%d: expected '('\n",
file, lineno);
}
if (poffset != nil)
@@ -438,6 +461,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
lastline = -1;
while (1) {
+ read_preprocessor_lines();
token = read_token();
if (token == nil)
return 0;
@@ -460,7 +484,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token();
if (token == nil || !streq(token, "(")) {
- fatal("%s:%ud: expected \"(\"\n",
+ fatal("%s:%d: expected \"(\"\n",
file, lineno);
}
*params = read_params(paramwid);
@@ -473,7 +497,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token();
}
if (token == nil || !streq(token, "{")) {
- fatal("%s:%ud: expected \"{\"\n",
+ fatal("%s:%d: expected \"{\"\n",
file, lineno);
}
return 1;
@@ -500,8 +524,13 @@ write_6g_func_header(char *package, char *name, struct params *params,
int paramwid, struct params *rets)
{
int first, n;
+ struct params *p;
+
+ bwritef(output, "void\n");
+ if(!contains(name, "·"))
+ bwritef(output, "%s·", package);
+ bwritef(output, "%s(", name);
- bwritef(output, "void\n%s·%s(", package, name);
first = 1;
write_params(params, &first);
@@ -518,6 +547,24 @@ write_6g_func_header(char *package, char *name, struct params *params,
write_params(rets, &first);
bwritef(output, ")\n{\n");
+
+ for (p = rets; p != nil; p = p->next) {
+ if(streq(p->name, "..."))
+ continue;
+ if(streq(p->type, "Slice"))
+ bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name);
+ else if(streq(p->type, "String"))
+ bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name);
+ else if(streq(p->type, "Eface"))
+ bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name);
+ else if(streq(p->type, "Iface"))
+ bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name);
+ else if(streq(p->type, "Complex128"))
+ bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name);
+ else
+ bwritef(output, "\t%s = 0;\n", p->name);
+ bwritef(output, "\tFLUSH(&%s);\n", p->name);
+ }
}
/* Write a 6g function trailer. */
@@ -527,7 +574,8 @@ write_6g_func_trailer(struct params *rets)
struct params *p;
for (p = rets; p != nil; p = p->next)
- bwritef(output, "\tFLUSH(&%s);\n", p->name);
+ if(!streq(p->name, "..."))
+ bwritef(output, "\tFLUSH(&%s);\n", p->name);
bwritef(output, "}\n");
}
@@ -726,6 +774,7 @@ process_file(void)
void
goc2c(char *goc, char *c)
{
+ int i;
Buf in, out;
binit(&in);
@@ -739,13 +788,15 @@ goc2c(char *goc, char *c)
if(!gcc) {
if(streq(goarch, "amd64")) {
type_table[Uintptr].size = 8;
- type_table[Eface].size = 8+8;
- type_table[String].size = 16;
if(use64bitint) {
type_table[Int].size = 8;
- type_table[Uint].size = 8;
+ } else {
+ type_table[Int].size = 4;
}
- type_table[Slice].size = 8+2*type_table[Int].size;
+ structround = 8;
+ } else if(streq(goarch, "amd64p32")) {
+ type_table[Uintptr].size = 4;
+ type_table[Int].size = 4;
structround = 8;
} else {
// NOTE: These are set in the initializer,
@@ -753,13 +804,22 @@ goc2c(char *goc, char *c)
// previous invocation of goc2c, so we have
// to restore them.
type_table[Uintptr].size = 4;
- type_table[String].size = 8;
- type_table[Slice].size = 16;
- type_table[Eface].size = 4+4;
type_table[Int].size = 4;
- type_table[Uint].size = 4;
structround = 4;
}
+
+ type_table[Uint].size = type_table[Int].size;
+ type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size;
+ type_table[Eface].size = 2*type_table[Uintptr].size;
+ type_table[String].size = 2*type_table[Uintptr].size;
+
+ for(i=0; i<nelem(type_table); i++)
+ type_table[i].rnd = type_table[i].size;
+
+ type_table[String].rnd = type_table[Uintptr].rnd;
+ type_table[Slice].rnd = type_table[Uintptr].rnd;
+ type_table[Eface].rnd = type_table[Uintptr].rnd;
+ type_table[Complex128].rnd = type_table[Float64].rnd;
}
bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
index fa388e058..8b943a2d9 100644
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <stdarg.h>
#include <setjmp.h>
+#include <signal.h>
// bprintf replaces the buffer with the result of the printf formatting
// and returns a pointer to the NUL-terminated buffer contents.
@@ -686,6 +687,14 @@ main(int argc, char **argv)
gohostos = "openbsd";
#elif defined(__NetBSD__)
gohostos = "netbsd";
+#elif defined(__sun) && defined(__SVR4)
+ gohostos = "solaris";
+ // Even on 64-bit platform, solaris uname -m prints i86pc.
+ run(&b, nil, 0, "isainfo", "-n", nil);
+ if(contains(bstr(&b), "amd64"))
+ gohostarch = "amd64";
+ if(contains(bstr(&b), "i386"))
+ gohostarch = "386";
#else
fatal("unknown operating system");
#endif
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
index 7d03989b2..2839c4bc5 100644
--- a/src/cmd/dist/windows.c
+++ b/src/cmd/dist/windows.c
@@ -840,34 +840,20 @@ void
xprintf(char *fmt, ...)
{
va_list arg;
- char *p;
- DWORD n, w;
-
+
va_start(arg, fmt);
- n = vsnprintf(NULL, 0, fmt, arg);
- p = xmalloc(n+1);
- vsnprintf(p, n+1, fmt, arg);
+ vprintf(fmt, arg);
va_end(arg);
- w = 0;
- WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), p, n, &w, 0);
- xfree(p);
}
void
errprintf(char *fmt, ...)
{
va_list arg;
- char *p;
- DWORD n, w;
-
+
va_start(arg, fmt);
- n = vsnprintf(NULL, 0, fmt, arg);
- p = xmalloc(n+1);
- vsnprintf(p, n+1, fmt, arg);
+ vfprintf(stderr, fmt, arg);
va_end(arg);
- w = 0;
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), p, n, &w, 0);
- xfree(p);
}
int
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 8e9677e75..b809640e4 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -175,11 +175,11 @@ dowidth(Type *t)
case TFLOAT64:
case TCOMPLEX64:
w = 8;
- t->align = widthptr;
+ t->align = widthreg;
break;
case TCOMPLEX128:
w = 16;
- t->align = widthptr;
+ t->align = widthreg;
break;
case TPTR32:
w = 4;
@@ -288,10 +288,10 @@ dowidth(Type *t)
// compute their widths as side-effect.
t1 = t->type;
w = widstruct(t->type, *getthis(t1), 0, 0);
- w = widstruct(t->type, *getinarg(t1), w, widthptr);
- w = widstruct(t->type, *getoutarg(t1), w, widthptr);
+ w = widstruct(t->type, *getinarg(t1), w, widthreg);
+ w = widstruct(t->type, *getoutarg(t1), w, widthreg);
t1->argwid = w;
- if(w%widthptr)
+ if(w%widthreg)
warn("bad type %T %d\n", t1, w);
t->align = 1;
break;
diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c
new file mode 100644
index 000000000..5e53c1ff0
--- /dev/null
+++ b/src/cmd/gc/array.c
@@ -0,0 +1,129 @@
+// 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 <u.h>
+#include <libc.h>
+#include "go.h"
+
+enum {
+ DEFAULTCAPACITY = 16,
+};
+
+struct Array
+{
+ int32 length; // number of elements
+ int32 size; // element size
+ int32 capacity; // size of data in elements
+ char *data; // element storage
+};
+
+Array*
+arraynew(int32 capacity, int32 size)
+{
+ Array *result;
+
+ if(capacity < 0)
+ fatal("arraynew: capacity %d is not positive", capacity);
+ if(size < 0)
+ fatal("arraynew: size %d is not positive\n", size);
+ result = malloc(sizeof(*result));
+ if(result == nil)
+ fatal("arraynew: malloc failed\n");
+ result->length = 0;
+ result->size = size;
+ result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity;
+ result->data = malloc(result->capacity * result->size);
+ if(result->data == nil)
+ fatal("arraynew: malloc failed\n");
+ return result;
+}
+
+void
+arrayfree(Array *array)
+{
+ if(array == nil)
+ return;
+ free(array->data);
+ free(array);
+}
+
+int32
+arraylength(Array *array)
+{
+ return array->length;
+}
+
+void*
+arrayget(Array *array, int32 index)
+{
+ if(array == nil)
+ fatal("arrayget: array is nil\n");
+ if(index < 0 || index >= array->length)
+ fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
+ return array->data + index * array->size;
+}
+
+void
+arrayset(Array *array, int32 index, void *element)
+{
+ if(array == nil)
+ fatal("arrayset: array is nil\n");
+ if(element == nil)
+ fatal("arrayset: element is nil\n");
+ if(index < 0 || index >= array->length)
+ fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
+ memmove(array->data + index * array->size, element, array->size);
+}
+
+static void
+ensurecapacity(Array *array, int32 capacity)
+{
+ int32 newcapacity;
+ char *newdata;
+
+ if(array == nil)
+ fatal("ensurecapacity: array is nil\n");
+ if(capacity < 0)
+ fatal("ensurecapacity: capacity %d is not positive", capacity);
+ if(capacity >= array->capacity) {
+ newcapacity = capacity + (capacity >> 1);
+ newdata = realloc(array->data, newcapacity * array->size);
+ if(newdata == nil)
+ fatal("ensurecapacity: realloc failed\n");
+ array->capacity = newcapacity;
+ array->data = newdata;
+ }
+}
+
+void
+arrayadd(Array *array, void *element)
+{
+ if(array == nil)
+ fatal("arrayset: array is nil\n");
+ if(element == nil)
+ fatal("arrayset: element is nil\n");
+ ensurecapacity(array, array->length + 1);
+ array->length++;
+ arrayset(array, array->length - 1, element);
+}
+
+int32
+arrayindexof(Array *array, void *element)
+{
+ void *p;
+ int32 i;
+
+ for(i = 0; i < array->length; i++) {
+ p = arrayget(array, i);
+ if(memcmp(p, &element, array->size) == 0)
+ return i;
+ }
+ return -1;
+}
+
+void
+arraysort(Array *array, int (*cmp)(const void*, const void*))
+{
+ qsort(array->data, array->length, array->size, cmp);
+}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
index c0fd4d85e..2e79f6f1d 100644
--- a/src/cmd/gc/bits.c
+++ b/src/cmd/gc/bits.c
@@ -153,7 +153,7 @@ Qconv(Fmt *fp)
if(var[i].node == N || var[i].node->sym == S)
fmtprint(fp, "$%d", i);
else {
- fmtprint(fp, "%s", var[i].node->sym->name);
+ fmtprint(fp, "%s(%d)", var[i].node->sym->name, i);
if(var[i].offset != 0)
fmtprint(fp, "%+lld", (vlong)var[i].offset);
}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index 309dc1ea0..5ca5aeb77 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -5,6 +5,7 @@ char *runtimeimport =
"func @\"\".new (@\"\".typ·2 *byte) (? *any)\n"
"func @\"\".panicindex ()\n"
"func @\"\".panicslice ()\n"
+ "func @\"\".panicdivide ()\n"
"func @\"\".throwreturn ()\n"
"func @\"\".throwinit ()\n"
"func @\"\".panicwrap (? string, ? string, ? string)\n"
@@ -23,11 +24,16 @@ char *runtimeimport =
"func @\"\".printnl ()\n"
"func @\"\".printsp ()\n"
"func @\"\".goprintf ()\n"
- "func @\"\".concatstring ()\n"
+ "func @\"\".concatstring2 (? string, ? string) (? string)\n"
+ "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n"
+ "func @\"\".concatstrings (? []string) (? string)\n"
"func @\"\".cmpstring (? string, ? string) (? int)\n"
"func @\"\".eqstring (? string, ? string) (? bool)\n"
"func @\"\".intstring (? int64) (? string)\n"
"func @\"\".slicebytetostring (? []byte) (? string)\n"
+ "func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
"func @\"\".slicerunetostring (? []rune) (? string)\n"
"func @\"\".stringtoslicebyte (? string) (? []byte)\n"
"func @\"\".stringtoslicerune (? string) (? []rune)\n"
@@ -38,8 +44,8 @@ char *runtimeimport =
"func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n"
"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n"
"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
- "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 any) (@\"\".ret·1 any)\n"
+ "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n"
+ "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n"
"func @\"\".assertE2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
"func @\"\".assertE2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
"func @\"\".assertE2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
@@ -60,26 +66,24 @@ char *runtimeimport =
"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
"func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n"
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
- "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 any)\n"
+ "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
- "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 any, @\"\".pres·2 bool)\n"
+ "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
- "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any, @\"\".val·4 any)\n"
+ "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n"
"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n"
- "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any)\n"
+ "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n"
"func @\"\".mapiternext (@\"\".hiter·1 *any)\n"
- "func @\"\".mapiter1 (@\"\".hiter·2 *any) (@\"\".key·1 any)\n"
- "func @\"\".mapiter2 (@\"\".hiter·3 *any) (@\"\".key·1 any, @\"\".val·2 any)\n"
"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n"
- "func @\"\".chanrecv1 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any) (@\"\".elem·1 any)\n"
- "func @\"\".chanrecv2 (@\"\".chanType·3 *byte, @\"\".hchan·4 <-chan any) (@\"\".elem·1 any, @\"\".received·2 bool)\n"
- "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 any)\n"
+ "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n"
+ "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n"
+ "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
"func @\"\".closechan (@\"\".hchan·1 any)\n"
- "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 any) (? bool)\n"
+ "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"
"func @\"\".newselect (@\"\".size·2 int32) (@\"\".sel·1 *byte)\n"
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
index 92834a97b..2efbbc565 100644
--- a/src/cmd/gc/bv.c
+++ b/src/cmd/gc/bv.c
@@ -11,12 +11,24 @@ enum {
WORDBITS = 32,
};
-uintptr
+static uintptr
bvsize(uintptr n)
{
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
}
+int32
+bvbits(Bvec *bv)
+{
+ return bv->n;
+}
+
+int32
+bvwords(Bvec *bv)
+{
+ return (bv->n + WORDBITS - 1) / WORDBITS;
+}
+
Bvec*
bvalloc(int32 n)
{
@@ -34,26 +46,49 @@ bvalloc(int32 n)
return bv;
}
+/* difference */
void
-bvset(Bvec *bv, int32 i)
+bvandnot(Bvec *dst, Bvec *src1, Bvec *src2)
{
- uint32 mask;
+ int32 i, w;
- if(i < 0 || i >= bv->n)
- fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
- mask = 1U << (i % WORDBITS);
- bv->b[i / WORDBITS] |= mask;
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvand: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] & ~src2->b[w];
+}
+
+int
+bvcmp(Bvec *bv1, Bvec *bv2)
+{
+ uintptr nbytes;
+
+ if(bv1->n != bv2->n)
+ fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n);
+ nbytes = bvsize(bv1->n);
+ return memcmp(bv1->b, bv2->b, nbytes);
}
void
-bvres(Bvec *bv, int32 i)
+bvcopy(Bvec *dst, Bvec *src)
{
- uint32 mask;
+ memmove(dst->b, src->b, bvsize(dst->n));
+}
- if(i < 0 || i >= bv->n)
- fatal("bvres: index %d is out of bounds with length %d\n", i, bv->n);
- mask = ~(1 << (i % WORDBITS));
- bv->b[i / WORDBITS] &= mask;
+Bvec*
+bvconcat(Bvec *src1, Bvec *src2)
+{
+ Bvec *dst;
+ int32 i;
+
+ dst = bvalloc(src1->n + src2->n);
+ for(i = 0; i < src1->n; i++)
+ if(bvget(src1, i))
+ bvset(dst, i);
+ for(i = 0; i < src2->n; i++)
+ if(bvget(src2, i))
+ bvset(dst, i + src1->n);
+ return dst;
}
int
@@ -63,7 +98,7 @@ bvget(Bvec *bv, int32 i)
if(i < 0 || i >= bv->n)
fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n);
- mask = 1 << (i % WORDBITS);
+ mask = 1U << (i % WORDBITS);
word = bv->b[i / WORDBITS] & mask;
return word ? 1 : 0;
}
@@ -78,3 +113,74 @@ bvisempty(Bvec *bv)
return 0;
return 1;
}
+
+void
+bvnot(Bvec *bv)
+{
+ int32 i, w;
+
+ for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++)
+ bv->b[w] = ~bv->b[w];
+}
+
+/* union */
+void
+bvor(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+ int32 i, w;
+
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] | src2->b[w];
+}
+
+/* intersection */
+void
+bvand(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+ int32 i, w;
+
+ if(dst->n != src1->n || dst->n != src2->n)
+ fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+ for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+ dst->b[w] = src1->b[w] & src2->b[w];
+}
+
+void
+bvprint(Bvec *bv)
+{
+ int32 i;
+
+ print("#*");
+ for(i = 0; i < bv->n; i++)
+ print("%d", bvget(bv, i));
+}
+
+void
+bvreset(Bvec *bv, int32 i)
+{
+ uint32 mask;
+
+ if(i < 0 || i >= bv->n)
+ fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n);
+ mask = ~(1 << (i % WORDBITS));
+ bv->b[i / WORDBITS] &= mask;
+}
+
+void
+bvresetall(Bvec *bv)
+{
+ memset(bv->b, 0x00, bvsize(bv->n));
+}
+
+void
+bvset(Bvec *bv, int32 i)
+{
+ uint32 mask;
+
+ if(i < 0 || i >= bv->n)
+ fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
+ mask = 1U << (i % WORDBITS);
+ bv->b[i / WORDBITS] |= mask;
+}
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 5a84dfb1b..ad4e5bd02 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -161,6 +161,7 @@ makeclosure(Node *func)
// and initialize in entry prologue.
body = nil;
offset = widthptr;
+ xfunc->needctxt = func->cvars != nil;
for(l=func->cvars; l; l=l->next) {
v = l->n;
if(v->op == 0)
@@ -252,6 +253,14 @@ walkclosure(Node *func, NodeList **init)
// typecheck will insert a PTRLIT node under CONVNOP,
// tag it with escape analysis result.
clos->left->esc = func->esc;
+ // non-escaping temp to use, if any.
+ // orderexpr did not compute the type; fill it in now.
+ if(func->alloc != N) {
+ func->alloc->type = clos->left->left->type;
+ func->alloc->orig->type = func->alloc->type;
+ clos->left->right = func->alloc;
+ func->alloc = N;
+ }
walkexpr(&clos, init);
return clos;
@@ -361,9 +370,12 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
// Declare and initialize variable holding receiver.
body = nil;
+ xfunc->needctxt = 1;
cv = nod(OCLOSUREVAR, N, N);
cv->xoffset = widthptr;
cv->type = rcvrtype;
+ if(cv->type->align > widthptr)
+ cv->xoffset = cv->type->align;
ptr = nod(ONAME, N, N);
ptr->sym = lookup("rcvr");
ptr->class = PAUTO;
@@ -441,6 +453,14 @@ walkpartialcall(Node *n, NodeList **init)
// typecheck will insert a PTRLIT node under CONVNOP,
// tag it with escape analysis result.
clos->left->esc = n->esc;
+ // non-escaping temp to use, if any.
+ // orderexpr did not compute the type; fill it in now.
+ if(n->alloc != N) {
+ n->alloc->type = clos->left->left->type;
+ n->alloc->orig->type = n->alloc->type;
+ clos->left->right = n->alloc;
+ n->alloc = N;
+ }
walkexpr(&clos, init);
return clos;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index cfb1f0ade..143c1730d 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -22,19 +22,22 @@ Mpflt*
truncfltlit(Mpflt *oldv, Type *t)
{
double d;
- float f;
Mpflt *fv;
+ Val v;
if(t == T)
return oldv;
+ memset(&v, 0, sizeof v);
+ v.ctype = CTFLT;
+ v.u.fval = oldv;
+ overflow(v, t);
+
fv = mal(sizeof *fv);
*fv = *oldv;
// convert large precision literal floating
// into limited precision (float64 or float32)
- // botch -- this assumes that compiler fp
- // has same precision as runtime fp
switch(t->etype) {
case TFLOAT64:
d = mpgetflt(fv);
@@ -42,10 +45,9 @@ truncfltlit(Mpflt *oldv, Type *t)
break;
case TFLOAT32:
- d = mpgetflt(fv);
- f = d;
- d = f;
+ d = mpgetflt32(fv);
mpmovecflt(fv, d);
+
break;
}
return fv;
@@ -235,7 +237,6 @@ convlit1(Node **np, Type *t, int explicit)
n->val = toflt(n->val);
// flowthrough
case CTFLT:
- overflow(n->val, t);
n->val.u.fval = truncfltlit(n->val.u.fval, t);
break;
}
@@ -521,6 +522,7 @@ evconst(Node *n)
int wl, wr, lno, et;
Val v, rv;
Mpint b;
+ NodeList *l1, *l2;
// pick off just the opcodes that can be
// constant evaluated.
@@ -528,7 +530,6 @@ evconst(Node *n)
default:
return;
case OADD:
- case OADDSTR:
case OAND:
case OANDAND:
case OANDNOT:
@@ -559,6 +560,47 @@ evconst(Node *n)
if(!okforconst[n->type->etype] && n->type->etype != TNIL)
return;
break;
+
+ case OADDSTR:
+ // merge adjacent constants in the argument list.
+ for(l1=n->list; l1 != nil; l1= l1->next) {
+ if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) {
+ l2 = l1;
+ len = 0;
+ while(l2 != nil && isconst(l2->n, CTSTR)) {
+ nr = l2->n;
+ len += nr->val.u.sval->len;
+ l2 = l2->next;
+ }
+ // merge from l1 up to but not including l2
+ str = mal(sizeof(*str) + len);
+ str->len = len;
+ len = 0;
+ l2 = l1;
+ while(l2 != nil && isconst(l2->n, CTSTR)) {
+ nr = l2->n;
+ memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len);
+ len += nr->val.u.sval->len;
+ l2 = l2->next;
+ }
+ nl = nod(OXXX, N, N);
+ *nl = *l1->n;
+ nl->orig = nl;
+ nl->val.ctype = CTSTR;
+ nl->val.u.sval = str;
+ l1->n = nl;
+ l1->next = l2;
+ }
+ }
+ // fix list end pointer.
+ for(l2=n->list; l2 != nil; l2=l2->next)
+ n->list->end = l2;
+ // collapse single-constant list to single constant.
+ if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) {
+ n->op = OLITERAL;
+ n->val = n->list->n->val;
+ }
+ return;
}
nl = n->left;
@@ -861,15 +903,6 @@ evconst(Node *n)
if(cmpslit(nl, nr) > 0)
goto settrue;
goto setfalse;
- case TUP(OADDSTR, CTSTR):
- len = v.u.sval->len + rv.u.sval->len;
- str = mal(sizeof(*str) + len);
- str->len = len;
- memcpy(str->s, v.u.sval->s, v.u.sval->len);
- memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
- str->len = len;
- v.u.sval = str;
- break;
case TUP(OOROR, CTBOOL):
if(v.u.bval || rv.u.bval)
@@ -918,6 +951,7 @@ unary:
case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR):
convlit1(&nl, n->type, 1);
+ v = nl->val;
break;
case TUP(OPLUS, CTINT):
@@ -1144,7 +1178,10 @@ defaultlit(Node **np, Type *t)
}
if(n->val.ctype == CTNIL) {
lineno = lno;
- yyerror("use of untyped nil");
+ if(!n->diag) {
+ yyerror("use of untyped nil");
+ n->diag = 1;
+ }
n->type = T;
break;
}
@@ -1559,7 +1596,7 @@ isgoconst(Node *n)
case ONAME:
l = n->sym->def;
- if(l->op == OLITERAL && n->val.ctype != CTNIL)
+ if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
return 1;
break;
@@ -1594,10 +1631,25 @@ hascallchan(Node *n)
if(n == N)
return 0;
switch(n->op) {
+ case OAPPEND:
case OCALL:
case OCALLFUNC:
- case OCALLMETH:
case OCALLINTER:
+ case OCALLMETH:
+ case OCAP:
+ case OCLOSE:
+ case OCOMPLEX:
+ case OCOPY:
+ case ODELETE:
+ case OIMAG:
+ case OLEN:
+ case OMAKE:
+ case ONEW:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ case OREAL:
+ case ORECOVER:
case ORECV:
return 1;
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index c7d13ef06..73c2581be 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -130,7 +130,7 @@ dumpdcl(char *st)
}
print(" '%s'", d->name);
s = pkglookup(d->name, d->pkg);
- print(" %lS\n", s);
+ print(" %S\n", s);
}
}
@@ -643,8 +643,8 @@ funcargs(Node *nt)
fatal("funcargs out %O", n->op);
if(n->left == N) {
- // give it a name so escape analysis has nodes to work with
- snprint(namebuf, sizeof(namebuf), "~anon%d", gen++);
+ // Name so that escape analysis can track it. ~r stands for 'result'.
+ snprint(namebuf, sizeof(namebuf), "~r%d", gen++);
n->left = newname(lookup(namebuf));
// TODO: n->left->missing = 1;
}
@@ -652,14 +652,20 @@ funcargs(Node *nt)
n->left->op = ONAME;
if(isblank(n->left)) {
- // Give it a name so we can assign to it during return.
- // preserve the original in ->orig
+ // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+ // The name must be different from ~r above because if you have
+ // func f() (_ int)
+ // func g() int
+ // f is allowed to use a plain 'return' with no arguments, while g is not.
+ // So the two cases must be distinguished.
+ // We do not record a pointer to the original node (n->orig).
+ // Having multiple names causes too much confusion in later passes.
nn = nod(OXXX, N, N);
*nn = *n->left;
+ nn->orig = nn;
+ snprint(namebuf, sizeof(namebuf), "~b%d", gen++);
+ nn->sym = lookup(namebuf);
n->left = nn;
-
- snprint(namebuf, sizeof(namebuf), "~anon%d", gen++);
- n->left->sym = lookup(namebuf);
}
n->left->ntype = n->right;
@@ -941,8 +947,6 @@ interfacefield(Node *n)
f->nname = n->left;
f->embedded = n->embedded;
f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
}
} else {
@@ -1211,7 +1215,7 @@ functype(Node *this, NodeList *in, NodeList *out)
t->outnamed = 0;
if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) {
s = out->n->left->orig->sym;
- if(s != S && s->name[0] != '~')
+ if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
t->outnamed = 1;
}
@@ -1434,6 +1438,8 @@ funccompile(Node *n, int isclosure)
// record offset to actual frame pointer.
// for closure, have to skip over leading pointers and PC slot.
+ // TODO(rsc): this is the old jit closure handling code.
+ // with the new closures, isclosure is always 0; delete this block.
nodfp->xoffset = 0;
if(isclosure) {
NodeList *l;
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 791967708..03df93a3e 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -37,6 +37,8 @@ Substitute 6g with 8g or 5g where appropriate.
Flags:
-o file
output file, default file.6 for 6g, etc.
+ -pack
+ write an archive file rather than an object file
-e
normally the compiler quits after 10 errors; -e prints all errors
-p path
@@ -50,12 +52,14 @@ Flags:
add dir1 and dir2 to the list of paths to check for imported packages
-N
disable optimizations
+ -nolocalimports
+ disallow local (relative) imports
-S
write assembly language text to standard output (code only)
-S -S
write assembly language text to standard output (code and data)
-u
- disallow importing packages not marked as safe
+ disallow importing packages not marked as safe; implies -nolocalimports
-V
print the compiler version
-race
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index b84b66ef1..78624d7cb 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -185,12 +185,12 @@ visitcode(Node *n, uint32 min)
typedef struct EscState EscState;
static void escfunc(EscState*, Node *func);
-static void esclist(EscState*, NodeList *l);
-static void esc(EscState*, Node *n);
+static void esclist(EscState*, NodeList *l, Node *up);
+static void esc(EscState*, Node *n, Node *up);
static void escloopdepthlist(EscState*, NodeList *l);
static void escloopdepth(EscState*, Node *n);
static void escassign(EscState*, Node *dst, Node *src);
-static void esccall(EscState*, Node*);
+static void esccall(EscState*, Node*, Node *up);
static void escflows(EscState*, Node *dst, Node *src);
static void escflood(EscState*, Node *dst);
static void escwalk(EscState*, int level, Node *dst, Node *src);
@@ -204,6 +204,13 @@ struct EscState {
// flow to.
Node theSink;
+ // If an analyzed function is recorded to return
+ // pieces obtained via indirection from a parameter,
+ // and later there is a call f(x) to that function,
+ // we create a link funcParam <- x to record that fact.
+ // The funcParam node is handled specially in escflood.
+ Node funcParam;
+
NodeList* dsts; // all dst nodes
int loopdepth; // for detecting nested loop scopes
int pdepth; // for debug printing in recursions.
@@ -269,7 +276,13 @@ analyze(NodeList *all, int recursive)
e->theSink.sym = lookup(".sink");
e->theSink.escloopdepth = -1;
e->recursive = recursive;
-
+
+ e->funcParam.op = ONAME;
+ e->funcParam.orig = &e->funcParam;
+ e->funcParam.class = PAUTO;
+ e->funcParam.sym = lookup(".param");
+ e->funcParam.escloopdepth = 10000000;
+
for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC)
l->n->esc = EscFuncPlanned;
@@ -328,6 +341,7 @@ escfunc(EscState *e, Node *func)
ll->n->escloopdepth = 0;
break;
case PPARAM:
+ ll->n->escloopdepth = 1;
if(ll->n->type && !haspointers(ll->n->type))
break;
if(curfn->nbody == nil && !curfn->noescape)
@@ -335,7 +349,6 @@ escfunc(EscState *e, Node *func)
else
ll->n->esc = EscNone; // prime for escflood later
e->noesc = list(e->noesc, ll->n);
- ll->n->escloopdepth = 1;
break;
}
}
@@ -347,7 +360,7 @@ escfunc(EscState *e, Node *func)
escflows(e, &e->theSink, ll->n);
escloopdepthlist(e, curfn->nbody);
- esclist(e, curfn->nbody);
+ esclist(e, curfn->nbody, curfn);
curfn = savefn;
e->loopdepth = saveld;
}
@@ -405,14 +418,14 @@ escloopdepth(EscState *e, Node *n)
}
static void
-esclist(EscState *e, NodeList *l)
+esclist(EscState *e, NodeList *l, Node *up)
{
for(; l; l=l->next)
- esc(e, l->n);
+ esc(e, l->n, up);
}
static void
-esc(EscState *e, Node *n)
+esc(EscState *e, Node *n, Node *up)
{
int lno;
NodeList *ll, *lr;
@@ -423,18 +436,32 @@ esc(EscState *e, Node *n)
lno = setlineno(n);
+ // ninit logically runs at a different loopdepth than the rest of the for loop.
+ esclist(e, n->ninit, n);
+
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth++;
- esc(e, n->left);
- esc(e, n->right);
- esc(e, n->ntest);
- esc(e, n->nincr);
- esclist(e, n->ninit);
- esclist(e, n->nbody);
- esclist(e, n->nelse);
- esclist(e, n->list);
- esclist(e, n->rlist);
+ // type switch variables have no ODCL.
+ // process type switch as declaration.
+ // must happen before processing of switch body,
+ // so before recursion.
+ if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
+ for(ll=n->list; ll; ll=ll->next) { // cases
+ // ll->n->nname is the variable per case
+ if(ll->n->nname)
+ ll->n->nname->escloopdepth = e->loopdepth;
+ }
+ }
+
+ esc(e, n->left, n);
+ esc(e, n->right, n);
+ esc(e, n->ntest, n);
+ esc(e, n->nincr, n);
+ esclist(e, n->nbody, n);
+ esclist(e, n->nelse, n);
+ esclist(e, n->list, n);
+ esclist(e, n->rlist, n);
if(n->op == OFOR || n->op == ORANGE)
e->loopdepth--;
@@ -520,7 +547,7 @@ esc(EscState *e, Node *n)
case OCALLMETH:
case OCALLFUNC:
case OCALLINTER:
- esccall(e, n);
+ esccall(e, n, up);
break;
case OAS2FUNC: // x,y = f()
@@ -628,7 +655,6 @@ esc(EscState *e, Node *n)
escassign(e, n, a);
}
// fallthrough
- case OADDR:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
@@ -637,6 +663,35 @@ esc(EscState *e, Node *n)
n->esc = EscNone; // until proven otherwise
e->noesc = list(e->noesc, n);
break;
+
+ case OADDR:
+ n->esc = EscNone; // until proven otherwise
+ e->noesc = list(e->noesc, n);
+ // current loop depth is an upper bound on actual loop depth
+ // of addressed value.
+ n->escloopdepth = e->loopdepth;
+ // for &x, use loop depth of x if known.
+ // it should always be known, but if not, be conservative
+ // and keep the current loop depth.
+ if(n->left->op == ONAME) {
+ switch(n->left->class) {
+ case PAUTO:
+ if(n->left->escloopdepth != 0)
+ n->escloopdepth = n->left->escloopdepth;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ // PPARAM is loop depth 1 always.
+ // PPARAMOUT is loop depth 0 for writes
+ // but considered loop depth 1 for address-of,
+ // so that writing the address of one result
+ // to another (or the same) result makes the
+ // first result move to the heap.
+ n->escloopdepth = 1;
+ break;
+ }
+ }
+ break;
}
lineno = lno;
@@ -748,8 +803,8 @@ escassign(EscState *e, Node *dst, Node *src)
case ODOTTYPE:
case ODOTTYPE2:
case OSLICE:
- case OSLICEARR:
case OSLICE3:
+ case OSLICEARR:
case OSLICE3ARR:
// Conversions, field access, slice all preserve the input value.
escassign(e, dst, src->left);
@@ -792,24 +847,34 @@ escassign(EscState *e, Node *dst, Node *src)
lineno = lno;
}
-static void
+static int
escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
{
- int em;
+ int em, em0;
em = parsetag(note);
-
+
if(em == EscUnknown) {
escassign(e, &e->theSink, src);
- return;
+ return em;
}
-
- for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next)
+
+ if(em == EscNone)
+ return em;
+
+ // If content inside parameter (reached via indirection)
+ // escapes back to results, mark as such.
+ if(em & EscContentEscapes)
+ escassign(e, &e->funcParam, src);
+
+ em0 = em;
+ for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next)
if(em & 1)
escassign(e, dsts->n, src);
if (em != 0 && dsts == nil)
fatal("corrupt esc tag %Z or messed up escretval list\n", note);
+ return em0;
}
// This is a bit messier than fortunate, pulled out of esc's big
@@ -819,7 +884,7 @@ escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
// different for methods vs plain functions and for imported vs
// this-package
static void
-esccall(EscState *e, Node *n)
+esccall(EscState *e, Node *n, Node *up)
{
NodeList *ll, *lr;
Node *a, *fn, *src;
@@ -856,7 +921,7 @@ esccall(EscState *e, Node *n)
if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
ll = a->escretval;
}
-
+
if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
// function in same mutually recursive group. Incorporate into flow graph.
// print("esc local fn: %N\n", fn->ntype);
@@ -876,6 +941,10 @@ esccall(EscState *e, Node *n)
if(lr->n->isddd && !n->isddd) {
// Introduce ODDDARG node to represent ... allocation.
src = nod(ODDDARG, N, N);
+ src->type = typ(TARRAY);
+ src->type->type = lr->n->type->type;
+ src->type->bound = count(ll);
+ src->type = ptrto(src->type); // make pointer so it will be tracked
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
src->esc = EscNone; // until we find otherwise
@@ -916,8 +985,12 @@ esccall(EscState *e, Node *n)
// print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
// Receiver.
- if(n->op != OCALLFUNC)
- escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left);
+ if(n->op != OCALLFUNC) {
+ t = getthisx(fntype)->type;
+ src = n->left->left;
+ if(haspointers(t->type))
+ escassignfromtag(e, t->note, n->escretval, src);
+ }
for(t=getinargx(fntype)->type; ll; ll=ll->next) {
src = ll->n;
@@ -926,11 +999,40 @@ esccall(EscState *e, Node *n)
src = nod(ODDDARG, N, N);
src->escloopdepth = e->loopdepth;
src->lineno = n->lineno;
+ src->type = typ(TARRAY);
+ src->type->type = t->type->type;
+ src->type->bound = count(ll);
+ src->type = ptrto(src->type); // make pointer so it will be tracked
src->esc = EscNone; // until we find otherwise
e->noesc = list(e->noesc, src);
n->right = src;
}
- escassignfromtag(e, t->note, n->escretval, src);
+ if(haspointers(t->type)) {
+ if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) {
+ a = src;
+ while(a->op == OCONVNOP)
+ a = a->left;
+ switch(a->op) {
+ case OCALLPART:
+ case OCLOSURE:
+ case ODDDARG:
+ case OARRAYLIT:
+ case OPTRLIT:
+ case OSTRUCTLIT:
+ // The callee has already been analyzed, so its arguments have esc tags.
+ // The argument is marked as not escaping at all.
+ // Record that fact so that any temporary used for
+ // synthesizing this expression can be reclaimed when
+ // the function returns.
+ // This 'noescape' is even stronger than the usual esc == EscNone.
+ // src->esc == EscNone means that src does not escape the current function.
+ // src->noescape = 1 here means that src does not escape this statement
+ // in the current function.
+ a->noescape = 1;
+ break;
+ }
+ }
+ }
if(src != ll->n)
break;
t = t->down;
@@ -1029,19 +1131,30 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
// Input parameter flowing to output parameter?
if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
- if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) {
- if(src->esc != EscScope && src->esc != EscHeap) {
+ if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) {
+ if(level == 0) {
if(debug['m'])
warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
if((src->esc&EscMask) != EscReturn)
src->esc = EscReturn;
- src->esc |= 1<<((dst->vargen-1) + EscBits);
+ src->esc |= 1<<((dst->vargen-1) + EscReturnBits);
+ goto recurse;
+ } else if(level > 0) {
+ if(debug['m'])
+ warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym);
+ if((src->esc&EscMask) != EscReturn)
+ src->esc = EscReturn;
+ src->esc |= EscContentEscapes;
goto recurse;
}
}
}
- leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
+ // The second clause is for values pointed at by an object passed to a call
+ // that returns something reached via indirect from the object.
+ // We don't know which result it is or how many indirects, so we treat it as leaking.
+ leaks = level <= 0 && dst->escloopdepth < src->escloopdepth ||
+ level < 0 && dst == &e->funcParam && haspointers(src->type);
switch(src->op) {
case ONAME:
@@ -1094,6 +1207,10 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
break;
case ODOT:
+ case OSLICE:
+ case OSLICEARR:
+ case OSLICE3:
+ case OSLICE3ARR:
escwalk(e, level, dst, src->left);
break;
@@ -1103,7 +1220,6 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
break;
}
// fall through
- case OSLICE:
case ODOTPTR:
case OINDEXMAP:
case OIND:
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 31bcdf8e7..da5984ceb 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -354,7 +354,7 @@ dumpexport(void)
lno = lineno;
- Bprint(bout, "\n$$ // exports\n package %s", localpkg->name);
+ Bprint(bout, "\n$$\npackage %s", localpkg->name);
if(safemode)
Bprint(bout, " safe");
Bprint(bout, "\n");
@@ -369,8 +369,7 @@ dumpexport(void)
dumpsym(l->n->sym);
}
- Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c)
-
+ Bprint(bout, "\n$$\n");
lineno = lno;
}
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index 9cd344870..b5f8a834f 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -17,7 +17,7 @@
// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
//
// %J Node* Node details
-// Flags: "%hJ" supresses things not relevant until walk.
+// Flags: "%hJ" suppresses things not relevant until walk.
//
// %V Val* Constant values
//
@@ -102,75 +102,7 @@ setfmode(unsigned long *flags)
static int
Lconv(Fmt *fp)
{
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 lno, d;
- int i, n;
- Hist *h;
-
- lno = va_arg(fp->args, int32);
-
- n = 0;
- for(h=hist; h!=H; h=h->link) {
- if(h->offset < 0)
- continue;
- if(lno < h->line)
- break;
- if(h->name) {
- if(h->offset > 0) {
- // #line directive
- if(n > 0 && n < HISTSZ) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- // beginning of file
- if(n < HISTSZ) {
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
-
- if(n > HISTSZ)
- n = HISTSZ;
-
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec))
- break;
- fmtprint(fp, " ");
- }
- if(debug['L'] || (fp->flags&FmtLong))
- fmtprint(fp, "%s/", pathname);
- if(a[i].line)
- fmtprint(fp, "%s:%d[%s:%d]",
- a[i].line->name, lno-a[i].ldel+1,
- a[i].incl->name, lno-a[i].idel+1);
- else
- fmtprint(fp, "%s:%d",
- a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; // now print out start of this file
- }
- if(n == 0)
- fmtprint(fp, "<unknown line number>");
-
- return 0;
+ return linklinefmt(ctxt, fp);
}
static char*
@@ -702,9 +634,17 @@ typefmt(Fmt *fp, Type *t)
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->map != T) {
+ if(t->map->bucket == t) {
+ return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type);
+ }
+ if(t->map->hmap == t) {
+ return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type);
+ }
+ if(t->map->hiter == t) {
+ return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type);
+ }
+ yyerror("unknown internal map type");
}
if(t->funarg) {
@@ -738,12 +678,17 @@ typefmt(Fmt *fp, Type *t)
if(!(fp->flags&FmtShort)) {
s = t->sym;
- // Take the name from the original, lest we substituted it with ~anon%d
+ // Take the name from the original, lest we substituted it with ~r%d or ~b%d.
+ // ~r%d is a (formerly) unnamed result.
if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) {
if(t->nname->orig != N) {
s = t->nname->orig->sym;
- if(s != S && s->name[0] == '~')
- s = S;
+ if(s != S && s->name[0] == '~') {
+ if(s->name[1] == 'r') // originally an unnamed result
+ s = S;
+ else if(s->name[1] == 'b') // originally the blank identifier _
+ s = lookup("_");
+ }
} else
s = S;
}
@@ -1099,6 +1044,7 @@ static int opprec[] = {
[OEMPTY] = -1,
[OFALL] = -1,
[OFOR] = -1,
+ [OGOTO] = -1,
[OIF] = -1,
[OLABEL] = -1,
[OPROC] = -1,
@@ -1163,7 +1109,10 @@ exprfmt(Fmt *f, Node *n, int prec)
case PAUTO:
case PPARAM:
case PPARAMOUT:
- if(fmtmode == FExp && n->sym && !isblanksym(n->sym) && n->vargen > 0)
+ // _ becomes ~b%d internally; print as _ for export
+ if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
+ return fmtprint(f, "_");
+ if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
return fmtprint(f, "%S·%d", n->sym, n->vargen);
}
@@ -1390,7 +1339,6 @@ exprfmt(Fmt *f, Node *n, int prec)
// Binary
case OADD:
- case OADDSTR:
case OAND:
case OANDAND:
case OANDNOT:
@@ -1415,6 +1363,14 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->right, nprec+1);
return 0;
+ case OADDSTR:
+ for(l=n->list; l; l=l->next) {
+ if(l != n->list)
+ fmtprint(f, " + ");
+ exprfmt(f, l->n, nprec);
+ }
+ return 0;
+
case OCMPSTR:
case OCMPIFACE:
exprfmt(f, n->left, nprec);
@@ -1572,6 +1528,9 @@ Sconv(Fmt *fp)
int r, sm;
unsigned long sf;
+ if(fp->flags&FmtLong)
+ return linksymfmt(fp);
+
s = va_arg(fp->args, Sym*);
if(s == S)
return fmtstrcpy(fp, "<S>");
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index ada16eacc..cf630f348 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -301,6 +301,9 @@ gen(Node *n)
break;
case OLABEL:
+ if(isblanksym(n->left->sym))
+ break;
+
lab = newlab(n);
// if there are pending gotos, resolve them all to the current pc.
@@ -495,6 +498,11 @@ gen(Node *n)
case OCHECKNIL:
cgen_checknil(n->left);
+ break;
+
+ case OVARKILL:
+ gvarkill(n->left);
+ break;
}
ret:
@@ -562,8 +570,7 @@ cgen_proc(Node *n, int proc)
/*
* generate declaration.
- * nothing to do for on-stack automatics,
- * but might have to allocate heap copy
+ * have to allocate heap copy
* for escaped variables.
*/
static void
@@ -739,6 +746,8 @@ cgen_as(Node *nl, Node *nr)
if(tl == T)
return;
if(isfat(tl)) {
+ if(nl->op == ONAME)
+ gvardef(nl);
clearfat(nl);
return;
}
@@ -767,10 +776,18 @@ cgen_eface(Node *n, Node *res)
* so it's important that it is done first
*/
Node dst;
+ Node *tmp;
+
+ tmp = temp(types[tptr]);
+ cgen(n->right, tmp);
+
+ gvardef(res);
+
dst = *res;
dst.type = types[tptr];
dst.xoffset += widthptr;
- cgen(n->right, &dst);
+ cgen(tmp, &dst);
+
dst.xoffset -= widthptr;
cgen(n->left, &dst);
}
@@ -787,7 +804,7 @@ cgen_eface(Node *n, Node *res)
void
cgen_slice(Node *n, Node *res)
{
- Node src, dst, *cap, *len, *offs, *add;
+ Node src, dst, *cap, *len, *offs, *add, *base;
cap = n->list->n;
len = n->list->next->n;
@@ -795,24 +812,15 @@ cgen_slice(Node *n, Node *res)
if(n->list->next->next)
offs = n->list->next->next->n;
- // dst.len = hi [ - lo ]
- dst = *res;
- dst.xoffset += Array_nel;
- dst.type = types[simtype[TUINT]];
- cgen(len, &dst);
-
- if(n->op != OSLICESTR) {
- // dst.cap = cap [ - lo ]
- dst = *res;
- dst.xoffset += Array_cap;
- dst.type = types[simtype[TUINT]];
- cgen(cap, &dst);
- }
-
- // dst.array = src.array [ + lo *width ]
- dst = *res;
- dst.xoffset += Array_array;
- dst.type = types[TUINTPTR];
+ // evaluate base pointer first, because it is the only
+ // possibly complex expression. once that is evaluated
+ // and stored, updating the len and cap can be done
+ // without making any calls, so without doing anything that
+ // might cause preemption or garbage collection.
+ // this makes the whole slice update atomic as far as the
+ // garbage collector can see.
+
+ base = temp(types[TUINTPTR]);
if(isnil(n->left)) {
tempname(&src, n->left->type);
@@ -821,24 +829,49 @@ cgen_slice(Node *n, Node *res)
src = *n->left;
if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
src.xoffset += Array_array;
- src.type = types[TUINTPTR];
if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
if(!isptr[n->left->type->etype])
fatal("slicearr is supposed to work on pointer: %+N\n", n);
- cgen(&src, &dst);
- cgen_checknil(&dst);
+ cgen(&src, base);
+ cgen_checknil(base);
if(offs != N) {
- add = nod(OADD, &dst, offs);
+ add = nod(OADD, base, offs);
typecheck(&add, Erv);
- cgen(add, &dst);
+ cgen(add, base);
}
} else if(offs == N) {
- cgen(&src, &dst);
+ src.type = types[tptr];
+ cgen(&src, base);
} else {
- add = nod(OADD, &src, offs);
+ src.type = types[tptr];
+ add = nod(OADDPTR, &src, offs);
typecheck(&add, Erv);
- cgen(add, &dst);
+ cgen(add, base);
+ }
+
+ // committed to the update
+ gvardef(res);
+
+ // dst.array = src.array [ + lo *width ]
+ dst = *res;
+ dst.xoffset += Array_array;
+ dst.type = types[tptr];
+
+ cgen(base, &dst);
+
+ // dst.len = hi [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_nel;
+ dst.type = types[simtype[TUINT]];
+ cgen(len, &dst);
+
+ if(n->op != OSLICESTR) {
+ // dst.cap = cap [ - lo ]
+ dst = *res;
+ dst.xoffset += Array_cap;
+ dst.type = types[simtype[TUINT]];
+ cgen(cap, &dst);
}
}
@@ -935,5 +968,5 @@ temp(Type *t)
n = nod(OXXX, N, N);
tempname(n, t);
n->sym->def->used = 1;
- return n;
+ return n->orig;
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 562f16890..413e71069 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include <bio.h>
+#include <link.h>
#undef OAPPEND
@@ -31,7 +32,6 @@ enum
STRINGSZ = 200,
MAXALIGN = 7,
UINF = 100,
- HISTSZ = 10,
PRIME1 = 3,
@@ -129,6 +129,10 @@ struct Val
} u;
};
+// prevent incompatible type signatures between libgc and 8g on Plan 9
+#pragma incomplete struct Array
+
+typedef struct Array Array;
typedef struct Bvec Bvec;
typedef struct Pkg Pkg;
typedef struct Sym Sym;
@@ -190,6 +194,8 @@ struct Type
// TMAP
Type* bucket; // internal type representing a hash bucket
Type* hmap; // internal type representing a Hmap (map header object)
+ Type* hiter; // internal type representing hash iterator state
+ Type* map; // link from the above 3 internal types back to the map type.
int32 maplineno; // first use of TFORW as map key
int32 embedlineno; // first use of TFORW as embedded type
@@ -230,8 +236,10 @@ enum
EscNone,
EscReturn,
EscNever,
- EscBits = 4,
+ EscBits = 3,
EscMask = (1<<EscBits) - 1,
+ EscContentEscapes = 1<<EscBits, // value obtained by indirect of parameter escapes to some returned result
+ EscReturnBits = EscBits+1,
};
struct Node
@@ -277,6 +285,7 @@ struct Node
schar likely; // likeliness of if statement
uchar hasbreak; // has break statement
uchar needzero; // if it contains pointers, needs to be zeroed on function entry
+ uchar needctxt; // function uses context register (has closure variables)
uint esc; // EscXXX
int funcdepth;
@@ -392,6 +401,7 @@ struct Sym
int32 block; // blocknumber to catch redeclaration
int32 lastlineno; // last declaration for diagnostic
Pkg* origpkg; // original package for . import
+ LSym* lsym;
};
#define S ((Sym*)0)
@@ -420,16 +430,6 @@ struct Iter
Node* n;
};
-typedef struct Hist Hist;
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
// Node ops.
enum
{
@@ -447,11 +447,13 @@ enum
OSUB, // x - y
OOR, // x | y
OXOR, // x ^ y
+ OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
OADDSTR, // s + "foo"
OADDR, // &x
OANDAND, // b0 && b1
OAPPEND, // append
OARRAYBYTESTR, // string(bytes)
+ OARRAYBYTESTRTMP, // string(bytes) ephemeral
OARRAYRUNESTR, // string(runes)
OSTRARRAYBYTE, // []byte(s)
OSTRARRAYRUNE, // []rune(s)
@@ -506,7 +508,7 @@ enum
OKEY, // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
OPARAM, // The on-stack copy of a parameter or return value that escapes.
OLEN, // len
- OMAKE, // make, typechecking may convert to a more specfic OMAKEXXX.
+ OMAKE, // make, typechecking may convert to a more specific OMAKEXXX.
OMAKECHAN, // make(chan int)
OMAKEMAP, // make(map[string]int)
OMAKESLICE, // make([]int, 0)
@@ -528,7 +530,7 @@ enum
OPRINTN, // println
OPAREN, // (x)
OSEND, // c <- x
- OSLICE, // v[1:2], typechecking may convert to a more specfic OSLICEXXX.
+ OSLICE, // v[1:2], typechecking may convert to a more specific OSLICEXXX.
OSLICEARR, // a[1:2]
OSLICESTR, // s[1:2]
OSLICE3, // v[1:2:3], typechecking may convert to OSLICE3ARR.
@@ -583,6 +585,7 @@ enum
OCLOSUREVAR, // variable reference at beginning of closure function
OCFUNC, // reference to c function pointer (not go func value)
OCHECKNIL, // emit code to ensure pointer/interface not nil
+ OVARKILL, // variable is dead
// arch-specific registers
OREGISTER, // a register, such as AX.
@@ -724,6 +727,7 @@ struct Var
{
vlong offset;
Node* node;
+ Var* nextinnode;
int width;
char name;
char etype;
@@ -804,9 +808,6 @@ struct Magic
int ua; // output - adder
};
-typedef struct Prog Prog;
-#pragma incomplete Prog
-
struct Label
{
uchar used;
@@ -859,9 +860,6 @@ EXTERN Io pushedio;
EXTERN int32 lexlineno;
EXTERN int32 lineno;
EXTERN int32 prevlineno;
-EXTERN char* pathname;
-EXTERN Hist* hist;
-EXTERN Hist* ehist;
EXTERN char* infile;
EXTERN char* outfile;
@@ -870,6 +868,7 @@ EXTERN int nerrors;
EXTERN int nsavederrors;
EXTERN int nsyntaxerrors;
EXTERN int safemode;
+EXTERN int nolocalimports;
EXTERN char namebuf[NSYMB];
EXTERN char lexbuf[NSYMB];
EXTERN char litbuf[NSYMB];
@@ -950,7 +949,6 @@ EXTERN Node* lasttype;
EXTERN vlong maxarg;
EXTERN vlong stksize; // stack size for current frame
EXTERN vlong stkptrsize; // prefix of stack containing pointers
-EXTERN vlong stkzerosize; // prefix of stack that must be zeroed on entry
EXTERN int32 blockgen; // max block number
EXTERN int32 block; // current block number
EXTERN int hasdefer; // flag that curfn has defer statetment
@@ -959,12 +957,14 @@ EXTERN Node* curfn;
EXTERN int widthptr;
EXTERN int widthint;
+EXTERN int widthreg;
EXTERN Node* typesw;
EXTERN Node* nblank;
extern int thechar;
extern char* thestring;
+extern LinkArch* thelinkarch;
EXTERN int use_sse;
EXTERN char* hunk;
@@ -980,10 +980,17 @@ EXTERN char* flag_installsuffix;
EXTERN int flag_race;
EXTERN int flag_largemodel;
EXTERN int noescape;
+EXTERN int debuglive;
+EXTERN Link* ctxt;
EXTERN int nointerface;
EXTERN int fieldtrack_enabled;
EXTERN int precisestack_enabled;
+EXTERN int writearchive;
+
+EXTERN Biobuf bstdout;
+
+EXTERN int nacl;
/*
* y.tab.c
@@ -1002,6 +1009,18 @@ vlong rnd(vlong o, vlong r);
void typeinit(void);
/*
+ * array.c
+ */
+Array* arraynew(int32 capacity, int32 size);
+void arrayfree(Array *array);
+int32 arraylength(Array *array);
+void* arrayget(Array *array, int32 index);
+void arrayset(Array *array, int32 index, void *element);
+void arrayadd(Array *array, void *element);
+int32 arrayindexof(Array* array, void *element);
+void arraysort(Array* array, int (*cmp)(const void*, const void*));
+
+/*
* bits.c
*/
int Qconv(Fmt *fp);
@@ -1019,11 +1038,19 @@ int bset(Bits a, uint n);
* bv.c
*/
Bvec* bvalloc(int32 n);
-void bvset(Bvec *bv, int32 i);
-void bvres(Bvec *bv, int32 i);
+void bvandnot(Bvec *dst, Bvec *src1, Bvec *src2);
+int bvcmp(Bvec *bv1, Bvec *bv2);
+void bvcopy(Bvec *dst, Bvec *src);
+Bvec* bvconcat(Bvec *src1, Bvec *src2);
int bvget(Bvec *bv, int32 i);
int bvisempty(Bvec *bv);
-int bvcmp(Bvec *bv1, Bvec *bv2);
+void bvnot(Bvec *bv);
+void bvor(Bvec *dst, Bvec *src1, Bvec *src2);
+void bvand(Bvec *dst, Bvec *src1, Bvec *src2);
+void bvprint(Bvec *bv);
+void bvreset(Bvec *bv, int32 i);
+void bvresetall(Bvec *bv);
+void bvset(Bvec *bv, int32 i);
/*
* closure.c
@@ -1173,7 +1200,6 @@ char* expstring(void);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);
-extern int windows;
extern int yylast;
extern int yyprev;
@@ -1230,17 +1256,19 @@ void mpxorfixfix(Mpint *a, Mpint *b);
void mpaddfltflt(Mpflt *a, Mpflt *b);
void mpdivfltflt(Mpflt *a, Mpflt *b);
double mpgetflt(Mpflt *a);
+double mpgetflt32(Mpflt *a);
void mpmovecflt(Mpflt *a, double c);
void mpmulfltflt(Mpflt *a, Mpflt *b);
void mpnegflt(Mpflt *a);
void mpnorm(Mpflt *a);
+void mpsetexp(Mpflt *a, int exp);
int mptestflt(Mpflt *a);
int sigfig(Mpflt *a);
/*
* obj.c
*/
-void Bputname(Biobuf *b, Sym *s);
+void Bputname(Biobuf *b, LSym *s);
int duint16(Sym *s, int off, uint16 v);
int duint32(Sym *s, int off, uint32 v);
int duint64(Sym *s, int off, uint64 v);
@@ -1248,8 +1276,9 @@ int duint8(Sym *s, int off, uint8 v);
int duintptr(Sym *s, int off, uint64 v);
int dsname(Sym *s, int off, char *dat, int ndat);
void dumpobj(void);
-void ieeedtod(uint64 *ieee, double native);
Sym* stringsym(char*, int);
+void slicebytes(Node*, char*, int);
+LSym* linksym(Sym*);
/*
* order.c
@@ -1274,6 +1303,7 @@ Sym* tracksym(Type *t);
Sym* typesymprefix(char *prefix, Type *t);
int haspointers(Type *t);
void usefield(Node*);
+Type* hiter(Type* t);
/*
* select.c
@@ -1434,32 +1464,21 @@ void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
Node* conv(Node*, Type*);
int candiscard(Node*);
+Node* outervalue(Node*);
/*
- * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
+ * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
*/
#define P ((Prog*)0)
-typedef struct Plist Plist;
-struct Plist
-{
- Node* name;
- Prog* firstpc;
- int recur;
- Plist* link;
-};
-
-EXTERN Plist* plist;
-EXTERN Plist* plast;
-
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
-EXTERN Prog* retpc;
EXTERN Node* nodfp;
EXTERN int disable_checknil;
+EXTERN vlong zerosize;
int anyregalloc(void);
void betypeinit(void);
@@ -1474,59 +1493,52 @@ void cgen_checknil(Node*);
void cgen_ret(Node *n);
void clearfat(Node *n);
void compile(Node*);
-void defframe(Prog*, Bvec*);
+void defframe(Prog*);
int dgostringptr(Sym*, int off, char *str);
int dgostrlitptr(Sym*, int off, Strlit*);
int dstringptr(Sym *s, int off, char *str);
int dsymptr(Sym *s, int off, Sym *x, int xoff);
int duintxx(Sym *s, int off, uint64 v, int wid);
void dumpdata(void);
-void dumpfuncs(void);
void fixautoused(Prog*);
void gdata(Node*, Node*, int);
void gdatacomplex(Node*, Mpcplx*);
void gdatastring(Node*, Strlit*);
void ggloblnod(Node *nam);
void ggloblsym(Sym *s, int32 width, int dupok, int rodata);
+void gvardef(Node*);
+void gvarkill(Node*);
Prog* gjmp(Prog*);
void gused(Node*);
void movelarge(NodeList*);
int isfat(Type*);
+void linkarchinit(void);
+void liveness(Node*, Prog*, Sym*, Sym*);
void markautoused(Prog*);
Plist* newplist(void);
Node* nodarg(Type*, int);
void nopout(Prog*);
void patch(Prog*, Prog*);
Prog* unpatch(Prog*);
-void zfile(Biobuf *b, char *p, int n);
-void zhist(Biobuf *b, int line, vlong offset);
-void zname(Biobuf *b, Sym *s, int t);
-#pragma varargck type "A" int
#pragma varargck type "B" Mpint*
-#pragma varargck type "D" Addr*
-#pragma varargck type "lD" Addr*
#pragma varargck type "E" int
#pragma varargck type "E" uint
#pragma varargck type "F" Mpflt*
#pragma varargck type "H" NodeList*
#pragma varargck type "J" Node*
-#pragma varargck type "lL" int
-#pragma varargck type "lL" uint
-#pragma varargck type "L" int
-#pragma varargck type "L" uint
+#pragma varargck type "lL" int32
+#pragma varargck type "L" int32
#pragma varargck type "N" Node*
#pragma varargck type "lN" Node*
+#pragma varargck type "O" int
#pragma varargck type "O" uint
-#pragma varargck type "P" Prog*
#pragma varargck type "Q" Bits
-#pragma varargck type "R" int
#pragma varargck type "S" Sym*
-#pragma varargck type "lS" Sym*
+#pragma varargck type "lS" LSym*
#pragma varargck type "T" Type*
#pragma varargck type "lT" Type*
#pragma varargck type "V" Val*
-#pragma varargck type "Y" char*
#pragma varargck type "Z" Strlit*
/*
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 5432eca85..2f354f723 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -557,6 +557,7 @@ caseblock:
// This is so that the stmt_list action doesn't look at
// the case tokens if the stmt_list is empty.
yylast = yychar;
+ $1->xoffset = block;
}
stmt_list
{
@@ -1730,6 +1731,7 @@ non_dcl_stmt:
{
// will be converted to OFALL
$$ = nod(OXFALL, N, N);
+ $$->xoffset = block;
}
| LBREAK onew_name
{
@@ -2138,6 +2140,10 @@ hidden_literal:
case CTFLT:
mpnegflt($$->val.u.fval);
break;
+ case CTCPLX:
+ mpnegflt(&$$->val.u.cval->real);
+ mpnegflt(&$$->val.u.cval->imag);
+ break;
default:
yyerror("bad negated constant");
}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
index 6800884a0..cf89b0090 100644
--- a/src/cmd/gc/inl.c
+++ b/src/cmd/gc/inl.c
@@ -392,6 +392,8 @@ inlnode(Node **np)
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
+ case OAPPEND:
+ case OCOMPLEX:
// if we just replaced arg in f(arg()) or return arg with an inlined call
// and arg returns multiple values, glue as list
if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
@@ -800,6 +802,7 @@ inlvar(Node *var)
n->class = PAUTO;
n->used = 1;
n->curfn = curfn; // the calling function, not the called one
+ n->addrtaken = var->addrtaken;
// esc pass wont run if we're inlining into a iface wrapper
// luckily, we can steal the results from the target func
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 8c739391a..a50101c42 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -14,7 +14,6 @@
#define ungetc ccungetc
extern int yychar;
-int windows;
int yyprev;
int yylast;
@@ -61,7 +60,7 @@ static void
addexp(char *s)
{
int i;
-
+
for(i=0; exper[i].name != nil; i++) {
if(strcmp(exper[i].name, s) == 0) {
*exper[i].val = 1;
@@ -78,8 +77,10 @@ setexp(void)
{
char *f[20];
int i, nf;
-
- // The makefile #defines GOEXPERIMENT for us.
+
+ precisestack_enabled = 1; // on by default
+
+ // cmd/dist #defines GOEXPERIMENT for us.
nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
for(i=0; i<nf; i++)
addexp(f[i]);
@@ -165,6 +166,21 @@ fault(int s)
fatal("fault");
}
+#ifdef PLAN9
+void
+catcher(void *v, char *s)
+{
+ USED(v);
+
+ if(strncmp(s, "sys: trap: fault read", 21) == 0) {
+ if(nsavederrors + nerrors > 0)
+ errorexit();
+ fatal("fault");
+ }
+ noted(NDFLT);
+}
+#endif
+
void
doversion(void)
{
@@ -189,6 +205,24 @@ main(int argc, char *argv[])
signal(SIGSEGV, fault);
#endif
+#ifdef PLAN9
+ notify(catcher);
+ // Tell the FPU to handle all exceptions.
+ setfcr(FPPDBL|FPRNR);
+#endif
+ // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+ // but not other values.
+ p = getgoarch();
+ if(strncmp(p, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cg with GOARCH=%s", thechar, p);
+ goarch = p;
+
+ linkarchinit();
+ ctxt = linknew(thelinkarch);
+ ctxt->diag = yyerror;
+ ctxt->bso = &bstdout;
+ Binit(&bstdout, 1, OWRITE);
+
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
@@ -229,8 +263,11 @@ main(int argc, char *argv[])
goroot = getgoroot();
goos = getgoos();
- goarch = thestring;
-
+
+ nacl = strcmp(goos, "nacl") == 0;
+ if(nacl)
+ flag_largemodel = 1;
+
setexp();
outfile = nil;
@@ -260,12 +297,16 @@ main(int argc, char *argv[])
flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
flagcount("j", "debug runtime-initialized variables", &debug['j']);
flagcount("l", "disable inlining", &debug['l']);
+ flagcount("live", "debug liveness analysis", &debuglive);
flagcount("m", "print optimization decisions", &debug['m']);
+ flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports);
flagstr("o", "obj: set output file", &outfile);
flagstr("p", "path: set expected package import path", &myimportpath);
+ flagcount("pack", "write package file instead of object file", &writearchive);
flagcount("r", "debug generated wrappers", &debug['r']);
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
+ flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
flagcount("u", "reject unsafe code", &safemode);
flagcount("v", "increase debug verbosity", &debug['v']);
flagcount("w", "debug type checking", &debug['w']);
@@ -275,6 +316,7 @@ main(int argc, char *argv[])
flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
flagparse(&argc, &argv, usage);
+ ctxt->debugasm = debug['S'];
if(argc < 1)
usage();
@@ -319,20 +361,6 @@ main(int argc, char *argv[])
sysfatal("unsupported setting GO386=%s", p);
}
- pathname = mal(1000);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
-
- if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
- // On Windows.
- windows = 1;
-
- // Canonicalize path by converting \ to / (Windows accepts both).
- for(p=pathname; *p; p++)
- if(*p == '\\')
- *p = '/';
- }
-
fmtinstallgo();
betypeinit();
if(widthptr == 0)
@@ -527,12 +555,13 @@ skiptopkgdef(Biobuf *b)
return 0;
if(memcmp(p, "!<arch>\n", 8) != 0)
return 0;
- /* symbol table is first; skip it */
+ /* symbol table may be first; skip it */
sz = arsize(b, "__.GOSYMDEF");
- if(sz < 0)
- return 0;
- Bseek(b, sz, 1);
- /* package export block is second */
+ if(sz >= 0)
+ Bseek(b, sz, 1);
+ else
+ Bseek(b, 8, 0);
+ /* package export block is next */
sz = arsize(b, "__.PKGDEF");
if(sz <= 0)
return 0;
@@ -560,7 +589,7 @@ islocalname(Strlit *name)
{
if(name->len >= 1 && name->s[0] == '/')
return 1;
- if(windows && name->len >= 3 &&
+ if(ctxt->windows && name->len >= 3 &&
yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
return 1;
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
@@ -581,7 +610,7 @@ findpkg(Strlit *name)
char *q, *suffix, *suffixsep;
if(islocalname(name)) {
- if(safemode)
+ if(safemode || nolocalimports)
return 0;
// try .a before .6. important for building libraries:
// if there is an array.6 in the array.a library,
@@ -702,7 +731,7 @@ importfile(Val *f, int line)
fakeimport();
return;
}
- prefix = pathname;
+ prefix = ctxt->pathname;
if(localimport != nil)
prefix = localimport;
cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
@@ -760,7 +789,7 @@ importfile(Val *f, int line)
yyerror("import %s: not a go object file", file);
errorexit();
}
- q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
+ q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
if(strcmp(p+10, q) != 0) {
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
errorexit();
@@ -1528,7 +1557,7 @@ getlinepragma(void)
goto out;
// try to avoid allocating file name over and over
- for(h=hist; h!=H; h=h->link) {
+ for(h=ctxt->hist; h!=nil; h=h->link) {
if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
linehist(h->name, n, 0);
goto out;
@@ -2143,14 +2172,18 @@ struct
} lexn[] =
{
LANDAND, "ANDAND",
+ LANDNOT, "ANDNOT",
LASOP, "ASOP",
LBREAK, "BREAK",
LCASE, "CASE",
LCHAN, "CHAN",
LCOLAS, "COLAS",
+ LCOMM, "<-",
LCONST, "CONST",
LCONTINUE, "CONTINUE",
+ LDDD, "...",
LDEC, "DEC",
+ LDEFAULT, "DEFAULT",
LDEFER, "DEFER",
LELSE, "ELSE",
LEQ, "EQ",
@@ -2177,6 +2210,7 @@ struct
LRANGE, "RANGE",
LRETURN, "RETURN",
LRSH, "RSH",
+ LSELECT, "SELECT",
LSTRUCT, "STRUCT",
LSWITCH, "SWITCH",
LTYPE, "TYPE",
@@ -2207,6 +2241,7 @@ struct
"LASOP", "op=",
"LBREAK", "break",
"LCASE", "case",
+ "LCHAN", "chan",
"LCOLAS", ":=",
"LCONST", "const",
"LCONTINUE", "continue",
@@ -2354,7 +2389,7 @@ mkpackage(char* pkgname)
if(outfile == nil) {
p = strrchr(infile, '/');
- if(windows) {
+ if(ctxt->windows) {
q = strrchr(infile, '\\');
if(q > p)
p = q;
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
index bbd4e298f..0051ac964 100644
--- a/src/cmd/gc/md5.c
+++ b/src/cmd/gc/md5.c
@@ -63,7 +63,7 @@ md5write(MD5 *d, uchar *p, int nn)
}
uint64
-md5sum(MD5 *d)
+md5sum(MD5 *d, uint64 *hi)
{
uchar tmp[64];
int i;
@@ -87,6 +87,8 @@ md5sum(MD5 *d)
if(d->nx != 0)
fatal("md5sum");
+ if(hi != nil)
+ *hi = d->s[2] | ((uint64)d->s[3]<<32);
return d->s[0] | ((uint64)d->s[1]<<32);
}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
index f153e30f2..5a60106b2 100644
--- a/src/cmd/gc/md5.h
+++ b/src/cmd/gc/md5.h
@@ -13,4 +13,4 @@ struct MD5
void md5reset(MD5*);
void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*);
+uint64 md5sum(MD5*, uint64*);
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index e25044a8b..1519caec7 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -65,7 +65,7 @@ mpcmpfltc(Mpflt *b, double c)
Mpflt a;
mpmovecflt(&a, c);
- return mpcmpfltflt(&a, b);
+ return mpcmpfltflt(b, &a);
}
void
@@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as)
if(eb) {
if(dp)
goto bad;
- a->exp += ex;
+ mpsetexp(a, a->exp+ex);
goto out;
}
@@ -427,8 +427,14 @@ mpatoflt(Mpflt *a, char *as)
mppow10flt(&b, ex-dp);
mpmulfltflt(a, &b);
} else {
- mppow10flt(&b, dp-ex);
- mpdivfltflt(a, &b);
+ // 4 approximates least_upper_bound(log2(10)).
+ if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
+ mpmovecflt(a, 0.0);
+ }
+ else {
+ mppow10flt(&b, dp-ex);
+ mpdivfltflt(a, &b);
+ }
}
}
@@ -573,20 +579,40 @@ Fconv(Fmt *fp)
{
char buf[500];
Mpflt *fvp, fv;
- double d;
+ double d, dexp;
+ int exp;
fvp = va_arg(fp->args, Mpflt*);
if(fp->flags & FmtSharp) {
// alternate form - decimal for error messages.
// for well in range, convert to double and use print's %g
- if(-900 < fvp->exp && fvp->exp < 900) {
+ exp = fvp->exp + sigfig(fvp)*Mpscale;
+ if(-900 < exp && exp < 900) {
d = mpgetflt(fvp);
if(d >= 0 && (fp->flags & FmtSign))
fmtprint(fp, "+");
- return fmtprint(fp, "%g", d);
+ return fmtprint(fp, "%g", d, exp, fvp);
+ }
+
+ // very out of range. compute decimal approximation by hand.
+ // decimal exponent
+ dexp = fvp->exp * 0.301029995663981195; // log_10(2)
+ exp = (int)dexp;
+ // decimal mantissa
+ fv = *fvp;
+ fv.val.neg = 0;
+ fv.exp = 0;
+ d = mpgetflt(&fv);
+ d *= pow(10, dexp-exp);
+ while(d >= 9.99995) {
+ d /= 10;
+ exp++;
}
- // TODO(rsc): for well out of range, print
- // an approximation like 1.234e1000
+ if(fvp->val.neg)
+ fmtprint(fp, "-");
+ else if(fp->flags & FmtSign)
+ fmtprint(fp, "+");
+ return fmtprint(fp, "%.5fe+%d", d, exp);
}
if(sigfig(fvp) == 0) {
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index 9b2f664f7..5cf98c62c 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -300,13 +300,21 @@ mpmulfixfix(Mpint *a, Mpint *b)
for(i=0; i<na; i++) {
x = *a1++;
for(j=0; j<Mpscale; j++) {
- if(x & 1)
+ if(x & 1) {
+ if(s.ovf) {
+ q.ovf = 1;
+ goto out;
+ }
mpaddfixfix(&q, &s, 1);
+ if(q.ovf)
+ goto out;
+ }
mplsh(&s, 1);
x >>= 1;
}
}
+out:
q.neg = a->neg ^ b->neg;
mpmovefixfix(a, &q);
if(a->ovf)
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index f8344c9b4..95618f1c6 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -23,6 +23,27 @@ sigfig(Mpflt *a)
}
/*
+ * sets the exponent.
+ * a too large exponent is an error.
+ * a too small exponent rounds the number to zero.
+ */
+void
+mpsetexp(Mpflt *a, int exp) {
+ if((short)exp != exp) {
+ if(exp > 0) {
+ yyerror("float constant is too large");
+ a->exp = 0x7fff;
+ }
+ else {
+ mpmovecflt(a, 0);
+ }
+ }
+ else {
+ a->exp = exp;
+ }
+}
+
+/*
* shifts the leading non-zero
* word of the number to Mpnorm
*/
@@ -60,7 +81,7 @@ mpnorm(Mpflt *a)
}
mpshiftfix(&a->val, s);
- a->exp -= s;
+ mpsetexp(a, a->exp-s);
}
/// implements float arihmetic
@@ -95,7 +116,7 @@ mpaddfltflt(Mpflt *a, Mpflt *b)
if(s < 0) {
// b is larger, shift a right
mpshiftfix(&a->val, s);
- a->exp -= s;
+ mpsetexp(a, a->exp-s);
mpaddfixfix(&a->val, &b->val, 0);
goto out;
}
@@ -131,7 +152,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b)
}
mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
+ mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
mpnorm(a);
if(Mpdebug)
@@ -171,18 +192,18 @@ mpdivfltflt(Mpflt *a, Mpflt *b)
// divide
mpdivfract(&a->val, &c.val);
- a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
+ mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
mpnorm(a);
if(Mpdebug)
print(" = %F\n\n", a);
}
-double
-mpgetflt(Mpflt *a)
+static double
+mpgetfltN(Mpflt *a, int prec, int bias)
{
- int s, i, e;
- uvlong v, vm;
+ int s, i, e, minexp;
+ uvlong v;
double f;
if(a->val.ovf && nsavederrors+nerrors == 0)
@@ -199,59 +220,69 @@ mpgetflt(Mpflt *a)
while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
mpshiftfix(&a->val, 1);
- a->exp -= 1;
+ mpsetexp(a, a->exp-1); // can set 'a' to zero
+ s = sigfig(a);
+ if(s == 0)
+ return 0;
}
- // the magic numbers (64, 63, 53, 10, -1074) are
- // IEEE specific. this should be done machine
- // independently or in the 6g half of the compiler
-
- // pick up the mantissa and a rounding bit in a uvlong
- s = 53+1;
+ // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
+ s = prec+2;
v = 0;
for(i=Mpnorm-1; s>=Mpscale; i--) {
v = (v<<Mpscale) | a->val.a[i];
s -= Mpscale;
}
- vm = v;
- if(s > 0)
- vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // continue with 64 more bits
- s += 64;
- for(; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- if(s > 0)
+ if(s > 0) {
v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
+ if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
+ v |= 1;
+ i--;
+ }
+ for(; i >= 0; i--) {
+ if(a->val.a[i] != 0)
+ v |= 1;
+ }
// gradual underflow
- e = Mpnorm*Mpscale + a->exp - 53;
- if(e < -1074) {
- s = -e - 1074;
- if(s > 54)
- s = 54;
- v |= vm & ((1ULL<<s) - 1);
- vm >>= s;
- e = -1074;
+ e = Mpnorm*Mpscale + a->exp - prec;
+ minexp = bias+1-prec+1;
+ if(e < minexp) {
+ s = minexp - e;
+ if(s > prec+1)
+ s = prec+1;
+ if((v & ((1<<s)-1)) != 0)
+ v |= 1<<s;
+ v >>= s;
+ e = minexp;
}
+
+ // round to even
+ v |= (v&4)>>2;
+ v += v&1;
+ v >>= 2;
-//print("vm=%.16llux v=%.16llux\n", vm, v);
- // round toward even
- if(v != 0 || (vm&2ULL) != 0)
- vm = (vm>>1) + (vm&1ULL);
- else
- vm >>= 1;
-
- f = (double)(vm);
+ f = (double)(v);
f = ldexp(f, e);
if(a->val.neg)
f = -f;
+
return f;
}
+double
+mpgetflt(Mpflt *a)
+{
+ return mpgetfltN(a, 53, -1023);
+}
+
+double
+mpgetflt32(Mpflt *a)
+{
+ return mpgetfltN(a, 24, -127);
+}
+
void
mpmovecflt(Mpflt *a, double c)
{
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index 4cad08924..4eeb03aa8 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -10,13 +10,28 @@
* architecture-independent object file output
*/
-static void outhist(Biobuf *b);
static void dumpglobls(void);
+enum
+{
+ ArhdrSize = 60
+};
+
+static void
+formathdr(char *arhdr, char *name, vlong size)
+{
+ snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
+ name, 0, 0, 0, 0644, size);
+ arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
+}
+
void
dumpobj(void)
{
NodeList *externs, *tmp;
+ char arhdr[ArhdrSize];
+ vlong startobj, size;
+ Sym *zero;
bout = Bopen(outfile, OWRITE);
if(bout == nil) {
@@ -25,13 +40,34 @@ dumpobj(void)
errorexit();
}
- Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
- Bprint(bout, " exports automatically generated from\n");
- Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
+ startobj = 0;
+ if(writearchive) {
+ Bwrite(bout, "!<arch>\n", 8);
+ memset(arhdr, 0, sizeof arhdr);
+ Bwrite(bout, arhdr, sizeof arhdr);
+ startobj = Boffset(bout);
+ }
+ Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
dumpexport();
- Bprint(bout, "\n!\n");
+
+ if(writearchive) {
+ Bflush(bout);
+ size = Boffset(bout) - startobj;
+ if(size&1)
+ Bputc(bout, 0);
+ Bseek(bout, startobj - ArhdrSize, 0);
+ formathdr(arhdr, "__.PKGDEF", size);
+ Bwrite(bout, arhdr, ArhdrSize);
+ Bflush(bout);
+
+ Bseek(bout, startobj + size + (size&1), 0);
+ memset(arhdr, 0, ArhdrSize);
+ Bwrite(bout, arhdr, ArhdrSize);
+ startobj = Boffset(bout);
+ Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
+ }
- outhist(bout);
+ Bprint(bout, "\n!\n");
externs = nil;
if(externdcl != nil)
@@ -47,9 +83,22 @@ dumpobj(void)
dumpglobls();
externdcl = tmp;
- dumpdata();
- dumpfuncs();
+ zero = pkglookup("zerovalue", runtimepkg);
+ ggloblsym(zero, zerosize, 1, 1);
+ dumpdata();
+ writeobj(ctxt, bout);
+
+ if(writearchive) {
+ Bflush(bout);
+ size = Boffset(bout) - startobj;
+ if(size&1)
+ Bputc(bout, 0);
+ Bseek(bout, startobj - ArhdrSize, 0);
+ snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
+ formathdr(arhdr, namebuf, size);
+ Bwrite(bout, arhdr, ArhdrSize);
+ }
Bterm(bout);
}
@@ -75,184 +124,50 @@ dumpglobls(void)
ggloblnod(n);
}
-
+
for(l=funcsyms; l; l=l->next) {
n = l->n;
dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
ggloblsym(n->sym, widthptr, 1, 1);
}
+
+ // Do not reprocess funcsyms on next dumpglobls call.
+ funcsyms = nil;
}
void
-Bputname(Biobuf *b, Sym *s)
+Bputname(Biobuf *b, LSym *s)
{
- Bprint(b, "%s", s->pkg->prefix);
- BPUTC(b, '.');
Bwrite(b, s->name, strlen(s->name)+1);
}
-static void
-outzfile(Biobuf *b, char *p)
-{
- char *q, *q2;
-
- while(p) {
- q = utfrune(p, '/');
- if(windows) {
- q2 = utfrune(p, '\\');
- if(q2 && (!q || q2 < q))
- q = q2;
- }
- if(!q) {
- zfile(b, p, strlen(p));
- return;
- }
- if(q > p)
- zfile(b, p, q-p);
- p = q + 1;
- }
-}
-
-#define isdelim(c) (c == '/' || c == '\\')
-
-static void
-outwinname(Biobuf *b, Hist *h, char *ds, char *p)
+LSym*
+linksym(Sym *s)
{
- if(isdelim(p[0])) {
- // full rooted name
- zfile(b, ds, 3); // leading "c:/"
- outzfile(b, p+1);
- } else {
- // relative name
- if(h->offset >= 0 && pathname && pathname[1] == ':') {
- if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
- // using current drive
- zfile(b, pathname, 3); // leading "c:/"
- outzfile(b, pathname+3);
- } else {
- // using drive other then current,
- // we don't have any simple way to
- // determine current working directory
- // there, therefore will output name as is
- zfile(b, ds, 2); // leading "c:"
- }
- }
- outzfile(b, p);
+ char *p;
+
+ if(s == nil)
+ return nil;
+ if(s->lsym != nil)
+ return s->lsym;
+ if(isblanksym(s))
+ s->lsym = linklookup(ctxt, "_", 0);
+ else {
+ p = smprint("%s.%s", s->pkg->prefix, s->name);
+ s->lsym = linklookup(ctxt, p, 0);
+ free(p);
}
+ return s->lsym;
}
-static void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, ds[] = {'c', ':', '/', 0};
- char *tofree;
- int n;
- static int first = 1;
- static char *goroot, *goroot_final;
-
- if(first) {
- // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
- first = 0;
- goroot = getenv("GOROOT");
- goroot_final = getenv("GOROOT_FINAL");
- if(goroot == nil)
- goroot = "";
- if(goroot_final == nil)
- goroot_final = goroot;
- if(strcmp(goroot, goroot_final) == 0) {
- goroot = nil;
- goroot_final = nil;
- }
- }
-
- tofree = nil;
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p) {
- if(goroot != nil) {
- n = strlen(goroot);
- if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
- tofree = smprint("%s%s", goroot_final, p+n);
- p = tofree;
- }
- }
- if(windows) {
- // if windows variable is set, then, we know already,
- // pathname is started with windows drive specifier
- // and all '\' were replaced with '/' (see lex.c)
- if(isdelim(p[0]) && isdelim(p[1])) {
- // file name has network name in it,
- // like \\server\share\dir\file.go
- zfile(b, "//", 2); // leading "//"
- outzfile(b, p+2);
- } else if(p[1] == ':') {
- // file name has drive letter in it
- ds[0] = p[0];
- outwinname(b, h, ds, p+2);
- } else {
- // no drive letter in file name
- outwinname(b, h, pathname, p);
- }
- } else {
- if(p[0] == '/') {
- // full rooted name, like /home/rsc/dir/file.go
- zfile(b, "/", 1); // leading "/"
- outzfile(b, p+1);
- } else {
- // relative name, like dir/file.go
- if(h->offset >= 0 && pathname && pathname[0] == '/') {
- zfile(b, "/", 1); // leading "/"
- outzfile(b, pathname+1);
- }
- outzfile(b, p);
- }
- }
- }
- zhist(b, h->line, h->offset);
- if(tofree) {
- free(tofree);
- tofree = nil;
- }
- }
-}
-
-void
-ieeedtod(uint64 *ieee, double native)
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
{
- double fr, ho, f;
- int exp;
- uint32 h, l;
- uint64 bits;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- *ieee |= 1ULL<<63;
- return;
- }
- if(native == 0) {
- *ieee = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldn't use fp constants here */
- fr = modf(fr*f, &ho);
- h = ho;
- h &= 0xfffffL;
- f = 65536L;
- fr = modf(fr*f, &ho);
- l = ho;
- l <<= 16;
- l |= (int32)(fr*f);
- bits = ((uint64)h<<32) | l;
- if(exp < -1021) {
- // gradual underflow
- bits |= 1LL<<52;
- bits >>= -1021 - exp;
- exp = -1022;
- }
- bits |= (uint64)(exp+1022L) << 52;
- *ieee = bits;
+ // Update symbol data directly instead of generating a
+ // DATA instruction that liblink will have to interpret later.
+ // This reduces compilation time and memory usage.
+ off = rnd(off, wid);
+ return setuintxx(ctxt, linksym(s), off, v, wid);
}
int
@@ -338,3 +253,31 @@ stringsym(char *s, int len)
return sym;
}
+
+void
+slicebytes(Node *nam, char *s, int len)
+{
+ int off, n, m;
+ static int gen;
+ Sym *sym;
+
+ snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
+ sym = pkglookup(namebuf, localpkg);
+ sym->def = newname(sym);
+
+ off = 0;
+ for(n=0; n<len; n+=m) {
+ m = 8;
+ if(m > len-n)
+ m = len-n;
+ off = dsname(sym, off, s+n, m);
+ }
+ ggloblsym(sym, off, 0, 0);
+
+ if(nam->op != ONAME)
+ fatal("slicebytes %N", nam);
+ off = nam->xoffset;
+ off = dsymptr(nam->sym, off, sym, 0);
+ off = duintxx(nam->sym, off, len, widthint);
+ duintxx(nam->sym, off, len, widthint);
+}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
index 7552510e9..30dbc7dac 100644
--- a/src/cmd/gc/order.c
+++ b/src/cmd/gc/order.c
@@ -5,79 +5,343 @@
// Rewrite tree to use separate statements to enforce
// order of evaluation. Makes walk easier, because it
// can (after this runs) reorder at will within an expression.
+//
+// Rewrite x op= y into x = x op y.
+//
+// Introduce temporaries as needed by runtime routines.
+// For example, the map runtime routines take the map key
+// by reference, so make sure all map keys are addressable
+// by copying them to temporaries as needed.
+// The same is true for channel operations.
+//
+// Arrange that map index expressions only appear in direct
+// assignments x = m[k] or m[k] = x, never in larger expressions.
+//
+// Arrange that receive expressions only appear in direct assignments
+// x = <-c or as standalone statements <-c, never in larger expressions.
+
+// TODO(rsc): The temporary introduction during multiple assignments
+// should be moved into this file, so that the temporaries can be cleaned
+// and so that conversions implicit in the OAS2FUNC and OAS2RECV
+// nodes can be made explicit and then have their temporaries cleaned.
+
+// TODO(rsc): Goto and multilevel break/continue can jump over
+// inserted VARKILL annotations. Work out a way to handle these.
+// The current implementation is safe, in that it will execute correctly.
+// But it won't reuse temporaries as aggressively as it might, and
+// it can result in unnecessary zeroing of those variables in the function
+// prologue.
#include <u.h>
#include <libc.h>
#include "go.h"
-static void orderstmt(Node*, NodeList**);
-static void orderstmtlist(NodeList*, NodeList**);
+// Order holds state during the ordering process.
+typedef struct Order Order;
+struct Order
+{
+ NodeList *out; // list of generated statements
+ NodeList *temp; // head of stack of temporary variables
+ NodeList *free; // free list of NodeList* structs (for use in temp)
+};
+
+static void orderstmt(Node*, Order*);
+static void orderstmtlist(NodeList*, Order*);
static void orderblock(NodeList **l);
-static void orderexpr(Node**, NodeList**);
-static void orderexprlist(NodeList*, NodeList**);
+static void orderexpr(Node**, Order*);
+static void orderexprinplace(Node**, Order*);
+static void orderexprlist(NodeList*, Order*);
+static void orderexprlistinplace(NodeList*, Order*);
+// Order rewrites fn->nbody to apply the ordering constraints
+// described in the comment at the top of the file.
void
order(Node *fn)
{
orderblock(&fn->nbody);
}
+// Ordertemp allocates a new temporary with the given type,
+// pushes it onto the temp stack, and returns it.
+// If clear is true, ordertemp emits code to zero the temporary.
+static Node*
+ordertemp(Type *t, Order *order, int clear)
+{
+ Node *var, *a;
+ NodeList *l;
+
+ var = temp(t);
+ if(clear) {
+ a = nod(OAS, var, N);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ }
+ if((l = order->free) == nil)
+ l = mal(sizeof *l);
+ order->free = l->next;
+ l->next = order->temp;
+ l->n = var;
+ order->temp = l;
+ return var;
+}
+
+// Ordercopyexpr behaves like ordertemp but also emits
+// code to initialize the temporary to the value n.
+//
+// The clear argument is provided for use when the evaluation
+// of tmp = n turns into a function call that is passed a pointer
+// to the temporary as the output space. If the call blocks before
+// tmp has been written, the garbage collector will still treat the
+// temporary as live, so we must zero it before entering that call.
+// Today, this only happens for channel receive operations.
+// (The other candidate would be map access, but map access
+// returns a pointer to the result data instead of taking a pointer
+// to be filled in.)
+static Node*
+ordercopyexpr(Node *n, Type *t, Order *order, int clear)
+{
+ Node *a, *var;
+
+ var = ordertemp(t, order, clear);
+ a = nod(OAS, var, n);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ return var;
+}
+
+// Ordercheapexpr returns a cheap version of n.
+// The definition of cheap is that n is a variable or constant.
+// If not, ordercheapexpr allocates a new tmp, emits tmp = n,
+// and then returns tmp.
+static Node*
+ordercheapexpr(Node *n, Order *order)
+{
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+ return ordercopyexpr(n, n->type, order, 0);
+}
+
+// Ordersafeexpr returns a safe version of n.
+// The definition of safe is that n can appear multiple times
+// without violating the semantics of the original program,
+// and that assigning to the safe version has the same effect
+// as assigning to the original n.
+//
+// The intended use is to apply to x when rewriting x += y into x = x + y.
+static Node*
+ordersafeexpr(Node *n, Order *order)
+{
+ Node *l, *r, *a;
+
+ switch(n->op) {
+ default:
+ fatal("ordersafeexpr %O", n->op);
+
+ case ONAME:
+ case OLITERAL:
+ return n;
+
+ case ODOT:
+ l = ordersafeexpr(n->left, order);
+ if(l == n->left)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ typecheck(&a, Erv);
+ return a;
+
+ case ODOTPTR:
+ case OIND:
+ l = ordercheapexpr(n->left, order);
+ if(l == n->left)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ typecheck(&a, Erv);
+ return a;
+
+ case OINDEX:
+ case OINDEXMAP:
+ if(isfixedarray(n->left->type))
+ l = ordersafeexpr(n->left, order);
+ else
+ l = ordercheapexpr(n->left, order);
+ r = ordercheapexpr(n->right, order);
+ if(l == n->left && r == n->right)
+ return n;
+ a = nod(OXXX, N, N);
+ *a = *n;
+ a->orig = a;
+ a->left = l;
+ a->right = r;
+ typecheck(&a, Erv);
+ return a;
+ }
+}
+
+// Istemp reports whether n is a temporary variable.
+static int
+istemp(Node *n)
+{
+ if(n->op != ONAME)
+ return 0;
+ return strncmp(n->sym->name, "autotmp_", 8) == 0;
+}
+
+// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
+// Taking the address of a variable makes the liveness and optimization analyses
+// lose track of where the variable's lifetime ends. To avoid hurting the analyses
+// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
+// because we emit explicit VARKILL instructions marking the end of those
+// temporaries' lifetimes.
+static int
+isaddrokay(Node *n)
+{
+ return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n));
+}
+
+// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
+// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
+// tmp = *np, and then sets *np to the tmp variable.
static void
-orderstmtlist(NodeList *l, NodeList **out)
+orderaddrtemp(Node **np, Order *order)
+{
+ Node *n;
+
+ n = *np;
+ if(isaddrokay(n))
+ return;
+ *np = ordercopyexpr(n, n->type, order, 0);
+}
+
+// Marktemp returns the top of the temporary variable stack.
+static NodeList*
+marktemp(Order *order)
+{
+ return order->temp;
+}
+
+// Poptemp pops temporaries off the stack until reaching the mark,
+// which must have been returned by marktemp.
+static void
+poptemp(NodeList *mark, Order *order)
+{
+ NodeList *l;
+
+ while((l = order->temp) != mark) {
+ order->temp = l->next;
+ l->next = order->free;
+ order->free = l;
+ }
+}
+
+// Cleantempnopop emits to *out VARKILL instructions for each temporary
+// above the mark on the temporary stack, but it does not pop them
+// from the stack.
+static void
+cleantempnopop(NodeList *mark, Order *order, NodeList **out)
+{
+ NodeList *l;
+ Node *kill;
+
+ for(l=order->temp; l != mark; l=l->next) {
+ kill = nod(OVARKILL, l->n, N);
+ typecheck(&kill, Etop);
+ *out = list(*out, kill);
+ }
+}
+
+// Cleantemp emits VARKILL instructions for each temporary above the
+// mark on the temporary stack and removes them from the stack.
+static void
+cleantemp(NodeList *top, Order *order)
+{
+ cleantempnopop(top, order, &order->out);
+ poptemp(top, order);
+}
+
+// Orderstmtlist orders each of the statements in the list.
+static void
+orderstmtlist(NodeList *l, Order *order)
{
for(; l; l=l->next)
- orderstmt(l->n, out);
+ orderstmt(l->n, order);
}
-// Order the block of statements *l onto a new list,
-// and then replace *l with that list.
+// Orderblock orders the block of statements *l onto a new list,
+// and then replaces *l with that list.
static void
orderblock(NodeList **l)
{
- NodeList *out;
+ Order order;
+ NodeList *mark;
- out = nil;
- orderstmtlist(*l, &out);
- *l = out;
+ memset(&order, 0, sizeof order);
+ mark = marktemp(&order);
+ orderstmtlist(*l, &order);
+ cleantemp(mark, &order);
+ *l = order.out;
}
-// Order the side effects in *np and leave them as
-// the init list of the final *np.
+// Orderexprinplace orders the side effects in *np and
+// leaves them as the init list of the final *np.
static void
-orderexprinplace(Node **np)
+orderexprinplace(Node **np, Order *outer)
{
Node *n;
- NodeList *out;
+ NodeList **lp;
+ Order order;
n = *np;
- out = nil;
- orderexpr(&n, &out);
- addinit(&n, out);
+ memset(&order, 0, sizeof order);
+ orderexpr(&n, &order);
+ addinit(&n, order.out);
+
+ // insert new temporaries from order
+ // at head of outer list.
+ lp = &order.temp;
+ while(*lp != nil)
+ lp = &(*lp)->next;
+ *lp = outer->temp;
+ outer->temp = order.temp;
+
*np = n;
}
-// Like orderblock, but applied to a single statement.
+// Orderstmtinplace orders the side effects of the single statement *np
+// and replaces it with the resulting statement list.
static void
orderstmtinplace(Node **np)
{
Node *n;
- NodeList *out;
-
+ Order order;
+ NodeList *mark;
+
n = *np;
- out = nil;
- orderstmt(n, &out);
- *np = liststmt(out);
+ memset(&order, 0, sizeof order);
+ mark = marktemp(&order);
+ orderstmt(n, &order);
+ cleantemp(mark, &order);
+ *np = liststmt(order.out);
}
-// Move n's init list to *out.
+// Orderinit moves n's init list to order->out.
static void
-orderinit(Node *n, NodeList **out)
+orderinit(Node *n, Order *order)
{
- orderstmtlist(n->ninit, out);
+ orderstmtlist(n->ninit, order);
n->ninit = nil;
}
-// Is the list l actually just f() for a multi-value function?
+// Ismulticall reports whether the list l is f() for a multi-value function.
+// Such an f() could appear as the lone argument to a multi-arg function.
static int
ismulticall(NodeList *l)
{
@@ -102,10 +366,10 @@ ismulticall(NodeList *l)
return n->left->type->outtuple > 1;
}
-// n is a multi-value function call. Add t1, t2, .. = n to out
-// and return the list t1, t2, ...
+// Copyret emits t1, t2, ... = n, where n is a function call,
+// and then returns the list t1, t2, ....
static NodeList*
-copyret(Node *n, NodeList **out)
+copyret(Node *n, Order *order)
{
Type *t;
Node *tmp, *as;
@@ -127,86 +391,224 @@ copyret(Node *n, NodeList **out)
as->list = l1;
as->rlist = list1(n);
typecheck(&as, Etop);
- orderstmt(as, out);
+ orderstmt(as, order);
return l2;
}
+// Ordercallargs orders the list of call arguments *l.
static void
-ordercallargs(NodeList **l, NodeList **out)
+ordercallargs(NodeList **l, Order *order)
{
if(ismulticall(*l)) {
// return f() where f() is multiple values.
- *l = copyret((*l)->n, out);
+ *l = copyret((*l)->n, order);
} else {
- orderexprlist(*l, out);
+ orderexprlist(*l, order);
}
}
+// Ordercall orders the call expression n.
+// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
static void
-ordercall(Node *n, NodeList **out)
+ordercall(Node *n, Order *order)
{
- orderexpr(&n->left, out);
- ordercallargs(&n->list, out);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order); // ODDDARG temp
+ ordercallargs(&n->list, order);
}
+// Ordermapassign appends n to order->out, introducing temporaries
+// to make sure that all map assignments have the form m[k] = x,
+// where x is adressable.
+// (Orderexpr has already been called on n, so we know k is addressable.)
+//
+// If n is m[k] = x where x is not addressable, the rewrite is:
+// tmp = x
+// m[k] = tmp
+//
+// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
+// t1 = m
+// t2 = k
+// ...., t3, ... = x
+// t1[t2] = t3
+//
+// The temporaries t1, t2 are needed in case the ... being assigned
+// contain m or k. They are usually unnecessary, but in the unnecessary
+// cases they are also typically registerizable, so not much harm done.
+// And this only applies to the multiple-assignment form.
+// We could do a more precise analysis if needed, like in walk.c.
static void
-orderstmt(Node *n, NodeList **out)
+ordermapassign(Node *n, Order *order)
{
- int lno;
+ Node *m, *a;
NodeList *l;
- Node *r;
+ NodeList *post;
+
+ switch(n->op) {
+ default:
+ fatal("ordermapassign %O", n->op);
+
+ case OAS:
+ order->out = list(order->out, n);
+ if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) {
+ m = n->left;
+ n->left = ordertemp(m->type, order, 0);
+ a = nod(OAS, m, n->left);
+ typecheck(&a, Etop);
+ order->out = list(order->out, a);
+ }
+ break;
+
+ case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2MAPR:
+ case OAS2FUNC:
+ post = nil;
+ for(l=n->list; l != nil; l=l->next) {
+ if(l->n->op == OINDEXMAP) {
+ m = l->n;
+ if(!istemp(m->left))
+ m->left = ordercopyexpr(m->left, m->left->type, order, 0);
+ if(!istemp(m->right))
+ m->right = ordercopyexpr(m->right, m->right->type, order, 0);
+ l->n = ordertemp(m->type, order, 0);
+ a = nod(OAS, m, l->n);
+ typecheck(&a, Etop);
+ post = list(post, a);
+ }
+ }
+ order->out = list(order->out, n);
+ order->out = concat(order->out, post);
+ break;
+ }
+}
+
+// Orderstmt orders the statement n, appending to order->out.
+// Temporaries created during the statement are cleaned
+// up using VARKILL instructions as possible.
+static void
+orderstmt(Node *n, Order *order)
+{
+ int lno;
+ NodeList *l, *t, *t1;
+ Node *r, *tmp1, *tmp2, **np;
+ Type *ch;
if(n == N)
return;
lno = setlineno(n);
- orderinit(n, out);
+ orderinit(n, order);
switch(n->op) {
default:
fatal("orderstmt %O", n->op);
+ case OVARKILL:
+ order->out = list(order->out, n);
+ break;
+
+ case OAS:
case OAS2:
case OAS2DOTTYPE:
- case OAS2MAPR:
- case OAS:
- case OASOP:
case OCLOSE:
case OCOPY:
- case ODELETE:
- case OPANIC:
case OPRINT:
case OPRINTN:
case ORECOVER:
case ORECV:
- case OSEND:
- orderexpr(&n->left, out);
- orderexpr(&n->right, out);
- orderexprlist(n->list, out);
- orderexprlist(n->rlist, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ switch(n->op) {
+ case OAS:
+ case OAS2:
+ case OAS2DOTTYPE:
+ ordermapassign(n, order);
+ break;
+ default:
+ order->out = list(order->out, n);
+ break;
+ }
+ cleantemp(t, order);
break;
-
+
+ case OASOP:
+ // Special: rewrite l op= r into l = l op r.
+ // This simplies quite a few operations;
+ // most important is that it lets us separate
+ // out map read from map write when l is
+ // a map index expression.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ n->left = ordersafeexpr(n->left, order);
+ tmp1 = treecopy(n->left);
+ if(tmp1->op == OINDEXMAP)
+ tmp1->etype = 0; // now an rvalue not an lvalue
+ tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0);
+ n->right = nod(n->etype, tmp1, n->right);
+ typecheck(&n->right, Erv);
+ orderexpr(&n->right, order);
+ n->etype = 0;
+ n->op = OAS;
+ ordermapassign(n, order);
+ cleantemp(t, order);
+ break;
+
+ case OAS2MAPR:
+ // Special: make sure key is addressable,
+ // and make sure OINDEXMAP is not copied out.
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ r = n->rlist->n;
+ orderexpr(&r->left, order);
+ orderexpr(&r->right, order);
+ // See case OINDEXMAP below.
+ if(r->right->op == OARRAYBYTESTR)
+ r->right->op = OARRAYBYTESTRTMP;
+ orderaddrtemp(&r->right, order);
+ ordermapassign(n, order);
+ cleantemp(t, order);
+ break;
+
case OAS2FUNC:
// Special: avoid copy of func call n->rlist->n.
- orderexprlist(n->list, out);
- ordercall(n->rlist->n, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ ordercall(n->rlist->n, order);
+ ordermapassign(n, order);
+ cleantemp(t, order);
break;
case OAS2RECV:
// Special: avoid copy of receive.
- orderexprlist(n->list, out);
- orderexpr(&n->rlist->n->left, out); // arg to recv
- *out = list(*out, n);
+ // Use temporary variables to hold result,
+ // so that chanrecv can take address of temporary.
+ t = marktemp(order);
+ orderexprlist(n->list, order);
+ orderexpr(&n->rlist->n->left, order); // arg to recv
+ ch = n->rlist->n->left->type;
+ tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
+ tmp2 = ordertemp(types[TBOOL], order, 0);
+ order->out = list(order->out, n);
+ r = nod(OAS, n->list->n, tmp1);
+ typecheck(&r, Etop);
+ ordermapassign(r, order);
+ r = nod(OAS, n->list->next->n, tmp2);
+ typecheck(&r, Etop);
+ ordermapassign(r, order);
+ n->list = list(list1(tmp1), tmp2);
+ cleantemp(t, order);
break;
case OBLOCK:
case OEMPTY:
// Special: does not save n onto out.
- orderstmtlist(n->list, out);
+ orderstmtlist(n->list, order);
break;
case OBREAK:
@@ -215,109 +617,329 @@ orderstmt(Node *n, NodeList **out)
case ODCLCONST:
case ODCLTYPE:
case OFALL:
- case_OFALL:
+ case OXFALL:
case OGOTO:
case OLABEL:
case ORETJMP:
// Special: n->left is not an expression; save as is.
- *out = list(*out, n);
+ order->out = list(order->out, n);
break;
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
// Special: handle call arguments.
- ordercall(n, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ ordercall(n, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ODEFER:
case OPROC:
// Special: order arguments to inner call but not call itself.
- ordercall(n->left, out);
- *out = list(*out, n);
+ t = marktemp(order);
+ switch(n->left->op) {
+ case ODELETE:
+ // Delete will take the address of the key.
+ // Copy key into new temp and do not clean it
+ // (it persists beyond the statement).
+ orderexprlist(n->left->list, order);
+ t1 = marktemp(order);
+ np = &n->left->list->next->n; // map key
+ *np = ordercopyexpr(*np, (*np)->type, order, 0);
+ poptemp(t1, order);
+ break;
+ default:
+ ordercall(n->left, order);
+ break;
+ }
+ order->out = list(order->out, n);
+ cleantemp(t, order);
+ break;
+
+ case ODELETE:
+ t = marktemp(order);
+ orderexpr(&n->list->n, order);
+ orderexpr(&n->list->next->n, order);
+ orderaddrtemp(&n->list->next->n, order); // map key
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OFOR:
- orderexprinplace(&n->ntest);
- orderstmtinplace(&n->nincr);
+ // Clean temporaries from condition evaluation at
+ // beginning of loop body and after for statement.
+ t = marktemp(order);
+ orderexprinplace(&n->ntest, order);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nbody = concat(l, n->nbody);
orderblock(&n->nbody);
- *out = list(*out, n);
+ orderstmtinplace(&n->nincr);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OIF:
- orderexprinplace(&n->ntest);
+ // Clean temporaries from condition at
+ // beginning of both branches.
+ t = marktemp(order);
+ orderexprinplace(&n->ntest, order);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nbody = concat(l, n->nbody);
+ l = nil;
+ cleantempnopop(t, order, &l);
+ n->nelse = concat(l, n->nelse);
+ poptemp(t, order);
orderblock(&n->nbody);
orderblock(&n->nelse);
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ break;
+
+ case OPANIC:
+ // Special: argument will be converted to interface using convT2E
+ // so make sure it is an addressable temporary.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ if(!isinter(n->left->type))
+ orderaddrtemp(&n->left, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ORANGE:
- orderexpr(&n->right, out);
+ // n->right is the expression being ranged over.
+ // order it, and then make a copy if we need one.
+ // We almost always do, to ensure that we don't
+ // see any value changes made during the loop.
+ // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
+ // The exception is ranging over an array value (not a slice, not a pointer to array),
+ // which must make a copy to avoid seeing updates made during
+ // the range body. Ranging over an array value is uncommon though.
+ t = marktemp(order);
+ orderexpr(&n->right, order);
+ switch(n->type->etype) {
+ default:
+ fatal("orderstmt range %T", n->type);
+ case TARRAY:
+ if(count(n->list) < 2 || isblank(n->list->next->n)) {
+ // for i := range x will only use x once, to compute len(x).
+ // No need to copy it.
+ break;
+ }
+ // fall through
+ case TCHAN:
+ case TSTRING:
+ // chan, string, slice, array ranges use value multiple times.
+ // make copy.
+ r = n->right;
+ if(r->type->etype == TSTRING && r->type != types[TSTRING]) {
+ r = nod(OCONV, r, N);
+ r->type = types[TSTRING];
+ typecheck(&r, Erv);
+ }
+ n->right = ordercopyexpr(r, r->type, order, 0);
+ break;
+ case TMAP:
+ // copy the map value in case it is a map literal.
+ // TODO(rsc): Make tmp = literal expressions reuse tmp.
+ // For maps tmp is just one word so it hardly matters.
+ r = n->right;
+ n->right = ordercopyexpr(r, r->type, order, 0);
+ // n->alloc is the temp for the iterator.
+ n->alloc = ordertemp(types[TUINT8], order, 1);
+ break;
+ }
for(l=n->list; l; l=l->next)
- orderexprinplace(&l->n);
+ orderexprinplace(&l->n, order);
orderblock(&n->nbody);
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case ORETURN:
- ordercallargs(&n->list, out);
- *out = list(*out, n);
+ ordercallargs(&n->list, order);
+ order->out = list(order->out, n);
break;
case OSELECT:
+ // Special: clean case temporaries in each block entry.
+ // Select must enter one of its blocks, so there is no
+ // need for a cleaning at the end.
+ t = marktemp(order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order select case %O", l->n->op);
r = l->n->left;
- if(r == nil)
- continue;
- switch(r->op) {
- case OSELRECV:
- case OSELRECV2:
- orderexprinplace(&r->left);
- orderexprinplace(&r->ntest);
- orderexpr(&r->right->left, &l->n->ninit);
- break;
- case OSEND:
- orderexpr(&r->left, &l->n->ninit);
- orderexpr(&r->right, &l->n->ninit);
- break;
+ setlineno(l->n);
+ // Append any new body prologue to ninit.
+ // The next loop will insert ninit into nbody.
+ if(l->n->ninit != nil)
+ fatal("order select ninit");
+ if(r != nil) {
+ switch(r->op) {
+ default:
+ yyerror("unknown op in select %O", r->op);
+ dump("select case", r);
+ break;
+
+ case OSELRECV:
+ case OSELRECV2:
+ // If this is case x := <-ch or case x, y := <-ch, the case has
+ // the ODCL nodes to declare x and y. We want to delay that
+ // declaration (and possible allocation) until inside the case body.
+ // Delete the ODCL nodes here and recreate them inside the body below.
+ if(r->colas) {
+ t = r->ninit;
+ if(t != nil && t->n->op == ODCL && t->n->left == r->left)
+ t = t->next;
+ if(t != nil && t->n->op == ODCL && t->n->left == r->ntest)
+ t = t->next;
+ if(t == nil)
+ r->ninit = nil;
+ }
+ if(r->ninit != nil) {
+ yyerror("ninit on select recv");
+ dumplist("ninit", r->ninit);
+ }
+ // case x = <-c
+ // case x, ok = <-c
+ // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
+ // r->left == N means 'case <-c'.
+ // c is always evaluated; x and ok are only evaluated when assigned.
+ orderexpr(&r->right->left, order);
+
+ // Introduce temporary for receive and move actual copy into case body.
+ // avoids problems with target being addressed, as usual.
+ // NOTE: If we wanted to be clever, we could arrange for just one
+ // temporary per distinct type, sharing the temp among all receives
+ // with that temp. Similarly one ok bool could be shared among all
+ // the x,ok receives. Not worth doing until there's a clear need.
+ if(r->left != N && isblank(r->left))
+ r->left = N;
+ if(r->left != N) {
+ // use channel element type for temporary to avoid conversions,
+ // such as in case interfacevalue = <-intchan.
+ // the conversion happens in the OAS instead.
+ tmp1 = r->left;
+ if(r->colas) {
+ tmp2 = nod(ODCL, tmp1, N);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type));
+ tmp2 = nod(OAS, tmp1, r->left);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ if(r->ntest != N && isblank(r->ntest))
+ r->ntest = N;
+ if(r->ntest != N) {
+ tmp1 = r->ntest;
+ if(r->colas) {
+ tmp2 = nod(ODCL, tmp1, N);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ r->ntest = ordertemp(tmp1->type, order, 0);
+ tmp2 = nod(OAS, tmp1, r->ntest);
+ typecheck(&tmp2, Etop);
+ l->n->ninit = list(l->n->ninit, tmp2);
+ }
+ orderblock(&l->n->ninit);
+ break;
+
+ case OSEND:
+ if(r->ninit != nil) {
+ yyerror("ninit on select send");
+ dumplist("ninit", r->ninit);
+ }
+ // case c <- x
+ // r->left is c, r->right is x, both are always evaluated.
+ orderexpr(&r->left, order);
+ if(!istemp(r->left))
+ r->left = ordercopyexpr(r->left, r->left->type, order, 0);
+ orderexpr(&r->right, order);
+ if(!istemp(r->right))
+ r->right = ordercopyexpr(r->right, r->right->type, order, 0);
+ break;
+ }
}
+ orderblock(&l->n->nbody);
}
- *out = list(*out, n);
+ // Now that we have accumulated all the temporaries, clean them.
+ // Also insert any ninit queued during the previous loop.
+ // (The temporary cleaning must follow that ninit work.)
+ for(l=n->list; l; l=l->next) {
+ cleantempnopop(t, order, &l->n->ninit);
+ l->n->nbody = concat(l->n->ninit, l->n->nbody);
+ l->n->ninit = nil;
+ }
+ order->out = list(order->out, n);
+ poptemp(t, order);
+ break;
+
+ case OSEND:
+ // Special: value being sent is passed as a pointer; make it addressable.
+ t = marktemp(order);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderaddrtemp(&n->right, order);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
case OSWITCH:
- orderexpr(&n->ntest, out);
+ // TODO(rsc): Clean temporaries more aggressively.
+ // Note that because walkswitch will rewrite some of the
+ // switch into a binary search, this is not as easy as it looks.
+ // (If we ran that code here we could invoke orderstmt on
+ // the if-else chain instead.)
+ // For now just clean all the temporaries at the end.
+ // In practice that's fine.
+ t = marktemp(order);
+ orderexpr(&n->ntest, order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
fatal("order switch case %O", l->n->op);
- orderexpr(&l->n->left, &l->n->ninit);
+ orderexprlistinplace(l->n->list, order);
+ orderblock(&l->n->nbody);
}
- *out = list(*out, n);
+ order->out = list(order->out, n);
+ cleantemp(t, order);
break;
-
- case OXFALL:
- yyerror("fallthrough statement out of place");
- n->op = OFALL;
- goto case_OFALL;
}
lineno = lno;
}
+// Orderexprlist orders the expression list l into order.
+static void
+orderexprlist(NodeList *l, Order *order)
+{
+ for(; l; l=l->next)
+ orderexpr(&l->n, order);
+}
+
+// Orderexprlist orders the expression list l but saves
+// the side effects on the individual expression ninit lists.
static void
-orderexprlist(NodeList *l, NodeList **out)
+orderexprlistinplace(NodeList *l, Order *order)
{
for(; l; l=l->next)
- orderexpr(&l->n, out);
+ orderexprinplace(&l->n, order);
}
+// Orderexpr orders a single expression, appending side
+// effects to order->out as needed.
static void
-orderexpr(Node **np, NodeList **out)
+orderexpr(Node **np, Order *order)
{
Node *n;
+ NodeList *mark, *l;
+ Type *t;
int lno;
n = *np;
@@ -325,31 +947,113 @@ orderexpr(Node **np, NodeList **out)
return;
lno = setlineno(n);
- orderinit(n, out);
+ orderinit(n, order);
switch(n->op) {
default:
- orderexpr(&n->left, out);
- orderexpr(&n->right, out);
- orderexprlist(n->list, out);
- orderexprlist(n->rlist, out);
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ break;
+
+ case OADDSTR:
+ // Addition of strings turns into a function call.
+ // Allocate a temporary to hold the strings.
+ // Fewer than 5 strings use direct runtime helpers.
+ orderexprlist(n->list, order);
+ if(count(n->list) > 5) {
+ t = typ(TARRAY);
+ t->bound = count(n->list);
+ t->type = types[TSTRING];
+ n->alloc = ordertemp(t, order, 0);
+ }
+ break;
+
+ case OINDEXMAP:
+ // key must be addressable
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+
+ // For x = m[string(k)] where k is []byte, the allocation of
+ // backing bytes for the string can be avoided by reusing
+ // the []byte backing array. This is a special case that it
+ // would be nice to handle more generally, but because
+ // there are no []byte-keyed maps, this specific case comes
+ // up in important cases in practice. See issue 3512.
+ // Nothing can change the []byte we are not copying before
+ // the map index, because the map access is going to
+ // be forced to happen immediately following this
+ // conversion (by the ordercopyexpr a few lines below).
+ if(n->etype == 0 && n->right->op == OARRAYBYTESTR)
+ n->right->op = OARRAYBYTESTRTMP;
+
+ orderaddrtemp(&n->right, order);
+ if(n->etype == 0) {
+ // use of value (not being assigned);
+ // make copy in temporary.
+ n = ordercopyexpr(n, n->type, order, 0);
+ }
+ break;
+
+ case OCONVIFACE:
+ // concrete type (not interface) argument must be addressable
+ // temporary to pass to runtime.
+ orderexpr(&n->left, order);
+ if(!isinter(n->left->type))
+ orderaddrtemp(&n->left, order);
break;
case OANDAND:
case OOROR:
- orderexpr(&n->left, out);
- orderexprinplace(&n->right);
+ mark = marktemp(order);
+ orderexpr(&n->left, order);
+ // Clean temporaries from first branch at beginning of second.
+ // Leave them on the stack so that they can be killed in the outer
+ // context in case the short circuit is taken.
+ l = nil;
+ cleantempnopop(mark, order, &l);
+ n->right->ninit = concat(l, n->right->ninit);
+ orderexprinplace(&n->right, order);
break;
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
- ordercall(n, out);
- n = copyexpr(n, n->type, out);
+ case OAPPEND:
+ case OCOMPLEX:
+ ordercall(n, order);
+ n = ordercopyexpr(n, n->type, order, 0);
+ break;
+
+ case OCLOSURE:
+ if(n->noescape && n->cvars != nil)
+ n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
+ break;
+
+ case OARRAYLIT:
+ case OCALLPART:
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ orderexprlist(n->list, order);
+ orderexprlist(n->rlist, order);
+ if(n->noescape)
+ n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
+ break;
+
+ case ODDDARG:
+ if(n->noescape) {
+ // The ddd argument does not live beyond the call it is created for.
+ // Allocate a temporary that will be cleaned up when this statement
+ // completes. We could be more aggressive and try to arrange for it
+ // to be cleaned up when the call completes.
+ n->alloc = ordertemp(n->type->type, order, 0);
+ }
break;
case ORECV:
- n = copyexpr(n, n->type, out);
+ orderexpr(&n->left, order);
+ n = ordercopyexpr(n, n->type, order, 1);
break;
}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 2850af6bb..40620c3da 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -8,30 +8,159 @@
#include <u.h>
#include <libc.h>
+#include "md5.h"
#include "gg.h"
#include "opt.h"
#include "../../pkg/runtime/funcdata.h"
-enum { BitsPerPointer = 2 };
-
static void allocauto(Prog* p);
-static void dumpgcargs(Node*, Sym*);
-static Bvec* dumpgclocals(Node*, Sym*);
+
+static Sym*
+makefuncdatasym(char *namefmt, int64 funcdatakind)
+{
+ Node nod;
+ Node *pnod;
+ Sym *sym;
+ static int32 nsym;
+
+ snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
+ sym = lookup(namebuf);
+ pnod = newname(sym);
+ pnod->class = PEXTERN;
+ nodconst(&nod, types[TINT32], funcdatakind);
+ gins(AFUNCDATA, &nod, pnod);
+ return sym;
+}
+
+// gvardef inserts a VARDEF for n into the instruction stream.
+// VARDEF is an annotation for the liveness analysis, marking a place
+// where a complete initialization (definition) of a variable begins.
+// Since the liveness analysis can see initialization of single-word
+// variables quite easy, gvardef is usually only called for multi-word
+// or 'fat' variables, those satisfying isfat(n->type).
+// However, gvardef is also called when a non-fat variable is initialized
+// via a block move; the only time this happens is when you have
+// return f()
+// for a function with multiple return values exactly matching the return
+// types of the current function.
+//
+// A 'VARDEF x' annotation in the instruction stream tells the liveness
+// analysis to behave as though the variable x is being initialized at that
+// point in the instruction stream. The VARDEF must appear before the
+// actual (multi-instruction) initialization, and it must also appear after
+// any uses of the previous value, if any. For example, if compiling:
+//
+// x = x[1:]
+//
+// it is important to generate code like:
+//
+// base, len, cap = pieces of x[1:]
+// VARDEF x
+// x = {base, len, cap}
+//
+// If instead the generated code looked like:
+//
+// VARDEF x
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+//
+// then the liveness analysis would decide the previous value of x was
+// unnecessary even though it is about to be used by the x[1:] computation.
+// Similarly, if the generated code looked like:
+//
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+// VARDEF x
+//
+// then the liveness analysis will not preserve the new value of x, because
+// the VARDEF appears to have "overwritten" it.
+//
+// VARDEF is a bit of a kludge to work around the fact that the instruction
+// stream is working on single-word values but the liveness analysis
+// wants to work on individual variables, which might be multi-word
+// aggregates. It might make sense at some point to look into letting
+// the liveness analysis work on single-word values as well, although
+// there are complications around interface values, slices, and strings,
+// all of which cannot be treated as individual words.
+//
+// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
+// even if its address has been taken. That is, a VARKILL annotation asserts
+// that its argument is certainly dead, for use when the liveness analysis
+// would not otherwise be able to deduce that fact.
+
+static void
+gvardefx(Node *n, int as)
+{
+ if(n == N)
+ fatal("gvardef nil");
+ if(n->op != ONAME) {
+ yyerror("gvardef %#O; %N", n->op, n);
+ return;
+ }
+ switch(n->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ gins(as, N, n);
+ }
+}
+
+void
+gvardef(Node *n)
+{
+ gvardefx(n, AVARDEF);
+}
+
+void
+gvarkill(Node *n)
+{
+ gvardefx(n, AVARKILL);
+}
+
+static void
+removevardef(Prog *firstp)
+{
+ Prog *p;
+
+ for(p = firstp; p != P; p = p->link) {
+ while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
+ p->link = p->link->link;
+ if(p->to.type == D_BRANCH)
+ while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
+ p->to.u.branch = p->to.u.branch->link;
+ }
+}
+
+static void
+gcsymdup(Sym *s)
+{
+ LSym *ls;
+ uint64 lo, hi;
+
+ ls = linksym(s);
+ if(ls->nr > 0)
+ fatal("cannot rosymdup %s with relocations", ls->name);
+ MD5 d;
+ md5reset(&d);
+ md5write(&d, ls->p, ls->np);
+ lo = md5sum(&d, &hi);
+ ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
+ ls->dupok = 1;
+}
void
compile(Node *fn)
{
- Bvec *bv;
Plist *pl;
- Node nod1, *n, *gcargsnod, *gclocalsnod;
- Prog *ptxt, *p, *p1;
+ Node nod1, *n;
+ Prog *ptxt, *p;
int32 lno;
Type *t;
Iter save;
vlong oldstksize;
NodeList *l;
- Sym *gcargssym, *gclocalssym;
- static int ngcargs, ngclocals;
+ Sym *gcargs;
+ Sym *gclocals;
if(newproc == N) {
newproc = sysfunc("newproc");
@@ -45,7 +174,7 @@ compile(Node *fn)
lno = setlineno(fn);
if(fn->nbody == nil) {
- if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0)
+ if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0)
yyerror("missing function body", fn);
goto ret;
}
@@ -88,7 +217,7 @@ compile(Node *fn)
breakpc = P;
pl = newplist();
- pl->name = curfn->nname;
+ pl->name = linksym(curfn->nname->sym);
setlineno(curfn);
@@ -98,6 +227,8 @@ compile(Node *fn)
ptxt->TEXTFLAG |= DUPOK;
if(fn->wrapper)
ptxt->TEXTFLAG |= WRAPPER;
+ if(fn->needctxt)
+ ptxt->TEXTFLAG |= NEEDCTXT;
// Clumsy but important.
// See test/recover.go for test cases and src/pkg/reflect/value.go
@@ -111,21 +242,8 @@ compile(Node *fn)
ginit();
- snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++);
- gcargssym = lookup(namebuf);
- gcargsnod = newname(gcargssym);
- gcargsnod->class = PEXTERN;
-
- nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs);
- gins(AFUNCDATA, &nod1, gcargsnod);
-
- snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++);
- gclocalssym = lookup(namebuf);
- gclocalsnod = newname(gclocalssym);
- gclocalsnod->class = PEXTERN;
-
- nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals);
- gins(AFUNCDATA, &nod1, gclocalsnod);
+ gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
+ gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
for(t=curfn->paramfld; t; t=t->down)
gtrack(tracksym(t->type));
@@ -140,20 +258,12 @@ compile(Node *fn)
case PPARAMOUT:
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
p = gins(ATYPE, l->n, &nod1);
- p->from.gotype = ngotype(l->n);
+ p->from.gotype = linksym(ngotype(l->n));
break;
}
}
genlist(curfn->enter);
-
- retpc = nil;
- if(hasdefer || curfn->exit) {
- p1 = gjmp(nil);
- retpc = gjmp(nil);
- patch(p1, pc);
- }
-
genlist(curfn->nbody);
gclean();
checklabels();
@@ -165,13 +275,15 @@ compile(Node *fn)
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
- if(retpc)
- patch(retpc, pc);
ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
+ // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
+ cgen_ret(nil);
+ if(hasdefer) {
+ // deferreturn pretends to have one uintptr argument.
+ // Reserve space for it so stack scanner is happy.
+ if(maxarg < widthptr)
+ maxarg = widthptr;
+ }
gclean();
if(nerrors != 0)
goto ret;
@@ -179,6 +291,7 @@ compile(Node *fn)
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
+ fixjmp(ptxt);
if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
nilopt(ptxt);
@@ -190,6 +303,7 @@ compile(Node *fn)
if(0)
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
+ USED(oldstksize);
setlineno(curfn);
if((int64)stksize+maxarg > (1ULL<<31)) {
@@ -198,184 +312,21 @@ compile(Node *fn)
}
// Emit garbage collection symbols.
- dumpgcargs(fn, gcargssym);
- bv = dumpgclocals(curfn, gclocalssym);
+ liveness(curfn, ptxt, gcargs, gclocals);
+ gcsymdup(gcargs);
+ gcsymdup(gclocals);
- defframe(ptxt, bv);
- free(bv);
+ defframe(ptxt);
if(0)
frame(0);
+ // Remove leftover instrumentation from the instruction stream.
+ removevardef(ptxt);
ret:
lineno = lno;
}
-static void
-walktype1(Type *t, vlong *xoffset, Bvec *bv)
-{
- vlong fieldoffset, i, o;
- Type *t1;
-
- if(t->align > 0 && (*xoffset % t->align) != 0)
- fatal("walktype1: invalid initial alignment, %T", t);
-
- switch(t->etype) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TFLOAT32:
- case TFLOAT64:
- case TCOMPLEX64:
- case TCOMPLEX128:
- *xoffset += t->width;
- break;
-
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TFUNC:
- case TCHAN:
- case TMAP:
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- break;
-
- case TSTRING:
- // struct { byte *str; intgo len; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- break;
-
- case TINTER:
- // struct { Itab* tab; union { void* ptr, uintptr val } data; }
- // or, when isnilinter(t)==true:
- // struct { Type* type; union { void* ptr, uintptr val } data; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid alignment, %T", t);
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1);
- if(isnilinter(t))
- bvset(bv, ((*xoffset / widthptr) * BitsPerPointer));
- *xoffset += t->width;
- break;
-
- case TARRAY:
- // The value of t->bound is -1 for slices types and >0 for
- // for fixed array types. All other values are invalid.
- if(t->bound < -1)
- fatal("walktype1: invalid bound, %T", t);
- if(isslice(t)) {
- // struct { byte* array; uintgo len; uintgo cap; }
- if(*xoffset % widthptr != 0)
- fatal("walktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer);
- *xoffset += t->width;
- } else if(!haspointers(t->type))
- *xoffset += t->width;
- else
- for(i = 0; i < t->bound; ++i)
- walktype1(t->type, xoffset, bv);
- break;
-
- case TSTRUCT:
- o = 0;
- for(t1 = t->type; t1 != T; t1 = t1->down) {
- fieldoffset = t1->width;
- *xoffset += fieldoffset - o;
- walktype1(t1->type, xoffset, bv);
- o = fieldoffset + t1->type->width;
- }
- *xoffset += t->width - o;
- break;
-
- default:
- fatal("walktype1: unexpected type, %T", t);
- }
-}
-
-static void
-walktype(Type *type, Bvec *bv)
-{
- vlong xoffset;
-
- // Start the walk at offset 0. The correct offset will be
- // filled in by the first type encountered during the walk.
- xoffset = 0;
- walktype1(type, &xoffset, bv);
-}
-
-// Compute a bit vector to describe the pointer-containing locations
-// in the in and out argument list and dump the bitvector length and
-// data to the provided symbol.
-static void
-dumpgcargs(Node *fn, Sym *sym)
-{
- Type *thistype, *inargtype, *outargtype;
- Bvec *bv;
- int32 i;
- int off;
-
- thistype = getthisx(fn->type);
- inargtype = getinargx(fn->type);
- outargtype = getoutargx(fn->type);
- bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer);
- if(thistype != nil)
- walktype(thistype, bv);
- if(inargtype != nil)
- walktype(inargtype, bv);
- if(outargtype != nil)
- walktype(outargtype, bv);
- off = duint32(sym, 0, bv->n);
- for(i = 0; i < bv->n; i += 32)
- off = duint32(sym, off, bv->b[i/32]);
- free(bv);
- ggloblsym(sym, off, 0, 1);
-}
-
-// Compute a bit vector to describe the pointer-containing locations
-// in local variables and dump the bitvector length and data out to
-// the provided symbol. Return the vector for use and freeing by caller.
-static Bvec*
-dumpgclocals(Node* fn, Sym *sym)
-{
- Bvec *bv;
- NodeList *ll;
- Node *node;
- vlong xoffset;
- int32 i;
- int off;
-
- bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer);
- for(ll = fn->dcl; ll != nil; ll = ll->next) {
- node = ll->n;
- if(node->class == PAUTO && node->op == ONAME) {
- if(haspointers(node->type)) {
- xoffset = node->xoffset + stkptrsize;
- walktype1(node->type, &xoffset, bv);
- }
- }
- }
- off = duint32(sym, 0, bv->n);
- for(i = 0; i < bv->n; i += 32) {
- off = duint32(sym, off, bv->b[i/32]);
- }
- ggloblsym(sym, off, 0, 1);
- return bv;
-}
-
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.
@@ -415,7 +366,8 @@ cmpstackvar(Node *a, Node *b)
return +1;
if(a->type->width > b->type->width)
return -1;
- return 0;
+
+ return strcmp(a->sym->name, b->sym->name);
}
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
@@ -428,7 +380,6 @@ allocauto(Prog* ptxt)
stksize = 0;
stkptrsize = 0;
- stkzerosize = 0;
if(curfn->dcl == nil)
return;
@@ -440,13 +391,6 @@ allocauto(Prog* ptxt)
markautoused(ptxt);
- if(precisestack_enabled) {
- // TODO: Remove when liveness analysis sets needzero instead.
- for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if(ll->n->class == PAUTO)
- ll->n->needzero = 1; // ll->n->addrtaken;
- }
-
listsort(&curfn->dcl, cmpstackvar);
// Unused autos are at the end, chop 'em off.
@@ -480,11 +424,8 @@ allocauto(Prog* ptxt)
fatal("bad width");
stksize += w;
stksize = rnd(stksize, n->type->align);
- if(haspointers(n->type)) {
+ if(haspointers(n->type))
stkptrsize = stksize;
- if(n->needzero)
- stkzerosize = stksize;
- }
if(thechar == '5')
stksize = rnd(stksize, widthptr);
if(stksize >= (1ULL<<31)) {
@@ -493,9 +434,8 @@ allocauto(Prog* ptxt)
}
n->stkdelta = -stksize - n->xoffset;
}
- stksize = rnd(stksize, widthptr);
- stkptrsize = rnd(stkptrsize, widthptr);
- stkzerosize = rnd(stkzerosize, widthptr);
+ stksize = rnd(stksize, widthreg);
+ stkptrsize = rnd(stkptrsize, widthreg);
fixautoused(ptxt);
@@ -538,12 +478,12 @@ cgen_checknil(Node *n)
if(disable_checknil)
return;
- // Ideally we wouldn't see any TUINTPTR here, but we do.
- if(n->type == T || (!isptr[n->type->etype] && n->type->etype != TUINTPTR && n->type->etype != TUNSAFEPTR)) {
+ // Ideally we wouldn't see any integer types here, but we do.
+ if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
dump("checknil", n);
fatal("bad checknil");
}
- if((thechar == '5' && n->op != OREGISTER) || !n->addable) {
+ if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
regalloc(&reg, types[tptr], n);
cgen(n, &reg);
gins(ACHECKNIL, &reg, N);
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
new file mode 100644
index 000000000..eb8901733
--- /dev/null
+++ b/src/cmd/gc/plive.c
@@ -0,0 +1,1985 @@
+// 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.
+
+// Garbage collector liveness bitmap generation.
+
+// The command line flag -live causes this code to print debug information.
+// The levels are:
+//
+// -live (aka -live=1): print liveness lists as code warnings at safe points
+// -live=2: print an assembly listing with liveness annotations
+// -live=3: print information during each computation phase (much chattier)
+//
+// Each level includes the earlier output as well.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+#include "../../pkg/runtime/funcdata.h"
+
+enum { BitsPerPointer = 2 };
+
+enum {
+ UNVISITED = 0,
+ VISITED = 1,
+};
+
+// An ordinary basic block.
+//
+// Instructions are threaded together in a doubly-linked list. To iterate in
+// program order follow the link pointer from the first node and stop after the
+// last node has been visited
+//
+// for(p = bb->first;; p = p->link) {
+// ...
+// if(p == bb->last)
+// break;
+// }
+//
+// To iterate in reverse program order by following the opt pointer from the
+// last node
+//
+// for(p = bb->last; p != nil; p = p->opt) {
+// ...
+// }
+typedef struct BasicBlock BasicBlock;
+struct BasicBlock {
+ // An array of preceding blocks. If the length of this array is 0 the
+ // block is probably the start block of the CFG.
+ Array *pred;
+
+ // An array out succeeding blocks. If the length of this array is zero,
+ // the block probably ends in a return instruction.
+ Array *succ;
+
+ // First instruction in the block. When part of a fully initialized
+ // control flow graph, the opt member will be nil.
+ Prog *first;
+
+ // Last instruction in the basic block.
+ Prog *last;
+
+ // The reverse post order number. This value is initialized to -1 and
+ // will be replaced by a non-negative value when the CFG is constructed.
+ // After CFG construction, if rpo is -1 this block is unreachable.
+ int rpo;
+
+ // State to denote whether the block has been visited during a
+ // traversal.
+ int mark;
+
+ // For use during livenessepilogue.
+ int lastbitmapindex;
+};
+
+// A collection of global state used by liveness analysis.
+typedef struct Liveness Liveness;
+struct Liveness {
+ // A pointer to the node corresponding to the function being analyzed.
+ Node *fn;
+
+ // A linked list of instructions for this function.
+ Prog *ptxt;
+
+ // A list of arguments and local variables in this function.
+ Array *vars;
+
+ // A list of basic blocks that are overlayed on the instruction list.
+ // The blocks are roughly in the same order as the instructions
+ // in the function (first block has TEXT instruction, and so on).
+ Array *cfg;
+
+ // Summary sets of block effects.
+ // The Bvec** is indexed by bb->rpo to yield a single Bvec*.
+ // That bit vector is indexed by variable number (same as lv->vars).
+ //
+ // Computed during livenessprologue using only the content of
+ // individual blocks:
+ //
+ // uevar: upward exposed variables (used before set in block)
+ // varkill: killed variables (set in block)
+ // avarinit: addrtaken variables set or used (proof of initialization)
+ //
+ // Computed during livenesssolve using control flow information:
+ //
+ // livein: variables live at block entry
+ // liveout: variables live at block exit
+ // avarinitany: addrtaken variables possibly initialized at block exit
+ // (initialized in block or at exit from any predecessor block)
+ // avarinitall: addrtaken variables certainly initialized at block exit
+ // (initialized in block or at exit from all predecessor blocks)
+ Bvec **uevar;
+ Bvec **varkill;
+ Bvec **livein;
+ Bvec **liveout;
+ Bvec **avarinit;
+ Bvec **avarinitany;
+ Bvec **avarinitall;
+
+ // An array with a bit vector for each safe point tracking live pointers
+ // in the arguments and locals area, indexed by bb->rpo.
+ Array *argslivepointers;
+ Array *livepointers;
+};
+
+static void*
+xmalloc(uintptr size)
+{
+ void *result;
+
+ result = malloc(size);
+ if(result == nil)
+ fatal("malloc failed");
+ return result;
+}
+
+// Constructs a new basic block containing a single instruction.
+static BasicBlock*
+newblock(Prog *prog)
+{
+ BasicBlock *result;
+
+ if(prog == nil)
+ fatal("newblock: prog cannot be nil");
+ result = xmalloc(sizeof(*result));
+ result->rpo = -1;
+ result->mark = UNVISITED;
+ result->first = prog;
+ result->last = prog;
+ result->pred = arraynew(2, sizeof(BasicBlock*));
+ result->succ = arraynew(2, sizeof(BasicBlock*));
+ return result;
+}
+
+// Frees a basic block and all of its leaf data structures.
+static void
+freeblock(BasicBlock *bb)
+{
+ if(bb == nil)
+ fatal("freeblock: cannot free nil");
+ arrayfree(bb->pred);
+ arrayfree(bb->succ);
+ free(bb);
+}
+
+// Adds an edge between two basic blocks by making from a predecessor of to and
+// to a successor of from.
+static void
+addedge(BasicBlock *from, BasicBlock *to)
+{
+ if(from == nil)
+ fatal("addedge: from is nil");
+ if(to == nil)
+ fatal("addedge: to is nil");
+ arrayadd(from->succ, &to);
+ arrayadd(to->pred, &from);
+}
+
+// Inserts prev before curr in the instruction
+// stream. Any control flow, such as branches or fall throughs, that target the
+// existing instruction are adjusted to target the new instruction.
+static void
+splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr)
+{
+ Prog *next, tmp;
+
+ USED(lv);
+
+ // There may be other instructions pointing at curr,
+ // and we want them to now point at prev. Instead of
+ // trying to find all such instructions, swap the contents
+ // so that the problem becomes inserting next after curr.
+ // The "opt" field is the backward link in the linked list.
+
+ // Overwrite curr's data with prev, but keep the list links.
+ tmp = *curr;
+ *curr = *prev;
+ curr->opt = tmp.opt;
+ curr->link = tmp.link;
+
+ // Overwrite prev (now next) with curr's old data.
+ next = prev;
+ *next = tmp;
+ next->opt = nil;
+ next->link = nil;
+
+ // Now insert next after curr.
+ next->link = curr->link;
+ next->opt = curr;
+ curr->link = next;
+ if(next->link && next->link->opt == curr)
+ next->link->opt = next;
+
+ if(bb->last == curr)
+ bb->last = next;
+}
+
+// A pretty printer for basic blocks.
+static void
+printblock(BasicBlock *bb)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+ Prog *prog;
+ int i;
+
+ print("basic block %d\n", bb->rpo);
+ print("\tpred:");
+ for(i = 0; i < arraylength(bb->pred); i++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, i);
+ print(" %d", pred->rpo);
+ }
+ print("\n");
+ print("\tsucc:");
+ for(i = 0; i < arraylength(bb->succ); i++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, i);
+ print(" %d", succ->rpo);
+ }
+ print("\n");
+ print("\tprog:\n");
+ for(prog = bb->first;; prog=prog->link) {
+ print("\t\t%P\n", prog);
+ if(prog == bb->last)
+ break;
+ }
+}
+
+
+// Iterates over a basic block applying a callback to each instruction. There
+// are two criteria for termination. If the end of basic block is reached a
+// value of zero is returned. If the callback returns a non-zero value, the
+// iteration is stopped and the value of the callback is returned.
+static int
+blockany(BasicBlock *bb, int (*callback)(Prog*))
+{
+ Prog *p;
+ int result;
+
+ for(p = bb->last; p != nil; p = p->opt) {
+ result = (*callback)(p);
+ if(result != 0)
+ return result;
+ }
+ return 0;
+}
+
+// Collects and returns and array of Node*s for functions arguments and local
+// variables.
+static Array*
+getvariables(Node *fn)
+{
+ Array *result;
+ NodeList *ll;
+
+ result = arraynew(0, sizeof(Node*));
+ for(ll = fn->dcl; ll != nil; ll = ll->next) {
+ if(ll->n->op == ONAME) {
+ // In order for GODEBUG=gcdead=1 to work, each bitmap needs
+ // to contain information about all variables covered by the bitmap.
+ // For local variables, the bitmap only covers the stkptrsize
+ // bytes in the frame where variables containing pointers live.
+ // For arguments and results, the bitmap covers all variables,
+ // so we must include all the variables, even the ones without
+ // pointers.
+ switch(ll->n->class) {
+ case PAUTO:
+ if(haspointers(ll->n->type))
+ arrayadd(result, &ll->n);
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ arrayadd(result, &ll->n);
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+// A pretty printer for control flow graphs. Takes an array of BasicBlock*s.
+static void
+printcfg(Array *cfg)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ printblock(bb);
+ }
+}
+
+// Assigns a reverse post order number to each connected basic block using the
+// standard algorithm. Unconnected blocks will not be affected.
+static void
+reversepostorder(BasicBlock *root, int32 *rpo)
+{
+ BasicBlock *bb;
+ int i;
+
+ root->mark = VISITED;
+ for(i = 0; i < arraylength(root->succ); i++) {
+ bb = *(BasicBlock**)arrayget(root->succ, i);
+ if(bb->mark == UNVISITED)
+ reversepostorder(bb, rpo);
+ }
+ *rpo -= 1;
+ root->rpo = *rpo;
+}
+
+// Comparison predicate used for sorting basic blocks by their rpo in ascending
+// order.
+static int
+blockrpocmp(const void *p1, const void *p2)
+{
+ BasicBlock *bb1;
+ BasicBlock *bb2;
+
+ bb1 = *(BasicBlock**)p1;
+ bb2 = *(BasicBlock**)p2;
+ if(bb1->rpo < bb2->rpo)
+ return -1;
+ if(bb1->rpo > bb2->rpo)
+ return 1;
+ return 0;
+}
+
+// A pattern matcher for call instructions. Returns true when the instruction
+// is a call to a specific package qualified function name.
+static int
+iscall(Prog *prog, LSym *name)
+{
+ if(prog == nil)
+ fatal("iscall: prog is nil");
+ if(name == nil)
+ fatal("iscall: function name is nil");
+ if(prog->as != ACALL)
+ return 0;
+ return name == prog->to.sym;
+}
+
+// Returns true for instructions that call a runtime function implementing a
+// select communication clause.
+static int
+isselectcommcasecall(Prog *prog)
+{
+ static LSym* names[5];
+ int32 i;
+
+ if(names[0] == nil) {
+ names[0] = linksym(pkglookup("selectsend", runtimepkg));
+ names[1] = linksym(pkglookup("selectrecv", runtimepkg));
+ names[2] = linksym(pkglookup("selectrecv2", runtimepkg));
+ names[3] = linksym(pkglookup("selectdefault", runtimepkg));
+ }
+ for(i = 0; names[i] != nil; i++)
+ if(iscall(prog, names[i]))
+ return 1;
+ return 0;
+}
+
+// Returns true for call instructions that target runtime·newselect.
+static int
+isnewselect(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("newselect", runtimepkg));
+ return iscall(prog, sym);
+}
+
+// Returns true for call instructions that target runtime·selectgo.
+static int
+isselectgocall(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("selectgo", runtimepkg));
+ return iscall(prog, sym);
+}
+
+static int
+isdeferreturn(Prog *prog)
+{
+ static LSym *sym;
+
+ if(sym == nil)
+ sym = linksym(pkglookup("deferreturn", runtimepkg));
+ return iscall(prog, sym);
+}
+
+// Walk backwards from a runtime·selectgo call up to its immediately dominating
+// runtime·newselect call. Any successor nodes of communication clause nodes
+// are implicit successors of the runtime·selectgo call node. The goal of this
+// analysis is to add these missing edges to complete the control flow graph.
+static void
+addselectgosucc(BasicBlock *selectgo)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+
+ pred = selectgo;
+ for(;;) {
+ if(arraylength(pred->pred) == 0)
+ fatal("selectgo does not have a newselect");
+ pred = *(BasicBlock**)arrayget(pred->pred, 0);
+ if(blockany(pred, isselectcommcasecall)) {
+ // A select comm case block should have exactly one
+ // successor.
+ if(arraylength(pred->succ) != 1)
+ fatal("select comm case has too many successors");
+ succ = *(BasicBlock**)arrayget(pred->succ, 0);
+ // Its successor should have exactly two successors.
+ // The drop through should flow to the selectgo block
+ // and the branch should lead to the select case
+ // statements block.
+ if(arraylength(succ->succ) != 2)
+ fatal("select comm case successor has too many successors");
+ // Add the block as a successor of the selectgo block.
+ addedge(selectgo, succ);
+ }
+ if(blockany(pred, isnewselect)) {
+ // Reached the matching newselect.
+ break;
+ }
+ }
+}
+
+// The entry point for the missing selectgo control flow algorithm. Takes an
+// array of BasicBlock*s containing selectgo calls.
+static void
+fixselectgo(Array *selectgo)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(selectgo); i++) {
+ bb = *(BasicBlock**)arrayget(selectgo, i);
+ addselectgosucc(bb);
+ }
+}
+
+// Constructs a control flow graph from a sequence of instructions. This
+// procedure is complicated by various sources of implicit control flow that are
+// not accounted for using the standard cfg construction algorithm. Returns an
+// array of BasicBlock*s in control flow graph form (basic blocks ordered by
+// their RPO number).
+static Array*
+newcfg(Prog *firstp)
+{
+ Prog *p;
+ Prog *prev;
+ BasicBlock *bb;
+ Array *cfg;
+ Array *selectgo;
+ int32 i;
+ int32 rpo;
+
+ // Reset the opt field of each prog to nil. In the first and second
+ // passes, instructions that are labels temporarily use the opt field to
+ // point to their basic block. In the third pass, the opt field reset
+ // to point to the predecessor of an instruction in its basic block.
+ for(p = firstp; p != P; p = p->link)
+ p->opt = nil;
+
+ // Allocate an array to remember where we have seen selectgo calls.
+ // These blocks will be revisited to add successor control flow edges.
+ selectgo = arraynew(0, sizeof(BasicBlock*));
+
+ // Loop through all instructions identifying branch targets
+ // and fall-throughs and allocate basic blocks.
+ cfg = arraynew(0, sizeof(BasicBlock*));
+ bb = newblock(firstp);
+ arrayadd(cfg, &bb);
+ for(p = firstp; p != P; p = p->link) {
+ if(p->to.type == D_BRANCH) {
+ if(p->to.u.branch == nil)
+ fatal("prog branch to nil");
+ if(p->to.u.branch->opt == nil) {
+ p->to.u.branch->opt = newblock(p->to.u.branch);
+ arrayadd(cfg, &p->to.u.branch->opt);
+ }
+ if(p->as != AJMP && p->link != nil && p->link->opt == nil) {
+ p->link->opt = newblock(p->link);
+ arrayadd(cfg, &p->link->opt);
+ }
+ } else if(isselectcommcasecall(p) || isselectgocall(p)) {
+ // Accommodate implicit selectgo control flow.
+ if(p->link->opt == nil) {
+ p->link->opt = newblock(p->link);
+ arrayadd(cfg, &p->link->opt);
+ }
+ }
+ }
+
+ // Loop through all basic blocks maximally growing the list of
+ // contained instructions until a label is reached. Add edges
+ // for branches and fall-through instructions.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ for(p = bb->last; p != nil; p = p->link) {
+ if(p->opt != nil && p != bb->last)
+ break;
+ bb->last = p;
+
+ // Stop before an unreachable RET, to avoid creating
+ // unreachable control flow nodes.
+ if(p->link != nil && p->link->as == ARET && p->link->mode == 1)
+ break;
+
+ // Collect basic blocks with selectgo calls.
+ if(isselectgocall(p))
+ arrayadd(selectgo, &bb);
+ }
+ if(bb->last->to.type == D_BRANCH)
+ addedge(bb, bb->last->to.u.branch->opt);
+ if(bb->last->link != nil) {
+ // Add a fall-through when the instruction is
+ // not an unconditional control transfer.
+ switch(bb->last->as) {
+ case AJMP:
+ case ARET:
+ case AUNDEF:
+ break;
+ default:
+ addedge(bb, bb->last->link->opt);
+ }
+ }
+ }
+
+ // Add back links so the instructions in a basic block can be traversed
+ // backward. This is the final state of the instruction opt field.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ p = bb->first;
+ prev = nil;
+ for(;;) {
+ p->opt = prev;
+ if(p == bb->last)
+ break;
+ prev = p;
+ p = p->link;
+ }
+ }
+
+ // Add missing successor edges to the selectgo blocks.
+ if(arraylength(selectgo))
+ fixselectgo(selectgo);
+ arrayfree(selectgo);
+
+ // Find a depth-first order and assign a depth-first number to
+ // all basic blocks.
+ for(i = 0; i < arraylength(cfg); i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ bb->mark = UNVISITED;
+ }
+ bb = *(BasicBlock**)arrayget(cfg, 0);
+ rpo = arraylength(cfg);
+ reversepostorder(bb, &rpo);
+
+ // Sort the basic blocks by their depth first number. The
+ // array is now a depth-first spanning tree with the first
+ // node being the root.
+ arraysort(cfg, blockrpocmp);
+ bb = *(BasicBlock**)arrayget(cfg, 0);
+
+ // Unreachable control flow nodes are indicated by a -1 in the rpo
+ // field. If we see these nodes something must have gone wrong in an
+ // upstream compilation phase.
+ if(bb->rpo == -1) {
+ print("newcfg: unreachable basic block for %P\n", bb->last);
+ printcfg(cfg);
+ fatal("newcfg: invalid control flow graph");
+ }
+
+ return cfg;
+}
+
+// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
+// data structures.
+static void
+freecfg(Array *cfg)
+{
+ BasicBlock *bb;
+ BasicBlock *bb0;
+ Prog *p;
+ int32 i;
+ int32 len;
+
+ len = arraylength(cfg);
+ if(len > 0) {
+ bb0 = *(BasicBlock**)arrayget(cfg, 0);
+ for(p = bb0->first; p != P; p = p->link) {
+ p->opt = nil;
+ }
+ for(i = 0; i < len; i++) {
+ bb = *(BasicBlock**)arrayget(cfg, i);
+ freeblock(bb);
+ }
+ }
+ arrayfree(cfg);
+}
+
+// Returns true if the node names a variable that is otherwise uninteresting to
+// the liveness computation.
+static int
+isfunny(Node *node)
+{
+ char *names[] = { ".fp", ".args", nil };
+ int i;
+
+ if(node->sym != nil && node->sym->name != nil)
+ for(i = 0; names[i] != nil; i++)
+ if(strcmp(node->sym->name, names[i]) == 0)
+ return 1;
+ return 0;
+}
+
+// Computes the effects of an instruction on a set of
+// variables. The vars argument is an array of Node*s.
+//
+// The output vectors give bits for variables:
+// uevar - used by this instruction
+// varkill - killed by this instruction
+// for variables without address taken, means variable was set
+// for variables with address taken, means variable was marked dead
+// avarinit - initialized or referred to by this instruction,
+// only for variables with address taken but not escaping to heap
+//
+// The avarinit output serves as a signal that the data has been
+// initialized, because any use of a variable must come after its
+// initialization.
+static void
+progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
+{
+ ProgInfo info;
+ Adr *from;
+ Adr *to;
+ Node *node;
+ int32 i;
+ int32 pos;
+
+ bvresetall(uevar);
+ bvresetall(varkill);
+ bvresetall(avarinit);
+
+ proginfo(&info, prog);
+ if(prog->as == ARET) {
+ // Return instructions implicitly read all the arguments. For
+ // the sake of correctness, out arguments must be read. For the
+ // sake of backtrace quality, we read in arguments as well.
+ //
+ // A return instruction with a p->to is a tail return, which brings
+ // the stack pointer back up (if it ever went down) and then jumps
+ // to a new function entirely. That form of instruction must read
+ // all the parameters for correctness, and similarly it must not
+ // read the out arguments - they won't be set until the new
+ // function runs.
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class & ~PHEAP) {
+ case PPARAM:
+ bvset(uevar, i);
+ break;
+ case PPARAMOUT:
+ // If the result had its address taken, it is being tracked
+ // by the avarinit code, which does not use uevar.
+ // If we added it to uevar too, we'd not see any kill
+ // and decide that the varible was live entry, which it is not.
+ // So only use uevar in the non-addrtaken case.
+ // The p->to.type == D_NONE limits the bvset to
+ // non-tail-call return instructions; see note above
+ // the for loop for details.
+ if(!node->addrtaken && prog->to.type == D_NONE)
+ bvset(uevar, i);
+ break;
+ }
+ }
+ return;
+ }
+ if(prog->as == ATEXT) {
+ // A text instruction marks the entry point to a function and
+ // the definition point of all in arguments.
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class & ~PHEAP) {
+ case PPARAM:
+ if(node->addrtaken)
+ bvset(avarinit, i);
+ bvset(varkill, i);
+ break;
+ }
+ }
+ return;
+ }
+ if(info.flags & (LeftRead | LeftWrite | LeftAddr)) {
+ from = &prog->from;
+ if (from->node != nil && from->sym != nil) {
+ switch(from->node->class & ~PHEAP) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ pos = arrayindexof(vars, from->node);
+ if(pos == -1)
+ goto Next;
+ if(from->node->addrtaken) {
+ bvset(avarinit, pos);
+ } else {
+ if(info.flags & (LeftRead | LeftAddr))
+ bvset(uevar, pos);
+ if(info.flags & LeftWrite)
+ if(from->node != nil && !isfat(from->node->type))
+ bvset(varkill, pos);
+ }
+ }
+ }
+ }
+Next:
+ if(info.flags & (RightRead | RightWrite | RightAddr)) {
+ to = &prog->to;
+ if (to->node != nil && to->sym != nil) {
+ switch(to->node->class & ~PHEAP) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ pos = arrayindexof(vars, to->node);
+ if(pos == -1)
+ goto Next1;
+ if(to->node->addrtaken) {
+ if(prog->as != AVARKILL)
+ bvset(avarinit, pos);
+ if(prog->as == AVARDEF || prog->as == AVARKILL)
+ bvset(varkill, pos);
+ } else {
+ // RightRead is a read, obviously.
+ // RightAddr by itself is also implicitly a read.
+ //
+ // RightAddr|RightWrite means that the address is being taken
+ // but only so that the instruction can write to the value.
+ // It is not a read. It is equivalent to RightWrite except that
+ // having the RightAddr bit set keeps the registerizer from
+ // trying to substitute a register for the memory location.
+ if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
+ bvset(uevar, pos);
+ if(info.flags & RightWrite)
+ if(to->node != nil && (!isfat(to->node->type) || prog->as == AVARDEF))
+ bvset(varkill, pos);
+ }
+ }
+ }
+ }
+Next1:;
+}
+
+// Constructs a new liveness structure used to hold the global state of the
+// liveness computation. The cfg argument is an array of BasicBlock*s and the
+// vars argument is an array of Node*s.
+static Liveness*
+newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars)
+{
+ Liveness *result;
+ int32 i;
+ int32 nblocks;
+ int32 nvars;
+
+ result = xmalloc(sizeof(*result));
+ result->fn = fn;
+ result->ptxt = ptxt;
+ result->cfg = cfg;
+ result->vars = vars;
+
+ nblocks = arraylength(cfg);
+ result->uevar = xmalloc(sizeof(Bvec*) * nblocks);
+ result->varkill = xmalloc(sizeof(Bvec*) * nblocks);
+ result->livein = xmalloc(sizeof(Bvec*) * nblocks);
+ result->liveout = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinit = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks);
+ result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks);
+
+ nvars = arraylength(vars);
+ for(i = 0; i < nblocks; i++) {
+ result->uevar[i] = bvalloc(nvars);
+ result->varkill[i] = bvalloc(nvars);
+ result->livein[i] = bvalloc(nvars);
+ result->liveout[i] = bvalloc(nvars);
+ result->avarinit[i] = bvalloc(nvars);
+ result->avarinitany[i] = bvalloc(nvars);
+ result->avarinitall[i] = bvalloc(nvars);
+ }
+
+ result->livepointers = arraynew(0, sizeof(Bvec*));
+ result->argslivepointers = arraynew(0, sizeof(Bvec*));
+ return result;
+}
+
+// Frees the liveness structure and all of its leaf data structures.
+static void
+freeliveness(Liveness *lv)
+{
+ int32 i;
+
+ if(lv == nil)
+ fatal("freeliveness: cannot free nil");
+
+ for(i = 0; i < arraylength(lv->livepointers); i++)
+ free(*(Bvec**)arrayget(lv->livepointers, i));
+ arrayfree(lv->livepointers);
+
+ for(i = 0; i < arraylength(lv->argslivepointers); i++)
+ free(*(Bvec**)arrayget(lv->argslivepointers, i));
+ arrayfree(lv->argslivepointers);
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ free(lv->uevar[i]);
+ free(lv->varkill[i]);
+ free(lv->livein[i]);
+ free(lv->liveout[i]);
+ free(lv->avarinit[i]);
+ free(lv->avarinitany[i]);
+ free(lv->avarinitall[i]);
+ }
+
+ free(lv->uevar);
+ free(lv->varkill);
+ free(lv->livein);
+ free(lv->liveout);
+ free(lv->avarinit);
+ free(lv->avarinitany);
+ free(lv->avarinitall);
+
+ free(lv);
+}
+
+static void
+printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
+{
+ print("effects of %P", p);
+ print("\nuevar: ");
+ bvprint(uevar);
+ print("\nvarkill: ");
+ bvprint(varkill);
+ print("\navarinit: ");
+ bvprint(avarinit);
+ print("\n");
+}
+
+// Pretty print a variable node. Uses Pascal like conventions for pointers and
+// addresses to avoid confusing the C like conventions used in the node variable
+// names.
+static void
+printnode(Node *node)
+{
+ char *p;
+ char *a;
+
+ p = haspointers(node->type) ? "^" : "";
+ a = node->addrtaken ? "@" : "";
+ print(" %N%s%s", node, p, a);
+}
+
+// Pretty print a list of variables. The vars argument is an array of Node*s.
+static void
+printvars(char *name, Bvec *bv, Array *vars)
+{
+ int32 i;
+
+ print("%s:", name);
+ for(i = 0; i < arraylength(vars); i++)
+ if(bvget(bv, i))
+ printnode(*(Node**)arrayget(vars, i));
+ print("\n");
+}
+
+// Prints a basic block annotated with the information computed by liveness
+// analysis.
+static void
+livenessprintblock(Liveness *lv, BasicBlock *bb)
+{
+ BasicBlock *pred;
+ BasicBlock *succ;
+ Prog *prog;
+ Bvec *live;
+ int i;
+ int32 pos;
+
+ print("basic block %d\n", bb->rpo);
+
+ print("\tpred:");
+ for(i = 0; i < arraylength(bb->pred); i++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, i);
+ print(" %d", pred->rpo);
+ }
+ print("\n");
+
+ print("\tsucc:");
+ for(i = 0; i < arraylength(bb->succ); i++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, i);
+ print(" %d", succ->rpo);
+ }
+ print("\n");
+
+ printvars("\tuevar", lv->uevar[bb->rpo], lv->vars);
+ printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars);
+ printvars("\tlivein", lv->livein[bb->rpo], lv->vars);
+ printvars("\tliveout", lv->liveout[bb->rpo], lv->vars);
+ printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars);
+ printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars);
+ printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars);
+
+ print("\tprog:\n");
+ for(prog = bb->first;; prog = prog->link) {
+ print("\t\t%P", prog);
+ if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
+ pos = prog->to.offset;
+ live = *(Bvec**)arrayget(lv->livepointers, pos);
+ print(" ");
+ bvprint(live);
+ }
+ print("\n");
+ if(prog == bb->last)
+ break;
+ }
+}
+
+// Prints a control flow graph annotated with any information computed by
+// liveness analysis.
+static void
+livenessprintcfg(Liveness *lv)
+{
+ BasicBlock *bb;
+ int32 i;
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ livenessprintblock(lv, bb);
+ }
+}
+
+static void
+checkauto(Node *fn, Prog *p, Node *n)
+{
+ NodeList *l;
+
+ for(l = fn->dcl; l != nil; l = l->next)
+ if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n)
+ return;
+
+ print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
+ for(l = fn->dcl; l != nil; l = l->next)
+ print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
+ yyerror("checkauto: invariant lost");
+}
+
+static void
+checkparam(Node *fn, Prog *p, Node *n)
+{
+ NodeList *l;
+ Node *a;
+ int class;
+
+ if(isfunny(n))
+ return;
+ for(l = fn->dcl; l != nil; l = l->next) {
+ a = l->n;
+ class = a->class & ~PHEAP;
+ if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n)
+ return;
+ }
+
+ print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
+ for(l = fn->dcl; l != nil; l = l->next)
+ print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
+ yyerror("checkparam: invariant lost");
+}
+
+static void
+checkprog(Node *fn, Prog *p)
+{
+ if(p->from.type == D_AUTO)
+ checkauto(fn, p, p->from.node);
+ if(p->from.type == D_PARAM)
+ checkparam(fn, p, p->from.node);
+ if(p->to.type == D_AUTO)
+ checkauto(fn, p, p->to.node);
+ if(p->to.type == D_PARAM)
+ checkparam(fn, p, p->to.node);
+}
+
+// Check instruction invariants. We assume that the nodes corresponding to the
+// sources and destinations of memory operations will be declared in the
+// function. This is not strictly true, as is the case for the so-called funny
+// nodes and there are special cases to skip over that stuff. The analysis will
+// fail if this invariant blindly changes.
+static void
+checkptxt(Node *fn, Prog *firstp)
+{
+ Prog *p;
+
+ for(p = firstp; p != P; p = p->link) {
+ if(0)
+ print("analyzing '%P'\n", p);
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ case ATYPE:
+ continue;
+ }
+ checkprog(fn, p);
+ }
+}
+
+// NOTE: The bitmap for a specific type t should be cached in t after the first run
+// and then simply copied into bv at the correct offset on future calls with
+// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
+// accounts for 40% of the 6g execution time.
+static void
+twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
+{
+ vlong fieldoffset;
+ vlong i;
+ vlong o;
+ Type *t1;
+
+ if(t->align > 0 && (*xoffset & (t->align - 1)) != 0)
+ fatal("twobitwalktype1: invalid initial alignment, %T", t);
+
+ switch(t->etype) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ for(i = 0; i < t->width; i++) {
+ bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar
+ }
+ *xoffset += t->width;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ case TUNSAFEPTR:
+ case TFUNC:
+ case TCHAN:
+ case TMAP:
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr
+ *xoffset += t->width;
+ break;
+
+ case TSTRING:
+ // struct { byte *str; intgo len; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string
+ *xoffset += t->width;
+ break;
+
+ case TINTER:
+ // struct { Itab *tab; union { void *ptr, uintptr val } data; }
+ // or, when isnilinter(t)==true:
+ // struct { Type *type; union { void *ptr, uintptr val } data; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid alignment, %T", t);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword
+ // next word contains 2 = Iface, 3 = Eface
+ if(isnilinter(t)) {
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2);
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
+ } else {
+ bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
+ }
+ *xoffset += t->width;
+ break;
+
+ case TARRAY:
+ // The value of t->bound is -1 for slices types and >0 for
+ // for fixed array types. All other values are invalid.
+ if(t->bound < -1)
+ fatal("twobitwalktype1: invalid bound, %T", t);
+ if(isslice(t)) {
+ // struct { byte *array; uintgo len; uintgo cap; }
+ if((*xoffset & (widthptr-1)) != 0)
+ fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1);
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice
+ *xoffset += t->width;
+ } else
+ for(i = 0; i < t->bound; i++)
+ twobitwalktype1(t->type, xoffset, bv);
+ break;
+
+ case TSTRUCT:
+ o = 0;
+ for(t1 = t->type; t1 != T; t1 = t1->down) {
+ fieldoffset = t1->width;
+ *xoffset += fieldoffset - o;
+ twobitwalktype1(t1->type, xoffset, bv);
+ o = fieldoffset + t1->type->width;
+ }
+ *xoffset += t->width - o;
+ break;
+
+ default:
+ fatal("twobitwalktype1: unexpected type, %T", t);
+ }
+}
+
+// Returns the number of words of local variables.
+static int32
+localswords(void)
+{
+ return stkptrsize / widthptr;
+}
+
+// Returns the number of words of in and out arguments.
+static int32
+argswords(void)
+{
+ return curfn->type->argwid / widthptr;
+}
+
+// Generates live pointer value maps for arguments and local variables. The
+// this argument and the in arguments are always assumed live. The vars
+// argument is an array of Node*s.
+static void
+twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals)
+{
+ Node *node;
+ Type *thisargtype;
+ Type *inargtype;
+ vlong xoffset;
+ int32 i;
+
+ for(i = 0; i < arraylength(vars); i++) {
+ node = *(Node**)arrayget(vars, i);
+ switch(node->class) {
+ case PAUTO:
+ if(bvget(liveout, i)) {
+ xoffset = node->xoffset + stkptrsize;
+ twobitwalktype1(node->type, &xoffset, locals);
+ }
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ if(bvget(liveout, i)) {
+ xoffset = node->xoffset;
+ twobitwalktype1(node->type, &xoffset, args);
+ }
+ break;
+ }
+ }
+
+ // The node list only contains declared names.
+ // If the receiver or arguments are unnamed, they will be omitted
+ // from the list above. Preserve those values - even though they are unused -
+ // in order to keep their addresses live for use in stack traces.
+ thisargtype = getthisx(lv->fn->type);
+ if(thisargtype != nil) {
+ xoffset = 0;
+ twobitwalktype1(thisargtype, &xoffset, args);
+ }
+ inargtype = getinargx(lv->fn->type);
+ if(inargtype != nil) {
+ xoffset = 0;
+ twobitwalktype1(inargtype, &xoffset, args);
+ }
+}
+
+// Construct a disembodied instruction.
+static Prog*
+unlinkedprog(int as)
+{
+ Prog *p;
+
+ p = mal(sizeof(*p));
+ clearp(p);
+ p->as = as;
+ return p;
+}
+
+// Construct a new PCDATA instruction associated with and for the purposes of
+// covering an existing instruction.
+static Prog*
+newpcdataprog(Prog *prog, int32 index)
+{
+ Node from, to;
+ Prog *pcdata;
+
+ nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
+ nodconst(&to, types[TINT32], index);
+ pcdata = unlinkedprog(APCDATA);
+ pcdata->lineno = prog->lineno;
+ naddr(&from, &pcdata->from, 0);
+ naddr(&to, &pcdata->to, 0);
+ return pcdata;
+}
+
+// Returns true for instructions that are safe points that must be annotated
+// with liveness information.
+static int
+issafepoint(Prog *prog)
+{
+ return prog->as == ATEXT || prog->as == ACALL;
+}
+
+// Initializes the sets for solving the live variables. Visits all the
+// instructions in each basic block to summarizes the information at each basic
+// block
+static void
+livenessprologue(Liveness *lv)
+{
+ BasicBlock *bb;
+ Bvec *uevar, *varkill, *avarinit;
+ Prog *p;
+ int32 i;
+ int32 nvars;
+
+ nvars = arraylength(lv->vars);
+ uevar = bvalloc(nvars);
+ varkill = bvalloc(nvars);
+ avarinit = bvalloc(nvars);
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ // Walk the block instructions backward and update the block
+ // effects with the each prog effects.
+ for(p = bb->last; p != nil; p = p->opt) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ if(debuglive >= 3)
+ printeffects(p, uevar, varkill, avarinit);
+ bvor(lv->varkill[i], lv->varkill[i], varkill);
+ bvandnot(lv->uevar[i], lv->uevar[i], varkill);
+ bvor(lv->uevar[i], lv->uevar[i], uevar);
+ }
+ // Walk the block instructions forward to update avarinit bits.
+ // avarinit describes the effect at the end of the block, not the beginning.
+ bvresetall(varkill);
+ for(p = bb->first;; p = p->link) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ if(debuglive >= 3)
+ printeffects(p, uevar, varkill, avarinit);
+ bvandnot(lv->avarinit[i], lv->avarinit[i], varkill);
+ bvor(lv->avarinit[i], lv->avarinit[i], avarinit);
+ if(p == bb->last)
+ break;
+ }
+ }
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+}
+
+// Solve the liveness dataflow equations.
+static void
+livenesssolve(Liveness *lv)
+{
+ BasicBlock *bb, *succ, *pred;
+ Bvec *newlivein, *newliveout, *any, *all;
+ int32 rpo, i, j, change;
+
+ // These temporary bitvectors exist to avoid successive allocations and
+ // frees within the loop.
+ newlivein = bvalloc(arraylength(lv->vars));
+ newliveout = bvalloc(arraylength(lv->vars));
+ any = bvalloc(arraylength(lv->vars));
+ all = bvalloc(arraylength(lv->vars));
+
+ // Push avarinitall, avarinitany forward.
+ // avarinitall says the addressed var is initialized along all paths reaching the block exit.
+ // avarinitany says the addressed var is initialized along some path reaching the block exit.
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ if(i == 0)
+ bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]);
+ else {
+ bvresetall(lv->avarinitall[rpo]);
+ bvnot(lv->avarinitall[rpo]);
+ }
+ bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]);
+ }
+
+ change = 1;
+ while(change != 0) {
+ change = 0;
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ bvresetall(any);
+ bvresetall(all);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, j);
+ if(j == 0) {
+ bvcopy(any, lv->avarinitany[pred->rpo]);
+ bvcopy(all, lv->avarinitall[pred->rpo]);
+ } else {
+ bvor(any, any, lv->avarinitany[pred->rpo]);
+ bvand(all, all, lv->avarinitall[pred->rpo]);
+ }
+ }
+ bvandnot(any, any, lv->varkill[rpo]);
+ bvandnot(all, all, lv->varkill[rpo]);
+ bvor(any, any, lv->avarinit[rpo]);
+ bvor(all, all, lv->avarinit[rpo]);
+ if(bvcmp(any, lv->avarinitany[rpo])) {
+ change = 1;
+ bvcopy(lv->avarinitany[rpo], any);
+ }
+ if(bvcmp(all, lv->avarinitall[rpo])) {
+ change = 1;
+ bvcopy(lv->avarinitall[rpo], all);
+ }
+ }
+ }
+
+ // Iterate through the blocks in reverse round-robin fashion. A work
+ // queue might be slightly faster. As is, the number of iterations is
+ // so low that it hardly seems to be worth the complexity.
+ change = 1;
+ while(change != 0) {
+ change = 0;
+ // Walk blocks in the general direction of propagation. This
+ // improves convergence.
+ for(i = arraylength(lv->cfg) - 1; i >= 0; i--) {
+ // A variable is live on output from this block
+ // if it is live on input to some successor.
+ //
+ // out[b] = \bigcup_{s \in succ[b]} in[s]
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+ rpo = bb->rpo;
+ bvresetall(newliveout);
+ for(j = 0; j < arraylength(bb->succ); j++) {
+ succ = *(BasicBlock**)arrayget(bb->succ, j);
+ bvor(newliveout, newliveout, lv->livein[succ->rpo]);
+ }
+ if(bvcmp(lv->liveout[rpo], newliveout)) {
+ change = 1;
+ bvcopy(lv->liveout[rpo], newliveout);
+ }
+
+ // A variable is live on input to this block
+ // if it is live on output from this block and
+ // not set by the code in this block.
+ //
+ // in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
+ bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]);
+ bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]);
+ }
+ }
+
+ free(newlivein);
+ free(newliveout);
+ free(any);
+ free(all);
+}
+
+// This function is slow but it is only used for generating debug prints.
+// Check whether n is marked live in args/locals.
+static int
+islive(Node *n, Bvec *args, Bvec *locals)
+{
+ int i;
+
+ switch(n->class) {
+ case PPARAM:
+ case PPARAMOUT:
+ for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+ if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i))
+ return 1;
+ break;
+ case PAUTO:
+ for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+ if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i))
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+// Visits all instructions in a basic block and computes a bit vector of live
+// variables at each safe point locations.
+static void
+livenessepilogue(Liveness *lv)
+{
+ BasicBlock *bb, *pred;
+ Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all;
+ Node *n;
+ Prog *p, *next;
+ int32 i, j, numlive, startmsg, nmsg, nvars, pos;
+ vlong xoffset;
+ char **msg;
+ Fmt fmt;
+
+ nvars = arraylength(lv->vars);
+ livein = bvalloc(nvars);
+ liveout = bvalloc(nvars);
+ uevar = bvalloc(nvars);
+ varkill = bvalloc(nvars);
+ avarinit = bvalloc(nvars);
+ any = bvalloc(nvars);
+ all = bvalloc(nvars);
+ ambig = bvalloc(localswords() * BitsPerPointer);
+ msg = nil;
+ nmsg = 0;
+ startmsg = 0;
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ // Compute avarinitany and avarinitall for entry to block.
+ // This duplicates information known during livenesssolve
+ // but avoids storing two more vectors for each block.
+ bvresetall(any);
+ bvresetall(all);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ pred = *(BasicBlock**)arrayget(bb->pred, j);
+ if(j == 0) {
+ bvcopy(any, lv->avarinitany[pred->rpo]);
+ bvcopy(all, lv->avarinitall[pred->rpo]);
+ } else {
+ bvor(any, any, lv->avarinitany[pred->rpo]);
+ bvand(all, all, lv->avarinitall[pred->rpo]);
+ }
+ }
+
+ // Walk forward through the basic block instructions and
+ // allocate liveness maps for those instructions that need them.
+ // Seed the maps with information about the addrtaken variables.
+ for(p = bb->first;; p = p->link) {
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ bvandnot(any, any, varkill);
+ bvandnot(all, all, varkill);
+ bvor(any, any, avarinit);
+ bvor(all, all, avarinit);
+
+ if(issafepoint(p)) {
+ // Annotate ambiguously live variables so that they can
+ // be zeroed at function entry.
+ // livein and liveout are dead here and used as temporaries.
+ // For now, only enabled when using GOEXPERIMENT=precisestack
+ // during make.bash / all.bash.
+ if(precisestack_enabled) {
+ bvresetall(livein);
+ bvandnot(liveout, any, all);
+ if(!bvisempty(liveout)) {
+ for(pos = 0; pos < liveout->n; pos++) {
+ if(!bvget(liveout, pos))
+ continue;
+ bvset(all, pos); // silence future warnings in this block
+ n = *(Node**)arrayget(lv->vars, pos);
+ if(!n->needzero) {
+ n->needzero = 1;
+ if(debuglive >= 1)
+ warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
+ // Record in 'ambiguous' bitmap.
+ xoffset = n->xoffset + stkptrsize;
+ twobitwalktype1(n->type, &xoffset, ambig);
+ }
+ }
+ }
+ }
+
+ // Allocate a bit vector for each class and facet of
+ // value we are tracking.
+
+ // Live stuff first.
+ args = bvalloc(argswords() * BitsPerPointer);
+ arrayadd(lv->argslivepointers, &args);
+ locals = bvalloc(localswords() * BitsPerPointer);
+ arrayadd(lv->livepointers, &locals);
+
+ if(debuglive >= 3) {
+ print("%P\n", p);
+ printvars("avarinitany", any, lv->vars);
+ }
+
+ // Record any values with an "address taken" reaching
+ // this code position as live. Must do now instead of below
+ // because the any/all calculation requires walking forward
+ // over the block (as this loop does), while the liveout
+ // requires walking backward (as the next loop does).
+ twobitlivepointermap(lv, any, lv->vars, args, locals);
+ }
+
+ if(p == bb->last)
+ break;
+ }
+ bb->lastbitmapindex = arraylength(lv->livepointers) - 1;
+ }
+
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') {
+ nmsg = arraylength(lv->livepointers);
+ startmsg = nmsg;
+ msg = xmalloc(nmsg*sizeof msg[0]);
+ for(j=0; j<nmsg; j++)
+ msg[j] = nil;
+ }
+
+ // walk backward, emit pcdata and populate the maps
+ pos = bb->lastbitmapindex;
+ if(pos < 0) {
+ // the first block we encounter should have the ATEXT so
+ // at no point should pos ever be less than zero.
+ fatal("livenessepilogue");
+ }
+
+ bvcopy(livein, lv->liveout[bb->rpo]);
+ for(p = bb->last; p != nil; p = next) {
+ next = p->opt; // splicebefore modifies p->opt
+ // Propagate liveness information
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ bvcopy(liveout, livein);
+ bvandnot(livein, liveout, varkill);
+ bvor(livein, livein, uevar);
+ if(debuglive >= 3 && issafepoint(p)){
+ print("%P\n", p);
+ printvars("uevar", uevar, lv->vars);
+ printvars("varkill", varkill, lv->vars);
+ printvars("livein", livein, lv->vars);
+ printvars("liveout", liveout, lv->vars);
+ }
+ if(issafepoint(p)) {
+ // Found an interesting instruction, record the
+ // corresponding liveness information.
+
+ // Useful sanity check: on entry to the function,
+ // the only things that can possibly be live are the
+ // input parameters.
+ if(p->as == ATEXT) {
+ for(j = 0; j < liveout->n; j++) {
+ if(!bvget(liveout, j))
+ continue;
+ n = *(Node**)arrayget(lv->vars, j);
+ if(n->class != PPARAM)
+ yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n);
+ }
+ }
+
+ // Record live pointers.
+ args = *(Bvec**)arrayget(lv->argslivepointers, pos);
+ locals = *(Bvec**)arrayget(lv->livepointers, pos);
+ twobitlivepointermap(lv, liveout, lv->vars, args, locals);
+
+ // Ambiguously live variables are zeroed immediately after
+ // function entry. Mark them live for all the non-entry bitmaps
+ // so that GODEBUG=gcdead=1 mode does not poison them.
+ if(p->as == ACALL)
+ bvor(locals, locals, ambig);
+
+ // Show live pointer bitmaps.
+ // We're interpreting the args and locals bitmap instead of liveout so that we
+ // include the bits added by the avarinit logic in the
+ // previous loop.
+ if(msg != nil) {
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "%L: live at ", p->lineno);
+ if(p->as == ACALL && p->to.node)
+ fmtprint(&fmt, "call to %s:", p->to.node->sym->name);
+ else if(p->as == ACALL)
+ fmtprint(&fmt, "indirect call:");
+ else
+ fmtprint(&fmt, "entry to %s:", p->from.node->sym->name);
+ numlive = 0;
+ for(j = 0; j < arraylength(lv->vars); j++) {
+ n = *(Node**)arrayget(lv->vars, j);
+ if(islive(n, args, locals)) {
+ fmtprint(&fmt, " %N", n);
+ numlive++;
+ }
+ }
+ fmtprint(&fmt, "\n");
+ if(numlive == 0) // squelch message
+ free(fmtstrflush(&fmt));
+ else
+ msg[--startmsg] = fmtstrflush(&fmt);
+ }
+
+ // Only CALL instructions need a PCDATA annotation.
+ // The TEXT instruction annotation is implicit.
+ if(p->as == ACALL) {
+ if(isdeferreturn(p)) {
+ // runtime.deferreturn modifies its return address to return
+ // back to the CALL, not to the subsequent instruction.
+ // Because the return comes back one instruction early,
+ // the PCDATA must begin one instruction early too.
+ // The instruction before a call to deferreturn is always a
+ // no-op, to keep PC-specific data unambiguous.
+ splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt);
+ } else {
+ splicebefore(lv, bb, newpcdataprog(p, pos), p);
+ }
+ }
+
+ pos--;
+ }
+ }
+ if(msg != nil) {
+ for(j=startmsg; j<nmsg; j++)
+ if(msg[j] != nil)
+ print("%s", msg[j]);
+ free(msg);
+ msg = nil;
+ nmsg = 0;
+ startmsg = 0;
+ }
+ }
+
+ free(livein);
+ free(liveout);
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+ free(any);
+ free(all);
+ free(ambig);
+
+ flusherrors();
+}
+
+// FNV-1 hash function constants.
+#define H0 2166136261UL
+#define Hp 16777619UL
+
+static uint32
+hashbitmap(uint32 h, Bvec *bv)
+{
+ uchar *p, *ep;
+
+ p = (uchar*)bv->b;
+ ep = p + 4*((bv->n+31)/32);
+ while(p < ep)
+ h = (h*Hp) ^ *p++;
+ return h;
+}
+
+// Compact liveness information by coalescing identical per-call-site bitmaps.
+// The merging only happens for a single function, not across the entire binary.
+//
+// There are actually two lists of bitmaps, one list for the local variables and one
+// list for the function arguments. Both lists are indexed by the same PCDATA
+// index, so the corresponding pairs must be considered together when
+// merging duplicates. The argument bitmaps change much less often during
+// function execution than the local variable bitmaps, so it is possible that
+// we could introduce a separate PCDATA index for arguments vs locals and
+// then compact the set of argument bitmaps separately from the set of
+// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
+// is actually a net loss: we save about 50k of argument bitmaps but the new
+// PCDATA tables cost about 100k. So for now we keep using a single index for
+// both bitmap lists.
+static void
+livenesscompact(Liveness *lv)
+{
+ int *table, *remap, i, j, n, tablesize, uniq;
+ uint32 h;
+ Bvec *local, *arg, *jlocal, *jarg;
+ Prog *p;
+
+ // Linear probing hash table of bitmaps seen so far.
+ // The hash table has 4n entries to keep the linear
+ // scan short. An entry of -1 indicates an empty slot.
+ n = arraylength(lv->livepointers);
+ tablesize = 4*n;
+ table = xmalloc(tablesize*sizeof table[0]);
+ memset(table, 0xff, tablesize*sizeof table[0]);
+
+ // remap[i] = the new index of the old bit vector #i.
+ remap = xmalloc(n*sizeof remap[0]);
+ memset(remap, 0xff, n*sizeof remap[0]);
+ uniq = 0; // unique tables found so far
+
+ // Consider bit vectors in turn.
+ // If new, assign next number using uniq,
+ // record in remap, record in lv->livepointers and lv->argslivepointers
+ // under the new index, and add entry to hash table.
+ // If already seen, record earlier index in remap and free bitmaps.
+ for(i=0; i<n; i++) {
+ local = *(Bvec**)arrayget(lv->livepointers, i);
+ arg = *(Bvec**)arrayget(lv->argslivepointers, i);
+ h = hashbitmap(hashbitmap(H0, local), arg) % tablesize;
+
+ for(;;) {
+ j = table[h];
+ if(j < 0)
+ break;
+ jlocal = *(Bvec**)arrayget(lv->livepointers, j);
+ jarg = *(Bvec**)arrayget(lv->argslivepointers, j);
+ if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) {
+ free(local);
+ free(arg);
+ remap[i] = j;
+ goto Next;
+ }
+ if(++h == tablesize)
+ h = 0;
+ }
+ table[h] = uniq;
+ remap[i] = uniq;
+ *(Bvec**)arrayget(lv->livepointers, uniq) = local;
+ *(Bvec**)arrayget(lv->argslivepointers, uniq) = arg;
+ uniq++;
+ Next:;
+ }
+
+ // We've already reordered lv->livepointers[0:uniq]
+ // and lv->argslivepointers[0:uniq] and freed the bitmaps
+ // we don't need anymore. Clear the pointers later in the
+ // array so that we can tell where the coalesced bitmaps stop
+ // and so that we don't double-free when cleaning up.
+ for(j=uniq; j<n; j++) {
+ *(Bvec**)arrayget(lv->livepointers, j) = nil;
+ *(Bvec**)arrayget(lv->argslivepointers, j) = nil;
+ }
+
+ // Rewrite PCDATA instructions to use new numbering.
+ for(p=lv->ptxt; p != P; p=p->link) {
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) {
+ i = p->to.offset;
+ if(i >= 0)
+ p->to.offset = remap[i];
+ }
+ }
+
+ free(table);
+ free(remap);
+}
+
+static int
+printbitset(int printed, char *name, Array *vars, Bvec *bits)
+{
+ int i, started;
+ Node *n;
+
+ started = 0;
+ for(i=0; i<arraylength(vars); i++) {
+ if(!bvget(bits, i))
+ continue;
+ if(!started) {
+ if(!printed)
+ print("\t");
+ else
+ print(" ");
+ started = 1;
+ printed = 1;
+ print("%s=", name);
+ } else {
+ print(",");
+ }
+ n = *(Node**)arrayget(vars, i);
+ print("%s", n->sym->name);
+ }
+ return printed;
+}
+
+// Prints the computed liveness information and inputs, for debugging.
+// This format synthesizes the information used during the multiple passes
+// into a single presentation.
+static void
+livenessprintdebug(Liveness *lv)
+{
+ int i, j, pcdata, printed;
+ BasicBlock *bb;
+ Prog *p;
+ Bvec *uevar, *varkill, *avarinit, *args, *locals;
+ Node *n;
+
+ print("liveness: %s\n", curfn->nname->sym->name);
+
+ uevar = bvalloc(arraylength(lv->vars));
+ varkill = bvalloc(arraylength(lv->vars));
+ avarinit = bvalloc(arraylength(lv->vars));
+
+ pcdata = 0;
+ for(i = 0; i < arraylength(lv->cfg); i++) {
+ if(i > 0)
+ print("\n");
+ bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+ // bb#0 pred=1,2 succ=3,4
+ print("bb#%d pred=", i);
+ for(j = 0; j < arraylength(bb->pred); j++) {
+ if(j > 0)
+ print(",");
+ print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo);
+ }
+ print(" succ=");
+ for(j = 0; j < arraylength(bb->succ); j++) {
+ if(j > 0)
+ print(",");
+ print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo);
+ }
+ print("\n");
+
+ // initial settings
+ printed = 0;
+ printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]);
+ printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]);
+ if(printed)
+ print("\n");
+
+ // program listing, with individual effects listed
+ for(p = bb->first;; p = p->link) {
+ print("%P\n", p);
+ if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex)
+ pcdata = p->to.offset;
+ progeffects(p, lv->vars, uevar, varkill, avarinit);
+ printed = 0;
+ printed = printbitset(printed, "uevar", lv->vars, uevar);
+ printed = printbitset(printed, "varkill", lv->vars, varkill);
+ printed = printbitset(printed, "avarinit", lv->vars, avarinit);
+ if(printed)
+ print("\n");
+ if(issafepoint(p)) {
+ args = *(Bvec**)arrayget(lv->argslivepointers, pcdata);
+ locals = *(Bvec**)arrayget(lv->livepointers, pcdata);
+ print("\tlive=");
+ printed = 0;
+ for(j = 0; j < arraylength(lv->vars); j++) {
+ n = *(Node**)arrayget(lv->vars, j);
+ if(islive(n, args, locals)) {
+ if(printed++)
+ print(",");
+ print("%N", n);
+ }
+ }
+ print("\n");
+ }
+ if(p == bb->last)
+ break;
+ }
+
+ // bb bitsets
+ print("end\n");
+ printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]);
+ printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]);
+ printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]);
+ printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]);
+ printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]);
+ if(printed)
+ print("\n");
+ }
+ print("\n");
+
+ free(uevar);
+ free(varkill);
+ free(avarinit);
+}
+
+// Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The
+// first word dumped is the total number of bitmaps. The second word is the
+// length of the bitmaps. All bitmaps are assumed to be of equal length. The
+// words that are followed are the raw bitmap words. The arr argument is an
+// array of Node*s.
+static void
+twobitwritesymbol(Array *arr, Sym *sym)
+{
+ Bvec *bv;
+ int off, i, j, len;
+ uint32 word;
+
+ len = arraylength(arr);
+ off = 0;
+ off += 4; // number of bitmaps, to fill in later
+ bv = *(Bvec**)arrayget(arr, 0);
+ off = duint32(sym, off, bv->n); // number of bits in each bitmap
+ for(i = 0; i < len; i++) {
+ // bitmap words
+ bv = *(Bvec**)arrayget(arr, i);
+ if(bv == nil)
+ break;
+ for(j = 0; j < bv->n; j += 32) {
+ word = bv->b[j/32];
+ off = duint32(sym, off, word);
+ }
+ }
+ duint32(sym, 0, i); // number of bitmaps
+ ggloblsym(sym, off, 0, 1);
+}
+
+static void
+printprog(Prog *p)
+{
+ while(p != nil) {
+ print("%P\n", p);
+ p = p->link;
+ }
+}
+
+// Entry pointer for liveness analysis. Constructs a complete CFG, solves for
+// the liveness of pointer variables in the function, and emits a runtime data
+// structure read by the garbage collector.
+void
+liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym)
+{
+ Array *cfg, *vars;
+ Liveness *lv;
+ int debugdelta;
+
+ // Change name to dump debugging information only for a specific function.
+ debugdelta = 0;
+ if(strcmp(curfn->nname->sym->name, "!") == 0)
+ debugdelta = 2;
+
+ debuglive += debugdelta;
+ if(debuglive >= 3) {
+ print("liveness: %s\n", curfn->nname->sym->name);
+ printprog(firstp);
+ }
+ checkptxt(fn, firstp);
+
+ // Construct the global liveness state.
+ cfg = newcfg(firstp);
+ if(debuglive >= 3)
+ printcfg(cfg);
+ vars = getvariables(fn);
+ lv = newliveness(fn, firstp, cfg, vars);
+
+ // Run the dataflow framework.
+ livenessprologue(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenesssolve(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenessepilogue(lv);
+ if(debuglive >= 3)
+ livenessprintcfg(lv);
+ livenesscompact(lv);
+
+ if(debuglive >= 2)
+ livenessprintdebug(lv);
+
+ // Emit the live pointer map data structures
+ twobitwritesymbol(lv->livepointers, livesym);
+ twobitwritesymbol(lv->argslivepointers, argssym);
+
+ // Free everything.
+ freeliveness(lv);
+ arrayfree(vars);
+ freecfg(cfg);
+
+ debuglive -= debugdelta;
+}
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
index 8d7afa011..ea88b94db 100644
--- a/src/cmd/gc/popt.c
+++ b/src/cmd/gc/popt.c
@@ -51,9 +51,14 @@ noreturn(Prog *p)
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
symlist[4] = pkglookup("panicwrap", runtimepkg);
+ symlist[5] = pkglookup("throwreturn", runtimepkg);
+ symlist[6] = pkglookup("selectgo", runtimepkg);
+ symlist[7] = pkglookup("block", runtimepkg);
}
- s = p->to.sym;
+ if(p->to.node == nil)
+ return 0;
+ s = p->to.node->sym;
if(s == S)
return 0;
for(i=0; symlist[i]!=S; i++)
@@ -144,7 +149,13 @@ fixjmp(Prog *firstp)
if(p->opt == dead) {
if(p->link == P && p->as == ARET && last && last->as != ARET) {
// This is the final ARET, and the code so far doesn't have one.
- // Let it stay.
+ // Let it stay. The register allocator assumes that all live code in
+ // the function can be traversed by starting at all the RET instructions
+ // and following predecessor links. If we remove the final RET,
+ // this assumption will not hold in the case of an infinite loop
+ // at the end of a function.
+ // Keep the RET but mark it dead for the liveness analysis.
+ p->mode = 1;
} else {
if(debug['R'] && debug['v'])
print("del %P\n", p);
@@ -489,8 +500,8 @@ struct TempVar
TempFlow *use; // use list, chained through TempFlow.uselink
TempVar *freelink; // next free temp in Type.opt list
TempVar *merge; // merge var with this one
- uint32 start; // smallest Prog.loc in live range
- uint32 end; // largest Prog.loc in live range
+ vlong start; // smallest Prog.pc in live range
+ vlong end; // largest Prog.pc in live range
uchar addr; // address taken - no accurate end
uchar removed; // removed from program
};
@@ -520,10 +531,11 @@ startcmp(const void *va, const void *vb)
static int
canmerge(Node *n)
{
- return n->class == PAUTO && !n->addrtaken && strncmp(n->sym->name, "autotmp", 7) == 0;
+ return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
}
static void mergewalk(TempVar*, TempFlow*, uint32);
+static void varkillwalk(TempVar*, TempFlow*, uint32);
void
mergetemp(Prog *firstp)
@@ -544,7 +556,7 @@ mergetemp(Prog *firstp)
g = flowstart(firstp, sizeof(TempFlow));
if(g == nil)
return;
-
+
// Build list of all mergeable variables.
nvar = 0;
for(l = curfn->dcl; l != nil; l = l->next)
@@ -640,6 +652,11 @@ mergetemp(Prog *firstp)
gen++;
for(r = v->use; r != nil; r = r->uselink)
mergewalk(v, r, gen);
+ if(v->addr) {
+ gen++;
+ for(r = v->use; r != nil; r = r->uselink)
+ varkillwalk(v, r, gen);
+ }
}
// Sort variables by start.
@@ -659,7 +676,7 @@ mergetemp(Prog *firstp)
nfree = nvar;
for(i=0; i<nvar; i++) {
v = bystart[i];
- if(v->addr || v->removed)
+ if(v->removed)
continue;
// Expire no longer in use.
@@ -672,7 +689,12 @@ mergetemp(Prog *firstp)
t = v->node->type;
for(j=nfree; j<nvar; j++) {
v1 = inuse[j];
- if(eqtype(t, v1->node->type)) {
+ // Require the types to match but also require the addrtaken bits to match.
+ // If a variable's address is taken, that disables registerization for the individual
+ // words of the variable (for example, the base,len,cap of a slice).
+ // We don't want to merge a non-addressed var with an addressed one and
+ // inhibit registerization of the former.
+ if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) {
inuse[j] = inuse[nfree++];
if(v1->merge)
v->merge = v1->merge;
@@ -695,7 +717,7 @@ mergetemp(Prog *firstp)
if(Debug) {
print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
for(v=var; v<var+nvar; v++) {
- print("var %#N %T %d-%d", v->node, v->node->type, v->start, v->end);
+ print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
if(v->addr)
print(" addr=1");
if(v->removed)
@@ -752,10 +774,10 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
break;
r1->f.active = gen;
p = r1->f.prog;
- if(v->end < p->loc)
- v->end = p->loc;
+ if(v->end < p->pc)
+ v->end = p->pc;
if(r1 == v->def) {
- v->start = p->loc;
+ v->start = p->pc;
break;
}
}
@@ -765,6 +787,29 @@ mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
mergewalk(v, r2, gen);
}
+static void
+varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
+{
+ Prog *p;
+ TempFlow *r1, *r;
+
+ for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) {
+ if(r1->f.active == gen)
+ break;
+ r1->f.active = gen;
+ p = r1->f.prog;
+ if(v->end < p->pc)
+ v->end = p->pc;
+ if(v->start > p->pc)
+ v->start = p->pc;
+ if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node))
+ break;
+ }
+
+ for(r = r0; r != r1; r = (TempFlow*)r->f.s1)
+ varkillwalk(v, (TempFlow*)r->f.s2, gen);
+}
+
// Eliminate redundant nil pointer checks.
//
// The code generation pass emits a CHECKNIL for every possibly nil pointer.
@@ -911,7 +956,7 @@ nilwalkback(NilFlow *rcheck)
static void
nilwalkfwd(NilFlow *rcheck)
{
- NilFlow *r;
+ NilFlow *r, *last;
Prog *p;
ProgInfo info;
@@ -922,6 +967,7 @@ nilwalkfwd(NilFlow *rcheck)
// avoid problems like:
// _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible
+ last = nil;
for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
p = r->f.prog;
proginfo(&info, p);
@@ -944,5 +990,12 @@ nilwalkfwd(NilFlow *rcheck)
// Stop if memory write.
if((info.flags & RightWrite) && !regtyp(&p->to))
return;
+ // Stop if we jump backward.
+ // This test is valid because all the NilFlow* are pointers into
+ // a single contiguous array. We will need to add an explicit
+ // numbering when the code is converted to Go.
+ if(last != nil && r <= last)
+ return;
+ last = r;
}
}
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index d6a5b3cce..285bd78a2 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -166,6 +166,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
goto ret;
case OCFUNC:
+ case OVARKILL:
// can't matter
goto ret;
@@ -181,7 +182,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
// x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
// We don't want to instrument between the statements because it will
// smash the results.
- racewalknode(&n->list->n, &n->ninit, 0, 0);
+ racewalknode(&n->list->n, &n->list->n->ninit, 0, 0);
fini = nil;
racewalklist(n->list->next, &fini);
n->list = concat(n->list, fini);
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index bd271da38..45aa521b3 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -111,6 +111,8 @@ walkrange(Node *n)
Node *hb; // hidden bool
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn, *tmp;
+ Node *keyname, *valname;
+ Node *key, *val;
NodeList *body, *init;
Type *th, *t;
int lno;
@@ -120,34 +122,23 @@ walkrange(Node *n)
a = n->right;
lno = setlineno(a);
- if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
- a = nod(OCONV, n->right, N);
- a->type = types[TSTRING];
- }
v1 = n->list->n;
v2 = N;
- if(n->list->next)
+ if(n->list->next && !isblank(n->list->next->n))
v2 = n->list->next->n;
// n->list has no meaning anymore, clear it
// to avoid erroneous processing by racewalk.
n->list = nil;
hv2 = N;
- if(v2 == N && t->etype == TARRAY) {
- // will have just one reference to argument.
- // no need to make a potentially expensive copy.
- ha = a;
- } else {
- ha = temp(a->type);
- init = list(init, nod(OAS, ha, a));
- }
-
switch(t->etype) {
default:
fatal("walkrange");
case TARRAY:
+ // orderstmt arranged for a copy of the array/slice variable if needed.
+ ha = a;
hv1 = temp(types[TINT]);
hn = temp(types[TINT]);
hp = nil;
@@ -162,8 +153,7 @@ walkrange(Node *n)
}
n->ntest = nod(OLT, hv1, hn);
- n->nincr = nod(OASOP, hv1, nodintconst(1));
- n->nincr->etype = OADD;
+ n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
if(v2 == N)
body = list1(nod(OAS, v1, hv1));
else {
@@ -171,54 +161,70 @@ walkrange(Node *n)
a->list = list(list1(v1), v2);
a->rlist = list(list1(hv1), nod(OIND, hp, N));
body = list1(a);
-
+
+ // Advance pointer as part of increment.
+ // We used to advance the pointer before executing the loop body,
+ // but doing so would make the pointer point past the end of the
+ // array during the final iteration, possibly causing another unrelated
+ // piece of memory not to be garbage collected until the loop finished.
+ // Advancing during the increment ensures that the pointer p only points
+ // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
+ // after which p is dead, so it cannot confuse the collector.
tmp = nod(OADD, hp, nodintconst(t->type->width));
tmp->type = hp->type;
tmp->typecheck = 1;
tmp->right->type = types[tptr];
tmp->right->typecheck = 1;
- body = list(body, nod(OAS, hp, tmp));
+ a = nod(OAS, hp, tmp);
+ typecheck(&a, Etop);
+ n->nincr->ninit = list1(a);
}
break;
case TMAP:
- th = typ(TARRAY);
- th->type = ptrto(types[TUINT8]);
- // see ../../pkg/runtime/hashmap.c:/hash_iter
- // Size of hash_iter in # of pointers.
- th->bound = 11;
- hit = temp(th);
+ // orderstmt allocated the iterator for us.
+ // we only use a once, so no copy needed.
+ ha = a;
+ th = hiter(t);
+ hit = n->alloc;
+ hit->type = th;
+ n->left = N;
+ keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter
+ valname = newname(th->type->down->sym); // ditto
fn = syslook("mapiterinit", 1);
argtype(fn, t->down);
argtype(fn, t->type);
argtype(fn, th);
init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
- n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
+ n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil());
fn = syslook("mapiternext", 1);
argtype(fn, th);
n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
+ key = nod(ODOT, hit, keyname);
+ key = nod(OIND, key, N);
if(v2 == N) {
- fn = syslook("mapiter1", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
+ a = nod(OAS, v1, key);
} else {
- fn = syslook("mapiter2", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- argtype(fn, t->type);
+ val = nod(ODOT, hit, valname);
+ val = nod(OIND, val, N);
a = nod(OAS2, N, N);
a->list = list(list1(v1), v2);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
+ a->rlist = list(list1(key), val);
}
body = list1(a);
break;
case TCHAN:
+ // orderstmt arranged for a copy of the channel variable.
+ ha = a;
+ n->ntest = N;
+
hv1 = temp(t->type);
+ if(haspointers(t->type))
+ init = list(init, nod(OAS, hv1, N));
hb = temp(types[TBOOL]);
n->ntest = nod(ONE, hb, nodbool(0));
@@ -231,6 +237,9 @@ walkrange(Node *n)
break;
case TSTRING:
+ // orderstmt arranged for a copy of the string variable.
+ ha = a;
+
ohv1 = temp(types[TINT]);
hv1 = temp(types[TINT]);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 0a8aa8d7a..dbb447e4e 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -125,6 +125,8 @@ mapbucket(Type *t)
keytype = t->down;
valtype = t->type;
+ dowidth(keytype);
+ dowidth(valtype);
if(keytype->width > MAXKEYSIZE)
keytype = ptrto(keytype);
if(valtype->width > MAXVALSIZE)
@@ -143,6 +145,11 @@ mapbucket(Type *t)
overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
overflowfield->sym->name = "overflow";
offset += widthptr;
+
+ // The keys are padded to the native integer alignment.
+ // This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
+ if(widthreg > widthptr)
+ offset += widthreg - widthptr;
keysfield = typ(TFIELD);
keysfield->type = typ(TARRAY);
@@ -173,6 +180,7 @@ mapbucket(Type *t)
bucket->width = offset;
bucket->local = t->local;
t->bucket = bucket;
+ bucket->map = t;
return bucket;
}
@@ -229,10 +237,89 @@ hmap(Type *t)
h->width = offset;
h->local = t->local;
t->hmap = h;
- h->hmap = t;
+ h->map = t;
return h;
}
+Type*
+hiter(Type *t)
+{
+ int32 n, off;
+ Type *field[7];
+ Type *i;
+
+ if(t->hiter != T)
+ return t->hiter;
+
+ // build a struct:
+ // hash_iter {
+ // key *Key
+ // val *Value
+ // t *MapType
+ // h *Hmap
+ // buckets *Bucket
+ // bptr *Bucket
+ // other [4]uintptr
+ // }
+ // must match ../../pkg/runtime/hashmap.c:hash_iter.
+ field[0] = typ(TFIELD);
+ field[0]->type = ptrto(t->down);
+ field[0]->sym = mal(sizeof(Sym));
+ field[0]->sym->name = "key";
+
+ field[1] = typ(TFIELD);
+ field[1]->type = ptrto(t->type);
+ field[1]->sym = mal(sizeof(Sym));
+ field[1]->sym->name = "val";
+
+ field[2] = typ(TFIELD);
+ field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type?
+ field[2]->sym = mal(sizeof(Sym));
+ field[2]->sym->name = "t";
+
+ field[3] = typ(TFIELD);
+ field[3]->type = ptrto(hmap(t));
+ field[3]->sym = mal(sizeof(Sym));
+ field[3]->sym->name = "h";
+
+ field[4] = typ(TFIELD);
+ field[4]->type = ptrto(mapbucket(t));
+ field[4]->sym = mal(sizeof(Sym));
+ field[4]->sym->name = "buckets";
+
+ field[5] = typ(TFIELD);
+ field[5]->type = ptrto(mapbucket(t));
+ field[5]->sym = mal(sizeof(Sym));
+ field[5]->sym->name = "bptr";
+
+ // all other non-pointer fields
+ field[6] = typ(TFIELD);
+ field[6]->type = typ(TARRAY);
+ field[6]->type->type = types[TUINTPTR];
+ field[6]->type->bound = 4;
+ field[6]->type->width = 4 * widthptr;
+ field[6]->sym = mal(sizeof(Sym));
+ field[6]->sym->name = "other";
+
+ // build iterator struct holding the above fields
+ i = typ(TSTRUCT);
+ i->noalg = 1;
+ i->type = field[0];
+ off = 0;
+ for(n = 0; n < 6; n++) {
+ field[n]->down = field[n+1];
+ field[n]->width = off;
+ off += field[n]->type->width;
+ }
+ field[6]->down = T;
+ off += field[6]->type->width;
+ if(off != 10 * widthptr)
+ yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
+ t->hiter = i;
+ i->map = t;
+ return i;
+}
+
/*
* f is method type, with receiver.
* return function type, receiver as first argument (or not).
@@ -396,9 +483,8 @@ imethods(Type *t)
last->link = a;
last = a;
- // Compiler can only refer to wrappers for
- // named interface types and non-blank methods.
- if(t->sym == S || isblanksym(method))
+ // Compiler can only refer to wrappers for non-blank methods.
+ if(isblanksym(method))
continue;
// NOTE(rsc): Perhaps an oversight that
@@ -620,6 +706,10 @@ haspointers(Type *t)
ret = 1;
break;
}
+ if(t->bound == 0) { // empty array
+ ret = 0;
+ break;
+ }
ret = haspointers(t->type);
break;
case TSTRUCT:
@@ -656,7 +746,7 @@ static int
dcommontype(Sym *s, int ot, Type *t)
{
int i, alg, sizeofAlg;
- Sym *sptr, *algsym;
+ Sym *sptr, *algsym, *zero;
static Sym *algarray;
char *p;
@@ -677,6 +767,18 @@ dcommontype(Sym *s, int ot, Type *t)
else
sptr = weaktypesym(ptrto(t));
+ // All (non-reflect-allocated) Types share the same zero object.
+ // Each place in the compiler where a pointer to the zero object
+ // might be returned by a runtime call (map access return value,
+ // 2-arg type cast) declares the size of the zerovalue it needs.
+ // The linker magically takes the max of all the sizes.
+ zero = pkglookup("zerovalue", runtimepkg);
+
+ // We use size 0 here so we get the pointer to the zero value,
+ // but don't allocate space for the zero value unless we need it.
+ // TODO: how do we get this symbol into bss? We really want
+ // a read-only bss, but I don't think such a thing exists.
+
// ../../pkg/reflect/type.go:/^type.commonType
// actual type structure
// type commonType struct {
@@ -691,6 +793,7 @@ dcommontype(Sym *s, int ot, Type *t)
// string *string
// *extraType
// ptrToThis *Type
+ // zero unsafe.Pointer
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
@@ -728,6 +831,7 @@ dcommontype(Sym *s, int ot, Type *t)
ot += widthptr;
ot = dsymptr(s, ot, sptr, 0); // ptrto type
+ ot = dsymptr(s, ot, zero, 0); // ptr to zero value
return ot;
}
@@ -893,7 +997,7 @@ ok:
switch(t->etype) {
default:
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
break;
case TARRAY:
@@ -905,7 +1009,7 @@ ok:
t2->bound = -1; // slice
s2 = dtypesym(t2);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = dsymptr(s, ot, s2, 0);
ot = duintptr(s, ot, t->bound);
@@ -913,7 +1017,7 @@ ok:
// ../../pkg/runtime/type.go:/SliceType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
}
break;
@@ -922,7 +1026,7 @@ ok:
// ../../pkg/runtime/type.go:/ChanType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = duintptr(s, ot, t->chan);
break;
@@ -939,7 +1043,7 @@ ok:
dtypesym(t1->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = duint8(s, ot, isddd);
// two slice headers: in and out.
@@ -971,7 +1075,7 @@ ok:
// ../../pkg/runtime/type.go:/InterfaceType
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
@@ -990,7 +1094,7 @@ ok:
s3 = dtypesym(mapbucket(t));
s4 = dtypesym(hmap(t));
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
ot = dsymptr(s, ot, s2, 0);
ot = dsymptr(s, ot, s3, 0);
@@ -1007,7 +1111,7 @@ ok:
// ../../pkg/runtime/type.go:/PtrType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s1, 0);
break;
@@ -1020,7 +1124,7 @@ ok:
n++;
}
ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
+ xt = ot - 3*widthptr;
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
@@ -1218,7 +1322,22 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
// NOTE: Any changes here need to be made to reflect.PtrTo as well.
if(*off % widthptr != 0)
fatal("dgcsym1: invalid alignment, %T", t);
- if(!haspointers(t->type) || t->type->etype == TUINT8) {
+
+ // NOTE(rsc): Emitting GC_APTR here for *nonptrtype
+ // (pointer to non-pointer-containing type) means that
+ // we do not record 'nonptrtype' and instead tell the
+ // garbage collector to look up the type of the memory in
+ // type information stored in the heap. In effect we are telling
+ // the collector "we don't trust our information - use yours".
+ // It's not completely clear why we want to do this.
+ // It does have the effect that if you have a *SliceHeader and a *[]int
+ // pointing at the same actual slice header, *SliceHeader will not be
+ // used as an authoritative type for the memory, which is good:
+ // if the collector scanned the memory as type *SliceHeader, it would
+ // see no pointers inside but mark the block as scanned, preventing
+ // the seeing of pointers when we followed the *[]int pointer.
+ // Perhaps that kind of situation is the rationale.
+ if(!haspointers(t->type)) {
ot = duintptr(s, ot, GC_APTR);
ot = duintptr(s, ot, *off);
} else {
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index c8d57ab33..fb5c2a150 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -15,6 +15,7 @@ package PACKAGE
func new(typ *byte) *any
func panicindex()
func panicslice()
+func panicdivide()
func throwreturn()
func throwinit()
func panicwrap(string, string, string)
@@ -36,13 +37,17 @@ func printnl()
func printsp()
func goprintf()
-// filled in by compiler: int n, string, string, ...
-func concatstring()
+func concatstring2(string, string) string
+func concatstring3(string, string, string) string
+func concatstring4(string, string, string, string) string
+func concatstring5(string, string, string, string, string) string
+func concatstrings([]string) string
func cmpstring(string, string) int
func eqstring(string, string) bool
func intstring(int64) string
func slicebytetostring([]byte) string
+func slicebytetostringtmp([]byte) string
func slicerunetostring([]rune) string
func stringtoslicebyte(string) []byte
func stringtoslicerune(string) []rune
@@ -55,8 +60,8 @@ func slicestringcopy(to any, fr any) int
func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
func convI2E(elem any) (ret any)
func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem any) (ret any)
-func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
+func convT2E(typ *byte, elem *any) (ret any)
+func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
// interface type assertions x.(T)
func assertE2E(typ *byte, iface any) (ret any)
@@ -83,29 +88,27 @@ func equal(typ *byte, x1, x2 any) (ret bool)
// *byte is really *runtime.Type
func makemap(mapType *byte, hint int64) (hmap map[any]any)
-func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any)
+func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)
+func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapassign1(mapType *byte, hmap map[any]any, key any, val any)
+func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
-func mapdelete(mapType *byte, hmap map[any]any, key any)
+func mapdelete(mapType *byte, hmap map[any]any, key *any)
func mapiternext(hiter *any)
-func mapiter1(hiter *any) (key any)
-func mapiter2(hiter *any) (key any, val any)
// *byte is really *runtime.Type
func makechan(chanType *byte, hint int64) (hchan chan any)
-func chanrecv1(chanType *byte, hchan <-chan any) (elem any)
-func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool)
-func chansend1(chanType *byte, hchan chan<- any, elem any)
+func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
+func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
+func chansend1(chanType *byte, hchan chan<- any, elem *any)
func closechan(hchan any)
-func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool
+func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index cd3de8c7b..58a120674 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -69,6 +69,7 @@ typecheckselect(Node *sel)
n->op = OSELRECV2;
n->left = n->list->n;
n->ntest = n->list->next->n;
+ n->list = nil;
n->right = n->rlist->n;
n->rlist = nil;
break;
@@ -94,7 +95,7 @@ void
walkselect(Node *sel)
{
int lno, i;
- Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
+ Node *n, *r, *a, *var, *cas, *dflt, *ch;
NodeList *l, *init;
if(sel->list == nil && sel->xoffset != 0)
@@ -110,6 +111,8 @@ walkselect(Node *sel)
}
// optimization: one-case select: single op.
+ // TODO(rsc): Reenable optimization once order.c can handle it.
+ // golang.org/issue/7672.
if(i == 1) {
cas = sel->list->n;
setlineno(cas);
@@ -123,32 +126,34 @@ walkselect(Node *sel)
fatal("select %O", n->op);
case OSEND:
- ch = cheapexpr(n->left, &l);
- n->left = ch;
+ // ok already
+ ch = n->left;
break;
case OSELRECV:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
+ ch = n->right->left;
+ Selrecv1:
if(n->left == N)
- n = r;
- else {
- n = nod(OAS, n->left, r);
- typecheck(&n, Etop);
- }
+ n = n->right;
+ else
+ n->op = OAS;
break;
case OSELRECV2:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- a = nod(OAS2, N, N);
- a->list = n->list;
- a->rlist = list1(n->right);
- n = a;
+ ch = n->right->left;
+ if(n->ntest == N)
+ goto Selrecv1;
+ if(n->left == N) {
+ typecheck(&nblank, Erv | Easgn);
+ n->left = nblank;
+ }
+ n->op = OAS2;
+ n->list = list(list1(n->left), n->ntest);
+ n->rlist = list1(n->right);
+ n->right = N;
+ n->left = N;
+ n->ntest = N;
+ n->typecheck = 0;
typecheck(&n, Etop);
break;
}
@@ -166,7 +171,7 @@ walkselect(Node *sel)
goto out;
}
- // introduce temporary variables for OSELRECV where needed.
+ // convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization.
for(l=sel->list; l; l=l->next) {
cas = l->n;
@@ -175,58 +180,24 @@ walkselect(Node *sel)
if(n == N)
continue;
switch(n->op) {
+ case OSEND:
+ n->right = nod(OADDR, n->right, N);
+ typecheck(&n->right, Erv);
+ break;
case OSELRECV:
case OSELRECV2:
- ch = n->right->left;
-
- // If we can use the address of the target without
- // violating addressability or order of operations, do so.
- // Otherwise introduce a temporary.
- // Also introduce a temporary for := variables that escape,
- // so that we can delay the heap allocation until the case
- // is selected.
+ if(n->op == OSELRECV2 && n->ntest == N)
+ n->op = OSELRECV;
if(n->op == OSELRECV2) {
- if(n->ntest == N || isblank(n->ntest))
- n->ntest = nodnil();
- else if(n->ntest->op == ONAME &&
- (!n->colas || (n->ntest->class&PHEAP) == 0) &&
- convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
- n->ntest = nod(OADDR, n->ntest, N);
- n->ntest->etype = 1; // pointer does not escape
- typecheck(&n->ntest, Erv);
- } else {
- tmp = temp(types[TBOOL]);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->ntest, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->ntest = a;
- }
+ n->ntest = nod(OADDR, n->ntest, N);
+ typecheck(&n->ntest, Erv);
}
-
- if(n->left == N || isblank(n->left))
+ if(n->left == N)
n->left = nodnil();
- else if(n->left->op == ONAME &&
- (!n->colas || (n->left->class&PHEAP) == 0) &&
- convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
+ else {
n->left = nod(OADDR, n->left, N);
- n->left->etype = 1; // pointer does not escape
typecheck(&n->left, Erv);
- } else {
- tmp = temp(ch->type->type);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->left, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->left = a;
- }
-
- cas->nbody = concat(n->ninit, cas->nbody);
- n->ninit = nil;
+ }
break;
}
}
@@ -250,8 +221,8 @@ walkselect(Node *sel)
fatal("select %O", n->op);
case OSEND:
- // if c != nil && selectnbsend(c, v) { body } else { default body }
- ch = cheapexpr(n->left, &r->ninit);
+ // if selectnbsend(c, v) { body } else { default body }
+ ch = n->left;
r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
break;
@@ -260,7 +231,7 @@ walkselect(Node *sel)
// if c != nil && selectnbrecv(&v, c) { body } else { default body }
r = nod(OIF, N, N);
r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
+ ch = n->right->left;
r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
break;
@@ -269,7 +240,7 @@ walkselect(Node *sel)
// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
r = nod(OIF, N, N);
r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
+ ch = n->right->left;
r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
break;
@@ -313,11 +284,6 @@ walkselect(Node *sel)
case OSEND:
// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
- n->left = localexpr(safeexpr(n->left, &r->ninit), n->left->type, &r->ninit);
- n->right = localexpr(n->right, n->left->type->type, &r->ninit);
- n->right = nod(OADDR, n->right, N);
- n->right->etype = 1; // pointer does not escape
- typecheck(&n->right, Erv);
r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
&r->ninit, var, n->left, n->right);
break;
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 446b1110a..59804cd8d 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -286,8 +286,8 @@ staticcopy(Node *l, Node *r, NodeList **out)
if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
return 0;
- if(r->defn == N) // zeroed
- return 1;
+ if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value
+ return 0;
if(r->defn->op != OAS)
return 0;
orig = r;
@@ -354,11 +354,13 @@ staticcopy(Node *l, Node *r, NodeList **out)
else {
ll = nod(OXXX, N, N);
*ll = n1;
+ ll->orig = ll; // completely separate copy
if(!staticassign(ll, e->expr, out)) {
// Requires computation, but we're
// copying someone else's computation.
rr = nod(OXXX, N, N);
*rr = *orig;
+ rr->orig = rr; // completely separate copy
rr->type = ll->type;
rr->xoffset += e->xoffset;
*out = list(*out, nod(OAS, ll, rr));
@@ -378,6 +380,7 @@ staticassign(Node *l, Node *r, NodeList **out)
InitPlan *p;
InitEntry *e;
int i;
+ Strlit *sval;
switch(r->op) {
default:
@@ -426,6 +429,14 @@ staticassign(Node *l, Node *r, NodeList **out)
}
break;
+ case OSTRARRAYBYTE:
+ if(l->class == PEXTERN && r->left->op == OLITERAL) {
+ sval = r->left->val.u.sval;
+ slicebytes(l, sval->s, sval->len);
+ return 1;
+ }
+ break;
+
case OARRAYLIT:
initplan(r);
if(isslice(r->type)) {
@@ -459,6 +470,7 @@ staticassign(Node *l, Node *r, NodeList **out)
else {
a = nod(OXXX, N, N);
*a = n1;
+ a->orig = a; // completely separate copy
if(!staticassign(a, e->expr, out))
*out = list(*out, nod(OAS, a, e->expr));
}
@@ -756,11 +768,24 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
vauto = temp(ptrto(t));
// set auto to point at new temp or heap (3 assign)
- if(n->esc == EscNone) {
- a = nod(OAS, temp(t), N);
- typecheck(&a, Etop);
- *init = list(*init, a); // zero new temp
- a = nod(OADDR, a->left, N);
+ if(n->alloc != N) {
+ // temp allocated during order.c for dddarg
+ n->alloc->type = t;
+ if(vstat == N) {
+ a = nod(OAS, n->alloc, N);
+ typecheck(&a, Etop);
+ *init = list(*init, a); // zero new temp
+ }
+ a = nod(OADDR, n->alloc, N);
+ } else if(n->esc == EscNone) {
+ a = temp(t);
+ if(vstat == N) {
+ a = nod(OAS, temp(t), N);
+ typecheck(&a, Etop);
+ *init = list(*init, a); // zero new temp
+ a = a->left;
+ }
+ a = nod(OADDR, a, N);
} else {
a = nod(ONEW, N, N);
a->list = list1(typenod(t));
@@ -827,7 +852,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
int nerr;
int64 b;
Type *t, *tk, *tv, *t1;
- Node *vstat, *index, *value;
+ Node *vstat, *index, *value, *key, *val;
Sym *syma, *symb;
USED(ctxt);
@@ -846,7 +871,7 @@ ctxt = 0;
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
@@ -890,7 +915,7 @@ ctxt = 0;
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
@@ -941,8 +966,7 @@ ctxt = 0;
a->ninit = list1(nod(OAS, index, nodintconst(0)));
a->ntest = nod(OLT, index, nodintconst(t->bound));
- a->nincr = nod(OASOP, index, nodintconst(1));
- a->nincr->etype = OADD;
+ a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1)));
typecheck(&a, Etop);
walkstmt(&a);
@@ -950,25 +974,49 @@ ctxt = 0;
}
// put in dynamic entries one-at-a-time
+ key = nil;
+ val = nil;
for(l=n->list; l; l=l->next) {
r = l->n;
if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
+ fatal("maplit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
if(isliteral(index) && isliteral(value))
continue;
+
+ // build list of var[c] = expr.
+ // use temporary so that mapassign1 can have addressable key, val.
+ if(key == nil) {
+ key = temp(var->type->down);
+ val = temp(var->type->type);
+ }
+ a = nod(OAS, key, r->left);
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
+ a = nod(OAS, val, r->right);
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
- // build list of var[c] = expr
- a = nod(OINDEX, var, r->left);
- a = nod(OAS, a, r->right);
+ a = nod(OAS, nod(OINDEX, var, key), val);
typecheck(&a, Etop);
- walkexpr(&a, init);
+ walkstmt(&a);
+ *init = list(*init, a);
+
if(nerr != nerrors)
break;
-
+ }
+
+ if(key != nil) {
+ a = nod(OVARKILL, key, N);
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+ a = nod(OVARKILL, val, N);
+ typecheck(&a, Etop);
*init = list(*init, a);
}
}
@@ -988,12 +1036,16 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(!isptr[t->etype])
fatal("anylit: not ptr");
- r = nod(ONEW, N, N);
- r->typecheck = 1;
- r->type = t;
- r->esc = n->esc;
+ if(n->right != N) {
+ r = nod(OADDR, n->right, N);
+ typecheck(&r, Erv);
+ } else {
+ r = nod(ONEW, N, N);
+ r->typecheck = 1;
+ r->type = t;
+ r->esc = n->esc;
+ }
walkexpr(&r, init);
-
a = nod(OAS, var, r);
typecheck(&a, Etop);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index bea90b87b..72a9ac20c 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -88,6 +88,7 @@ flusherrors(void)
{
int i;
+ Bflush(&bstdout);
if(nerr == 0)
return;
qsort(err, nerr, sizeof err[0], errcmp);
@@ -258,9 +259,6 @@ fatal(char *fmt, ...)
void
linehist(char *file, int32 off, int relative)
{
- Hist *h;
- char *cp;
-
if(debug['i']) {
if(file != nil) {
if(off < 0)
@@ -274,25 +272,10 @@ linehist(char *file, int32 off, int relative)
print("end of import");
print(" at line %L\n", lexlineno);
}
-
- if(off < 0 && file[0] != '/' && !relative) {
- cp = mal(strlen(file) + strlen(pathname) + 2);
- sprint(cp, "%s/%s", pathname, file);
- file = cp;
- }
-
- h = mal(sizeof(Hist));
- h->name = file;
- h->line = lexlineno;
- h->offset = off;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
+
+ if(off < 0 && file[0] != '/' && !relative)
+ file = smprint("%s/%s", ctxt->pathname, file);
+ linklinehist(ctxt, lexlineno, file, off);
}
int32
@@ -607,8 +590,6 @@ algtype1(Type *t, Type **bad)
*bad = t;
return ANOEQ;
}
- if(t->bound == 0)
- return AMEM;
a = algtype1(t->type, bad);
if(a == ANOEQ || a == AMEM) {
if(a == ANOEQ && bad)
@@ -1242,8 +1223,10 @@ assignop(Type *src, Type *dst, char **why)
// 2. src and dst have identical underlying types
// and either src or dst is not a named type or
- // both are interface types.
- if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER))
+ // both are empty interface types.
+ // For assignable but different non-empty interface types,
+ // we want to recompute the itab.
+ if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src)))
return OCONVNOP;
// 3. dst is an interface type and src implements dst.
@@ -1251,13 +1234,16 @@ assignop(Type *src, Type *dst, char **why)
if(implements(src, dst, &missing, &have, &ptr))
return OCONVIFACE;
- // we'll have complained about this method anyway, supress spurious messages.
+ // we'll have complained about this method anyway, suppress spurious messages.
if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
return OCONVIFACE;
if(why != nil) {
if(isptrto(src, TINTER))
*why = smprint(":\n\t%T is pointer to interface, not interface", src);
+ else if(have && have->sym == missing->sym && have->nointerface)
+ *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')",
+ src, dst, missing->sym);
else if(have && have->sym == missing->sym)
*why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
@@ -1692,7 +1678,7 @@ typehash(Type *t)
md5reset(&d);
md5write(&d, (uchar*)p, strlen(p));
free(p);
- return md5sum(&d);
+ return md5sum(&d, nil);
}
Type*
@@ -2115,7 +2101,7 @@ cheapexpr(Node *n, NodeList **init)
Node*
localexpr(Node *n, Type *t, NodeList **init)
{
- if(n->op == ONAME && !n->addrtaken &&
+ if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) &&
(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
convertop(n->type, t, nil) == OCONVNOP)
return n;
@@ -2257,6 +2243,7 @@ adddot(Node *n)
int c, d;
typecheck(&n->left, Etype|Erv);
+ n->diag |= n->left->diag;
t = n->left->type;
if(t == T)
goto ret;
@@ -2506,12 +2493,19 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
Type *tpad, *methodrcvr;
int isddd;
Val v;
+ static int linehistdone = 0;
if(0 && debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
- lineno = 1; // less confusing than end of input
+ lexlineno++;
+ lineno = lexlineno;
+ if (linehistdone == 0) {
+ // All the wrappers can share the same linehist entry.
+ linehist("<autogenerated>", 0, 0);
+ linehistdone = 1;
+ }
dclcontext = PEXTERN;
markdcl();
@@ -2608,8 +2602,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
funcbody(fn);
curfn = fn;
- // wrappers where T is anonymous (struct{ NamedType }) can be duplicated.
- if(rcvr->etype == TSTRUCT || isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
+ // wrappers where T is anonymous (struct or interface) can be duplicated.
+ if(rcvr->etype == TSTRUCT ||
+ rcvr->etype == TINTER ||
+ isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
fn->dupok = 1;
typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop);
@@ -3631,7 +3627,8 @@ ngotype(Node *n)
* only in the last segment of the path, and it makes for happier
* users if we escape that as little as possible.
*
- * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too.
+ * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
+ * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too.
*/
static char*
pathtoprefix(char *s)
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index d6aa021a9..ce0190507 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -317,7 +317,7 @@ casebody(Node *sw, Node *typeswvar)
// botch - shouldn't fall thru declaration
last = stat->end->n;
- if(last->op == OXFALL) {
+ if(last->xoffset == n->xoffset && last->op == OXFALL) {
if(typeswvar) {
setlineno(last);
yyerror("cannot fallthrough in type switch");
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 31a2f2c5c..c50b2285b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -310,7 +310,7 @@ typecheck1(Node **np, int top)
int ok, ntop;
Type *t, *tp, *missing, *have, *badtype;
Val v;
- char *why;
+ char *why, *desc, descbuf[64];
n = *np;
@@ -368,7 +368,7 @@ reswitch:
goto ret;
case OPACK:
- yyerror("use of package %S not in selector", n->sym);
+ yyerror("use of package %S without selector", n->sym);
goto error;
case ODDD:
@@ -535,6 +535,19 @@ reswitch:
op = n->etype;
goto arith;
+ case OADDPTR:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ if(l->type->etype != tptr)
+ fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left);
+ if(r->type->etype != TUINTPTR)
+ fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right);
+ n->type = types[tptr];
+ goto ret;
+
case OADD:
case OAND:
case OANDAND:
@@ -654,8 +667,20 @@ reswitch:
if(iscmp[n->op]) {
n->etype = n->op;
n->op = OCMPSTR;
- } else if(n->op == OADD)
+ } else if(n->op == OADD) {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
n->op = OADDSTR;
+ if(l->op == OADDSTR)
+ n->list = l->list;
+ else
+ n->list = list1(l);
+ if(r->op == OADDSTR)
+ n->list = concat(n->list, r->list);
+ else
+ n->list = list(n->list, r);
+ n->left = N;
+ n->right = N;
+ }
}
if(et == TINTER) {
if(l->op == OLITERAL && l->val.ctype == CTNIL) {
@@ -721,8 +746,11 @@ reswitch:
if(n->left->type == T)
goto error;
checklvalue(n->left, "take the address of");
- for(l=n->left; l->op == ODOT; l=l->left)
+ r = outervalue(n->left);
+ for(l = n->left; l != r; l = l->left)
l->addrtaken = 1;
+ if(l->orig != l && l->op == ONAME)
+ fatal("found non-orig name node %N", l);
l->addrtaken = 1;
defaultlit(&n->left, T);
l = n->left;
@@ -864,7 +892,7 @@ reswitch:
goto error;
switch(t->etype) {
default:
- yyerror("invalid operation: %N (index of type %T)", n, t);
+ yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
goto error;
@@ -947,7 +975,7 @@ reswitch:
r = n->right;
if(r->type == T)
goto error;
- r = assignconv(r, l->type->type, "send");
+ n->right = assignconv(r, l->type->type, "send");
// TODO: more aggressive
n->etype = 0;
n->type = T;
@@ -1062,6 +1090,7 @@ reswitch:
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
+ n->diag |= n->left->diag;
l = n->left;
if(l->op == ONAME && l->etype != 0) {
if(n->isddd && l->etype != OAPPEND)
@@ -1123,7 +1152,11 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
+ if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf)
+ desc = descbuf;
+ else
+ desc = "function argument";
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc);
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -1209,17 +1242,29 @@ reswitch:
case OCOMPLEX:
ok |= Erv;
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- if(l->type == T || r->type == T)
- goto error;
- n->left = l;
- n->right = r;
+ if(count(n->list) == 1) {
+ typechecklist(n->list, Efnstruct);
+ t = n->list->n->left->type;
+ if(t->outtuple != 2) {
+ yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
+ goto error;
+ }
+ t = n->list->n->type->type;
+ l = t->nname;
+ r = t->down->nname;
+ } else {
+ if(twoarg(n) < 0)
+ goto error;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ r = typecheck(&n->right, Erv | (top & Eiota));
+ if(l->type == T || r->type == T)
+ goto error;
+ defaultlit2(&l, &r, 0);
+ if(l->type == T || r->type == T)
+ goto error;
+ n->left = l;
+ n->right = r;
+ }
if(!eqtype(l->type, r->type)) {
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
@@ -1298,9 +1343,22 @@ reswitch:
yyerror("missing arguments to append");
goto error;
}
- typechecklist(args, Erv);
+
+ if(count(args) == 1 && !n->isddd)
+ typecheck(&args->n, Erv | Efnstruct);
+ else
+ typechecklist(args, Erv);
+
if((t = args->n->type) == T)
goto error;
+
+ // Unpack multiple-return result before type-checking.
+ if(istype(t, TSTRUCT)) {
+ t = t->type;
+ if(istype(t, TFIELD))
+ t = t->type;
+ }
+
n->type = t;
if(!isslice(t)) {
if(isconst(args->n, CTNIL)) {
@@ -1355,6 +1413,8 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
+ if(n->left->type == T || n->right->type == T)
+ goto error;
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
@@ -1406,6 +1466,9 @@ reswitch:
}
break;
case OSTRARRAYBYTE:
+ // do not use stringtoarraylit.
+ // generated code and compiler memory footprint is better without it.
+ break;
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);
@@ -1621,6 +1684,7 @@ reswitch:
case OGOTO:
case OLABEL:
case OXFALL:
+ case OVARKILL:
ok |= Etop;
goto ret;
@@ -2116,6 +2180,31 @@ nokeys(NodeList *l)
return 1;
}
+static int
+hasddd(Type *t)
+{
+ Type *tl;
+
+ for(tl=t->type; tl; tl=tl->down) {
+ if(tl->isddd)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+downcount(Type *t)
+{
+ Type *tl;
+ int n;
+
+ n = 0;
+ for(tl=t->type; tl; tl=tl->down) {
+ n++;
+ }
+ return n;
+}
+
/*
* typecheck assignment: type list = expression list
*/
@@ -2126,14 +2215,25 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
Node *n;
int lno;
char *why;
+ int n1, n2;
lno = lineno;
if(tstruct->broke)
goto out;
+ n = N;
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
if(n->type->etype == TSTRUCT && n->type->funarg) {
+ if(!hasddd(tstruct)) {
+ n1 = downcount(tstruct);
+ n2 = downcount(n->type);
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+
tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
@@ -2162,6 +2262,26 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
goto out;
}
+ n1 = downcount(tstruct);
+ n2 = count(nl);
+ if(!hasddd(tstruct)) {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ else {
+ if(!isddd) {
+ if(n2 < n1-1)
+ goto notenough;
+ } else {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ }
+
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(tl->isddd) {
@@ -2206,10 +2326,14 @@ out:
return;
notenough:
- if(call != N)
- yyerror("not enough arguments in call to %N", call);
- else
- yyerror("not enough arguments to %O", op);
+ if(n == N || !n->diag) {
+ if(call != N)
+ yyerror("not enough arguments in call to %N", call);
+ else
+ yyerror("not enough arguments to %O", op);
+ if(n != N)
+ n->diag = 1;
+ }
goto out;
toomany:
@@ -2252,10 +2376,13 @@ keydup(Node *n, Node *hash[], ulong nhash)
ulong b;
double d;
int i;
- Node *a;
+ Node *a, *orign;
Node cmp;
char *s;
+ orign = n;
+ if(n->op == OCONVIFACE)
+ n = n->left;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
@@ -2288,17 +2415,25 @@ keydup(Node *n, Node *hash[], ulong nhash)
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
+ b = 0;
+ if(a->op == OCONVIFACE && orign->op == OCONVIFACE) {
+ if(eqtype(a->left->type, n->type)) {
+ cmp.right = a->left;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
+ } else if(eqtype(a->type, n->type)) {
+ cmp.right = a;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
if(b) {
- // too lazy to print the literal
yyerror("duplicate key %N in map literal", n);
return;
}
}
- n->ntest = hash[h];
- hash[h] = n;
+ orign->ntest = hash[h];
+ hash[h] = orign;
}
static void
@@ -2486,8 +2621,9 @@ typecheckcomplit(Node **np)
typecheck(&l->left, Erv);
evconst(l->left);
i = nonnegconst(l->left);
- if(i < 0) {
+ if(i < 0 && !l->left->diag) {
yyerror("array index must be non-negative integer constant");
+ l->left->diag = 1;
i = -(1<<30); // stay negative for a while
}
if(i >= 0)
@@ -2497,7 +2633,7 @@ typecheckcomplit(Node **np)
len = i;
if(t->bound >= 0 && len > t->bound) {
setlineno(l);
- yyerror("array index %d out of bounds [0:%d]", len, t->bound);
+ yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
t->bound = -1; // no more errors
}
}
@@ -2680,6 +2816,11 @@ checkassign(Node *n)
n->etype = 1;
return;
}
+
+ // have already complained about n being undefined
+ if(n->op == ONONAME)
+ return;
+
yyerror("cannot assign to %N", n);
}
@@ -2804,7 +2945,7 @@ typecheckas2(Node *n)
n->op = OAS2FUNC;
t = structfirst(&s, &r->type);
for(ll=n->list; ll; ll=ll->next) {
- if(ll->n->type != T)
+ if(t->type != T && ll->n->type != T)
checkassignto(t->type, ll->n);
if(ll->n->defn == n && ll->n->ntype == N)
ll->n->type = t->type;
@@ -3130,7 +3271,10 @@ typecheckdef(Node *n)
goto ret;
}
if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
- yyerror("const initializer %N is not a constant", e);
+ if(!e->diag) {
+ yyerror("const initializer %N is not a constant", e);
+ e->diag = 1;
+ }
goto ret;
}
t = n->type;
@@ -3220,29 +3364,38 @@ static int
checkmake(Type *t, char *arg, Node *n)
{
if(n->op == OLITERAL) {
- n->val = toint(n->val);
- if(mpcmpfixc(n->val.u.xval, 0) < 0) {
- yyerror("negative %s argument in make(%T)", arg, t);
- return -1;
- }
- if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
- yyerror("%s argument too large in make(%T)", arg, t);
- return -1;
+ switch(n->val.ctype) {
+ case CTINT:
+ case CTRUNE:
+ case CTFLT:
+ case CTCPLX:
+ n->val = toint(n->val);
+ if(mpcmpfixc(n->val.u.xval, 0) < 0) {
+ yyerror("negative %s argument in make(%T)", arg, t);
+ return -1;
+ }
+ if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
+ yyerror("%s argument too large in make(%T)", arg, t);
+ return -1;
+ }
+
+ // Delay defaultlit until after we've checked range, to avoid
+ // a redundant "constant NNN overflows int" error.
+ defaultlit(&n, types[TINT]);
+ return 0;
+ default:
+ break;
}
-
- // Delay defaultlit until after we've checked range, to avoid
- // a redundant "constant NNN overflows int" error.
- defaultlit(&n, types[TINT]);
- return 0;
}
-
- // Defaultlit still necessary for non-constant: n might be 1<<k.
- defaultlit(&n, types[TINT]);
- if(!isint[n->type->etype]) {
+ if(!isint[n->type->etype] && n->type->etype != TIDEAL) {
yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
return -1;
}
+
+ // Defaultlit still necessary for non-constant: n might be 1<<k.
+ defaultlit(&n, types[TINT]);
+
return 0;
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 66409d530..1cb25512e 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -21,7 +21,7 @@ static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
-static Node* copyany(Node*, NodeList**);
+static Node* copyany(Node*, NodeList**, int);
static Node* sliceany(Node*, NodeList**);
static void walkcompare(Node**, NodeList**);
static void walkrotate(Node**);
@@ -163,7 +163,6 @@ walkstmt(Node **np)
case OCALLFUNC:
case ODELETE:
case OSEND:
- case ORECV:
case OPRINT:
case OPRINTN:
case OPANIC:
@@ -179,6 +178,21 @@ walkstmt(Node **np)
n->op = OEMPTY; // don't leave plain values as statements.
break;
+ case ORECV:
+ // special case for a receive where we throw away
+ // the value received.
+ if(n->typecheck == 0)
+ fatal("missing typecheck: %+N", n);
+ init = n->ninit;
+ n->ninit = nil;
+
+ walkexpr(&n->left, &init);
+ n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil());
+ walkexpr(&n, &init);
+
+ addinit(&n, init);
+ break;
+
case OBREAK:
case ODCL:
case OCONTINUE:
@@ -188,6 +202,7 @@ walkstmt(Node **np)
case ODCLCONST:
case ODCLTYPE:
case OCHECKNIL:
+ case OVARKILL:
break;
case OBLOCK:
@@ -209,6 +224,9 @@ walkstmt(Node **np)
walkexprlist(n->left->list, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break;
+ case OCOPY:
+ n->left = copyany(n->left, &n->ninit, 1);
+ break;
default:
walkexpr(&n->left, &n->ninit);
break;
@@ -240,6 +258,9 @@ walkstmt(Node **np)
walkexprlist(n->left->list, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break;
+ case OCOPY:
+ n->left = copyany(n->left, &n->ninit, 1);
+ break;
default:
walkexpr(&n->left, &n->ninit);
break;
@@ -341,7 +362,8 @@ void
walkexpr(Node **np, NodeList **init)
{
Node *r, *l, *var, *a;
- NodeList *ll, *lr, *lpost;
+ Node *map, *key;
+ NodeList *ll, *lr;
Type *t;
int et, old_safemode;
int64 v;
@@ -455,7 +477,6 @@ walkexpr(Node **np, NodeList **init)
case ORSH:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
- shiftwalked:
t = n->left->type;
n->bounded = bounded(n->right, 8*t->width);
if(debug['m'] && n->etype && !isconst(n->right, CTINT))
@@ -472,6 +493,11 @@ walkexpr(Node **np, NodeList **init)
case OADD:
case OCOMPLEX:
case OLROT:
+ // Use results from call expression as arguments for complex.
+ if(n->op == OCOMPLEX && n->left == N && n->right == N) {
+ n->left = n->list->n;
+ n->right = n->list->next->n;
+ }
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
@@ -576,13 +602,32 @@ walkexpr(Node **np, NodeList **init)
case OAS:
*init = concat(*init, n->ninit);
n->ninit = nil;
+
walkexpr(&n->left, init);
n->left = safeexpr(n->left, init);
if(oaslit(n, init))
goto ret;
- walkexpr(&n->right, init);
+ if(n->right == N)
+ goto ret;
+
+ switch(n->right->op) {
+ default:
+ walkexpr(&n->right, init);
+ break;
+
+ case ORECV:
+ // x = <-c; n->left is x, n->right->left is c.
+ // orderstmt made sure x is addressable.
+ walkexpr(&n->right->left, init);
+ n1 = nod(OADDR, n->left, N);
+ r = n->right->left; // the channel
+ n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1);
+ walkexpr(&n, init);
+ goto ret;
+ }
+
if(n->left != N && n->right != N) {
r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata;
@@ -602,53 +647,35 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OAS2FUNC:
- as2func:
// a,b,... = fn()
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r, init);
- l = n->list->n;
-
- // all the really hard stuff - explicit function calls and so on -
- // is gone, but map assignments remain.
- // if there are map assignments here, assign via
- // temporaries, because ascompatet assumes
- // the targets can be addressed without function calls
- // and map index has an implicit one.
- lpost = nil;
- if(l->op == OINDEXMAP) {
- var = temp(l->type);
- n->list->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- l = n->list->next->n;
- if(l->op == OINDEXMAP) {
- var = temp(l->type);
- n->list->next->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
+
ll = ascompatet(n->op, n->list, &r->type, 0, init);
- walkexprlist(lpost, init);
- n = liststmt(concat(concat(list1(r), ll), lpost));
+ n = liststmt(concat(list1(r), ll));
goto ret;
case OAS2RECV:
+ // x, y = <-c
+ // orderstmt made sure x is addressable.
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
+ if(isblank(n->list->n))
+ n1 = nodnil();
+ else
+ n1 = nod(OADDR, n->list->n, N);
+ n1->etype = 1; // addr does not escape
fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left);
- n->rlist->n = r;
- n->op = OAS2FUNC;
- goto as2func;
+ r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1);
+ n = nod(OAS, n->list->next->n, r);
+ typecheck(&n, Etop);
+ goto ret;
case OAS2MAPR:
// a,b = m[i];
@@ -657,6 +684,7 @@ walkexpr(Node **np, NodeList **init)
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
+ walkexpr(&r->right, init);
t = r->left->type;
p = nil;
if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
@@ -675,41 +703,50 @@ walkexpr(Node **np, NodeList **init)
}
}
if(p != nil) {
- // from:
- // a,b = m[i]
- // to:
- // var,b = mapaccess2_fast*(t, m, i)
- // a = *var
- a = n->list->n;
- var = temp(ptrto(t->type));
- var->typecheck = 1;
-
- fn = mapfn(p, t);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
- n->rlist = list1(r);
- n->op = OAS2FUNC;
- n->list->n = var;
- walkexpr(&n, init);
- *init = list(*init, n);
-
- n = nod(OAS, a, nod(OIND, var, N));
- typecheck(&n, Etop);
- walkexpr(&n, init);
- goto ret;
- }
- fn = mapfn("mapaccess2", t);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
+ // fast versions take key by value
+ key = r->right;
+ } else {
+ // standard version takes key by reference
+ // orderexpr made sure key is addressable.
+ key = nod(OADDR, r->right, N);
+ p = "mapaccess2";
+ }
+
+ // from:
+ // a,b = m[i]
+ // to:
+ // var,b = mapaccess2*(t, m, i)
+ // a = *var
+ a = n->list->n;
+ var = temp(ptrto(t->type));
+ var->typecheck = 1;
+ fn = mapfn(p, t);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
n->rlist = list1(r);
n->op = OAS2FUNC;
- goto as2func;
+ n->list->n = var;
+ walkexpr(&n, init);
+ *init = list(*init, n);
+ n = nod(OAS, a, nod(OIND, var, N));
+ typecheck(&n, Etop);
+ walkexpr(&n, init);
+ // mapaccess needs a zero value to be at least this big.
+ if(zerosize < t->type->width)
+ zerosize = t->type->width;
+ // TODO: ptr is always non-nil, so disable nil check for this OIND op.
+ goto ret;
case ODELETE:
*init = concat(*init, n->ninit);
n->ninit = nil;
- l = n->list->n;
- r = n->list->next->n;
- t = l->type;
- n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r);
+ map = n->list->n;
+ key = n->list->next->n;
+ walkexpr(&map, init);
+ walkexpr(&key, init);
+ // orderstmt made sure key is addressable.
+ key = nod(OADDR, key, N);
+ t = map->type;
+ n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key);
goto ret;
case OAS2DOTTYPE:
@@ -872,7 +909,20 @@ walkexpr(Node **np, NodeList **init)
goto ret;
}
}
- ll = list(ll, n->left);
+ if(isinter(n->left->type)) {
+ ll = list(ll, n->left);
+ } else {
+ // regular types are passed by reference to avoid C vararg calls
+ // orderexpr arranged for n->left to be a temporary for all
+ // the conversions it could see. comparison of an interface
+ // with a non-interface, especially in a switch on interface value
+ // with non-interface cases, is not visible to orderstmt, so we
+ // have to fall back on allocating a temp here.
+ if(islvalue(n->left))
+ ll = list(ll, nod(OADDR, n->left, N));
+ else
+ ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N));
+ }
argtype(fn, n->left->type);
argtype(fn, n->type);
dowidth(fn->type);
@@ -909,51 +959,6 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
goto ret;
- case OASOP:
- if(n->etype == OANDNOT) {
- n->etype = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- }
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
-
- /*
- * on 32-bit arch, rewrite 64-bit ops into l = l op r.
- * on 386, rewrite float ops into l = l op r.
- * everywhere, rewrite map ops into l = l op r.
- * everywhere, rewrite string += into l = l op r.
- * everywhere, rewrite integer/complex /= into l = l op r.
- * TODO(rsc): Maybe this rewrite should be done always?
- */
- et = n->left->type->etype;
- if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
- (thechar == '8' && isfloat[et]) ||
- l->op == OINDEXMAP ||
- et == TSTRING ||
- (!isfloat[et] && n->etype == ODIV) ||
- n->etype == OMOD) {
- l = safeexpr(n->left, init);
- a = l;
- if(a->op == OINDEXMAP) {
- // map index has "lhs" bit set in a->etype.
- // make a copy so we can clear it on the rhs.
- a = nod(OXXX, N, N);
- *a = *l;
- a->etype = 0;
- }
- r = nod(OAS, l, nod(n->etype, a, n->right));
- typecheck(&r, Etop);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
- if(n->etype == OLSH || n->etype == ORSH)
- goto shiftwalked;
- goto ret;
-
case OANDNOT:
walkexpr(&n->left, init);
n->op = OAND;
@@ -998,7 +1003,7 @@ walkexpr(Node **np, NodeList **init)
switch(n->op) {
case OMOD:
case ODIV:
- if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+ if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
goto ret;
if(et == TINT64)
strcpy(namebuf, "int64");
@@ -1063,6 +1068,8 @@ walkexpr(Node **np, NodeList **init)
case OINDEXMAP:
if(n->etype == 1)
goto ret;
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
t = n->left->type;
p = nil;
@@ -1082,23 +1089,25 @@ walkexpr(Node **np, NodeList **init)
}
}
if(p != nil) {
- // use fast version. The fast versions return a pointer to the value - we need
- // to dereference it to get the result.
- n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, n->right);
- n = nod(OIND, n, N);
- n->type = t->type;
- n->typecheck = 1;
+ // fast versions take key by value
+ key = n->right;
} else {
- // no fast version for this key
- n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
- }
+ // standard version takes key by reference.
+ // orderexpr made sure key is addressable.
+ key = nod(OADDR, n->right, N);
+ p = "mapaccess1";
+ }
+ n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key);
+ n = nod(OIND, n, N);
+ n->type = t->type;
+ n->typecheck = 1;
+ // mapaccess needs a zero value to be at least this big.
+ if(zerosize < t->type->width)
+ zerosize = t->type->width;
goto ret;
case ORECV:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left);
- goto ret;
+ fatal("walkexpr ORECV"); // should see inside OAS only
case OSLICE:
if(n->right != N && n->right->left == N && n->right->right == N) { // noop
@@ -1182,9 +1191,10 @@ walkexpr(Node **np, NodeList **init)
// s + "badgerbadgerbadger" == "badgerbadgerbadger"
if((n->etype == OEQ || n->etype == ONE) &&
isconst(n->right, CTSTR) &&
- n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
- cmpslit(n->right, n->left->right) == 0) {
- r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
+ n->left->op == OADDSTR && count(n->left->list) == 2 &&
+ isconst(n->left->list->next->n, CTSTR) &&
+ cmpslit(n->right, n->left->list->next->n) == 0) {
+ r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0));
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
@@ -1238,19 +1248,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OCOPY:
- if(flag_race) {
- if(n->right->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("copy", 1);
- argtype(fn, n->left->type);
- argtype(fn, n->right->type);
- n = mkcall1(fn, n->type, init,
- n->left, n->right,
- nodintconst(n->left->type->type->width));
- goto ret;
- }
- n = copyany(n, init);
+ n = copyany(n, init, flag_race);
goto ret;
case OCLOSE:
@@ -1321,6 +1319,11 @@ walkexpr(Node **np, NodeList **init)
n = mkcall("slicebytetostring", n->type, init, n->left);
goto ret;
+ case OARRAYBYTESTRTMP:
+ // slicebytetostringtmp([]byte) string;
+ n = mkcall("slicebytetostringtmp", n->type, init, n->left);
+ goto ret;
+
case OARRAYRUNESTR:
// slicerunetostring([]rune) string;
n = mkcall("slicerunetostring", n->type, init, n->left);
@@ -1368,13 +1371,18 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
+ // XXX TODO do we need to clear var?
var = temp(n->type);
anylit(0, n, var, init);
n = var;
goto ret;
case OSEND:
- n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right);
+ n1 = n->right;
+ n1 = assignconv(n1, n->left->type->type, "chan send");
+ walkexpr(&n1, init);
+ n1 = nod(OADDR, n1, N);
+ n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1);
goto ret;
case OCLOSURE:
@@ -1534,11 +1542,16 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
* package all the arguments that match a ... T parameter into a []T.
*/
static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc)
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd)
{
Node *a, *n;
Type *tslice;
-
+ int esc;
+
+ esc = EscUnknown;
+ if(ddd != nil)
+ esc = ddd->esc;
+
tslice = typ(TARRAY);
tslice->type = l->type->type;
tslice->bound = -1;
@@ -1548,6 +1561,8 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int
n->type = tslice;
} else {
n = nod(OCOMPLIT, N, typenod(tslice));
+ if(ddd != nil)
+ n->alloc = ddd->alloc; // temporary to use
n->list = lr0;
n->esc = esc;
typecheck(&n, Erv);
@@ -1619,7 +1634,6 @@ dumpnodetypes(NodeList *l, char *what)
static NodeList*
ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
- int esc;
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
@@ -1638,7 +1652,8 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
// optimization - can do block copy
if(eqtypenoname(r->type, *nl)) {
a = nodarg(*nl, fp);
- a->type = r->type;
+ r = nod(OCONVNOP, r, N);
+ r->type = a->type;
nn = list1(convas(nod(OAS, a, r), init));
goto ret;
}
@@ -1682,10 +1697,7 @@ loop:
// normal case -- make a slice of all
// remaining arguments and pass it to
// the ddd parameter.
- esc = EscUnknown;
- if(call->right)
- esc = call->right->esc;
- nn = mkdotargslice(lr, nn, l, fp, init, esc);
+ nn = mkdotargslice(lr, nn, l, fp, init, call->right);
goto ret;
}
@@ -1911,6 +1923,7 @@ static Node*
convas(Node *n, NodeList **init)
{
Type *lt, *rt;
+ Node *map, *key, *val;
if(n->op != OAS)
fatal("convas: not OAS %O", n->op);
@@ -1931,9 +1944,17 @@ convas(Node *n, NodeList **init)
}
if(n->left->op == OINDEXMAP) {
- n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
- typename(n->left->left->type),
- n->left->left, n->left->right, n->right);
+ map = n->left->left;
+ key = n->left->right;
+ val = n->right;
+ walkexpr(&map, init);
+ walkexpr(&key, init);
+ walkexpr(&val, init);
+ // orderexpr made sure key and val are addressable.
+ key = nod(OADDR, key, N);
+ val = nod(OADDR, val, N);
+ n = mkcall1(mapfn("mapassign1", map->type), T, init,
+ typename(map->type), map, key, val);
goto out;
}
@@ -2101,7 +2122,7 @@ reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
* what's the outer value that a write to n affects?
* outer value means containing struct or array.
*/
-static Node*
+Node*
outervalue(Node *n)
{
for(;;) {
@@ -2320,7 +2341,7 @@ paramstoheap(Type **argin, int out)
nn = nil;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
v = t->nname;
- if(v && v->sym && v->sym->name[0] == '~')
+ if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
v = N;
// In precisestack mode, the garbage collector assumes results
// are always live, so zero them always.
@@ -2493,33 +2514,38 @@ mapfndel(char *name, Type *t)
static Node*
addstr(Node *n, NodeList **init)
{
- Node *r, *cat, *typstr;
- NodeList *in, *args;
- int i, count;
-
- count = 0;
- for(r=n; r->op == OADDSTR; r=r->left)
- count++; // r->right
- count++; // r
-
- // prepare call of runtime.catstring of type int, string, string, string
- // with as many strings as we have.
- cat = syslook("concatstring", 1);
- cat->type = T;
- cat->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
- typstr = typenod(types[TSTRING]);
- for(i=0; i<count; i++)
- in = list(in, nod(ODCLFIELD, N, typstr));
- cat->ntype->list = in;
- cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
+ Node *r, *cat, *slice;
+ NodeList *args, *l;
+ int c;
+ Type *t;
+
+ // orderexpr rewrote OADDSTR to have a list of strings.
+ c = count(n->list);
+ if(c < 2)
+ yyerror("addstr count %d too small", c);
+ // build list of string arguments
args = nil;
- for(r=n; r->op == OADDSTR; r=r->left)
- args = concat(list1(conv(r->right, types[TSTRING])), args);
- args = concat(list1(conv(r, types[TSTRING])), args);
- args = concat(list1(nodintconst(count)), args);
+ for(l=n->list; l != nil; l=l->next)
+ args = list(args, conv(l->n, types[TSTRING]));
+ if(c <= 5) {
+ // small numbers of strings use direct runtime helpers.
+ // note: orderexpr knows this cutoff too.
+ snprint(namebuf, sizeof(namebuf), "concatstring%d", c);
+ } else {
+ // large numbers of strings are passed to the runtime as a slice.
+ strcpy(namebuf, "concatstrings");
+ t = typ(TARRAY);
+ t->type = types[TSTRING];
+ t->bound = -1;
+ slice = nod(OCOMPLIT, N, typenod(t));
+ slice->alloc = n->alloc;
+ slice->list = args;
+ slice->esc = EscNone;
+ args = list1(slice);
+ }
+ cat = syslook(namebuf, 1);
r = nod(OCALL, cat, N);
r->list = args;
typecheck(&r, Erv);
@@ -2597,9 +2623,10 @@ appendslice(Node *n, NodeList **init)
fn = syslook("copy", 1);
argtype(fn, l1->type);
argtype(fn, l2->type);
- l = list(l, mkcall1(fn, types[TINT], init,
+ nt = mkcall1(fn, types[TINT], &l,
nptr1, nptr2,
- nodintconst(s->type->type->width)));
+ nodintconst(s->type->type->width));
+ l = list(l, nt);
} else {
// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
nptr1 = nod(OINDEX, s, nod(OLEN, l1, N));
@@ -2614,7 +2641,8 @@ appendslice(Node *n, NodeList **init)
nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
- l = list(l, mkcall1(fn, T, init, nptr1, nptr2, nwid));
+ nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
+ l = list(l, nt);
}
// s = s[:len(l1)+len(l2)]
@@ -2660,6 +2688,10 @@ append(Node *n, NodeList **init)
l->n = cheapexpr(l->n, init);
nsrc = n->list->n;
+
+ // Resolve slice type of multi-valued return.
+ if(istype(nsrc->type, TSTRUCT))
+ nsrc->type = nsrc->type->type->type;
argc = count(n->list) - 1;
if (argc < 1) {
return nsrc;
@@ -2705,7 +2737,7 @@ append(Node *n, NodeList **init)
return ns;
}
-// Lower copy(a, b) to a memmove call.
+// Lower copy(a, b) to a memmove call or a runtime call.
//
// init {
// n := len(a)
@@ -2717,11 +2749,22 @@ append(Node *n, NodeList **init)
// Also works if b is a string.
//
static Node*
-copyany(Node *n, NodeList **init)
+copyany(Node *n, NodeList **init, int runtimecall)
{
Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
NodeList *l;
+ if(runtimecall) {
+ if(n->right->type->etype == TSTRING)
+ fn = syslook("slicestringcopy", 1);
+ else
+ fn = syslook("copy", 1);
+ argtype(fn, n->left->type);
+ argtype(fn, n->right->type);
+ return mkcall1(fn, n->type, init,
+ n->left, n->right,
+ nodintconst(n->left->type->type->width));
+ }
walkexpr(&n->left, init);
walkexpr(&n->right, init);
nl = temp(n->left->type);
@@ -2802,17 +2845,13 @@ sliceany(Node* n, NodeList **init)
if(isconst(cb, CTINT)) {
cbv = mpgetfix(cb->val.u.xval);
- if(cbv < 0 || cbv > bv) {
+ if(cbv < 0 || cbv > bv)
yyerror("slice index out of bounds");
- cbv = -1;
- }
}
if(isconst(hb, CTINT)) {
hbv = mpgetfix(hb->val.u.xval);
- if(hbv < 0 || hbv > bv) {
+ if(hbv < 0 || hbv > bv)
yyerror("slice index out of bounds");
- hbv = -1;
- }
}
if(isconst(lb, CTINT)) {
lbv = mpgetfix(lb->val.u.xval);
@@ -3052,13 +3091,10 @@ walkcompare(Node **np, NodeList **init)
}
if(expr == N)
expr = nodbool(n->op == OEQ);
- typecheck(&expr, Erv);
- walkexpr(&expr, init);
- expr->type = n->type;
- *np = expr;
- return;
+ r = expr;
+ goto ret;
}
-
+
if(t->etype == TSTRUCT && countfield(t) <= 4) {
// Struct of four or fewer fields.
// Inline comparisons.
@@ -3075,13 +3111,10 @@ walkcompare(Node **np, NodeList **init)
}
if(expr == N)
expr = nodbool(n->op == OEQ);
- typecheck(&expr, Erv);
- walkexpr(&expr, init);
- expr->type = n->type;
- *np = expr;
- return;
+ r = expr;
+ goto ret;
}
-
+
// Chose not to inline, but still have addresses.
// Call equality function directly.
// The equality function requires a bool pointer for
@@ -3114,10 +3147,7 @@ walkcompare(Node **np, NodeList **init)
if(n->op != OEQ)
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- walkexpr(&r, init);
- *np = r;
- return;
+ goto ret;
hard:
// Cannot take address of one or both of the operands.
@@ -3133,7 +3163,16 @@ hard:
r = mkcall1(fn, n->type, init, typename(n->left->type), l, r);
if(n->op == ONE) {
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
+ }
+ goto ret;
+
+ret:
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ if(r->type != n->type) {
+ r = nod(OCONVNOP, r, N);
+ r->type = n->type;
+ r->typecheck = 1;
}
*np = r;
return;
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
index 390ad80b3..08d8ecff2 100644
--- a/src/cmd/gc/y.tab.c
+++ b/src/cmd/gc/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,52 +55,11 @@
/* Pure parsers. */
#define YYPURE 0
-/* Push parsers. */
-#define YYPUSH 0
-
-/* Pull parsers. */
-#define YYPULL 1
-
/* Using locations. */
#define YYLSP_NEEDED 0
-/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
-#line 20 "go.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-
-
-/* Line 268 of yacc.c */
-#line 81 "y.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -209,36 +171,61 @@ static void fixlbrace(int);
+/* Copy the first part of user declarations. */
+#line 20 "go.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
+#include <libc.h>
+#include "go.h"
+
+static void fixlbrace(int);
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 293 of yacc.c */
#line 28 "go.y"
-
+{
Node* node;
NodeList* list;
Type* type;
Sym* sym;
struct Val val;
int i;
-
-
-
-/* Line 293 of yacc.c */
-#line 230 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 193 of yacc.c. */
+#line 216 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
+
/* Copy the second part of user declarations. */
-/* Line 343 of yacc.c */
-#line 242 "y.tab.c"
+/* Line 216 of yacc.c. */
+#line 229 "y.tab.c"
#ifdef short
# undef short
@@ -313,14 +300,14 @@ typedef short int yytype_int16;
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -341,11 +328,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -368,24 +355,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -401,9 +388,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -414,27 +401,6 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
@@ -452,7 +418,24 @@ union yyalloc
while (YYID (0))
# endif
# endif
-#endif /* !YYCOPY_NEEDED */
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 4
@@ -681,36 +664,36 @@ static const yytype_uint16 yyrline[] =
308, 312, 316, 322, 328, 334, 339, 343, 347, 353,
359, 363, 367, 373, 377, 383, 384, 388, 394, 403,
409, 427, 432, 444, 460, 465, 472, 492, 510, 519,
- 538, 537, 552, 551, 582, 585, 592, 591, 602, 608,
- 617, 628, 634, 637, 645, 644, 655, 661, 673, 677,
- 682, 672, 703, 702, 715, 718, 724, 727, 739, 743,
- 738, 761, 760, 776, 777, 781, 785, 789, 793, 797,
- 801, 805, 809, 813, 817, 821, 825, 829, 833, 837,
- 841, 845, 849, 854, 860, 861, 865, 876, 880, 884,
- 888, 893, 897, 907, 911, 916, 924, 928, 929, 940,
- 944, 948, 952, 956, 964, 965, 971, 978, 984, 991,
- 994, 1001, 1007, 1024, 1031, 1032, 1039, 1040, 1059, 1060,
- 1063, 1066, 1070, 1081, 1090, 1096, 1099, 1102, 1109, 1110,
- 1116, 1129, 1144, 1152, 1164, 1169, 1175, 1176, 1177, 1178,
- 1179, 1180, 1186, 1187, 1188, 1189, 1195, 1196, 1197, 1198,
- 1199, 1205, 1206, 1209, 1212, 1213, 1214, 1215, 1216, 1219,
- 1220, 1233, 1237, 1242, 1247, 1252, 1256, 1257, 1260, 1266,
- 1273, 1279, 1286, 1292, 1303, 1317, 1346, 1386, 1411, 1429,
- 1438, 1441, 1449, 1453, 1457, 1464, 1470, 1475, 1487, 1490,
- 1500, 1501, 1507, 1508, 1514, 1518, 1524, 1525, 1531, 1535,
- 1541, 1564, 1569, 1575, 1581, 1588, 1597, 1606, 1621, 1627,
- 1632, 1636, 1643, 1656, 1657, 1663, 1669, 1672, 1676, 1682,
- 1685, 1694, 1697, 1698, 1702, 1703, 1709, 1710, 1711, 1712,
- 1713, 1715, 1714, 1729, 1734, 1738, 1742, 1746, 1750, 1755,
- 1774, 1780, 1788, 1792, 1798, 1802, 1808, 1812, 1818, 1822,
- 1831, 1835, 1839, 1843, 1849, 1852, 1860, 1861, 1863, 1864,
- 1867, 1870, 1873, 1876, 1879, 1882, 1885, 1888, 1891, 1894,
- 1897, 1900, 1903, 1906, 1912, 1916, 1920, 1924, 1928, 1932,
- 1952, 1959, 1970, 1971, 1972, 1975, 1976, 1979, 1983, 1993,
- 1997, 2001, 2005, 2009, 2013, 2017, 2023, 2029, 2037, 2045,
- 2051, 2058, 2074, 2096, 2100, 2106, 2109, 2112, 2116, 2126,
- 2130, 2145, 2153, 2154, 2166, 2167, 2170, 2174, 2180, 2184,
- 2190, 2194
+ 538, 537, 552, 551, 583, 586, 593, 592, 603, 609,
+ 618, 629, 635, 638, 646, 645, 656, 662, 674, 678,
+ 683, 673, 704, 703, 716, 719, 725, 728, 740, 744,
+ 739, 762, 761, 777, 778, 782, 786, 790, 794, 798,
+ 802, 806, 810, 814, 818, 822, 826, 830, 834, 838,
+ 842, 846, 850, 855, 861, 862, 866, 877, 881, 885,
+ 889, 894, 898, 908, 912, 917, 925, 929, 930, 941,
+ 945, 949, 953, 957, 965, 966, 972, 979, 985, 992,
+ 995, 1002, 1008, 1025, 1032, 1033, 1040, 1041, 1060, 1061,
+ 1064, 1067, 1071, 1082, 1091, 1097, 1100, 1103, 1110, 1111,
+ 1117, 1130, 1145, 1153, 1165, 1170, 1176, 1177, 1178, 1179,
+ 1180, 1181, 1187, 1188, 1189, 1190, 1196, 1197, 1198, 1199,
+ 1200, 1206, 1207, 1210, 1213, 1214, 1215, 1216, 1217, 1220,
+ 1221, 1234, 1238, 1243, 1248, 1253, 1257, 1258, 1261, 1267,
+ 1274, 1280, 1287, 1293, 1304, 1318, 1347, 1387, 1412, 1430,
+ 1439, 1442, 1450, 1454, 1458, 1465, 1471, 1476, 1488, 1491,
+ 1501, 1502, 1508, 1509, 1515, 1519, 1525, 1526, 1532, 1536,
+ 1542, 1565, 1570, 1576, 1582, 1589, 1598, 1607, 1622, 1628,
+ 1633, 1637, 1644, 1657, 1658, 1664, 1670, 1673, 1677, 1683,
+ 1686, 1695, 1698, 1699, 1703, 1704, 1710, 1711, 1712, 1713,
+ 1714, 1716, 1715, 1730, 1736, 1740, 1744, 1748, 1752, 1757,
+ 1776, 1782, 1790, 1794, 1800, 1804, 1810, 1814, 1820, 1824,
+ 1833, 1837, 1841, 1845, 1851, 1854, 1862, 1863, 1865, 1866,
+ 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896,
+ 1899, 1902, 1905, 1908, 1914, 1918, 1922, 1926, 1930, 1934,
+ 1954, 1961, 1972, 1973, 1974, 1977, 1978, 1981, 1985, 1995,
+ 1999, 2003, 2007, 2011, 2015, 2019, 2025, 2031, 2039, 2047,
+ 2053, 2060, 2076, 2098, 2102, 2108, 2111, 2114, 2118, 2128,
+ 2132, 2151, 2159, 2160, 2172, 2173, 2176, 2180, 2186, 2190,
+ 2196, 2200
};
#endif
@@ -729,16 +712,16 @@ const char *yytname[] =
"'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
"PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
"'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
- "package", "loadsys", "$@1", "imports", "import", "import_stmt",
+ "package", "loadsys", "@1", "imports", "import", "import_stmt",
"import_stmt_list", "import_here", "import_package", "import_safety",
- "import_there", "$@2", "xdcl", "common_dcl", "lconst", "vardcl",
+ "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl",
"constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case",
- "compound_stmt", "$@3", "caseblock", "$@4", "caseblock_list",
- "loop_body", "$@5", "range_stmt", "for_header", "for_body", "for_stmt",
- "$@6", "if_header", "if_stmt", "$@7", "$@8", "$@9", "elseif", "$@10",
- "elseif_list", "else", "switch_stmt", "$@11", "$@12", "select_stmt",
- "$@13", "expr", "uexpr", "pseudocall", "pexpr_no_paren", "start_complit",
- "keyval", "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
+ "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body",
+ "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6",
+ "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list",
+ "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr",
+ "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval",
+ "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
"name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym",
"hidden_importsym", "name", "labelname", "dotdotdot", "ntype",
"non_expr_type", "non_recvchantype", "convtype", "comptype",
@@ -748,7 +731,7 @@ const char *yytname[] =
"vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list",
"interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl",
"indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt",
- "non_dcl_stmt", "$@14", "stmt_list", "new_name_list", "dcl_name_list",
+ "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list",
"expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list",
"osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt",
"ohidden_funarg_list", "ohidden_structdcl_list",
@@ -861,8 +844,8 @@ static const yytype_uint8 yyr2[] =
1, 3
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint16 yydefact[] =
{
@@ -1051,7 +1034,8 @@ static const yytype_int16 yypgoto[] =
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
- number is the opposite. If YYTABLE_NINF, syntax error. */
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -277
static const yytype_int16 yytable[] =
{
@@ -1285,12 +1269,6 @@ static const yytype_int16 yytable[] =
198
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-474))
-
-#define yytable_value_is_error(yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
37, 37, 61, 143, 67, 37, 37, 202, 324, 251,
@@ -1608,18 +1586,9 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -1629,6 +1598,7 @@ do \
{ \
yychar = (Token); \
yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK (1); \
goto yybackup; \
} \
@@ -1670,10 +1640,19 @@ while (YYID (0))
#endif
-/* This macro is provided for backward compatibility. */
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
@@ -1777,20 +1756,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1824,11 +1800,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1865,6 +1841,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1967,142 +1944,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# endif
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
- about the unexpected token YYTOKEN for the state stack whose top is
- YYSSP.
-
- Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
- not large enough to hold the message. In that case, also set
- *YYMSG_ALLOC to the required number of bytes. Return 2 if the
- required number of bytes is too large to store. */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
- yytype_int16 *yyssp, int yytoken)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = 0;
- /* Arguments of yyformat. */
- char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - Assume YYFAIL is not used. It's too flawed to consider. See
- <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
- for details. YYERROR is fine as it does not invoke this
- function.
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yychar) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yychar.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (yytoken != YYEMPTY)
- {
- int yyn = yypact[*yyssp];
- yyarg[yycount++] = yytname[yytoken];
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for
- this state because they are default actions. */
- int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- int yychecklim = YYLAST - yyn + 1;
- int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- int yyx;
-
- for (yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- yysize = yysize0;
- break;
- }
- yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
+ int yyn = yypact[yystate];
- switch (yycount)
- {
-# define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
- if (*yymsg_alloc < yysize)
- {
- *yymsg_alloc = 2 * yysize;
- if (! (yysize <= *yymsg_alloc
- && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
- *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
- return 1;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* Avoid sprintf, as that infringes on the user's name space.
- Don't have undefined behavior even if the translation
- produced a string with the wrong number of "%s"s. */
- {
- char *yyp = *yymsg;
- int yyi = 0;
- while ((*yyp = *yyformat) != '\0')
- if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
- {
- yyp += yytnamerr (yyp, yyarg[yyi++]);
- yyformat += 2;
- }
- else
- {
- yyp++;
- yyformat++;
- }
- }
- return 0;
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -2134,9 +2084,10 @@ yydestruct (yymsg, yytype, yyvaluep)
break;
}
}
-
+
/* Prevent warnings from -Wmissing-prototypes. */
+
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
@@ -2152,16 +2103,18 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-/* The lookahead symbol. */
+
+/* The look-ahead symbol. */
int yychar, yystate;
-/* The semantic value of the lookahead symbol. */
+/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -2188,36 +2141,13 @@ yyparse ()
#endif
#endif
{
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
-
- /* The stacks and their tools:
- `yyss': related to states.
- `yyvs': related to semantic values.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- yytype_int16 yyssa[YYINITDEPTH];
- yytype_int16 *yyss;
- yytype_int16 *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs;
- YYSTYPE *yyvsp;
-
- YYSIZE_T yystacksize;
-
+
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken;
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
#if YYERROR_VERBOSE
/* Buffer for error messages, and its allocated size. */
char yymsgbuf[128];
@@ -2225,28 +2155,51 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
+
yyssp = yyss;
yyvsp = yyvs;
@@ -2276,6 +2229,7 @@ yyparse ()
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
+
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
@@ -2283,6 +2237,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -2305,8 +2260,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -2317,6 +2273,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -2326,9 +2283,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -2337,16 +2291,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -2372,22 +2326,26 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
*++yyvsp = yylval;
@@ -2427,8 +2385,6 @@ yyreduce:
switch (yyn)
{
case 2:
-
-/* Line 1806 of yacc.c */
#line 128 "go.y"
{
xtop = concat(xtop, (yyvsp[(4) - (4)].list));
@@ -2436,8 +2392,6 @@ yyreduce:
break;
case 3:
-
-/* Line 1806 of yacc.c */
#line 134 "go.y"
{
prevlineno = lineno;
@@ -2447,8 +2401,6 @@ yyreduce:
break;
case 4:
-
-/* Line 1806 of yacc.c */
#line 140 "go.y"
{
mkpackage((yyvsp[(2) - (3)].sym)->name);
@@ -2456,8 +2408,6 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
#line 150 "go.y"
{
importpkg = runtimepkg;
@@ -2471,8 +2421,6 @@ yyreduce:
break;
case 6:
-
-/* Line 1806 of yacc.c */
#line 161 "go.y"
{
importpkg = nil;
@@ -2480,8 +2428,6 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
#line 175 "go.y"
{
Pkg *ipkg;
@@ -2522,8 +2468,6 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
#line 212 "go.y"
{
// When an invalid import path is passed to importfile,
@@ -2536,8 +2480,6 @@ yyreduce:
break;
case 16:
-
-/* Line 1806 of yacc.c */
#line 227 "go.y"
{
// import with original name
@@ -2548,8 +2490,6 @@ yyreduce:
break;
case 17:
-
-/* Line 1806 of yacc.c */
#line 234 "go.y"
{
// import with given name
@@ -2560,8 +2500,6 @@ yyreduce:
break;
case 18:
-
-/* Line 1806 of yacc.c */
#line 241 "go.y"
{
// import into my name space
@@ -2572,8 +2510,6 @@ yyreduce:
break;
case 19:
-
-/* Line 1806 of yacc.c */
#line 250 "go.y"
{
if(importpkg->name == nil) {
@@ -2590,8 +2526,6 @@ yyreduce:
break;
case 21:
-
-/* Line 1806 of yacc.c */
#line 265 "go.y"
{
if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
@@ -2600,8 +2534,6 @@ yyreduce:
break;
case 22:
-
-/* Line 1806 of yacc.c */
#line 271 "go.y"
{
defercheckwidth();
@@ -2609,8 +2541,6 @@ yyreduce:
break;
case 23:
-
-/* Line 1806 of yacc.c */
#line 275 "go.y"
{
resumecheckwidth();
@@ -2619,8 +2549,6 @@ yyreduce:
break;
case 24:
-
-/* Line 1806 of yacc.c */
#line 284 "go.y"
{
yyerror("empty top-level declaration");
@@ -2629,8 +2557,6 @@ yyreduce:
break;
case 26:
-
-/* Line 1806 of yacc.c */
#line 290 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
@@ -2638,8 +2564,6 @@ yyreduce:
break;
case 27:
-
-/* Line 1806 of yacc.c */
#line 294 "go.y"
{
yyerror("non-declaration statement outside function body");
@@ -2648,8 +2572,6 @@ yyreduce:
break;
case 28:
-
-/* Line 1806 of yacc.c */
#line 299 "go.y"
{
(yyval.list) = nil;
@@ -2657,8 +2579,6 @@ yyreduce:
break;
case 29:
-
-/* Line 1806 of yacc.c */
#line 305 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
@@ -2666,8 +2586,6 @@ yyreduce:
break;
case 30:
-
-/* Line 1806 of yacc.c */
#line 309 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2675,8 +2593,6 @@ yyreduce:
break;
case 31:
-
-/* Line 1806 of yacc.c */
#line 313 "go.y"
{
(yyval.list) = nil;
@@ -2684,8 +2600,6 @@ yyreduce:
break;
case 32:
-
-/* Line 1806 of yacc.c */
#line 317 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
@@ -2695,8 +2609,6 @@ yyreduce:
break;
case 33:
-
-/* Line 1806 of yacc.c */
#line 323 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2706,8 +2618,6 @@ yyreduce:
break;
case 34:
-
-/* Line 1806 of yacc.c */
#line 329 "go.y"
{
(yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
@@ -2717,8 +2627,6 @@ yyreduce:
break;
case 35:
-
-/* Line 1806 of yacc.c */
#line 335 "go.y"
{
(yyval.list) = nil;
@@ -2727,8 +2635,6 @@ yyreduce:
break;
case 36:
-
-/* Line 1806 of yacc.c */
#line 340 "go.y"
{
(yyval.list) = list1((yyvsp[(2) - (2)].node));
@@ -2736,8 +2642,6 @@ yyreduce:
break;
case 37:
-
-/* Line 1806 of yacc.c */
#line 344 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
@@ -2745,8 +2649,6 @@ yyreduce:
break;
case 38:
-
-/* Line 1806 of yacc.c */
#line 348 "go.y"
{
(yyval.list) = nil;
@@ -2754,8 +2656,6 @@ yyreduce:
break;
case 39:
-
-/* Line 1806 of yacc.c */
#line 354 "go.y"
{
iota = 0;
@@ -2763,8 +2663,6 @@ yyreduce:
break;
case 40:
-
-/* Line 1806 of yacc.c */
#line 360 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
@@ -2772,8 +2670,6 @@ yyreduce:
break;
case 41:
-
-/* Line 1806 of yacc.c */
#line 364 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
@@ -2781,8 +2677,6 @@ yyreduce:
break;
case 42:
-
-/* Line 1806 of yacc.c */
#line 368 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
@@ -2790,8 +2684,6 @@ yyreduce:
break;
case 43:
-
-/* Line 1806 of yacc.c */
#line 374 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
@@ -2799,8 +2691,6 @@ yyreduce:
break;
case 44:
-
-/* Line 1806 of yacc.c */
#line 378 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
@@ -2808,8 +2698,6 @@ yyreduce:
break;
case 46:
-
-/* Line 1806 of yacc.c */
#line 385 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
@@ -2817,8 +2705,6 @@ yyreduce:
break;
case 47:
-
-/* Line 1806 of yacc.c */
#line 389 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
@@ -2826,8 +2712,6 @@ yyreduce:
break;
case 48:
-
-/* Line 1806 of yacc.c */
#line 395 "go.y"
{
// different from dclname because the name
@@ -2838,8 +2722,6 @@ yyreduce:
break;
case 49:
-
-/* Line 1806 of yacc.c */
#line 404 "go.y"
{
(yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
@@ -2847,8 +2729,6 @@ yyreduce:
break;
case 50:
-
-/* Line 1806 of yacc.c */
#line 410 "go.y"
{
(yyval.node) = (yyvsp[(1) - (1)].node);
@@ -2870,8 +2750,6 @@ yyreduce:
break;
case 51:
-
-/* Line 1806 of yacc.c */
#line 428 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
@@ -2880,8 +2758,6 @@ yyreduce:
break;
case 52:
-
-/* Line 1806 of yacc.c */
#line 433 "go.y"
{
if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
@@ -2897,8 +2773,6 @@ yyreduce:
break;
case 53:
-
-/* Line 1806 of yacc.c */
#line 445 "go.y"
{
if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
@@ -2918,8 +2792,6 @@ yyreduce:
break;
case 54:
-
-/* Line 1806 of yacc.c */
#line 461 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
@@ -2928,8 +2800,6 @@ yyreduce:
break;
case 55:
-
-/* Line 1806 of yacc.c */
#line 466 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
@@ -2938,8 +2808,6 @@ yyreduce:
break;
case 56:
-
-/* Line 1806 of yacc.c */
#line 473 "go.y"
{
Node *n, *nn;
@@ -2963,8 +2831,6 @@ yyreduce:
break;
case 57:
-
-/* Line 1806 of yacc.c */
#line 493 "go.y"
{
Node *n;
@@ -2986,8 +2852,6 @@ yyreduce:
break;
case 58:
-
-/* Line 1806 of yacc.c */
#line 511 "go.y"
{
// will be converted to OCASE
@@ -3000,8 +2864,6 @@ yyreduce:
break;
case 59:
-
-/* Line 1806 of yacc.c */
#line 520 "go.y"
{
Node *n, *nn;
@@ -3021,8 +2883,6 @@ yyreduce:
break;
case 60:
-
-/* Line 1806 of yacc.c */
#line 538 "go.y"
{
markdcl();
@@ -3030,8 +2890,6 @@ yyreduce:
break;
case 61:
-
-/* Line 1806 of yacc.c */
#line 542 "go.y"
{
if((yyvsp[(3) - (4)].list) == nil)
@@ -3043,8 +2901,6 @@ yyreduce:
break;
case 62:
-
-/* Line 1806 of yacc.c */
#line 552 "go.y"
{
// If the last token read by the lexer was consumed
@@ -3054,13 +2910,12 @@ yyreduce:
// This is so that the stmt_list action doesn't look at
// the case tokens if the stmt_list is empty.
yylast = yychar;
+ (yyvsp[(1) - (1)].node)->xoffset = block;
}
break;
case 63:
-
-/* Line 1806 of yacc.c */
-#line 562 "go.y"
+#line 563 "go.y"
{
int last;
@@ -3082,36 +2937,28 @@ yyreduce:
break;
case 64:
-
-/* Line 1806 of yacc.c */
-#line 582 "go.y"
+#line 583 "go.y"
{
(yyval.list) = nil;
}
break;
case 65:
-
-/* Line 1806 of yacc.c */
-#line 586 "go.y"
+#line 587 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
}
break;
case 66:
-
-/* Line 1806 of yacc.c */
-#line 592 "go.y"
+#line 593 "go.y"
{
markdcl();
}
break;
case 67:
-
-/* Line 1806 of yacc.c */
-#line 596 "go.y"
+#line 597 "go.y"
{
(yyval.list) = (yyvsp[(3) - (4)].list);
popdcl();
@@ -3119,9 +2966,7 @@ yyreduce:
break;
case 68:
-
-/* Line 1806 of yacc.c */
-#line 603 "go.y"
+#line 604 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -3130,9 +2975,7 @@ yyreduce:
break;
case 69:
-
-/* Line 1806 of yacc.c */
-#line 609 "go.y"
+#line 610 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -3142,9 +2985,7 @@ yyreduce:
break;
case 70:
-
-/* Line 1806 of yacc.c */
-#line 618 "go.y"
+#line 619 "go.y"
{
// init ; test ; incr
if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
@@ -3158,9 +2999,7 @@ yyreduce:
break;
case 71:
-
-/* Line 1806 of yacc.c */
-#line 629 "go.y"
+#line 630 "go.y"
{
// normal test
(yyval.node) = nod(OFOR, N, N);
@@ -3169,9 +3008,7 @@ yyreduce:
break;
case 73:
-
-/* Line 1806 of yacc.c */
-#line 638 "go.y"
+#line 639 "go.y"
{
(yyval.node) = (yyvsp[(1) - (2)].node);
(yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
@@ -3179,18 +3016,14 @@ yyreduce:
break;
case 74:
-
-/* Line 1806 of yacc.c */
-#line 645 "go.y"
+#line 646 "go.y"
{
markdcl();
}
break;
case 75:
-
-/* Line 1806 of yacc.c */
-#line 649 "go.y"
+#line 650 "go.y"
{
(yyval.node) = (yyvsp[(3) - (3)].node);
popdcl();
@@ -3198,9 +3031,7 @@ yyreduce:
break;
case 76:
-
-/* Line 1806 of yacc.c */
-#line 656 "go.y"
+#line 657 "go.y"
{
// test
(yyval.node) = nod(OIF, N, N);
@@ -3209,9 +3040,7 @@ yyreduce:
break;
case 77:
-
-/* Line 1806 of yacc.c */
-#line 662 "go.y"
+#line 663 "go.y"
{
// init ; test
(yyval.node) = nod(OIF, N, N);
@@ -3222,18 +3051,14 @@ yyreduce:
break;
case 78:
-
-/* Line 1806 of yacc.c */
-#line 673 "go.y"
+#line 674 "go.y"
{
markdcl();
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 677 "go.y"
+#line 678 "go.y"
{
if((yyvsp[(3) - (3)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3241,18 +3066,14 @@ yyreduce:
break;
case 80:
-
-/* Line 1806 of yacc.c */
-#line 682 "go.y"
+#line 683 "go.y"
{
(yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
}
break;
case 81:
-
-/* Line 1806 of yacc.c */
-#line 686 "go.y"
+#line 687 "go.y"
{
Node *n;
NodeList *nn;
@@ -3270,18 +3091,14 @@ yyreduce:
break;
case 82:
-
-/* Line 1806 of yacc.c */
-#line 703 "go.y"
+#line 704 "go.y"
{
markdcl();
}
break;
case 83:
-
-/* Line 1806 of yacc.c */
-#line 707 "go.y"
+#line 708 "go.y"
{
if((yyvsp[(4) - (5)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3291,36 +3108,28 @@ yyreduce:
break;
case 84:
-
-/* Line 1806 of yacc.c */
-#line 715 "go.y"
+#line 716 "go.y"
{
(yyval.list) = nil;
}
break;
case 85:
-
-/* Line 1806 of yacc.c */
-#line 719 "go.y"
+#line 720 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
}
break;
case 86:
-
-/* Line 1806 of yacc.c */
-#line 724 "go.y"
+#line 725 "go.y"
{
(yyval.list) = nil;
}
break;
case 87:
-
-/* Line 1806 of yacc.c */
-#line 728 "go.y"
+#line 729 "go.y"
{
NodeList *node;
@@ -3332,18 +3141,14 @@ yyreduce:
break;
case 88:
-
-/* Line 1806 of yacc.c */
-#line 739 "go.y"
+#line 740 "go.y"
{
markdcl();
}
break;
case 89:
-
-/* Line 1806 of yacc.c */
-#line 743 "go.y"
+#line 744 "go.y"
{
Node *n;
n = (yyvsp[(3) - (3)].node)->ntest;
@@ -3354,9 +3159,7 @@ yyreduce:
break;
case 90:
-
-/* Line 1806 of yacc.c */
-#line 751 "go.y"
+#line 752 "go.y"
{
(yyval.node) = (yyvsp[(3) - (7)].node);
(yyval.node)->op = OSWITCH;
@@ -3367,18 +3170,14 @@ yyreduce:
break;
case 91:
-
-/* Line 1806 of yacc.c */
-#line 761 "go.y"
+#line 762 "go.y"
{
typesw = nod(OXXX, typesw, N);
}
break;
case 92:
-
-/* Line 1806 of yacc.c */
-#line 765 "go.y"
+#line 766 "go.y"
{
(yyval.node) = nod(OSELECT, N, N);
(yyval.node)->lineno = typesw->lineno;
@@ -3388,198 +3187,154 @@ yyreduce:
break;
case 94:
-
-/* Line 1806 of yacc.c */
-#line 778 "go.y"
+#line 779 "go.y"
{
(yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 95:
-
-/* Line 1806 of yacc.c */
-#line 782 "go.y"
+#line 783 "go.y"
{
(yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 96:
-
-/* Line 1806 of yacc.c */
-#line 786 "go.y"
+#line 787 "go.y"
{
(yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 97:
-
-/* Line 1806 of yacc.c */
-#line 790 "go.y"
+#line 791 "go.y"
{
(yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 98:
-
-/* Line 1806 of yacc.c */
-#line 794 "go.y"
+#line 795 "go.y"
{
(yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 99:
-
-/* Line 1806 of yacc.c */
-#line 798 "go.y"
+#line 799 "go.y"
{
(yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 100:
-
-/* Line 1806 of yacc.c */
-#line 802 "go.y"
+#line 803 "go.y"
{
(yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 101:
-
-/* Line 1806 of yacc.c */
-#line 806 "go.y"
+#line 807 "go.y"
{
(yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 102:
-
-/* Line 1806 of yacc.c */
-#line 810 "go.y"
+#line 811 "go.y"
{
(yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 103:
-
-/* Line 1806 of yacc.c */
-#line 814 "go.y"
+#line 815 "go.y"
{
(yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 104:
-
-/* Line 1806 of yacc.c */
-#line 818 "go.y"
+#line 819 "go.y"
{
(yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 105:
-
-/* Line 1806 of yacc.c */
-#line 822 "go.y"
+#line 823 "go.y"
{
(yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 106:
-
-/* Line 1806 of yacc.c */
-#line 826 "go.y"
+#line 827 "go.y"
{
(yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 107:
-
-/* Line 1806 of yacc.c */
-#line 830 "go.y"
+#line 831 "go.y"
{
(yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 108:
-
-/* Line 1806 of yacc.c */
-#line 834 "go.y"
+#line 835 "go.y"
{
(yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 109:
-
-/* Line 1806 of yacc.c */
-#line 838 "go.y"
+#line 839 "go.y"
{
(yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 110:
-
-/* Line 1806 of yacc.c */
-#line 842 "go.y"
+#line 843 "go.y"
{
(yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 111:
-
-/* Line 1806 of yacc.c */
-#line 846 "go.y"
+#line 847 "go.y"
{
(yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 112:
-
-/* Line 1806 of yacc.c */
-#line 850 "go.y"
+#line 851 "go.y"
{
(yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 113:
-
-/* Line 1806 of yacc.c */
-#line 855 "go.y"
+#line 856 "go.y"
{
(yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 115:
-
-/* Line 1806 of yacc.c */
-#line 862 "go.y"
+#line 863 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 116:
-
-/* Line 1806 of yacc.c */
-#line 866 "go.y"
+#line 867 "go.y"
{
if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
// Special case for &T{...}: turn into (*T){...}.
@@ -3593,36 +3348,28 @@ yyreduce:
break;
case 117:
-
-/* Line 1806 of yacc.c */
-#line 877 "go.y"
+#line 878 "go.y"
{
(yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 118:
-
-/* Line 1806 of yacc.c */
-#line 881 "go.y"
+#line 882 "go.y"
{
(yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 119:
-
-/* Line 1806 of yacc.c */
-#line 885 "go.y"
+#line 886 "go.y"
{
(yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
}
break;
case 120:
-
-/* Line 1806 of yacc.c */
-#line 889 "go.y"
+#line 890 "go.y"
{
yyerror("the bitwise complement operator is ^");
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
@@ -3630,36 +3377,28 @@ yyreduce:
break;
case 121:
-
-/* Line 1806 of yacc.c */
-#line 894 "go.y"
+#line 895 "go.y"
{
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
}
break;
case 122:
-
-/* Line 1806 of yacc.c */
-#line 898 "go.y"
+#line 899 "go.y"
{
(yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
}
break;
case 123:
-
-/* Line 1806 of yacc.c */
-#line 908 "go.y"
+#line 909 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
}
break;
case 124:
-
-/* Line 1806 of yacc.c */
-#line 912 "go.y"
+#line 913 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -3667,9 +3406,7 @@ yyreduce:
break;
case 125:
-
-/* Line 1806 of yacc.c */
-#line 917 "go.y"
+#line 918 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
(yyval.node)->list = (yyvsp[(3) - (6)].list);
@@ -3678,18 +3415,14 @@ yyreduce:
break;
case 126:
-
-/* Line 1806 of yacc.c */
-#line 925 "go.y"
+#line 926 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 128:
-
-/* Line 1806 of yacc.c */
-#line 930 "go.y"
+#line 931 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -3703,45 +3436,35 @@ yyreduce:
break;
case 129:
-
-/* Line 1806 of yacc.c */
-#line 941 "go.y"
+#line 942 "go.y"
{
(yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
}
break;
case 130:
-
-/* Line 1806 of yacc.c */
-#line 945 "go.y"
+#line 946 "go.y"
{
(yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
}
break;
case 131:
-
-/* Line 1806 of yacc.c */
-#line 949 "go.y"
+#line 950 "go.y"
{
(yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
}
break;
case 132:
-
-/* Line 1806 of yacc.c */
-#line 953 "go.y"
+#line 954 "go.y"
{
(yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
}
break;
case 133:
-
-/* Line 1806 of yacc.c */
-#line 957 "go.y"
+#line 958 "go.y"
{
if((yyvsp[(5) - (8)].node) == N)
yyerror("middle index required in 3-index slice");
@@ -3752,9 +3475,7 @@ yyreduce:
break;
case 135:
-
-/* Line 1806 of yacc.c */
-#line 966 "go.y"
+#line 967 "go.y"
{
// conversion
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
@@ -3763,9 +3484,7 @@ yyreduce:
break;
case 136:
-
-/* Line 1806 of yacc.c */
-#line 972 "go.y"
+#line 973 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3775,9 +3494,7 @@ yyreduce:
break;
case 137:
-
-/* Line 1806 of yacc.c */
-#line 979 "go.y"
+#line 980 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3786,9 +3503,7 @@ yyreduce:
break;
case 138:
-
-/* Line 1806 of yacc.c */
-#line 985 "go.y"
+#line 986 "go.y"
{
yyerror("cannot parenthesize type in composite literal");
(yyval.node) = (yyvsp[(5) - (7)].node);
@@ -3798,9 +3513,7 @@ yyreduce:
break;
case 140:
-
-/* Line 1806 of yacc.c */
-#line 994 "go.y"
+#line 995 "go.y"
{
// composite expression.
// make node early so we get the right line number.
@@ -3809,18 +3522,14 @@ yyreduce:
break;
case 141:
-
-/* Line 1806 of yacc.c */
-#line 1002 "go.y"
+#line 1003 "go.y"
{
(yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 142:
-
-/* Line 1806 of yacc.c */
-#line 1008 "go.y"
+#line 1009 "go.y"
{
// These nodes do not carry line numbers.
// Since a composite literal commonly spans several lines,
@@ -3840,9 +3549,7 @@ yyreduce:
break;
case 143:
-
-/* Line 1806 of yacc.c */
-#line 1025 "go.y"
+#line 1026 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3850,9 +3557,7 @@ yyreduce:
break;
case 145:
-
-/* Line 1806 of yacc.c */
-#line 1033 "go.y"
+#line 1034 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3860,9 +3565,7 @@ yyreduce:
break;
case 147:
-
-/* Line 1806 of yacc.c */
-#line 1041 "go.y"
+#line 1042 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
@@ -3882,27 +3585,21 @@ yyreduce:
break;
case 151:
-
-/* Line 1806 of yacc.c */
-#line 1067 "go.y"
+#line 1068 "go.y"
{
(yyval.i) = LBODY;
}
break;
case 152:
-
-/* Line 1806 of yacc.c */
-#line 1071 "go.y"
+#line 1072 "go.y"
{
(yyval.i) = '{';
}
break;
case 153:
-
-/* Line 1806 of yacc.c */
-#line 1082 "go.y"
+#line 1083 "go.y"
{
if((yyvsp[(1) - (1)].sym) == S)
(yyval.node) = N;
@@ -3912,27 +3609,21 @@ yyreduce:
break;
case 154:
-
-/* Line 1806 of yacc.c */
-#line 1091 "go.y"
+#line 1092 "go.y"
{
(yyval.node) = dclname((yyvsp[(1) - (1)].sym));
}
break;
case 155:
-
-/* Line 1806 of yacc.c */
-#line 1096 "go.y"
+#line 1097 "go.y"
{
(yyval.node) = N;
}
break;
case 157:
-
-/* Line 1806 of yacc.c */
-#line 1103 "go.y"
+#line 1104 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
// during imports, unqualified non-exported identifiers are from builtinpkg
@@ -3942,18 +3633,14 @@ yyreduce:
break;
case 159:
-
-/* Line 1806 of yacc.c */
-#line 1111 "go.y"
+#line 1112 "go.y"
{
(yyval.sym) = S;
}
break;
case 160:
-
-/* Line 1806 of yacc.c */
-#line 1117 "go.y"
+#line 1118 "go.y"
{
Pkg *p;
@@ -3969,9 +3656,7 @@ yyreduce:
break;
case 161:
-
-/* Line 1806 of yacc.c */
-#line 1130 "go.y"
+#line 1131 "go.y"
{
Pkg *p;
@@ -3987,9 +3672,7 @@ yyreduce:
break;
case 162:
-
-/* Line 1806 of yacc.c */
-#line 1145 "go.y"
+#line 1146 "go.y"
{
(yyval.node) = oldname((yyvsp[(1) - (1)].sym));
if((yyval.node)->pack != N)
@@ -3998,9 +3681,7 @@ yyreduce:
break;
case 164:
-
-/* Line 1806 of yacc.c */
-#line 1165 "go.y"
+#line 1166 "go.y"
{
yyerror("final argument in variadic function missing type");
(yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
@@ -4008,45 +3689,35 @@ yyreduce:
break;
case 165:
-
-/* Line 1806 of yacc.c */
-#line 1170 "go.y"
+#line 1171 "go.y"
{
(yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
}
break;
case 171:
-
-/* Line 1806 of yacc.c */
-#line 1181 "go.y"
+#line 1182 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 175:
-
-/* Line 1806 of yacc.c */
-#line 1190 "go.y"
+#line 1191 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 180:
-
-/* Line 1806 of yacc.c */
-#line 1200 "go.y"
+#line 1201 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 190:
-
-/* Line 1806 of yacc.c */
-#line 1221 "go.y"
+#line 1222 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -4060,18 +3731,14 @@ yyreduce:
break;
case 191:
-
-/* Line 1806 of yacc.c */
-#line 1234 "go.y"
+#line 1235 "go.y"
{
(yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
}
break;
case 192:
-
-/* Line 1806 of yacc.c */
-#line 1238 "go.y"
+#line 1239 "go.y"
{
// array literal of nelem
(yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
@@ -4079,9 +3746,7 @@ yyreduce:
break;
case 193:
-
-/* Line 1806 of yacc.c */
-#line 1243 "go.y"
+#line 1244 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
(yyval.node)->etype = Cboth;
@@ -4089,9 +3754,7 @@ yyreduce:
break;
case 194:
-
-/* Line 1806 of yacc.c */
-#line 1248 "go.y"
+#line 1249 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Csend;
@@ -4099,27 +3762,21 @@ yyreduce:
break;
case 195:
-
-/* Line 1806 of yacc.c */
-#line 1253 "go.y"
+#line 1254 "go.y"
{
(yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
}
break;
case 198:
-
-/* Line 1806 of yacc.c */
-#line 1261 "go.y"
+#line 1262 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 199:
-
-/* Line 1806 of yacc.c */
-#line 1267 "go.y"
+#line 1268 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Crecv;
@@ -4127,9 +3784,7 @@ yyreduce:
break;
case 200:
-
-/* Line 1806 of yacc.c */
-#line 1274 "go.y"
+#line 1275 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -4138,9 +3793,7 @@ yyreduce:
break;
case 201:
-
-/* Line 1806 of yacc.c */
-#line 1280 "go.y"
+#line 1281 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -4148,9 +3801,7 @@ yyreduce:
break;
case 202:
-
-/* Line 1806 of yacc.c */
-#line 1287 "go.y"
+#line 1288 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -4159,9 +3810,7 @@ yyreduce:
break;
case 203:
-
-/* Line 1806 of yacc.c */
-#line 1293 "go.y"
+#line 1294 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -4169,9 +3818,7 @@ yyreduce:
break;
case 204:
-
-/* Line 1806 of yacc.c */
-#line 1304 "go.y"
+#line 1305 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
if((yyval.node) == N)
@@ -4186,9 +3833,7 @@ yyreduce:
break;
case 205:
-
-/* Line 1806 of yacc.c */
-#line 1318 "go.y"
+#line 1319 "go.y"
{
Node *t;
@@ -4220,9 +3865,7 @@ yyreduce:
break;
case 206:
-
-/* Line 1806 of yacc.c */
-#line 1347 "go.y"
+#line 1348 "go.y"
{
Node *rcvr, *t;
@@ -4263,9 +3906,7 @@ yyreduce:
break;
case 207:
-
-/* Line 1806 of yacc.c */
-#line 1387 "go.y"
+#line 1388 "go.y"
{
Sym *s;
Type *t;
@@ -4293,9 +3934,7 @@ yyreduce:
break;
case 208:
-
-/* Line 1806 of yacc.c */
-#line 1412 "go.y"
+#line 1413 "go.y"
{
(yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right);
(yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
@@ -4314,9 +3953,7 @@ yyreduce:
break;
case 209:
-
-/* Line 1806 of yacc.c */
-#line 1430 "go.y"
+#line 1431 "go.y"
{
(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
(yyval.node) = nod(OTFUNC, N, N);
@@ -4326,18 +3963,14 @@ yyreduce:
break;
case 210:
-
-/* Line 1806 of yacc.c */
-#line 1438 "go.y"
+#line 1439 "go.y"
{
(yyval.list) = nil;
}
break;
case 211:
-
-/* Line 1806 of yacc.c */
-#line 1442 "go.y"
+#line 1443 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
if((yyval.list) == nil)
@@ -4346,27 +3979,21 @@ yyreduce:
break;
case 212:
-
-/* Line 1806 of yacc.c */
-#line 1450 "go.y"
+#line 1451 "go.y"
{
(yyval.list) = nil;
}
break;
case 213:
-
-/* Line 1806 of yacc.c */
-#line 1454 "go.y"
+#line 1455 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
}
break;
case 214:
-
-/* Line 1806 of yacc.c */
-#line 1458 "go.y"
+#line 1459 "go.y"
{
(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
(yyval.list) = (yyvsp[(2) - (3)].list);
@@ -4374,18 +4001,14 @@ yyreduce:
break;
case 215:
-
-/* Line 1806 of yacc.c */
-#line 1465 "go.y"
+#line 1466 "go.y"
{
closurehdr((yyvsp[(1) - (1)].node));
}
break;
case 216:
-
-/* Line 1806 of yacc.c */
-#line 1471 "go.y"
+#line 1472 "go.y"
{
(yyval.node) = closurebody((yyvsp[(3) - (4)].list));
fixlbrace((yyvsp[(2) - (4)].i));
@@ -4393,27 +4016,21 @@ yyreduce:
break;
case 217:
-
-/* Line 1806 of yacc.c */
-#line 1476 "go.y"
+#line 1477 "go.y"
{
(yyval.node) = closurebody(nil);
}
break;
case 218:
-
-/* Line 1806 of yacc.c */
-#line 1487 "go.y"
+#line 1488 "go.y"
{
(yyval.list) = nil;
}
break;
case 219:
-
-/* Line 1806 of yacc.c */
-#line 1491 "go.y"
+#line 1492 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
if(nsyntaxerrors == 0)
@@ -4424,72 +4041,56 @@ yyreduce:
break;
case 221:
-
-/* Line 1806 of yacc.c */
-#line 1502 "go.y"
+#line 1503 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 223:
-
-/* Line 1806 of yacc.c */
-#line 1509 "go.y"
+#line 1510 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 224:
-
-/* Line 1806 of yacc.c */
-#line 1515 "go.y"
+#line 1516 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 225:
-
-/* Line 1806 of yacc.c */
-#line 1519 "go.y"
+#line 1520 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 227:
-
-/* Line 1806 of yacc.c */
-#line 1526 "go.y"
+#line 1527 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 228:
-
-/* Line 1806 of yacc.c */
-#line 1532 "go.y"
+#line 1533 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 229:
-
-/* Line 1806 of yacc.c */
-#line 1536 "go.y"
+#line 1537 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 230:
-
-/* Line 1806 of yacc.c */
-#line 1542 "go.y"
+#line 1543 "go.y"
{
NodeList *l;
@@ -4515,9 +4116,7 @@ yyreduce:
break;
case 231:
-
-/* Line 1806 of yacc.c */
-#line 1565 "go.y"
+#line 1566 "go.y"
{
(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
(yyval.list) = list1((yyvsp[(1) - (2)].node));
@@ -4525,9 +4124,7 @@ yyreduce:
break;
case 232:
-
-/* Line 1806 of yacc.c */
-#line 1570 "go.y"
+#line 1571 "go.y"
{
(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
(yyval.list) = list1((yyvsp[(2) - (4)].node));
@@ -4536,9 +4133,7 @@ yyreduce:
break;
case 233:
-
-/* Line 1806 of yacc.c */
-#line 1576 "go.y"
+#line 1577 "go.y"
{
(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
@@ -4547,9 +4142,7 @@ yyreduce:
break;
case 234:
-
-/* Line 1806 of yacc.c */
-#line 1582 "go.y"
+#line 1583 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4559,9 +4152,7 @@ yyreduce:
break;
case 235:
-
-/* Line 1806 of yacc.c */
-#line 1589 "go.y"
+#line 1590 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4571,9 +4162,7 @@ yyreduce:
break;
case 236:
-
-/* Line 1806 of yacc.c */
-#line 1598 "go.y"
+#line 1599 "go.y"
{
Node *n;
@@ -4585,9 +4174,7 @@ yyreduce:
break;
case 237:
-
-/* Line 1806 of yacc.c */
-#line 1607 "go.y"
+#line 1608 "go.y"
{
Pkg *pkg;
@@ -4603,18 +4190,14 @@ yyreduce:
break;
case 238:
-
-/* Line 1806 of yacc.c */
-#line 1622 "go.y"
+#line 1623 "go.y"
{
(yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg);
}
break;
case 239:
-
-/* Line 1806 of yacc.c */
-#line 1628 "go.y"
+#line 1629 "go.y"
{
(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
ifacedcl((yyval.node));
@@ -4622,18 +4205,14 @@ yyreduce:
break;
case 240:
-
-/* Line 1806 of yacc.c */
-#line 1633 "go.y"
+#line 1634 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
}
break;
case 241:
-
-/* Line 1806 of yacc.c */
-#line 1637 "go.y"
+#line 1638 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
yyerror("cannot parenthesize embedded type");
@@ -4641,9 +4220,7 @@ yyreduce:
break;
case 242:
-
-/* Line 1806 of yacc.c */
-#line 1644 "go.y"
+#line 1645 "go.y"
{
// without func keyword
(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
@@ -4654,9 +4231,7 @@ yyreduce:
break;
case 244:
-
-/* Line 1806 of yacc.c */
-#line 1658 "go.y"
+#line 1659 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4665,9 +4240,7 @@ yyreduce:
break;
case 245:
-
-/* Line 1806 of yacc.c */
-#line 1664 "go.y"
+#line 1665 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4676,72 +4249,56 @@ yyreduce:
break;
case 247:
-
-/* Line 1806 of yacc.c */
-#line 1673 "go.y"
+#line 1674 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 248:
-
-/* Line 1806 of yacc.c */
-#line 1677 "go.y"
+#line 1678 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 249:
-
-/* Line 1806 of yacc.c */
-#line 1682 "go.y"
+#line 1683 "go.y"
{
(yyval.list) = nil;
}
break;
case 250:
-
-/* Line 1806 of yacc.c */
-#line 1686 "go.y"
+#line 1687 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 251:
-
-/* Line 1806 of yacc.c */
-#line 1694 "go.y"
+#line 1695 "go.y"
{
(yyval.node) = N;
}
break;
case 253:
-
-/* Line 1806 of yacc.c */
-#line 1699 "go.y"
+#line 1700 "go.y"
{
(yyval.node) = liststmt((yyvsp[(1) - (1)].list));
}
break;
case 255:
-
-/* Line 1806 of yacc.c */
-#line 1704 "go.y"
+#line 1705 "go.y"
{
(yyval.node) = N;
}
break;
case 261:
-
-/* Line 1806 of yacc.c */
-#line 1715 "go.y"
+#line 1716 "go.y"
{
(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
(yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
@@ -4749,9 +4306,7 @@ yyreduce:
break;
case 262:
-
-/* Line 1806 of yacc.c */
-#line 1720 "go.y"
+#line 1721 "go.y"
{
NodeList *l;
@@ -4764,55 +4319,44 @@ yyreduce:
break;
case 263:
-
-/* Line 1806 of yacc.c */
-#line 1730 "go.y"
+#line 1731 "go.y"
{
// will be converted to OFALL
(yyval.node) = nod(OXFALL, N, N);
+ (yyval.node)->xoffset = block;
}
break;
case 264:
-
-/* Line 1806 of yacc.c */
-#line 1735 "go.y"
+#line 1737 "go.y"
{
(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
}
break;
case 265:
-
-/* Line 1806 of yacc.c */
-#line 1739 "go.y"
+#line 1741 "go.y"
{
(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
}
break;
case 266:
-
-/* Line 1806 of yacc.c */
-#line 1743 "go.y"
+#line 1745 "go.y"
{
(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
}
break;
case 267:
-
-/* Line 1806 of yacc.c */
-#line 1747 "go.y"
+#line 1749 "go.y"
{
(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
}
break;
case 268:
-
-/* Line 1806 of yacc.c */
-#line 1751 "go.y"
+#line 1753 "go.y"
{
(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
(yyval.node)->sym = dclstack; // context, for goto restrictions
@@ -4820,9 +4364,7 @@ yyreduce:
break;
case 269:
-
-/* Line 1806 of yacc.c */
-#line 1756 "go.y"
+#line 1758 "go.y"
{
(yyval.node) = nod(ORETURN, N, N);
(yyval.node)->list = (yyvsp[(2) - (2)].list);
@@ -4842,9 +4384,7 @@ yyreduce:
break;
case 270:
-
-/* Line 1806 of yacc.c */
-#line 1775 "go.y"
+#line 1777 "go.y"
{
(yyval.list) = nil;
if((yyvsp[(1) - (1)].node) != N)
@@ -4853,9 +4393,7 @@ yyreduce:
break;
case 271:
-
-/* Line 1806 of yacc.c */
-#line 1781 "go.y"
+#line 1783 "go.y"
{
(yyval.list) = (yyvsp[(1) - (3)].list);
if((yyvsp[(3) - (3)].node) != N)
@@ -4864,243 +4402,189 @@ yyreduce:
break;
case 272:
-
-/* Line 1806 of yacc.c */
-#line 1789 "go.y"
+#line 1791 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 273:
-
-/* Line 1806 of yacc.c */
-#line 1793 "go.y"
+#line 1795 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 274:
-
-/* Line 1806 of yacc.c */
-#line 1799 "go.y"
+#line 1801 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 275:
-
-/* Line 1806 of yacc.c */
-#line 1803 "go.y"
+#line 1805 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 276:
-
-/* Line 1806 of yacc.c */
-#line 1809 "go.y"
+#line 1811 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 277:
-
-/* Line 1806 of yacc.c */
-#line 1813 "go.y"
+#line 1815 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 278:
-
-/* Line 1806 of yacc.c */
-#line 1819 "go.y"
+#line 1821 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 279:
-
-/* Line 1806 of yacc.c */
-#line 1823 "go.y"
+#line 1825 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 280:
-
-/* Line 1806 of yacc.c */
-#line 1832 "go.y"
+#line 1834 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 281:
-
-/* Line 1806 of yacc.c */
-#line 1836 "go.y"
+#line 1838 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 282:
-
-/* Line 1806 of yacc.c */
-#line 1840 "go.y"
+#line 1842 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 283:
-
-/* Line 1806 of yacc.c */
-#line 1844 "go.y"
+#line 1846 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 284:
-
-/* Line 1806 of yacc.c */
-#line 1849 "go.y"
+#line 1851 "go.y"
{
(yyval.list) = nil;
}
break;
case 285:
-
-/* Line 1806 of yacc.c */
-#line 1853 "go.y"
+#line 1855 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 290:
-
-/* Line 1806 of yacc.c */
-#line 1867 "go.y"
+#line 1869 "go.y"
{
(yyval.node) = N;
}
break;
case 292:
-
-/* Line 1806 of yacc.c */
-#line 1873 "go.y"
+#line 1875 "go.y"
{
(yyval.list) = nil;
}
break;
case 294:
-
-/* Line 1806 of yacc.c */
-#line 1879 "go.y"
+#line 1881 "go.y"
{
(yyval.node) = N;
}
break;
case 296:
-
-/* Line 1806 of yacc.c */
-#line 1885 "go.y"
+#line 1887 "go.y"
{
(yyval.list) = nil;
}
break;
case 298:
-
-/* Line 1806 of yacc.c */
-#line 1891 "go.y"
+#line 1893 "go.y"
{
(yyval.list) = nil;
}
break;
case 300:
-
-/* Line 1806 of yacc.c */
-#line 1897 "go.y"
+#line 1899 "go.y"
{
(yyval.list) = nil;
}
break;
case 302:
-
-/* Line 1806 of yacc.c */
-#line 1903 "go.y"
+#line 1905 "go.y"
{
(yyval.val).ctype = CTxxx;
}
break;
case 304:
-
-/* Line 1806 of yacc.c */
-#line 1913 "go.y"
+#line 1915 "go.y"
{
importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
}
break;
case 305:
-
-/* Line 1806 of yacc.c */
-#line 1917 "go.y"
+#line 1919 "go.y"
{
importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
}
break;
case 306:
-
-/* Line 1806 of yacc.c */
-#line 1921 "go.y"
+#line 1923 "go.y"
{
importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
}
break;
case 307:
-
-/* Line 1806 of yacc.c */
-#line 1925 "go.y"
+#line 1927 "go.y"
{
importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
}
break;
case 308:
-
-/* Line 1806 of yacc.c */
-#line 1929 "go.y"
+#line 1931 "go.y"
{
importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
}
break;
case 309:
-
-/* Line 1806 of yacc.c */
-#line 1933 "go.y"
+#line 1935 "go.y"
{
if((yyvsp[(2) - (4)].node) == N) {
dclcontext = PEXTERN; // since we skip the funcbody below
@@ -5121,9 +4605,7 @@ yyreduce:
break;
case 310:
-
-/* Line 1806 of yacc.c */
-#line 1953 "go.y"
+#line 1955 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
structpkg = (yyval.sym)->pkg;
@@ -5131,9 +4613,7 @@ yyreduce:
break;
case 311:
-
-/* Line 1806 of yacc.c */
-#line 1960 "go.y"
+#line 1962 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
importsym((yyvsp[(1) - (1)].sym), OTYPE);
@@ -5141,18 +4621,14 @@ yyreduce:
break;
case 317:
-
-/* Line 1806 of yacc.c */
-#line 1980 "go.y"
+#line 1982 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
}
break;
case 318:
-
-/* Line 1806 of yacc.c */
-#line 1984 "go.y"
+#line 1986 "go.y"
{
// predefined name like uint8
(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
@@ -5165,63 +4641,49 @@ yyreduce:
break;
case 319:
-
-/* Line 1806 of yacc.c */
-#line 1994 "go.y"
+#line 1996 "go.y"
{
(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
}
break;
case 320:
-
-/* Line 1806 of yacc.c */
-#line 1998 "go.y"
+#line 2000 "go.y"
{
(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
}
break;
case 321:
-
-/* Line 1806 of yacc.c */
-#line 2002 "go.y"
+#line 2004 "go.y"
{
(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
}
break;
case 322:
-
-/* Line 1806 of yacc.c */
-#line 2006 "go.y"
+#line 2008 "go.y"
{
(yyval.type) = tostruct((yyvsp[(3) - (4)].list));
}
break;
case 323:
-
-/* Line 1806 of yacc.c */
-#line 2010 "go.y"
+#line 2012 "go.y"
{
(yyval.type) = tointerface((yyvsp[(3) - (4)].list));
}
break;
case 324:
-
-/* Line 1806 of yacc.c */
-#line 2014 "go.y"
+#line 2016 "go.y"
{
(yyval.type) = ptrto((yyvsp[(2) - (2)].type));
}
break;
case 325:
-
-/* Line 1806 of yacc.c */
-#line 2018 "go.y"
+#line 2020 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(2) - (2)].type);
@@ -5230,9 +4692,7 @@ yyreduce:
break;
case 326:
-
-/* Line 1806 of yacc.c */
-#line 2024 "go.y"
+#line 2026 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (4)].type);
@@ -5241,9 +4701,7 @@ yyreduce:
break;
case 327:
-
-/* Line 1806 of yacc.c */
-#line 2030 "go.y"
+#line 2032 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -5252,9 +4710,7 @@ yyreduce:
break;
case 328:
-
-/* Line 1806 of yacc.c */
-#line 2038 "go.y"
+#line 2040 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -5263,18 +4719,14 @@ yyreduce:
break;
case 329:
-
-/* Line 1806 of yacc.c */
-#line 2046 "go.y"
+#line 2048 "go.y"
{
(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
}
break;
case 330:
-
-/* Line 1806 of yacc.c */
-#line 2052 "go.y"
+#line 2054 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
if((yyvsp[(1) - (3)].sym))
@@ -5284,9 +4736,7 @@ yyreduce:
break;
case 331:
-
-/* Line 1806 of yacc.c */
-#line 2059 "go.y"
+#line 2061 "go.y"
{
Type *t;
@@ -5303,9 +4753,7 @@ yyreduce:
break;
case 332:
-
-/* Line 1806 of yacc.c */
-#line 2075 "go.y"
+#line 2077 "go.y"
{
Sym *s;
Pkg *p;
@@ -5328,63 +4776,49 @@ yyreduce:
break;
case 333:
-
-/* Line 1806 of yacc.c */
-#line 2097 "go.y"
+#line 2099 "go.y"
{
(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
}
break;
case 334:
-
-/* Line 1806 of yacc.c */
-#line 2101 "go.y"
+#line 2103 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
}
break;
case 335:
-
-/* Line 1806 of yacc.c */
-#line 2106 "go.y"
+#line 2108 "go.y"
{
(yyval.list) = nil;
}
break;
case 337:
-
-/* Line 1806 of yacc.c */
-#line 2113 "go.y"
+#line 2115 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
}
break;
case 338:
-
-/* Line 1806 of yacc.c */
-#line 2117 "go.y"
+#line 2119 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
}
break;
case 339:
-
-/* Line 1806 of yacc.c */
-#line 2127 "go.y"
+#line 2129 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 340:
-
-/* Line 1806 of yacc.c */
-#line 2131 "go.y"
+#line 2133 "go.y"
{
(yyval.node) = nodlit((yyvsp[(2) - (2)].val));
switch((yyval.node)->val.ctype){
@@ -5395,6 +4829,10 @@ yyreduce:
case CTFLT:
mpnegflt((yyval.node)->val.u.fval);
break;
+ case CTCPLX:
+ mpnegflt(&(yyval.node)->val.u.cval->real);
+ mpnegflt(&(yyval.node)->val.u.cval->imag);
+ break;
default:
yyerror("bad negated constant");
}
@@ -5402,9 +4840,7 @@ yyreduce:
break;
case 341:
-
-/* Line 1806 of yacc.c */
-#line 2146 "go.y"
+#line 2152 "go.y"
{
(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
if((yyval.node)->op != OLITERAL)
@@ -5413,9 +4849,7 @@ yyreduce:
break;
case 343:
-
-/* Line 1806 of yacc.c */
-#line 2155 "go.y"
+#line 2161 "go.y"
{
if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
(yyval.node) = (yyvsp[(2) - (5)].node);
@@ -5429,76 +4863,52 @@ yyreduce:
break;
case 346:
-
-/* Line 1806 of yacc.c */
-#line 2171 "go.y"
+#line 2177 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 347:
-
-/* Line 1806 of yacc.c */
-#line 2175 "go.y"
+#line 2181 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 348:
-
-/* Line 1806 of yacc.c */
-#line 2181 "go.y"
+#line 2187 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 349:
-
-/* Line 1806 of yacc.c */
-#line 2185 "go.y"
+#line 2191 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 350:
-
-/* Line 1806 of yacc.c */
-#line 2191 "go.y"
+#line 2197 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 351:
-
-/* Line 1806 of yacc.c */
-#line 2195 "go.y"
+#line 2201 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
-
-/* Line 1806 of yacc.c */
-#line 5490 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 4911 "y.tab.c"
default: break;
}
- /* User semantic actions sometimes alter yychar, and that requires
- that yytoken be updated with the new translation. We take the
- approach of translating immediately before every use of yytoken.
- One alternative is translating here after every semantic action,
- but that translation would be missed if the semantic action invokes
- YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
- if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
- incorrect destructor might then be invoked immediately. In the
- case of YYERROR or YYBACKUP, subsequent parser actions might lead
- to an incorrect destructor call or verbose syntax error message
- before the lookahead is translated. */
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
YYPOPSTACK (yylen);
@@ -5507,6 +4917,7 @@ yyreduce:
*++yyvsp = yyval;
+
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -5526,10 +4937,6 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
/* If not already recovering from an error, report this error. */
if (!yyerrstatus)
{
@@ -5537,36 +4944,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char *yymsgp = YY_("syntax error");
- int yysyntax_error_status;
- yysyntax_error_status = YYSYNTAX_ERROR;
- if (yysyntax_error_status == 0)
- yymsgp = yymsg;
- else if (yysyntax_error_status == 1)
- {
- if (yymsg != yymsgbuf)
- YYSTACK_FREE (yymsg);
- yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
- if (!yymsg)
- {
- yymsg = yymsgbuf;
- yymsg_alloc = sizeof yymsgbuf;
- yysyntax_error_status = 2;
- }
- else
- {
- yysyntax_error_status = YYSYNTAX_ERROR;
- yymsgp = yymsg;
- }
- }
- yyerror (yymsgp);
- if (yysyntax_error_status == 2)
- goto yyexhaustedlab;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -5574,7 +4982,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -5591,7 +4999,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -5625,7 +5033,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -5648,6 +5056,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
@@ -5672,7 +5083,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -5683,14 +5094,9 @@ yyexhaustedlab:
#endif
yyreturn:
- if (yychar != YYEMPTY)
- {
- /* Make sure we have latest lookahead translation. See comments at
- user semantic actions for why this is necessary. */
- yytoken = YYTRANSLATE (yychar);
- yydestruct ("Cleanup: discarding lookahead",
- yytoken, &yylval);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
@@ -5714,9 +5120,7 @@ yyreturn:
}
-
-/* Line 2067 of yacc.c */
-#line 2199 "go.y"
+#line 2205 "go.y"
static void
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
index 6eeb831b2..d01fbe198 100644
--- a/src/cmd/gc/y.tab.h
+++ b/src/cmd/gc/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,11 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -144,28 +146,22 @@
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-
-/* Line 2068 of yacc.c */
#line 28 "go.y"
-
+{
Node* node;
NodeList* list;
Type* type;
Sym* sym;
struct Val val;
int i;
-
-
-
-/* Line 2068 of yacc.c */
-#line 163 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 1529 of yacc.c. */
+#line 160 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index f70f778d9..3645f1c2d 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -5,6 +5,7 @@
package main
import (
+ "bufio"
"bytes"
"container/heap"
"errors"
@@ -27,7 +28,7 @@ import (
)
var cmdBuild = &Command{
- UsageLine: "build [-o output] [build flags] [packages]",
+ UsageLine: "build [-o output] [-i] [build flags] [packages]",
Short: "compile packages and dependencies",
Long: `
Build compiles the packages named by the import paths,
@@ -49,7 +50,10 @@ derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
-The build flags are shared by the build, install, run, and test commands:
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
-a
force rebuilding of packages that are already up-to-date.
@@ -86,8 +90,8 @@ The build flags are shared by the build, install, run, and test commands:
arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
- See the documentation for the go/build package for
- more information about build tags.
+ For more information about build tags, see the description of
+ build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
@@ -106,6 +110,8 @@ func init() {
cmdBuild.Run = runBuild
cmdInstall.Run = runInstall
+ cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
+
addBuildFlags(cmdBuild)
addBuildFlags(cmdInstall)
}
@@ -116,6 +122,7 @@ var buildN bool // -n flag
var buildP = runtime.NumCPU() // -p flag
var buildV bool // -v flag
var buildX bool // -x flag
+var buildI bool // -i flag
var buildO = cmdBuild.Flag.String("o", "", "output file")
var buildWork bool // -work flag
var buildGcflags []string // -gcflags flag
@@ -158,7 +165,8 @@ func init() {
}
}
-// addBuildFlags adds the flags common to the build and install commands.
+// addBuildFlags adds the flags common to the build, clean, get,
+// install, list, run, and test commands.
func addBuildFlags(cmd *Command) {
// NOTE: If you add flags here, also add them to testflag.go.
cmd.Flag.BoolVar(&buildA, "a", false, "")
@@ -203,6 +211,9 @@ type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
var err error
*v, err = splitQuotedFields(s)
+ if *v == nil {
+ *v = []string{}
+ }
return err
}
@@ -286,8 +297,12 @@ func runBuild(cmd *Command, args []string) {
}
a := &action{}
+ depMode := modeBuild
+ if buildI {
+ depMode = modeInstall
+ }
for _, p := range packages(args) {
- a.deps = append(a.deps, b.action(modeBuild, modeBuild, p))
+ a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
b.do(a)
}
@@ -349,7 +364,12 @@ func init() {
var err error
archChar, err = build.ArchChar(goarch)
if err != nil {
- fatalf("%s", err)
+ if _, isgc := buildToolchain.(gcToolchain); isgc {
+ fatalf("%s", err)
+ }
+ // archChar is only required for gcToolchain, if we're using
+ // another toolchain leave it blank.
+ archChar = ""
}
}
@@ -438,7 +458,8 @@ func (b *builder) init() {
fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
}
if !buildWork {
- atexit(func() { os.RemoveAll(b.work) })
+ workdir := b.work
+ atexit(func() { os.RemoveAll(workdir) })
}
}
}
@@ -760,6 +781,11 @@ func (b *builder) build(a *action) (err error) {
return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
}
+ // Same as above for Objective-C files
+ if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+ return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
+ a.p.ImportPath, strings.Join(a.p.MFiles, ","))
+ }
defer func() {
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
@@ -799,25 +825,7 @@ func (b *builder) build(a *action) (err error) {
var gofiles, cfiles, sfiles, objects, cgoObjects []string
- // If we're doing coverage, preprocess the .go files and put them in the work directory
- if a.p.coverMode != "" {
- for _, file := range a.p.GoFiles {
- sourceFile := filepath.Join(a.p.Dir, file)
- cover := a.p.coverVars[file]
- if cover == nil || isTestFile(file) {
- // Not covering this file.
- gofiles = append(gofiles, file)
- continue
- }
- coverFile := filepath.Join(obj, file)
- if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
- return err
- }
- gofiles = append(gofiles, coverFile)
- }
- } else {
- gofiles = append(gofiles, a.p.GoFiles...)
- }
+ gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...)
@@ -851,7 +859,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
- outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles)
+ outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@@ -866,7 +874,7 @@ func (b *builder) build(a *action) (err error) {
gccfiles := append(cfiles, sfiles...)
cfiles = nil
sfiles = nil
- outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles)
+ outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@@ -874,21 +882,54 @@ func (b *builder) build(a *action) (err error) {
gofiles = append(gofiles, outGo...)
}
+ if len(gofiles) == 0 {
+ return &build.NoGoError{a.p.Dir}
+ }
+
+ // If we're doing coverage, preprocess the .go files and put them in the work directory
+ if a.p.coverMode != "" {
+ for i, file := range gofiles {
+ var sourceFile string
+ var coverFile string
+ var key string
+ if strings.HasSuffix(file, ".cgo1.go") {
+ // cgo files have absolute paths
+ base := filepath.Base(file)
+ sourceFile = file
+ coverFile = filepath.Join(obj, base)
+ key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
+ } else {
+ sourceFile = filepath.Join(a.p.Dir, file)
+ coverFile = filepath.Join(obj, file)
+ key = file
+ }
+ cover := a.p.coverVars[key]
+ if cover == nil || isTestFile(file) {
+ // Not covering this file.
+ continue
+ }
+ if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+ return err
+ }
+ gofiles[i] = coverFile
+ }
+ }
+
// Prepare Go import path list.
inc := b.includeArgs("-I", a.deps)
// Compile Go.
- if len(gofiles) > 0 {
- ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles)
- if len(out) > 0 {
- b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
- if err != nil {
- return errPrintedOutput
- }
- }
+ ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
+ if len(out) > 0 {
+ b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
if err != nil {
- return err
+ return errPrintedOutput
}
+ }
+ if err != nil {
+ return err
+ }
+ if ofile != a.objpkg {
objects = append(objects, ofile)
}
@@ -903,17 +944,17 @@ func (b *builder) build(a *action) (err error) {
switch {
case strings.HasSuffix(name, _goos_goarch):
targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goarch):
targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goos):
targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
}
@@ -952,9 +993,15 @@ func (b *builder) build(a *action) (err error) {
objects = append(objects, filepath.Join(a.p.Dir, syso))
}
- // Pack into archive in obj directory
- if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
- return err
+ // Pack into archive in obj directory.
+ // If the Go compiler wrote an archive, we only need to add the
+ // object files for non-Go sources to the archive.
+ // If the Go compiler wrote an archive and the package is entirely
+ // Go sources, there is no pack to execute at all.
+ if len(objects) > 0 {
+ if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
+ return err
+ }
}
// Link if needed.
@@ -979,9 +1026,9 @@ func (b *builder) install(a *action) (err error) {
}
}()
a1 := a.deps[0]
- perm := os.FileMode(0666)
+ perm := os.FileMode(0644)
if a1.link {
- perm = 0777
+ perm = 0755
}
// make target directory
@@ -1001,22 +1048,7 @@ func (b *builder) install(a *action) (err error) {
defer os.Remove(a1.target)
}
- if a.p.usesSwig() {
- for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) {
- dir = a.p.swigDir(&buildContext)
- if err := b.mkdir(dir); err != nil {
- return err
- }
- soname := a.p.swigSoname(f)
- source := filepath.Join(a.objdir, soname)
- target := filepath.Join(dir, soname)
- if err = b.copyFile(a, target, source, perm); err != nil {
- return err
- }
- }
- }
-
- return b.copyFile(a, a.target, a1.target, perm)
+ return b.moveOrCopyFile(a, a.target, a1.target, perm)
}
// includeArgs returns the -I or -L directory list for access
@@ -1062,6 +1094,27 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
return inc
}
+// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN {
+ b.showcmd("", "mv %s %s", src, dst)
+ return nil
+ }
+
+ // If we can update the mode and rename to the dst, do it.
+ // Otherwise fall back to standard copy.
+ if err := os.Chmod(src, perm); err == nil {
+ if err := os.Rename(src, dst); err == nil {
+ if buildX {
+ b.showcmd("", "mv %s %s", src, dst)
+ }
+ return nil
+ }
+ }
+
+ return b.copyFile(a, dst, src, perm)
+}
+
// copyFile is like 'cp src dst'.
func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN || buildX {
@@ -1262,6 +1315,7 @@ func relPaths(paths []string) []string {
var errPrintedOutput = errors.New("already printed output - no need to show error")
var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
+var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
@@ -1288,11 +1342,11 @@ func (b *builder) processOutput(out []byte) string {
messages := string(out)
// Fix up output referring to cgo-generated code to be more readable.
// Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
- // Replace _Ctype_foo with C.foo.
+ // Replace *[100]_Ctype_foo with *[100]C.foo.
// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
if !buildX && cgoLine.MatchString(messages) {
messages = cgoLine.ReplaceAllString(messages, "")
- messages = strings.Replace(messages, "type _Ctype_", "type C.", -1)
+ messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
}
return messages
}
@@ -1302,7 +1356,13 @@ func (b *builder) processOutput(out []byte) string {
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
- b.showcmd(dir, "%s", joinUnambiguously(cmdline))
+ var envcmdline string
+ for i := range env {
+ envcmdline += env[i]
+ envcmdline += " "
+ }
+ envcmdline += joinUnambiguously(cmdline)
+ b.showcmd(dir, "%s", envcmdline)
if buildN {
return nil, nil
}
@@ -1432,7 +1492,7 @@ type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
// The compiler runs in the directory dir.
- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+ gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
@@ -1469,7 +1529,7 @@ func (noToolchain) linker() string {
return ""
}
-func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
@@ -1505,9 +1565,14 @@ func (gcToolchain) linker() string {
return tool(archChar + "l")
}
-func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
- out := "_go_." + archChar
- ofile = obj + out
+func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+ if archive != "" {
+ ofile = archive
+ } else {
+ out := "_go_." + archChar
+ ofile = obj + out
+ }
+
gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" {
// runtime compiles with a special 6g flag to emit
@@ -1519,7 +1584,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
- extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+ extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time":
@@ -1533,7 +1598,10 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
}
- args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ if ofile == archive {
+ args = append(args, "-pack")
+ }
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
@@ -1544,7 +1612,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -1557,83 +1625,148 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
+ cmd := "c"
+ absAfile := mkAbs(objDir, afile)
+ appending := false
+ if _, err := os.Stat(absAfile); err == nil {
+ appending = true
+ cmd = "r"
+ }
+
+ cmdline := stringList("pack", cmd, absAfile, absOfiles)
+
+ if appending {
+ if buildN || buildX {
+ b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+ }
+ if buildN {
+ return nil
+ }
+ if err := packInternal(b, absAfile, absOfiles); err != nil {
+ b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+ return errPrintedOutput
+ }
+ return nil
+ }
+
+ // Need actual pack.
+ cmdline[0] = tool("pack")
+ return b.run(p.Dir, p.ImportPath, nil, cmdline)
+}
+
+func packInternal(b *builder, afile string, ofiles []string) error {
+ dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
+ if err != nil {
+ return err
+ }
+ defer dst.Close() // only for error returns or panics
+ w := bufio.NewWriter(dst)
+
+ for _, ofile := range ofiles {
+ src, err := os.Open(ofile)
+ if err != nil {
+ return err
+ }
+ fi, err := src.Stat()
+ if err != nil {
+ src.Close()
+ return err
+ }
+ // Note: Not using %-16.16s format because we care
+ // about bytes, not runes.
+ name := fi.Name()
+ if len(name) > 16 {
+ name = name[:16]
+ } else {
+ name += strings.Repeat(" ", 16-len(name))
+ }
+ size := fi.Size()
+ fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
+ name, 0, 0, 0, 0644, size)
+ n, err := io.Copy(w, src)
+ src.Close()
+ if err == nil && n < size {
+ err = io.ErrUnexpectedEOF
+ } else if err == nil && n > size {
+ err = fmt.Errorf("file larger than size reported by stat")
+ }
+ if err != nil {
+ return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
+ }
+ if size&1 != 0 {
+ w.WriteByte(0)
+ }
+ }
+
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return dst.Close()
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
- swigDirs := make(map[string]bool)
- swigArg := []string{}
cxx := false
for _, a := range allactions {
- if a.p != nil && a.p.usesSwig() {
- sd := a.p.swigDir(&buildContext)
- if len(swigArg) == 0 {
- swigArg = []string{"-r", sd}
- } else if !swigDirs[sd] {
- swigArg[1] += ":"
- swigArg[1] += sd
- }
- swigDirs[sd] = true
- if a.objdir != "" && !swigDirs[a.objdir] {
- swigArg[1] += ":"
- swigArg[1] += a.objdir
- swigDirs[a.objdir] = true
- }
- }
if a.p != nil && len(a.p.CXXFiles) > 0 {
cxx = true
}
}
ldflags := buildLdflags
+ // Limit slice capacity so that concurrent appends do not race on the shared array.
+ ldflags = ldflags[:len(ldflags):len(ldflags)]
if buildContext.InstallSuffix != "" {
ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
}
- if cxx {
- // The program includes C++ code. If the user has not
- // specified the -extld option, then default to
- // linking with the compiler named by the CXX
- // environment variable, or g++ if CXX is not set.
- extld := false
- for _, f := range ldflags {
- if f == "-extld" || strings.HasPrefix(f, "-extld=") {
- extld = true
- break
- }
+ if p.omitDWARF {
+ ldflags = append(ldflags, "-w")
+ }
+
+ // If the user has not specified the -extld option, then specify the
+ // appropriate linker. In case of C++ code, use the compiler named
+ // by the CXX environment variable or defaultCXX if CXX is not set.
+ // Else, use the CC environment variable and defaultCC as fallback.
+ extld := false
+ for _, f := range ldflags {
+ if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+ extld = true
+ break
}
- if !extld {
- compiler := strings.Fields(os.Getenv("CXX"))
- if len(compiler) == 0 {
- compiler = []string{"g++"}
- }
- ldflags = append(ldflags, "-extld="+compiler[0])
- if len(compiler) > 1 {
- extldflags := false
- add := strings.Join(compiler[1:], " ")
- for i, f := range ldflags {
- if f == "-extldflags" && i+1 < len(ldflags) {
- ldflags[i+1] = add + " " + ldflags[i+1]
- extldflags = true
- break
- } else if strings.HasPrefix(f, "-extldflags=") {
- ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
- extldflags = true
- break
- }
- }
- if !extldflags {
- ldflags = append(ldflags, "-extldflags="+add)
+ }
+ if !extld {
+ var compiler []string
+ if cxx {
+ compiler = envList("CXX", defaultCXX)
+ } else {
+ compiler = envList("CC", defaultCC)
+ }
+ ldflags = append(ldflags, "-extld="+compiler[0])
+ if len(compiler) > 1 {
+ extldflags := false
+ add := strings.Join(compiler[1:], " ")
+ for i, f := range ldflags {
+ if f == "-extldflags" && i+1 < len(ldflags) {
+ ldflags[i+1] = add + " " + ldflags[i+1]
+ extldflags = true
+ break
+ } else if strings.HasPrefix(f, "-extldflags=") {
+ ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+ extldflags = true
+ break
}
}
+ if !extldflags {
+ ldflags = append(ldflags, "-extldflags="+add)
+ }
}
}
- return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, ldflags, mainpkg)
+ return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
- args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
+ args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
return b.run(p.Dir, p.ImportPath, nil, args)
}
@@ -1650,7 +1783,7 @@ func (gccgoToolchain) linker() string {
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
@@ -1698,52 +1831,62 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
- afiles := make(map[*Package]string)
- sfiles := make(map[*Package][]string)
+ apackagesSeen := make(map[*Package]bool)
+ afiles := []string{}
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
cxx := false
- for _, a := range allactions {
- if a.p != nil {
- if !a.p.Standard {
- if afiles[a.p] == "" || a.objpkg != a.target {
- afiles[a.p] = a.target
+ objc := false
+
+ // Prefer the output of an install action to the output of a build action,
+ // because the install action will delete the output of the build action.
+ // Iterate over the list backward (reverse dependency order) so that we
+ // always see the install before the build.
+ for i := len(allactions) - 1; i >= 0; i-- {
+ a := allactions[i]
+ if !a.p.Standard {
+ if a.p != nil && !apackagesSeen[a.p] {
+ apackagesSeen[a.p] = true
+ if a.p.fake {
+ // move _test files to the top of the link order
+ afiles = append([]string{a.target}, afiles...)
+ } else {
+ afiles = append(afiles, a.target)
}
}
+ }
+ }
+
+ for _, a := range allactions {
+ if a.p != nil {
cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
if len(a.p.CgoFiles) > 0 {
usesCgo = true
}
if a.p.usesSwig() {
- sd := a.p.swigDir(&buildContext)
- if a.objdir != "" {
- sd = a.objdir
- }
- for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) {
- soname := a.p.swigSoname(f)
- sfiles[a.p] = append(sfiles[a.p], filepath.Join(sd, soname))
- }
usesCgo = true
}
if len(a.p.CXXFiles) > 0 {
cxx = true
}
+ if len(a.p.MFiles) > 0 {
+ objc = true
+ }
}
}
- for _, afile := range afiles {
- ldflags = append(ldflags, afile)
- }
- for _, sfiles := range sfiles {
- ldflags = append(ldflags, sfiles...)
- }
+ ldflags = append(ldflags, afiles...)
ldflags = append(ldflags, cgoldflags...)
+ ldflags = append(ldflags, p.CgoLDFLAGS...)
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
}
if cxx {
ldflags = append(ldflags, "-lstdc++")
}
+ if objc {
+ ldflags = append(ldflags, "-lobjc")
+ }
return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
}
@@ -1856,16 +1999,13 @@ func (b *builder) gxxCmd(objdir string) []string {
}
// ccompilerCmd returns a command line prefix for the given environment
-// variable and using the default command when the variable is empty
+// variable and using the default command when the variable is empty.
func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// NOTE: env.go's mkEnv knows that the first three
// strings returned are "gcc", "-I", objdir (and cuts them off).
- compiler := strings.Fields(os.Getenv(envvar))
- if len(compiler) == 0 {
- compiler = strings.Fields(defcmd)
- }
- a := []string{compiler[0], "-I", objdir, "-g", "-O2"}
+ compiler := envList(envvar, defcmd)
+ a := []string{compiler[0], "-I", objdir}
a = append(a, compiler[1:]...)
// Definitely want -fPIC but on Windows gcc complains
@@ -1892,6 +2032,9 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
a = append(a, "-Qunused-arguments")
}
+ // disable word wrapping in error messages
+ a = append(a, "-fmessage-length=0")
+
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See http://golang.org/issue/3253.
@@ -1915,8 +2058,28 @@ func (b *builder) gccArchArgs() []string {
return nil
}
-func envList(key string) []string {
- return strings.Fields(os.Getenv(key))
+// envList returns the value of the given environment variable broken
+// into fields, using the default value when the variable is empty.
+func envList(key, def string) []string {
+ v := os.Getenv(key)
+ if v == "" {
+ v = def
+ }
+ return strings.Fields(v)
+}
+
+// Return the flags to use when invoking the C or C++ compilers, or cgo.
+func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+ var defaults string
+ if def {
+ defaults = "-g -O2"
+ }
+
+ cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+ cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+ cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+ return
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
@@ -1927,15 +2090,14 @@ var (
cgoLibGccFileOnce sync.Once
)
-func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfiles []string) (outGo, outObj []string, err error) {
- if goos != toolGOOS {
- return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
- }
+func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
+ _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
- cgoCPPFLAGS := stringList(envList("CGO_CPPFLAGS"), p.CgoCPPFLAGS)
- cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
- cgoCXXFLAGS := stringList(envList("CGO_CXXFLAGS"), p.CgoCXXFLAGS)
- cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
+ // If we are compiling Objective-C code, then we need to link against libobjc
+ if len(mfiles) > 0 {
+ cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
+ }
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
@@ -2001,7 +2163,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
}
objExt = "o"
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, p.CgoFiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
@@ -2088,6 +2250,16 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
outObj = append(outObj, ofile)
}
+ for _, file := range mfiles {
+ // Append .o to the file, just in case the pkg has file.c and file.m
+ ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
linkobj = append(linkobj, p.SysoFiles...)
dynobj := obj + "_cgo_.o"
if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
@@ -2145,24 +2317,39 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
// Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking.
-func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (outGo, outObj []string, err error) {
+func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
+ cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
- var extraObj []string
for _, file := range gccfiles {
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
- if err := b.gcc(p, ofile, nil, file); err != nil {
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- extraObj = append(extraObj, ofile)
+ outObj = append(outObj, ofile)
}
for _, file := range gxxfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
- if err := b.gxx(p, ofile, nil, file); err != nil {
+ if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
- extraObj = append(extraObj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
+ for _, file := range mfiles {
+ // Append .o to the file, just in case the pkg has file.c and file.cpp
+ ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, ofile)
+ }
+
+ if err := b.swigVersionCheck(); err != nil {
+ return nil, nil, err
}
intgosize, err := b.swigIntSize(obj)
@@ -2171,7 +2358,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
}
for _, f := range p.SwigFiles {
- goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize, extraObj)
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
if err != nil {
return nil, nil, err
}
@@ -2181,9 +2368,12 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
if objFile != "" {
outObj = append(outObj, objFile)
}
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
}
for _, f := range p.SwigCXXFiles {
- goFile, objFile, err := b.swigOne(p, f, obj, true, intgosize, extraObj)
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
if err != nil {
return nil, nil, err
}
@@ -2193,10 +2383,48 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
if objFile != "" {
outObj = append(outObj, objFile)
}
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
}
return outGo, outObj, nil
}
+// Make sure SWIG is new enough.
+var (
+ swigCheckOnce sync.Once
+ swigCheck error
+)
+
+func (b *builder) swigDoVersionCheck() error {
+ out, err := b.runOut("", "", nil, "swig", "-version")
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`[vV]ersion +([\d])`)
+ matches := re.FindSubmatch(out)
+ if matches == nil {
+ // Can't find version number; hope for the best.
+ return nil
+ }
+ major, err := strconv.Atoi(string(matches[1]))
+ if err != nil {
+ // Can't find version number; hope for the best.
+ return nil
+ }
+ if major < 3 {
+ return errors.New("must have SWIG version >= 3.0")
+ }
+ return nil
+}
+
+func (b *builder) swigVersionCheck() error {
+ swigCheckOnce.Do(func() {
+ swigCheck = b.swigDoVersionCheck()
+ })
+ return swigCheck
+}
+
// This code fails to build if sizeof(int) <= 32
const swigIntSizeCode = `
package main
@@ -2217,14 +2445,22 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
p := goFilesPackage(srcs)
- if _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil {
+ if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
return "32", nil
}
return "64", nil
}
// Run SWIG on one SWIG input file.
-func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string, extraObj []string) (outGo, outObj string, err error) {
+func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ var cflags []string
+ if cxx {
+ cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ } else {
+ cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
+ }
+
n := 5 // length of ".swig"
if cxx {
n = 8 // length of ".swigcxx"
@@ -2237,7 +2473,6 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
if cxx {
gccExt = "cxx"
}
- soname := p.swigSoname(file)
_, gccgo := buildToolchain.(gccgoToolchain)
@@ -2246,12 +2481,14 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
"-go",
"-intgosize", intgosize,
"-module", base,
- "-soname", soname,
"-o", obj + gccBase + gccExt,
"-outdir", obj,
}
if gccgo {
args = append(args, "-gccgo")
+ if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+ args = append(args, "-go-pkgpath", pkgpath)
+ }
}
if cxx {
args = append(args, "-c++")
@@ -2260,12 +2497,12 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
- return "", "", errors.New("must have SWIG version >= 2.0.9\n")
+ return "", "", "", errors.New("must have SWIG version >= 3.0")
}
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
- return "", "", errPrintedOutput
+ return "", "", "", errPrintedOutput
}
- return "", "", err
+ return "", "", "", err
}
var cObj string
@@ -2273,32 +2510,23 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
// cc
cObj = obj + cBase + archChar
if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil {
- return "", "", err
+ return "", "", "", err
}
}
// gcc
gccObj := obj + gccBase + "o"
- if err := b.gcc(p, gccObj, []string{"-g", "-fPIC", "-O2"}, obj+gccBase+gccExt); err != nil {
- return "", "", err
- }
-
- // create shared library
- osldflags := map[string][]string{
- "darwin": {"-dynamiclib", "-Wl,-undefined,dynamic_lookup"},
- "freebsd": {"-shared", "-lpthread", "-lm"},
- "linux": {"-shared", "-lpthread", "-lm"},
- "windows": {"-shared", "-lm", "-mthreads"},
- }
- var cxxlib []string
- if cxx {
- cxxlib = []string{"-lstdc++"}
+ if !cxx {
+ if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
+ return "", "", "", err
+ }
+ } else {
+ if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
+ return "", "", "", err
+ }
}
- ldflags := stringList(osldflags[goos], cxxlib)
- target := filepath.Join(obj, soname)
- b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", target, gccObj, extraObj, ldflags)
- return obj + goFile, cObj, nil
+ return obj + goFile, cObj, gccObj, nil
}
// An actionQueue is a priority queue of actions.
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
index 16687f72f..16054a5b5 100644
--- a/src/cmd/go/clean.go
+++ b/src/cmd/go/clean.go
@@ -13,7 +13,7 @@ import (
)
var cmdClean = &Command{
- UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
+ UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
Short: "remove object files",
Long: `
Clean removes object files from package source directories.
@@ -52,23 +52,26 @@ dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them.
+For more about build flags, see 'go help build'.
+
For more about specifying packages, see 'go help packages'.
`,
}
var cleanI bool // clean -i flag
-var cleanN bool // clean -n flag
var cleanR bool // clean -r flag
-var cleanX bool // clean -x flag
func init() {
// break init cycle
cmdClean.Run = runClean
cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
- cmdClean.Flag.BoolVar(&cleanN, "n", false, "")
cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
- cmdClean.Flag.BoolVar(&cleanX, "x", false, "")
+ // -n and -x are important enough to be
+ // mentioned explicitly in the docs but they
+ // are part of the build flags.
+
+ addBuildFlags(cmdClean)
}
func runClean(cmd *Command, args []string) {
@@ -153,7 +156,7 @@ func clean(p *Package) {
elem+".test.exe",
)
- // Remove a potental executable for each .go file in the directory that
+ // Remove a potential executable for each .go file in the directory that
// is not part of the directory's package.
for _, dir := range dirs {
name := dir.Name()
@@ -169,7 +172,7 @@ func clean(p *Package) {
}
}
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
}
@@ -182,9 +185,9 @@ func clean(p *Package) {
if dir.IsDir() {
// TODO: Remove once Makefiles are forgotten.
if cleanDir[name] {
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd(p.Dir, "rm -r %s", name)
- if cleanN {
+ if buildN {
continue
}
}
@@ -195,7 +198,7 @@ func clean(p *Package) {
continue
}
- if cleanN {
+ if buildN {
continue
}
@@ -205,28 +208,14 @@ func clean(p *Package) {
}
if cleanI && p.target != "" {
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd("", "rm -f %s", p.target)
}
- if !cleanN {
+ if !buildN {
removeFile(p.target)
}
}
- if cleanI && p.usesSwig() {
- for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) {
- dir := p.swigDir(&buildContext)
- soname := p.swigSoname(f)
- target := filepath.Join(dir, soname)
- if cleanN || cleanX {
- b.showcmd("", "rm -f %s", target)
- }
- if !cleanN {
- removeFile(target)
- }
- }
- }
-
if cleanR {
for _, p1 := range p.imports {
clean(p1)
diff --git a/src/cmd/go/context.go b/src/cmd/go/context.go
new file mode 100644
index 000000000..68e518259
--- /dev/null
+++ b/src/cmd/go/context.go
@@ -0,0 +1,36 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/build"
+)
+
+type Context struct {
+ GOARCH string `json:",omitempty"` // target architecture
+ GOOS string `json:",omitempty"` // target operating system
+ GOROOT string `json:",omitempty"` // Go root
+ GOPATH string `json:",omitempty"` // Go path
+ CgoEnabled bool `json:",omitempty"` // whether cgo can be used
+ UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names
+ Compiler string `json:",omitempty"` // compiler to assume when computing target paths
+ BuildTags []string `json:",omitempty"` // build constraints to match in +build lines
+ ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with
+ InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir
+}
+
+func newContext(c *build.Context) *Context {
+ return &Context{
+ GOARCH: c.GOARCH,
+ GOOS: c.GOOS,
+ GOROOT: c.GOROOT,
+ CgoEnabled: c.CgoEnabled,
+ UseAllFiles: c.UseAllFiles,
+ Compiler: c.Compiler,
+ BuildTags: c.BuildTags,
+ ReleaseTags: c.ReleaseTags,
+ InstallSuffix: c.InstallSuffix,
+ }
+}
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
index 75228b52a..b9f427995 100644
--- a/src/cmd/go/discovery.go
+++ b/src/cmd/go/discovery.go
@@ -43,6 +43,9 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
for {
t, err = d.Token()
if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
return
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index ebb2f37fd..9840804ce 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -33,6 +33,7 @@ Use "go help [command]" for more information about a command.
Additional help topics:
c calling between Go and C
+ filetype file types
gopath GOPATH environment variable
importpath import path syntax
packages description of package lists
@@ -46,7 +47,7 @@ Compile packages and dependencies
Usage:
- go build [-o output] [build flags] [packages]
+ go build [-o output] [-i] [build flags] [packages]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
@@ -67,7 +68,10 @@ derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
-The build flags are shared by the build, install, run, and test commands:
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
-a
force rebuilding of packages that are already up-to-date.
@@ -104,8 +108,8 @@ The build flags are shared by the build, install, run, and test commands:
arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
- See the documentation for the go/build package for
- more information about build tags.
+ For more information about build tags, see the description of
+ build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
@@ -122,7 +126,7 @@ Remove object files
Usage:
- go clean [-i] [-r] [-n] [-x] [packages]
+ go clean [-i] [-r] [-n] [-x] [build flags] [packages]
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
@@ -160,6 +164,8 @@ dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them.
+For more about build flags, see 'go help build'.
+
For more about specifying packages, see 'go help packages'.
@@ -235,8 +241,7 @@ The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
-Get also accepts all the flags in the 'go build' and 'go install' commands,
-to control the installation. See 'go help build'.
+Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
@@ -271,7 +276,7 @@ List packages
Usage:
- go list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages]
+ go list [-e] [-f format] [-json] [build flags] [packages]
List lists the packages named by the import paths, one per line.
@@ -283,8 +288,7 @@ The default output shows the package import path:
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. One extra template function is available, "join",
-which calls strings.Join. The struct being passed to the template is:
+'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
@@ -303,6 +307,7 @@ which calls strings.Join. The struct being passed to the template is:
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -331,6 +336,26 @@ which calls strings.Join. The struct being passed to the template is:
XTestImports []string // imports from XTestGoFiles
}
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+ type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+ BuildTags []string // build constraints to match in +build lines
+ ReleaseTags []string // releases the current release is compatible with
+ InstallSuffix string // suffix to use in the name of the install dir
+ }
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
@@ -344,11 +369,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
-The -tags flag specifies a list of build tags, like in the 'go build'
-command.
-
-The -race flag causes the package data to include the dependencies
-required by the race detector.
+For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
@@ -357,11 +378,20 @@ Compile and run Go program
Usage:
- go run [build flags] gofiles... [arguments...]
+ go run [build flags] [-exec xprog] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
For more about build flags, see 'go help build'.
See also: go build.
@@ -408,6 +438,10 @@ In addition to the build flags, the flags handled by 'go test' itself are:
Install packages that are dependencies of the test.
Do not run the test.
+ -exec xprog
+ Run the test binary using xprog. The behavior is the same as
+ in 'go run'. See 'go help run' for details.
+
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
@@ -478,12 +512,49 @@ http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
-When either cgo or SWIG is used, go build will pass any .c, .s, or .S
-files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
+File types
+
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+ .go
+ Go source files.
+ .c, .h
+ C source files.
+ If the package uses cgo, these will be compiled with the
+ OS-native compiler (typically gcc); otherwise they will be
+ compiled with the Go-specific support compiler,
+ 5c, 6c, or 8c, etc. as appropriate.
+ .cc, .cpp, .cxx, .hh, .hpp, .hxx
+ C++ source files. Only useful with cgo or SWIG, and always
+ compiled with the OS-native compiler.
+ .m
+ Objective-C source files. Only useful with cgo, and always
+ compiled with the OS-native compiler.
+ .s, .S
+ Assembler source files.
+ If the package uses cgo, these will be assembled with the
+ OS-native assembler (typically gcc (sic)); otherwise they
+ will be assembled with the Go-specific support assembler,
+ 5a, 6a, or 8a, etc., as appropriate.
+ .swig, .swigcxx
+ SWIG definition files.
+ .syso
+ System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+
+
GOPATH environment variable
The Go path is used to resolve import statements.
@@ -638,7 +709,7 @@ example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
-example.com/repo or repo.git.
+example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
@@ -788,7 +859,8 @@ control the execution of any test:
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
- being tested. The default is "set".
+ being tested. The default is "set" unless -race is enabled,
+ in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
@@ -823,9 +895,7 @@ control the execution of any test:
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
- and set the environment variable GOGC=off to disable the
- garbage collector, provided the test can run in the available
- memory without garbage collection.
+ and pass --alloc_space flag to the pprof tool.
-outputdir directory
Place output files from profiling in the specified directory,
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 2db821797..26d37df4f 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -85,18 +85,28 @@ func runEnv(cmd *Command, args []string) {
return
}
- switch runtime.GOOS {
- default:
- for _, e := range env {
- fmt.Printf("%s=\"%s\"\n", e.name, e.value)
- }
- case "plan9":
- for _, e := range env {
- fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
- }
- case "windows":
- for _, e := range env {
- fmt.Printf("set %s=%s\n", e.name, e.value)
+ for _, e := range env {
+ if e.name != "TERM" {
+ switch runtime.GOOS {
+ default:
+ fmt.Printf("%s=\"%s\"\n", e.name, e.value)
+ case "plan9":
+ if strings.IndexByte(e.value, '\x00') < 0 {
+ fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
+ } else {
+ v := strings.Split(e.value, "\x00")
+ fmt.Printf("%s=(", e.name)
+ for x, s := range v {
+ if x > 0 {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%s", s)
+ }
+ fmt.Printf(")\n")
+ }
+ case "windows":
+ fmt.Printf("set %s=%s\n", e.name, e.value)
+ }
}
}
}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index e61da7e2a..e708fcf77 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO: Dashboard upload
-
package main
import (
@@ -37,8 +35,7 @@ The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
-Get also accepts all the flags in the 'go build' and 'go install' commands,
-to control the installation. See 'go help build'.
+Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
@@ -73,7 +70,7 @@ func runGet(cmd *Command, args []string) {
}
exitIfErrors()
- // Phase 2. Rescan packages and reevaluate args list.
+ // Phase 2. Rescan packages and re-evaluate args list.
// Code we downloaded and all code that depends on it
// needs to be evicted from the package cache so that
@@ -143,6 +140,10 @@ var downloadRootCache = map[string]bool{}
// for the package named by the argument.
func download(arg string, stk *importStack, getTestDeps bool) {
p := loadPackage(arg, stk)
+ if p.Error != nil && p.Error.hard {
+ errorf("%s", p.Error)
+ return
+ }
// There's nothing to do if this is a package in the standard library.
if p.Standard {
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 71e55175a..40da7e1f5 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -19,8 +19,8 @@ http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
-When either cgo or SWIG is used, go build will pass any .c, .s, or .S
-files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
`,
@@ -182,7 +182,7 @@ example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
-example.com/repo or repo.git.
+example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
@@ -295,3 +295,43 @@ but new packages are always downloaded into the first directory
in the list.
`,
}
+
+var helpFileType = &Command{
+ UsageLine: "filetype",
+ Short: "file types",
+ Long: `
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+ .go
+ Go source files.
+ .c, .h
+ C source files.
+ If the package uses cgo, these will be compiled with the
+ OS-native compiler (typically gcc); otherwise they will be
+ compiled with the Go-specific support compiler,
+ 5c, 6c, or 8c, etc. as appropriate.
+ .cc, .cpp, .cxx, .hh, .hpp, .hxx
+ C++ source files. Only useful with cgo or SWIG, and always
+ compiled with the OS-native compiler.
+ .m
+ Objective-C source files. Only useful with cgo, and always
+ compiled with the OS-native compiler.
+ .s, .S
+ Assembler source files.
+ If the package uses cgo, these will be assembled with the
+ OS-native assembler (typically gcc (sic)); otherwise they
+ will be assembled with the Go-specific support assembler,
+ 5a, 6a, or 8a, etc., as appropriate.
+ .swig, .swigcxx
+ SWIG definition files.
+ .syso
+ System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+ `,
+}
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index f56ebed38..0ead43502 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -14,7 +14,7 @@ import (
)
var cmdList = &Command{
- UsageLine: "list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages]",
+ UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
@@ -27,8 +27,7 @@ The default output shows the package import path:
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. One extra template function is available, "join",
-which calls strings.Join. The struct being passed to the template is:
+'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
@@ -47,6 +46,7 @@ which calls strings.Join. The struct being passed to the template is:
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -75,6 +75,26 @@ which calls strings.Join. The struct being passed to the template is:
XTestImports []string // imports from XTestGoFiles
}
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+ type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+ BuildTags []string // build constraints to match in +build lines
+ ReleaseTags []string // releases the current release is compatible with
+ InstallSuffix string // suffix to use in the name of the install dir
+ }
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
@@ -88,11 +108,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
-The -tags flag specifies a list of build tags, like in the 'go build'
-command.
-
-The -race flag causes the package data to include the dependencies
-required by the race detector.
+For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
`,
@@ -100,24 +116,18 @@ For more about specifying packages, see 'go help packages'.
func init() {
cmdList.Run = runList // break init cycle
- cmdList.Flag.Var(buildCompiler{}, "compiler", "")
- cmdList.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
+ addBuildFlags(cmdList)
}
var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
-var listRace = cmdList.Flag.Bool("race", false, "")
var nl = []byte{'\n'}
func runList(cmd *Command, args []string) {
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
- if *listRace {
- buildRace = true
- }
-
var do func(*Package)
if *listJson {
do = func(p *Package) {
@@ -130,7 +140,18 @@ func runList(cmd *Command, args []string) {
out.Write(nl)
}
} else {
- tmpl, err := template.New("main").Funcs(template.FuncMap{"join": strings.Join}).Parse(*listFmt)
+ var cachedCtxt *Context
+ context := func() *Context {
+ if cachedCtxt == nil {
+ cachedCtxt = newContext(&buildContext)
+ }
+ return cachedCtxt
+ }
+ fm := template.FuncMap{
+ "join": strings.Join,
+ "context": context,
+ }
+ tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil {
fatalf("%s", err)
}
@@ -140,7 +161,7 @@ func runList(cmd *Command, args []string) {
fatalf("%s", err)
}
if out.NeedNL() {
- out.Write([]byte{'\n'})
+ out.Write(nl)
}
}
}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index df0cf1b3f..5b1194aaa 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -89,6 +89,7 @@ var commands = []*Command{
cmdVet,
helpC,
+ helpFileType,
helpGopath,
helpImportPath,
helpPackages,
@@ -238,6 +239,11 @@ func printUsage(w io.Writer) {
}
func usage() {
+ // special case "go test -h"
+ if len(os.Args) > 1 && os.Args[1] == "test" {
+ help([]string{"testflag"})
+ os.Exit(2)
+ }
printUsage(os.Stderr)
os.Exit(2)
}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 71f14c74a..d45df265b 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -42,6 +42,7 @@ type Package struct {
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
CFiles []string `json:",omitempty"` // .c source files
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
SFiles []string `json:",omitempty"` // .s source files
SwigFiles []string `json:",omitempty"` // .swig files
@@ -88,6 +89,7 @@ type Package struct {
exeName string // desired name for temporary executable
coverMode string // preprocess Go source files with the coverage tool in this mode
coverVars map[string]*CoverVar // variables created by coverage analysis
+ omitDWARF bool // tell linker not to write DWARF information
}
// CoverVar holds the name of the generated coverage variables targeting the named file.
@@ -113,6 +115,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.IgnoredGoFiles = pp.IgnoredGoFiles
p.CFiles = pp.CFiles
p.CXXFiles = pp.CXXFiles
+ p.MFiles = pp.MFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
p.SwigFiles = pp.SwigFiles
@@ -136,12 +139,13 @@ type PackageError struct {
Pos string // position of error
Err string // the error itself
isImportCycle bool // the error is an import cycle
+ hard bool // whether the error is soft or hard; soft errors are ignored in some places
}
func (p *PackageError) Error() string {
// Import cycles deserve special treatment.
if p.isImportCycle {
- return fmt.Sprintf("%s: %s\npackage %s\n", p.Pos, p.Err, strings.Join(p.ImportStack, "\n\timports "))
+ return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
}
if p.Pos != "" {
// Omit import stack. The full path to the file where the error
@@ -304,9 +308,14 @@ const (
// goTools is a map of Go program import path to install target directory.
var goTools = map[string]targetDir{
+ "cmd/addr2line": toTool,
"cmd/api": toTool,
"cmd/cgo": toTool,
"cmd/fix": toTool,
+ "cmd/link": toTool,
+ "cmd/nm": toTool,
+ "cmd/objdump": toTool,
+ "cmd/pack": toTool,
"cmd/yacc": toTool,
"code.google.com/p/go.tools/cmd/cover": toTool,
"code.google.com/p/go.tools/cmd/godoc": toBin,
@@ -454,6 +463,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
+ p.MFiles,
p.HFiles,
p.SFiles,
p.SysoFiles,
@@ -551,24 +561,6 @@ func (p *Package) usesCgo() bool {
return len(p.CgoFiles) > 0
}
-// swigSoname returns the name of the shared library we create for a
-// SWIG input file.
-func (p *Package) swigSoname(file string) string {
- return strings.Replace(p.ImportPath, "/", "-", -1) + "-" + strings.Replace(file, ".", "-", -1) + ".so"
-}
-
-// swigDir returns the name of the shared SWIG directory for a
-// package.
-func (p *Package) swigDir(ctxt *build.Context) string {
- dir := p.build.PkgRoot
- if ctxt.Compiler == "gccgo" {
- dir = filepath.Join(dir, "gccgo_"+ctxt.GOOS+"_"+ctxt.GOARCH)
- } else {
- dir = filepath.Join(dir, ctxt.GOOS+"_"+ctxt.GOARCH)
- }
- return filepath.Join(dir, "swig")
-}
-
// packageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
func packageList(roots []*Package) []*Package {
@@ -681,7 +673,7 @@ func isStale(p *Package, topRoot map[string]bool) bool {
return false
}
- srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
+ srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true
@@ -724,6 +716,7 @@ func loadPackage(arg string, stk *importStack) *Package {
Error: &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
+ hard: true,
},
}
return p
diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go
new file mode 100644
index 000000000..06b9f0ac6
--- /dev/null
+++ b/src/cmd/go/pkg_test.go
@@ -0,0 +1,73 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var foldDupTests = []struct {
+ list []string
+ f1, f2 string
+}{
+ {stringList("math/rand", "math/big"), "", ""},
+ {stringList("math", "strings"), "", ""},
+ {stringList("strings"), "", ""},
+ {stringList("strings", "strings"), "strings", "strings"},
+ {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
+}
+
+func TestFoldDup(t *testing.T) {
+ for _, tt := range foldDupTests {
+ f1, f2 := foldDup(tt.list)
+ if f1 != tt.f1 || f2 != tt.f2 {
+ t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
+ }
+ }
+}
+
+var parseMetaGoImportsTests = []struct {
+ in string
+ out []metaImport
+}{
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+ []metaImport{
+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+ {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+ },
+ },
+ {
+ `<head>
+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ </head>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <body>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+}
+
+func TestParseMetaGoImports(t *testing.T) {
+ for i, tt := range parseMetaGoImportsTests {
+ out, err := parseMetaGoImports(strings.NewReader(tt.in))
+ if err != nil {
+ t.Errorf("test#%d: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index e6dadd229..ef8aa95a3 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -8,16 +8,43 @@ import (
"fmt"
"os"
"os/exec"
+ "runtime"
"strings"
)
+var execCmd []string // -exec flag, for run and test
+
+func findExecCmd() []string {
+ if execCmd != nil {
+ return execCmd
+ }
+ execCmd = []string{} // avoid work the second time
+ if goos == runtime.GOOS && goarch == runtime.GOARCH {
+ return execCmd
+ }
+ path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+ if err == nil {
+ execCmd = []string{path}
+ }
+ return execCmd
+}
+
var cmdRun = &Command{
- UsageLine: "run [build flags] gofiles... [arguments...]",
+ UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
For more about build flags, see 'go help build'.
See also: go build.
@@ -28,6 +55,7 @@ func init() {
cmdRun.Run = runRun // break init loop
addBuildFlags(cmdRun)
+ cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
}
func printStderr(args ...interface{}) (int, error) {
@@ -58,6 +86,7 @@ func runRun(cmd *Command, args []string) {
if p.Error != nil {
fatalf("%s", p.Error)
}
+ p.omitDWARF = true
for _, err := range p.DepsErrors {
errorf("%s", err)
}
@@ -89,20 +118,20 @@ func runRun(cmd *Command, args []string) {
// runProgram is the action for running a binary that has already
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
+ cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
- b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+ b.showcmd("", "%s", strings.Join(cmdline, " "))
if buildN {
return nil
}
}
- runStdin(a.deps[0].target, a.args)
+ runStdin(cmdline)
return nil
}
// runStdin is like run, but connects Stdin.
-func runStdin(cmdargs ...interface{}) {
- cmdline := stringList(cmdargs...)
+func runStdin(cmdline []string) {
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go
index 00c71657f..e86cd4652 100644
--- a/src/cmd/go/signal_unix.go
+++ b/src/cmd/go/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index f71d67818..0060ce218 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -36,8 +36,9 @@ stop() {
ok=true
allok=true
-unset GOPATH
unset GOBIN
+unset GOPATH
+unset GOROOT
TEST 'file:line in error messages'
# Test that error messages have file:line information at beginning of
@@ -258,6 +259,7 @@ if [ ! -x $d/gobin/godoc ]; then
fi
TEST godoc installs into GOROOT
+GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install code.google.com/p/go.tools/cmd/godoc
if [ ! -x $GOROOT/bin/godoc ]; then
@@ -425,10 +427,10 @@ d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
- cd $d/src/dir1
- echo package p >p.go
+ cd $d/src
+ echo package p >dir1/p.go
export GOPATH=$d
- if [ "$($old/testgo list -f '{{.Root}}' .)" != "$d" ]; then
+ if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
echo Confused by symlinks.
echo "Package in current directory $(pwd) should have Root $d"
env|grep WD
@@ -477,14 +479,20 @@ rm -rf $d
TEST case collisions '(issue 4773)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
-mkdir -p $d/src/example/a $d/src/example/b
+mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
cat >$d/src/example/a/a.go <<EOF
package p
import (
- _ "math/rand"
- _ "math/Rand"
+ _ "example/a/pkg"
+ _ "example/a/Pkg"
)
EOF
+cat >$d/src/example/a/pkg/pkg.go <<EOF
+package pkg
+EOF
+cat >$d/src/example/a/Pkg/pkg.go <<EOF
+package pkg
+EOF
if ./testgo list example/a 2>$d/out; then
echo go list example/a should have failed, did not.
ok=false
@@ -545,7 +553,7 @@ fi
# The error for go install should mention the conflicting directory.
err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
-if [ "$err" != "go install: no install location for directory $(pwd)/testdata/shadow/root2/src/foo hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
+if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
echo wrong shadowed install error: "$err"
ok=false
fi
@@ -555,10 +563,59 @@ TEST source file name order preserved
./testgo test testdata/example[12]_test.go || ok=false
# Check that coverage analysis works at all.
-# Don't worry about the exact numbers
+# Don't worry about the exact numbers but require not 0.0%.
+checkcoverage() {
+ if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
+ echo 'some coverage results are 0.0%'
+ ok=false
+ fi
+ cat testdata/cover.txt
+ rm -f testdata/cover.txt
+}
+
TEST coverage runs
-./testgo test -short -coverpkg=strings strings regexp || ok=false
-./testgo test -short -cover strings math regexp || ok=false
+./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
+./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
+checkcoverage
+
+# Check that coverage analysis uses set mode.
+TEST coverage uses set mode
+if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: set' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out testdata/cover.txt
+
+TEST coverage uses atomic mode for -race.
+if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: atomic' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage uses actual setting to override even for -race.
+if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: count' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage with cgo
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
+checkcoverage
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
@@ -600,7 +657,7 @@ export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
-// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
@@ -620,6 +677,136 @@ if ! ./testgo test -c -test.bench=XXX fmt; then
fi
rm -f fmt.test
+TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/cgoref
+ldflags="-L alibpath -lalib"
+echo "
+package main
+// #cgo LDFLAGS: $ldflags
+// void f(void) {}
+import \"C\"
+
+func main() { C.f() }
+" >$d/src/cgoref/cgoref.go
+go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
+ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
+if [ "$ldflags_count" -lt 1 ]; then
+ echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
+ ok=false
+fi
+rm -rf $d
+unset ldflags_count
+unset go_cmds
+unset ldflags
+unset GOPATH
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
+export GOPATH=$(pwd)/testdata
+if ./testgo test notest >/dev/null 2>&1; then
+ echo 'go test notest succeeded, but should fail'
+ ok=false
+fi
+unset GOPATH
+
+TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
+if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
+ echo "go test -x -a -c testdata/dep_test.go failed"
+ ok=false
+elif ! grep -q regexp deplist; then
+ echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
+ ok=false
+fi
+rm -f deplist
+rm -f deps.test
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST build -i installs dependencies
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/foo $d/src/x/y/bar
+echo '
+package foo
+func F() {}
+' >$d/src/x/y/foo/foo.go
+echo '
+package bar
+import "x/y/foo"
+func F() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo build -i failed
+ cat $d/err
+ ok=false
+elif ! grep x/y/foo $d/err >/dev/null; then
+ echo first build -i did not build x/y/foo
+ cat $d/err
+ ok=false
+fi
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo second build -i failed
+ cat $d/err
+ ok=false
+elif grep x/y/foo $d/err >/dev/null; then
+ echo second build -i built x/y/foo
+ cat $d/err
+ ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'go build in test-only directory fails with a good error'
+if ./testgo build ./testdata/testonly 2>testdata/err.out; then
+ echo "go build ./testdata/testonly succeeded, should have failed"
+ ok=false
+elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
+ echo "go build ./testdata/testonly produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+
+TEST 'go test detects test-only import cycles'
+export GOPATH=$(pwd)/testdata
+if ./testgo test -c testcycle/p3 2>testdata/err.out; then
+ echo "go test testcycle/p3 succeeded, should have failed"
+ ok=false
+elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
+ echo "go test testcycle/p3 produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+unset GOPATH
+
+TEST 'go test foo_test.go works'
+if ! ./testgo test testdata/standalone_test.go; then
+ echo "go test testdata/standalone_test.go failed"
+ ok=false
+fi
+
+TEST 'go test xtestonly works'
+export GOPATH=$(pwd)/testdata
+./testgo clean -i xtestonly
+if ! ./testgo test xtestonly >/dev/null; then
+ echo "go test xtestonly failed"
+ ok=false
+fi
+unset GOPATH
+
+
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 06ac9d206..5935c98db 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -72,6 +72,10 @@ In addition to the build flags, the flags handled by 'go test' itself are:
Install packages that are dependencies of the test.
Do not run the test.
+ -exec xprog
+ Run the test binary using xprog. The behavior is the same as
+ in 'go run'. See 'go help run' for details.
+
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
@@ -133,7 +137,8 @@ control the execution of any test:
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
- being tested. The default is "set".
+ being tested. The default is "set" unless -race is enabled,
+ in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
@@ -168,9 +173,7 @@ control the execution of any test:
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
- and set the environment variable GOGC=off to disable the
- garbage collector, provided the test can run in the available
- memory without garbage collection.
+ and pass --alloc_space flag to the pprof tool.
-outputdir directory
Place output files from profiling in the specified directory,
@@ -273,7 +276,6 @@ var (
testCoverPkgs []*Package // -coverpkg flag
testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around
- testI bool // -i flag
testV bool // -v flag
testFiles []string // -file flag(s) TODO: not respected
testTimeout string // -timeout flag
@@ -295,6 +297,8 @@ func runTest(cmd *Command, args []string) {
var pkgArgs []string
pkgArgs, testArgs = testFlags(args)
+ findExecCmd() // initialize cached result
+
raceInit()
pkgs := packagesForBuild(pkgArgs)
if len(pkgs) == 0 {
@@ -334,7 +338,7 @@ func runTest(cmd *Command, args []string) {
var b builder
b.init()
- if testI {
+ if buildI {
buildV = testV
deps := make(map[string]bool)
@@ -411,7 +415,11 @@ func runTest(cmd *Command, args []string) {
p.Stale = true // rebuild
p.fake = true // do not warn about rebuild
p.coverMode = testCoverMode
- p.coverVars = declareCoverVars(p.ImportPath, p.GoFiles...)
+ var coverFiles []string
+ coverFiles = append(coverFiles, p.GoFiles...)
+ coverFiles = append(coverFiles, p.CgoFiles...)
+ coverFiles = append(coverFiles, p.TestGoFiles...)
+ p.coverVars = declareCoverVars(p.ImportPath, coverFiles...)
}
}
@@ -516,7 +524,7 @@ func contains(x []string, s string) bool {
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
- build := &action{p: p}
+ build := b.action(modeBuild, modeBuild, p)
run := &action{p: p, deps: []*action{build}}
print := &action{f: (*builder).notest, p: p, deps: []*action{run}}
return build, run, print, nil
@@ -530,16 +538,31 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
var imports, ximports []*Package
var stk importStack
- stk.push(p.ImportPath + "_test")
+ stk.push(p.ImportPath + " (test)")
for _, path := range p.TestImports {
p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
+ if contains(p1.Deps, p.ImportPath) {
+ // Same error that loadPackage returns (via reusePackage) in pkg.go.
+ // Can't change that code, because that code is only for loading the
+ // non-test copy of a package.
+ err := &PackageError{
+ ImportStack: testImportStack(stk[0], p1, p.ImportPath),
+ Err: "import cycle not allowed in test",
+ isImportCycle: true,
+ }
+ return nil, nil, nil, err
+ }
imports = append(imports, p1)
}
+ stk.pop()
+ stk.push(p.ImportPath + "_test")
+ pxtestNeedsPtest := false
for _, path := range p.XTestImports {
if path == p.ImportPath {
+ pxtestNeedsPtest = true
continue
}
p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
@@ -618,7 +641,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if localCover {
ptest.coverMode = testCoverMode
- ptest.coverVars = declareCoverVars(ptest.ImportPath, ptest.GoFiles...)
+ var coverFiles []string
+ coverFiles = append(coverFiles, ptest.GoFiles...)
+ coverFiles = append(coverFiles, ptest.CgoFiles...)
+ ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
}
} else {
ptest = p
@@ -637,11 +663,14 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
build: &build.Package{
ImportPos: p.build.XTestImportPos,
},
- imports: append(ximports, ptest),
+ imports: ximports,
pkgdir: testDir,
fake: true,
Stale: true,
}
+ if pxtestNeedsPtest {
+ pxtest.imports = append(pxtest.imports, ptest)
+ }
}
// Action for building pkg.test.
@@ -651,21 +680,20 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
GoFiles: []string{"_testmain.go"},
ImportPath: "testmain",
Root: p.Root,
- imports: []*Package{ptest},
build: &build.Package{Name: "main"},
pkgdir: testDir,
fake: true,
Stale: true,
- }
- if pxtest != nil {
- pmain.imports = append(pmain.imports, pxtest)
+ omitDWARF: !testC && !testNeedBinary,
}
// The generated main also imports testing and regexp.
stk.push("testmain")
for dep := range testMainDeps {
- if ptest.ImportPath != dep {
- p1 := loadImport("testing", "", &stk, nil)
+ if dep == ptest.ImportPath {
+ pmain.imports = append(pmain.imports, ptest)
+ } else {
+ p1 := loadImport(dep, "", &stk, nil)
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
@@ -687,6 +715,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
}
}
+ // Do initial scan for metadata needed for writing _testmain.go
+ // Use that metadata to update the list of imports for package main.
+ // The list of imports is used by recompileForTest and by the loop
+ // afterward that gathers t.Cover information.
+ t, err := loadTestFuncs(ptest)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if t.NeedTest || ptest.coverMode != "" {
+ pmain.imports = append(pmain.imports, ptest)
+ }
+ if t.NeedXtest {
+ pmain.imports = append(pmain.imports, pxtest)
+ }
+
if ptest != p && localCover {
// We have made modifications to the package p being tested
// and are rebuilding p (as ptest), writing it to the testDir tree.
@@ -703,7 +746,15 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
recompileForTest(pmain, p, ptest, testDir)
}
- if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), pmain, ptest); err != nil {
+ for _, cp := range pmain.imports {
+ if len(cp.coverVars) > 0 {
+ t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
+ }
+ }
+
+ // writeTestmain writes _testmain.go. This must happen after recompileForTest,
+ // because recompileForTest modifies XXX.
+ if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
return nil, nil, nil, err
}
@@ -711,7 +762,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if ptest != p {
a := b.action(modeBuild, modeBuild, ptest)
- a.objdir = testDir + string(filepath.Separator)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
a.objpkg = ptestObj
a.target = ptestObj
a.link = false
@@ -719,7 +770,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if pxtest != nil {
a := b.action(modeBuild, modeBuild, pxtest)
- a.objdir = testDir + string(filepath.Separator)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
a.target = a.objpkg
}
@@ -765,6 +816,24 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
return pmainAction, runAction, printAction, nil
}
+func testImportStack(top string, p *Package, target string) []string {
+ stk := []string{top, p.ImportPath}
+Search:
+ for p.ImportPath != target {
+ for _, p1 := range p.imports {
+ if p1.ImportPath == target || contains(p1.Deps, target) {
+ stk = append(stk, p1.ImportPath)
+ p = p1
+ continue Search
+ }
+ }
+ // Can't happen, but in case it does...
+ stk = append(stk, "<lost path to cycle>")
+ break
+ }
+ return stk
+}
+
func recompileForTest(pmain, preal, ptest *Package, testDir string) {
// The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy"
@@ -836,7 +905,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
// runTest is the action for running a test binary.
func (b *builder) runTest(a *action) error {
- args := stringList(a.deps[0].target, testArgs)
+ args := stringList(findExecCmd(), a.deps[0].target, testArgs)
a.testOutput = new(bytes.Buffer)
if buildN || buildX {
@@ -1007,31 +1076,26 @@ type coverInfo struct {
Vars map[string]*CoverVar
}
-// writeTestmain writes the _testmain.go file for package p to
-// the file named out.
-func writeTestmain(out string, pmain, p *Package) error {
- var cover []coverInfo
- for _, cp := range pmain.imports {
- if len(cp.coverVars) > 0 {
- cover = append(cover, coverInfo{cp, cp.coverVars})
- }
- }
-
+// loadTestFuncs returns the testFuncs describing the tests that will be run.
+func loadTestFuncs(ptest *Package) (*testFuncs, error) {
t := &testFuncs{
- Package: p,
- Cover: cover,
+ Package: ptest,
}
- for _, file := range p.TestGoFiles {
- if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil {
- return err
+ for _, file := range ptest.TestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
+ return nil, err
}
}
- for _, file := range p.XTestGoFiles {
- if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil {
- return err
+ for _, file := range ptest.XTestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
+ return nil, err
}
}
+ return t, nil
+}
+// writeTestmain writes the _testmain.go file for t to the file named out.
+func writeTestmain(out string, t *testFuncs) error {
f, err := os.Create(out)
if err != nil {
return err
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/cgocover/p.go
new file mode 100644
index 000000000..a6a3891cd
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/src/cmd/go/testdata/cgocover/p_test.go b/src/cmd/go/testdata/cgocover/p_test.go
new file mode 100644
index 000000000..a8f057e35
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p_test.go
@@ -0,0 +1,7 @@
+package p
+
+import "testing"
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/src/cmd/go/testdata/dep_test.go b/src/cmd/go/testdata/dep_test.go
new file mode 100644
index 000000000..0c53ac4f9
--- /dev/null
+++ b/src/cmd/go/testdata/dep_test.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package deps
+
+import _ "testing"
diff --git a/src/cmd/go/testdata/src/notest/hello.go b/src/cmd/go/testdata/src/notest/hello.go
new file mode 100644
index 000000000..7c42c32fb
--- /dev/null
+++ b/src/cmd/go/testdata/src/notest/hello.go
@@ -0,0 +1,6 @@
+package notest
+
+func hello() {
+ println("hello world")
+}
+Hello world
diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1.go b/src/cmd/go/testdata/src/testcycle/p1/p1.go
new file mode 100644
index 000000000..65ab76d4e
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p1/p1.go
@@ -0,0 +1,7 @@
+package p1
+
+import _ "testcycle/p2"
+
+func init() {
+ println("p1 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1_test.go b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go
new file mode 100644
index 000000000..75abb13e6
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go
@@ -0,0 +1,6 @@
+package p1
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p2/p2.go b/src/cmd/go/testdata/src/testcycle/p2/p2.go
new file mode 100644
index 000000000..7e26cdf19
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p2/p2.go
@@ -0,0 +1,7 @@
+package p2
+
+import _ "testcycle/p3"
+
+func init() {
+ println("p2 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3.go b/src/cmd/go/testdata/src/testcycle/p3/p3.go
new file mode 100644
index 000000000..bb0a2f4f6
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p3/p3.go
@@ -0,0 +1,5 @@
+package p3
+
+func init() {
+ println("p3 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3_test.go b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go
new file mode 100644
index 000000000..9b4b0757f
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go
@@ -0,0 +1,10 @@
+package p3
+
+import (
+ "testing"
+
+ _ "testcycle/p1"
+)
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/src/xtestonly/f.go b/src/cmd/go/testdata/src/xtestonly/f.go
new file mode 100644
index 000000000..dac039e1a
--- /dev/null
+++ b/src/cmd/go/testdata/src/xtestonly/f.go
@@ -0,0 +1,3 @@
+package xtestonly
+
+func F() int { return 42 }
diff --git a/src/cmd/go/testdata/src/xtestonly/f_test.go b/src/cmd/go/testdata/src/xtestonly/f_test.go
new file mode 100644
index 000000000..01f6e8373
--- /dev/null
+++ b/src/cmd/go/testdata/src/xtestonly/f_test.go
@@ -0,0 +1,12 @@
+package xtestonly_test
+
+import (
+ "testing"
+ "xtestonly"
+)
+
+func TestF(t *testing.T) {
+ if x := xtestonly.F(); x != 42 {
+ t.Errorf("f.F() = %d, want 42", x)
+ }
+}
diff --git a/src/cmd/go/testdata/standalone_test.go b/src/cmd/go/testdata/standalone_test.go
new file mode 100644
index 000000000..59cf918b9
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_test.go
@@ -0,0 +1,6 @@
+package standalone_test
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/testonly/p_test.go b/src/cmd/go/testdata/testonly/p_test.go
new file mode 100644
index 000000000..c89cd18d0
--- /dev/null
+++ b/src/cmd/go/testdata/testonly/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index aea81d8f8..73f311e5f 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -66,7 +66,6 @@ var testFlagDefn = []*testFlagSpec{
// local.
{name: "c", boolVar: &testC},
{name: "file", multiOK: true},
- {name: "i", boolVar: &testI},
{name: "cover", boolVar: &testCover},
{name: "coverpkg"},
@@ -75,8 +74,11 @@ var testFlagDefn = []*testFlagSpec{
{name: "n", boolVar: &buildN},
{name: "p"},
{name: "x", boolVar: &buildX},
+ {name: "i", boolVar: &buildI},
{name: "work", boolVar: &buildWork},
+ {name: "ccflags"},
{name: "gcflags"},
+ {name: "exec"},
{name: "ldflags"},
{name: "gccgoflags"},
{name: "tags"},
@@ -116,7 +118,6 @@ var testFlagDefn = []*testFlagSpec{
func testFlags(args []string) (packageNames, passToTest []string) {
inPkg := false
outputDir := ""
- testCoverMode = "set"
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
if !inPkg && packageNames == nil {
@@ -154,6 +155,16 @@ func testFlags(args []string) (packageNames, passToTest []string) {
setBoolFlag(f.boolVar, value)
case "p":
setIntFlag(&buildP, value)
+ case "exec":
+ execCmd, err = splitQuotedFields(value)
+ if err != nil {
+ fatalf("invalid flag argument for -%s: %v", f.name, err)
+ }
+ case "ccflags":
+ buildCcflags, err = splitQuotedFields(value)
+ if err != nil {
+ fatalf("invalid flag argument for -%s: %v", f.name, err)
+ }
case "gcflags":
buildGcflags, err = splitQuotedFields(value)
if err != nil {
@@ -212,6 +223,14 @@ func testFlags(args []string) (packageNames, passToTest []string) {
}
}
+ if testCoverMode == "" {
+ testCoverMode = "set"
+ if buildRace {
+ // Default coverage mode is atomic when -race is set.
+ testCoverMode = "atomic"
+ }
+ }
+
// Tell the test what directory we're running in, so it can write the profiles there.
if testProfile && outputDir == "" {
dir, err := os.Getwd()
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 22d5ebc24..8f0bae0b7 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -354,6 +354,8 @@ type repoRoot struct {
root string
}
+var httpPrefixRE = regexp.MustCompile(`^https?:`)
+
// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
func repoRootForImportPath(importPath string) (*repoRoot, error) {
@@ -390,8 +392,12 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
//
// If scheme is non-empty, that scheme is forced.
func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
- if strings.Contains(importPath, "://") {
- return nil, fmt.Errorf("invalid import path %q", importPath)
+ // A common error is to use https://packagepath because that's what
+ // hg and git require. Diagnose this helpfully.
+ if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
+ // The importPath has been cleaned, so has only one slash. The pattern
+ // ignores the slashes; the error message puts them back on the RHS at least.
+ return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
}
for _, srv := range vcsPaths {
if !strings.HasPrefix(importPath, srv.prefix) {
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 94e67fd89..8f73ef5b9 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -4,6 +4,7 @@
/*
Gofmt formats Go programs.
+It uses tabs (width = 8) for indentation and blanks for alignment.
Without an explicit path, it processes the standard input. Given a file,
it operates on that file; given a directory, it operates on all .go files in
@@ -33,13 +34,9 @@ The flags are:
If a file's formatting is different from gofmt's, overwrite it
with gofmt's version.
-Formatting control flags:
- -comments=true
- Print comments; if false, all comments are elided from the output.
- -tabs=true
- Indent with tabs; if false, spaces are used instead.
- -tabwidth=8
- Tab width in spaces.
+Debugging support:
+ -cpuprofile filename
+ Write cpu profile to the specified file.
The rewrite rule specified with the -r flag must be a string of the form:
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 861ff9390..576cae522 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -31,21 +31,20 @@ var (
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
- // layout control
- comments = flag.Bool("comments", true, "print comments")
- tabWidth = flag.Int("tabwidth", 8, "tab width")
- tabIndent = flag.Bool("tabs", true, "indent with tabs")
-
// debugging
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)
+const (
+ tabWidth = 8
+ printerMode = printer.UseSpaces | printer.TabIndent
+)
+
var (
- fileSet = token.NewFileSet() // per process FileSet
- exitCode = 0
- rewrite func(*ast.File) *ast.File
- parserMode parser.Mode
- printerMode printer.Mode
+ fileSet = token.NewFileSet() // per process FileSet
+ exitCode = 0
+ rewrite func(*ast.File) *ast.File
+ parserMode parser.Mode
)
func report(err error) {
@@ -60,22 +59,12 @@ func usage() {
}
func initParserMode() {
- parserMode = parser.Mode(0)
- if *comments {
- parserMode |= parser.ParseComments
- }
+ parserMode = parser.ParseComments
if *allErrors {
parserMode |= parser.AllErrors
}
}
-func initPrinterMode() {
- printerMode = printer.UseSpaces
- if *tabIndent {
- printerMode |= printer.TabIndent
- }
-}
-
func isGoFile(f os.FileInfo) bool {
// ignore non-Go files
name := f.Name()
@@ -118,7 +107,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
}
var buf bytes.Buffer
- err = (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(&buf, fileSet, file)
+ err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
if err != nil {
return err
}
@@ -180,11 +169,6 @@ func main() {
func gofmtMain() {
flag.Usage = usage
flag.Parse()
- if *tabWidth < 0 {
- fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
- exitCode = 2
- return
- }
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
@@ -199,7 +183,6 @@ func gofmtMain() {
}
initParserMode()
- initPrinterMode()
initRewrite()
if flag.NArg() == 0 {
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index 75a322a6c..b9335b8f3 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -40,7 +40,6 @@ func runTest(t *testing.T, in, out, flags string) {
}
initParserMode()
- initPrinterMode()
initRewrite()
var buf bytes.Buffer
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index 862e9d987..108278b33 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -38,7 +38,7 @@ func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
}
ast.SortImports(fset, f)
src.Reset()
- return (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(src, fset, f)
+ return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
}
func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 66d2331a5..fb6c6fc81 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -48,7 +48,7 @@ func parseExpr(s, what string) ast.Expr {
/*
func dump(msg string, val reflect.Value) {
fmt.Printf("%s:\n", msg)
- ast.Print(fset, val.Interface())
+ ast.Print(fileSet, val.Interface())
fmt.Println()
}
*/
@@ -59,8 +59,9 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
m := make(map[string]reflect.Value)
pat := reflect.ValueOf(pattern)
repl := reflect.ValueOf(replace)
- var f func(val reflect.Value) reflect.Value // f is recursive
- f = func(val reflect.Value) reflect.Value {
+
+ var rewriteVal func(val reflect.Value) reflect.Value
+ rewriteVal = func(val reflect.Value) reflect.Value {
// don't bother if val is invalid to start with
if !val.IsValid() {
return reflect.Value{}
@@ -68,22 +69,22 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
for k := range m {
delete(m, k)
}
- val = apply(f, val)
+ val = apply(rewriteVal, val)
if match(m, pat, val) {
val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
}
return val
}
- r := apply(f, reflect.ValueOf(p)).Interface().(*ast.File)
+
+ r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
r.Comments = cmap.Filter(r).Comments() // recreate comments list
return r
}
-// setValue is a wrapper for x.SetValue(y); it protects
-// the caller from panics if x cannot be changed to y.
-func setValue(x, y reflect.Value) {
- // don't bother if y is invalid to start with
- if !y.IsValid() {
+// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
+func set(x, y reflect.Value) {
+ // don't bother if x cannot be set or y is invalid
+ if !x.CanSet() || !y.IsValid() {
return
}
defer func() {
@@ -134,16 +135,16 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
e := v.Index(i)
- setValue(e, f(e))
+ set(e, f(e))
}
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
e := v.Field(i)
- setValue(e, f(e))
+ set(e, f(e))
}
case reflect.Interface:
e := v.Elem()
- setValue(v, f(e))
+ set(v, f(e))
}
return val
}
diff --git a/src/cmd/gofmt/testdata/typeswitch.golden b/src/cmd/gofmt/testdata/typeswitch.golden
index 87e916181..2b1905edd 100644
--- a/src/cmd/gofmt/testdata/typeswitch.golden
+++ b/src/cmd/gofmt/testdata/typeswitch.golden
@@ -4,7 +4,7 @@
into the correct unparenthesized form.
Only type-switches that didn't declare a variable
- in the the type switch type assertion and which
+ in the type switch type assertion and which
contained only "expression-like" (named) types in their
cases were permitted to have their type assertion parenthesized
by go/parser (due to a weak predicate in the parser). All others
diff --git a/src/cmd/gofmt/testdata/typeswitch.input b/src/cmd/gofmt/testdata/typeswitch.input
index f90f28949..8f8cba9b8 100644
--- a/src/cmd/gofmt/testdata/typeswitch.input
+++ b/src/cmd/gofmt/testdata/typeswitch.input
@@ -4,7 +4,7 @@
into the correct unparenthesized form.
Only type-switches that didn't declare a variable
- in the the type switch type assertion and which
+ in the type switch type assertion and which
contained only "expression-like" (named) types in their
cases were permitted to have their type assertion parenthesized
by go/parser (due to a weak predicate in the parser). All others
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 30d7c8185..55d020710 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -38,15 +38,14 @@
#include "../../pkg/runtime/mgc0.h"
void dynreloc(void);
-static vlong addaddrplus4(Sym *s, Sym *t, vlong add);
/*
* divide-and-conquer list-link
- * sort of Sym* structures.
+ * sort of LSym* structures.
* Used for the data block.
*/
int
-datcmp(Sym *s1, Sym *s2)
+datcmp(LSym *s1, LSym *s2)
{
if(s1->type != s2->type)
return (int)s1->type - (int)s2->type;
@@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2)
return strcmp(s1->name, s2->name);
}
-Sym*
-listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
+LSym*
+listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off)
{
- Sym *l1, *l2, *le;
- #define NEXT(l) (*(Sym**)((char*)(l)+off))
+ LSym *l1, *l2, *le;
+ #define NEXT(l) (*(LSym**)((char*)(l)+off))
if(l == 0 || NEXT(l) == 0)
return l;
@@ -128,32 +127,16 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
#undef NEXT
}
-Reloc*
-addrel(Sym *s)
-{
- if(s->nr >= s->maxr) {
- if(s->maxr == 0)
- s->maxr = 4;
- else
- s->maxr <<= 1;
- s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
- memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
- }
- return &s->r[s->nr++];
-}
-
void
-relocsym(Sym *s)
+relocsym(LSym *s)
{
Reloc *r;
- Sym *rs;
- Prog p;
+ LSym *rs;
int32 i, off, siz, fl;
vlong o;
uchar *cast;
- cursym = s;
- memset(&p, 0, sizeof p);
+ ctxt->cursym = s;
for(r=s->r; r<s->r+s->nr; r++) {
r->done = 1;
off = r->off;
@@ -168,10 +151,12 @@ relocsym(Sym *s)
}
if(r->type >= 256)
continue;
+ if(r->siz == 0) // informational relocation - no work to do
+ continue;
- if(r->sym != S && r->sym->type == SDYNIMPORT)
+ // Solaris needs the ability to reference dynimport symbols.
+ if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT)
diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
-
if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
@@ -181,13 +166,56 @@ relocsym(Sym *s)
if(archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type);
break;
- case D_TLS:
+ case R_TLS:
+ if(linkmode == LinkInternal && iself && thechar == '5') {
+ // On ELF ARM, the thread pointer is 8 bytes before
+ // the start of the thread-local data block, so add 8
+ // to the actual TLS offset (r->sym->value).
+ // This 8 seems to be a fundamental constant of
+ // ELF on ARM (or maybe Glibc on ARM); it is not
+ // related to the fact that our own TLS storage happens
+ // to take up 8 bytes.
+ o = 8 + r->sym->value;
+ break;
+ }
r->done = 0;
o = 0;
if(thechar != '6')
o = r->add;
break;
- case D_ADDR:
+ case R_TLS_LE:
+ if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) {
+ r->done = 0;
+ r->sym = ctxt->gmsym;
+ r->xsym = ctxt->gmsym;
+ r->xadd = r->add;
+ o = 0;
+ if(thechar != '6')
+ o = r->add;
+ break;
+ }
+ o = ctxt->tlsoffset + r->add;
+ break;
+
+ case R_TLS_IE:
+ if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) {
+ r->done = 0;
+ r->sym = ctxt->gmsym;
+ r->xsym = ctxt->gmsym;
+ r->xadd = r->add;
+ o = 0;
+ if(thechar != '6')
+ o = r->add;
+ break;
+ }
+ if(iself || ctxt->headtype == Hplan9)
+ o = ctxt->tlsoffset + r->add;
+ else if(ctxt->headtype == Hwindows)
+ o = r->add;
+ else
+ sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype));
+ break;
+ case R_ADDR:
if(linkmode == LinkExternal && r->sym->type != SCONST) {
r->done = 0;
@@ -198,7 +226,7 @@ relocsym(Sym *s)
r->xadd += symaddr(rs) - symaddr(rs->outer);
rs = rs->outer;
}
- if(rs->type != SHOSTOBJ && rs->sect == nil)
+ if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
diag("missing section for %s", rs->name);
r->xsym = rs;
@@ -210,15 +238,26 @@ relocsym(Sym *s)
if(rs->type != SHOSTOBJ)
o += symaddr(rs);
} else {
- diag("unhandled pcrel relocation for %s", headtype);
+ diag("unhandled pcrel relocation for %s", headstring);
}
break;
}
o = symaddr(r->sym) + r->add;
+
+ // On amd64, 4-byte offsets will be sign-extended, so it is impossible to
+ // access more than 2GB of static data; fail at link time is better than
+ // fail at runtime. See http://golang.org/issue/7980.
+ // Instead of special casing only amd64, we treat this as an error on all
+ // 64-bit architectures so as to be future-proof.
+ if((int32)o < 0 && PtrSize > 4 && siz == 4) {
+ diag("non-pc-relative relocation address is too big: %#llux", o);
+ errorexit();
+ }
break;
- case D_PCREL:
+ case R_CALL:
+ case R_PCREL:
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
- if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
+ if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) {
r->done = 0;
// set up addend for eventual relocation via outer symbol.
@@ -229,7 +268,7 @@ relocsym(Sym *s)
rs = rs->outer;
}
r->xadd -= r->siz; // relative to address after the relocated chunk
- if(rs->type != SHOSTOBJ && rs->sect == nil)
+ if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
diag("missing section for %s", rs->name);
r->xsym = rs;
@@ -242,7 +281,7 @@ relocsym(Sym *s)
o += symaddr(rs) - rs->sect->vaddr;
o -= r->off; // WTF?
} else {
- diag("unhandled pcrel relocation for %s", headtype);
+ diag("unhandled pcrel relocation for %s", headstring);
}
break;
}
@@ -257,17 +296,21 @@ relocsym(Sym *s)
// the standard host compiler (gcc on most other systems).
o += r->add - (s->value + r->off + (int32)r->siz);
break;
- case D_SIZE:
+ case R_SIZE:
o = r->sym->size + r->add;
break;
}
-//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
+//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
switch(siz) {
default:
- cursym = s;
+ ctxt->cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name);
+ case 1:
+ // TODO(rsc): Remove.
+ s->p[off] = (int8)o;
+ break;
case 4:
- if(r->type == D_PCREL) {
+ if(r->type == R_PCREL || r->type == R_CALL) {
if(o != (int32)o)
diag("pc-relative relocation address is too big: %#llx", o);
} else {
@@ -291,31 +334,35 @@ relocsym(Sym *s)
void
reloc(void)
{
- Sym *s;
+ LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=S; s=s->next)
relocsym(s);
for(s=datap; s!=S; s=s->next)
relocsym(s);
}
void
-dynrelocsym(Sym *s)
+dynrelocsym(LSym *s)
{
Reloc *r;
-
+
if(HEADTYPE == Hwindows) {
- Sym *rel, *targ;
+ LSym *rel, *targ;
- rel = lookup(".rel", 0);
+ rel = linklookup(ctxt, ".rel", 0);
if(s == rel)
return;
for(r=s->r; r<s->r+s->nr; r++) {
targ = r->sym;
+ if(targ == nil)
+ continue;
+ if(!targ->reachable)
+ diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name);
if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
targ->plt = rel->size;
r->sym = rel;
@@ -323,17 +370,17 @@ dynrelocsym(Sym *s)
// jmp *addr
if(thechar == '8') {
- adduint8(rel, 0xff);
- adduint8(rel, 0x25);
- addaddr(rel, targ);
- adduint8(rel, 0x90);
- adduint8(rel, 0x90);
+ adduint8(ctxt, rel, 0xff);
+ adduint8(ctxt, rel, 0x25);
+ addaddr(ctxt, rel, targ);
+ adduint8(ctxt, rel, 0x90);
+ adduint8(ctxt, rel, 0x90);
} else {
- adduint8(rel, 0xff);
- adduint8(rel, 0x24);
- adduint8(rel, 0x25);
- addaddrplus4(rel, targ, 0);
- adduint8(rel, 0x90);
+ adduint8(ctxt, rel, 0xff);
+ adduint8(ctxt, rel, 0x24);
+ adduint8(ctxt, rel, 0x25);
+ addaddrplus4(ctxt, rel, targ, 0);
+ adduint8(ctxt, rel, 0x90);
}
} else if(r->sym->plt >= 0) {
r->sym = rel;
@@ -344,15 +391,18 @@ dynrelocsym(Sym *s)
}
for(r=s->r; r<s->r+s->nr; r++) {
- if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
+ if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) {
+ if(r->sym != S && !r->sym->reachable)
+ diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
adddynrel(s, r);
+ }
}
}
void
dynreloc(void)
{
- Sym *s;
+ LSym *s;
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
@@ -362,7 +412,7 @@ dynreloc(void)
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=S; s=s->next)
dynrelocsym(s);
for(s=datap; s!=S; s=s->next)
dynrelocsym(s);
@@ -370,118 +420,10 @@ dynreloc(void)
elfdynhash();
}
-void
-symgrow(Sym *s, int32 siz)
-{
- if(s->np >= siz)
- return;
-
- if(s->np > s->maxp) {
- cursym = s;
- diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
- errorexit();
- }
-
- if(s->maxp < siz) {
- if(s->maxp == 0)
- s->maxp = 8;
- while(s->maxp < siz)
- s->maxp <<= 1;
- s->p = erealloc(s->p, s->maxp);
- memset(s->p+s->np, 0, s->maxp-s->np);
- }
- s->np = siz;
-}
-
-void
-savedata(Sym *s, Prog *p, char *pn)
-{
- int32 off, siz, i, fl;
- uchar *cast;
- vlong o;
- Reloc *r;
-
- off = p->from.offset;
- siz = p->datasize;
- if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
- mangle(pn);
- symgrow(s, off+siz);
-
- switch(p->to.type) {
- default:
- diag("bad data: %P", p);
- break;
-
- case D_FCONST:
- switch(siz) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(i=0; i<4; i++)
- s->p[off+i] = cast[fnuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[fnuxi8[i]];
- break;
- }
- break;
-
- case D_SCONST:
- for(i=0; i<siz; i++)
- s->p[off+i] = p->to.scon[i];
- break;
-
- case D_CONST:
- if(p->to.sym)
- goto Addr;
- o = p->to.offset;
- fl = o;
- cast = (uchar*)&fl;
- switch(siz) {
- default:
- diag("bad nuxi %d\n%P", siz, p);
- break;
- case 1:
- s->p[off] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[off+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- break;
-
- case D_ADDR:
- case D_SIZE:
- Addr:
- r = addrel(s);
- r->off = off;
- r->siz = siz;
- r->sym = p->to.sym;
- r->type = p->to.type;
- if(r->type != D_SIZE)
- r->type = D_ADDR;
- r->add = p->to.offset;
- break;
- }
-}
-
static void
-blk(Sym *start, int32 addr, int32 size)
+blk(LSym *start, int32 addr, int32 size)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
uchar *p, *ep;
@@ -499,7 +441,7 @@ blk(Sym *start, int32 addr, int32 size)
diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
errorexit();
}
- cursym = sym;
+ ctxt->cursym = sym;
for(; addr < sym->value; addr++)
cput(0);
p = sym->p;
@@ -523,21 +465,20 @@ blk(Sym *start, int32 addr, int32 size)
void
codeblk(int32 addr, int32 size)
{
- Sym *sym;
- int32 eaddr, n, epc;
- Prog *p;
+ LSym *sym;
+ int32 eaddr, n;
uchar *q;
if(debug['a'])
Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
- blk(textp, addr, size);
+ blk(ctxt->textp, addr, size);
/* again for printing */
if(!debug['a'])
return;
- for(sym = textp; sym != nil; sym = sym->next) {
+ for(sym = ctxt->textp; sym != nil; sym = sym->next) {
if(!sym->reachable)
continue;
if(sym->value >= addr)
@@ -557,36 +498,20 @@ codeblk(int32 addr, int32 size)
Bprint(&bso, " %.2ux", 0);
Bprint(&bso, "\n");
}
- p = sym->text;
- if(p == nil) {
- Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
- n = sym->size;
- q = sym->p;
-
- while(n >= 16) {
- Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
- addr += 16;
- q += 16;
- n -= 16;
- }
- if(n > 0)
- Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
- addr += n;
- continue;
- }
- Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
- for(p = p->link; p != P; p = p->link) {
- if(p->link != P)
- epc = p->link->pc;
- else
- epc = sym->value + sym->size;
- Bprint(&bso, "%.6llux\t", (uvlong)p->pc);
- q = sym->p + p->pc - sym->value;
- n = epc - p->pc;
- Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
- addr += n;
+ Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name);
+ n = sym->size;
+ q = sym->p;
+
+ while(n >= 16) {
+ Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
+ addr += 16;
+ q += 16;
+ n -= 16;
}
+ if(n > 0)
+ Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
+ addr += n;
}
if(addr < eaddr) {
@@ -600,7 +525,7 @@ codeblk(int32 addr, int32 size)
void
datblk(int32 addr, int32 size)
{
- Sym *sym;
+ LSym *sym;
int32 i, eaddr;
uchar *p, *ep;
char *typ, *rsname;
@@ -648,12 +573,15 @@ datblk(int32 addr, int32 size)
rsname = r->sym->name;
typ = "?";
switch(r->type) {
- case D_ADDR:
+ case R_ADDR:
typ = "addr";
break;
- case D_PCREL:
+ case R_PCREL:
typ = "pcrel";
break;
+ case R_CALL:
+ typ = "call";
+ break;
}
Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n",
(uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add));
@@ -682,28 +610,28 @@ strnput(char *s, int n)
void
addstrdata(char *name, char *value)
{
- Sym *s, *sp;
+ LSym *s, *sp;
char *p;
p = smprint("%s.str", name);
- sp = lookup(p, 0);
+ sp = linklookup(ctxt, p, 0);
free(p);
addstring(sp, value);
- s = lookup(name, 0);
+ s = linklookup(ctxt, name, 0);
s->size = 0;
s->dupok = 1;
- addaddr(s, sp);
- adduint32(s, strlen(value));
+ addaddr(ctxt, s, sp);
+ adduint32(ctxt, s, strlen(value));
if(PtrSize == 8)
- adduint32(s, 0); // round struct to pointer width
+ adduint32(ctxt, s, 0); // round struct to pointer width
// in case reachability has already been computed
sp->reachable = s->reachable;
}
vlong
-addstring(Sym *s, char *str)
+addstring(LSym *s, char *str)
{
int n;
int32 r;
@@ -715,230 +643,18 @@ addstring(Sym *s, char *str)
n = strlen(str)+1;
if(strcmp(s->name, ".shstrtab") == 0)
elfsetstring(str, r);
- symgrow(s, r+n);
+ symgrow(ctxt, s, r+n);
memmove(s->p+r, str, n);
s->size += n;
return r;
}
-vlong
-setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
-{
- int32 i, fl;
- vlong o;
- uchar *cast;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- if(s->size < off+wid) {
- s->size = off+wid;
- symgrow(s, s->size);
- }
- fl = v;
- cast = (uchar*)&fl;
- switch(wid) {
- case 1:
- s->p[off] = cast[inuxi1[0]];
- break;
- case 2:
- for(i=0; i<2; i++)
- s->p[off+i] = cast[inuxi2[i]];
- break;
- case 4:
- for(i=0; i<4; i++)
- s->p[off+i] = cast[inuxi4[i]];
- break;
- case 8:
- o = v;
- cast = (uchar*)&o;
- for(i=0; i<8; i++)
- s->p[off+i] = cast[inuxi8[i]];
- break;
- }
- return off+wid;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong off;
-
- off = s->size;
- setuintxx(s, off, v, wid);
- return off;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-setuint8(Sym *s, vlong r, uint8 v)
-{
- return setuintxx(s, r, v, 1);
-}
-
-vlong
-setuint16(Sym *s, vlong r, uint16 v)
-{
- return setuintxx(s, r, v, 2);
-}
-
-vlong
-setuint32(Sym *s, vlong r, uint32 v)
-{
- return setuintxx(s, r, v, 4);
-}
-
-vlong
-setuint64(Sym *s, vlong r, uint64 v)
-{
- return setuintxx(s, r, v, 8);
-}
-
-vlong
-addaddrplus(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_ADDR;
- r->add = add;
- return i + r->siz;
-}
-
-static vlong
-addaddrplus4(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += 4;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = 4;
- r->type = D_ADDR;
- r->add = add;
- return i + r->siz;
-}
-
-vlong
-addpcrelplus(Sym *s, Sym *t, vlong add)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += 4;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->add = add;
- r->type = D_PCREL;
- r->siz = 4;
- return i + r->siz;
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- return addaddrplus(s, t, 0);
-}
-
-vlong
-setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
-{
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- if(off+PtrSize > s->size) {
- s->size = off + PtrSize;
- symgrow(s, s->size);
- }
- r = addrel(s);
- r->sym = t;
- r->off = off;
- r->siz = PtrSize;
- r->type = D_ADDR;
- r->add = add;
- return off + r->siz;
-}
-
-vlong
-setaddr(Sym *s, vlong off, Sym *t)
-{
- return setaddrplus(s, off, t, 0);
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong i;
- Reloc *r;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- i = s->size;
- s->size += PtrSize;
- symgrow(s, s->size);
- r = addrel(s);
- r->sym = t;
- r->off = i;
- r->siz = PtrSize;
- r->type = D_SIZE;
- return i + r->siz;
-}
-
void
dosymtype(void)
{
- Sym *s;
+ LSym *s;
- for(s = allsym; s != nil; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(s->np > 0) {
if(s->type == SBSS)
s->type = SDATA;
@@ -949,7 +665,7 @@ dosymtype(void)
}
static int32
-symalign(Sym *s)
+symalign(LSym *s)
{
int32 align;
@@ -965,7 +681,7 @@ symalign(Sym *s)
}
static vlong
-aligndatsize(vlong datsize, Sym *s)
+aligndatsize(vlong datsize, LSym *s)
{
return rnd(datsize, symalign(s));
}
@@ -973,7 +689,7 @@ aligndatsize(vlong datsize, Sym *s)
// maxalign returns the maximum required alignment for
// the list of symbols s; the list stops when s->type exceeds type.
static int32
-maxalign(Sym *s, int type)
+maxalign(LSym *s, int type)
{
int32 align, max;
@@ -987,10 +703,10 @@ maxalign(Sym *s, int type)
}
static void
-gcaddsym(Sym *gc, Sym *s, vlong off)
+gcaddsym(LSym *gc, LSym *s, vlong off)
{
vlong a;
- Sym *gotype;
+ LSym *gotype;
if(s->size < PtrSize)
return;
@@ -1000,22 +716,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off)
gotype = s->gotype;
if(gotype != nil) {
//print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name);
- adduintxx(gc, GC_CALL, PtrSize);
- adduintxx(gc, off, PtrSize);
- addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4);
+ adduintxx(ctxt, gc, GC_CALL, PtrSize);
+ adduintxx(ctxt, gc, off, PtrSize);
+ addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4);
if(PtrSize == 8)
- adduintxx(gc, 0, 4);
+ adduintxx(ctxt, gc, 0, 4);
} else {
//print("gcaddsym: %s %d <unknown type>\n", s->name, s->size);
for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) {
- adduintxx(gc, GC_APTR, PtrSize);
- adduintxx(gc, off+a, PtrSize);
+ adduintxx(ctxt, gc, GC_APTR, PtrSize);
+ adduintxx(ctxt, gc, off+a, PtrSize);
}
}
}
void
-growdatsize(vlong *datsizep, Sym *s)
+growdatsize(vlong *datsizep, LSym *s)
{
vlong datsize;
@@ -1034,27 +750,30 @@ dodata(void)
vlong datsize;
Section *sect;
Segment *segro;
- Sym *s, *last, **l;
- Sym *gcdata1, *gcbss1;
+ LSym *s, *last, **l;
+ LSym *gcdata1, *gcbss1;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
- gcdata1 = lookup("gcdata", 0);
- gcbss1 = lookup("gcbss", 0);
+ gcdata1 = linklookup(ctxt, "gcdata", 0);
+ gcbss1 = linklookup(ctxt, "gcbss", 0);
// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
- adduintxx(gcdata1, 0, PtrSize);
- adduintxx(gcbss1, 0, PtrSize);
+ adduintxx(ctxt, gcdata1, 0, PtrSize);
+ adduintxx(ctxt, gcbss1, 0, PtrSize);
last = nil;
datap = nil;
- for(s=allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(!s->reachable || s->special)
continue;
if(STEXT < s->type && s->type < SXREF) {
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
if(last == nil)
datap = s;
else
@@ -1092,7 +811,7 @@ dodata(void)
}
*l = nil;
- datap = listsort(datap, datcmp, offsetof(Sym, next));
+ datap = listsort(datap, datcmp, offsetof(LSym, next));
/*
* allocate sections. list is sorted by type,
@@ -1128,8 +847,8 @@ dodata(void)
sect->align = maxalign(s, SINITARR-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("noptrdata", 0)->sect = sect;
- lookup("enoptrdata", 0)->sect = sect;
+ linklookup(ctxt, "noptrdata", 0)->sect = sect;
+ linklookup(ctxt, "enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SINITARR; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1159,11 +878,11 @@ dodata(void)
sect->align = maxalign(s, SBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("data", 0)->sect = sect;
- lookup("edata", 0)->sect = sect;
+ linklookup(ctxt, "data", 0)->sect = sect;
+ linklookup(ctxt, "edata", 0)->sect = sect;
for(; s != nil && s->type < SBSS; s = s->next) {
if(s->type == SINITARR) {
- cursym = s;
+ ctxt->cursym = s;
diag("unexpected symbol type %d", s->type);
}
s->sect = sect;
@@ -1175,16 +894,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
- adduintxx(gcdata1, GC_END, PtrSize);
- setuintxx(gcdata1, 0, sect->len, PtrSize);
+ adduintxx(ctxt, gcdata1, GC_END, PtrSize);
+ setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize);
/* bss */
sect = addsection(&segdata, ".bss", 06);
sect->align = maxalign(s, SNOPTRBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("bss", 0)->sect = sect;
- lookup("ebss", 0)->sect = sect;
+ linklookup(ctxt, "bss", 0)->sect = sect;
+ linklookup(ctxt, "ebss", 0)->sect = sect;
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
datsize = aligndatsize(datsize, s);
@@ -1194,16 +913,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
- adduintxx(gcbss1, GC_END, PtrSize);
- setuintxx(gcbss1, 0, sect->len, PtrSize);
+ adduintxx(ctxt, gcbss1, GC_END, PtrSize);
+ setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize);
/* pointer-free bss */
sect = addsection(&segdata, ".noptrbss", 06);
sect->align = maxalign(s, SNOPTRBSS);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("noptrbss", 0)->sect = sect;
- lookup("enoptrbss", 0)->sect = sect;
+ linklookup(ctxt, "noptrbss", 0)->sect = sect;
+ linklookup(ctxt, "enoptrbss", 0)->sect = sect;
for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1211,7 +930,7 @@ dodata(void)
growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- lookup("end", 0)->sect = sect;
+ linklookup(ctxt, "end", 0)->sect = sect;
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if(datsize != (uint32)datsize) {
@@ -1230,10 +949,18 @@ dodata(void)
growdatsize(&datsize, s);
}
sect->len = datsize;
+ } else {
+ // Might be internal linking but still using cgo.
+ // In that case, the only possible STLSBSS symbol is tlsgm.
+ // Give it offset 0, because it's the only thing here.
+ if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsgm") == 0) {
+ s->value = 0;
+ s = s->next;
+ }
}
if(s != nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("unexpected symbol type %d for %s", s->type, s->name);
}
@@ -1274,8 +1001,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = 0;
- lookup("rodata", 0)->sect = sect;
- lookup("erodata", 0)->sect = sect;
+ linklookup(ctxt, "rodata", 0)->sect = sect;
+ linklookup(ctxt, "erodata", 0)->sect = sect;
for(; s != nil && s->type < STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1290,8 +1017,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("typelink", 0)->sect = sect;
- lookup("etypelink", 0)->sect = sect;
+ linklookup(ctxt, "typelink", 0)->sect = sect;
+ linklookup(ctxt, "etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1306,8 +1033,8 @@ dodata(void)
sect->align = maxalign(s, SPCLNTAB-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("symtab", 0)->sect = sect;
- lookup("esymtab", 0)->sect = sect;
+ linklookup(ctxt, "symtab", 0)->sect = sect;
+ linklookup(ctxt, "esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1322,8 +1049,8 @@ dodata(void)
sect->align = maxalign(s, SELFROSECT-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- lookup("pclntab", 0)->sect = sect;
- lookup("epclntab", 0)->sect = sect;
+ linklookup(ctxt, "pclntab", 0)->sect = sect;
+ linklookup(ctxt, "epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1366,9 +1093,8 @@ void
textaddress(void)
{
uvlong va;
- Prog *p;
Section *sect;
- Sym *sym, *sub;
+ LSym *sym, *sub;
addsection(&segtext, ".text", 05);
@@ -1376,28 +1102,24 @@ textaddress(void)
// Could parallelize, by assigning to text
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
- sect->align = FuncAlign;
- lookup("text", 0)->sect = sect;
- lookup("etext", 0)->sect = sect;
+ sect->align = funcalign;
+ linklookup(ctxt, "text", 0)->sect = sect;
+ linklookup(ctxt, "etext", 0)->sect = sect;
va = INITTEXT;
sect->vaddr = va;
- for(sym = textp; sym != nil; sym = sym->next) {
+ for(sym = ctxt->textp; sym != nil; sym = sym->next) {
sym->sect = sect;
if(sym->type & SSUB)
continue;
if(sym->align != 0)
va = rnd(va, sym->align);
- else if(sym->text != P)
- va = rnd(va, FuncAlign);
+ else
+ va = rnd(va, funcalign);
sym->value = 0;
- for(sub = sym; sub != S; sub = sub->sub) {
+ for(sub = sym; sub != S; sub = sub->sub)
sub->value += va;
- for(p = sub->text; p != P; p = p->link)
- p->pc += sub->value;
- }
- if(sym->size == 0 && sym->sub != S) {
- cursym = sym;
- }
+ if(sym->size == 0 && sym->sub != S)
+ ctxt->cursym = sym;
va += sym->size;
}
sect->len = va - sect->vaddr;
@@ -1409,7 +1131,7 @@ address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Section *typelink;
- Sym *sym, *sub;
+ LSym *sym, *sub;
uvlong va;
vlong vlen;
@@ -1418,13 +1140,14 @@ address(void)
segtext.vaddr = va;
segtext.fileoff = HEADR;
for(s=segtext.sect; s != nil; s=s->next) {
-//print("%s at %#llux + %#llux\n", s->name, va, (vlong)s->len);
va = rnd(va, s->align);
s->vaddr = va;
va += s->len;
}
segtext.len = va - INITTEXT;
segtext.filelen = segtext.len;
+ if(HEADTYPE == Hnacl)
+ va += 32; // room for the "halt sled"
if(segrodata.sect != nil) {
// align to page boundary so as not to mix
@@ -1451,7 +1174,7 @@ address(void)
segdata.filelen = 0;
if(HEADTYPE == Hwindows)
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
- if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32)
+ if(HEADTYPE == Hplan9)
segdata.fileoff = segtext.fileoff + segtext.filelen;
data = nil;
noptr = nil;
@@ -1485,8 +1208,9 @@ address(void)
pclntab = symtab->next;
for(sym = datap; sym != nil; sym = sym->next) {
- cursym = sym;
- sym->value += sym->sect->vaddr;
+ ctxt->cursym = sym;
+ if(sym->sect != nil)
+ sym->value += sym->sect->vaddr;
for(sub = sym->sub; sub != nil; sub = sub->sub)
sub->value += sym->value;
}
@@ -1498,13 +1222,13 @@ address(void)
xdefine("typelink", SRODATA, typelink->vaddr);
xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
- sym = lookup("gcdata", 0);
+ sym = linklookup(ctxt, "gcdata", 0);
xdefine("egcdata", SRODATA, symaddr(sym) + sym->size);
- lookup("egcdata", 0)->sect = sym->sect;
+ linklookup(ctxt, "egcdata", 0)->sect = sym->sect;
- sym = lookup("gcbss", 0);
+ sym = linklookup(ctxt, "gcbss", 0);
xdefine("egcbss", SRODATA, symaddr(sym) + sym->size);
- lookup("egcbss", 0)->sect = sym->sect;
+ linklookup(ctxt, "egcbss", 0)->sect = sym->sect;
xdefine("symtab", SRODATA, symtab->vaddr);
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
index ab3f4fbd5..da48d3786 100644
--- a/src/cmd/ld/decodesym.c
+++ b/src/cmd/ld/decodesym.c
@@ -11,7 +11,7 @@
// ../gc/reflect.c stuffs in these.
static Reloc*
-decode_reloc(Sym *s, int32 off)
+decode_reloc(LSym *s, int32 off)
{
int i;
@@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off)
return nil;
}
-static Sym*
-decode_reloc_sym(Sym *s, int32 off)
+static LSym*
+decode_reloc_sym(LSym *s, int32 off)
{
Reloc *r;
@@ -67,103 +67,109 @@ decode_inuxi(uchar* p, int sz)
return l;
}
+static int
+commonsize(void)
+{
+ return 7*PtrSize + 8;
+}
+
// Type.commonType.kind
uint8
-decodetype_kind(Sym *s)
+decodetype_kind(LSym *s)
{
return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
}
// Type.commonType.size
vlong
-decodetype_size(Sym *s)
+decodetype_size(LSym *s)
{
return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10
}
// Type.commonType.gc
-Sym*
-decodetype_gc(Sym *s)
+LSym*
+decodetype_gc(LSym *s)
{
return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
}
// Type.ArrayType.elem and Type.SliceType.Elem
-Sym*
-decodetype_arrayelem(Sym *s)
+LSym*
+decodetype_arrayelem(LSym *s)
{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+ return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30
}
vlong
-decodetype_arraylen(Sym *s)
+decodetype_arraylen(LSym *s)
{
- return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize);
+ return decode_inuxi(s->p + commonsize()+PtrSize, PtrSize);
}
// Type.PtrType.elem
-Sym*
-decodetype_ptrelem(Sym *s)
+LSym*
+decodetype_ptrelem(LSym *s)
{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+ return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30
}
// Type.MapType.key, elem
-Sym*
-decodetype_mapkey(Sym *s)
+LSym*
+decodetype_mapkey(LSym *s)
{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+ return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30
}
-Sym*
-decodetype_mapvalue(Sym *s)
+LSym*
+decodetype_mapvalue(LSym *s)
{
- return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38
+ return decode_reloc_sym(s, commonsize()+PtrSize); // 0x20 / 0x38
}
// Type.ChanType.elem
-Sym*
-decodetype_chanelem(Sym *s)
+LSym*
+decodetype_chanelem(LSym *s)
{
- return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
+ return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
int
-decodetype_funcdotdotdot(Sym *s)
+decodetype_funcdotdotdot(LSym *s)
{
- return s->p[CommonSize];
+ return s->p[commonsize()];
}
// Type.FuncType.in.len
int
-decodetype_funcincount(Sym *s)
+decodetype_funcincount(LSym *s)
{
- return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize);
}
int
-decodetype_funcoutcount(Sym *s)
+decodetype_funcoutcount(LSym *s)
{
- return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize);
+ return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize);
}
-Sym*
-decodetype_funcintype(Sym *s, int i)
+LSym*
+decodetype_funcintype(LSym *s, int i)
{
Reloc *r;
- r = decode_reloc(s, CommonSize + PtrSize);
+ r = decode_reloc(s, commonsize() + PtrSize);
if (r == nil)
return nil;
return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
-Sym*
-decodetype_funcouttype(Sym *s, int i)
+LSym*
+decodetype_funcouttype(LSym *s, int i)
{
Reloc *r;
- r = decode_reloc(s, CommonSize + 2*PtrSize + 2*IntSize);
+ r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize);
if (r == nil)
return nil;
return decode_reloc_sym(r->sym, r->add + i * PtrSize);
@@ -171,22 +177,25 @@ decodetype_funcouttype(Sym *s, int i)
// Type.StructType.fields.Slice::len
int
-decodetype_structfieldcount(Sym *s)
+decodetype_structfieldcount(LSym *s)
+{
+ return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
+}
+
+static int
+structfieldsize(void)
{
- return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
+ return 5*PtrSize;
}
-enum {
- StructFieldSize = 5*PtrSize
-};
// Type.StructType.fields[]-> name, typ and offset.
char*
-decodetype_structfieldname(Sym *s, int i)
+decodetype_structfieldname(LSym *s, int i)
{
Reloc *r;
// go.string."foo" 0x28 / 0x40
- s = decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize);
+ s = decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize());
if (s == nil) // embedded structs have a nil name.
return nil;
r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0
@@ -195,21 +204,21 @@ decodetype_structfieldname(Sym *s, int i)
return (char*) r->sym->p + r->add; // the c-string
}
-Sym*
-decodetype_structfieldtype(Sym *s, int i)
+LSym*
+decodetype_structfieldtype(LSym *s, int i)
{
- return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize);
+ return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize);
}
vlong
-decodetype_structfieldoffs(Sym *s, int i)
+decodetype_structfieldoffs(LSym *s, int i)
{
- return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize);
}
// InterfaceTYpe.methods.len
vlong
-decodetype_ifacemethodcount(Sym *s)
+decodetype_ifacemethodcount(LSym *s)
{
- return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
index 2adda25f2..8135bd549 100644
--- a/src/cmd/ld/doc.go
+++ b/src/cmd/ld/doc.go
@@ -43,6 +43,8 @@ Options new in this version:
Write NetBSD ELF binaries (default when $GOOS is netbsd)
-H openbsd (only in 6l/8l)
Write OpenBSD ELF binaries (default when $GOOS is openbsd)
+ -H solaris (only in 6l)
+ Write Solaris ELF binaries (default when $GOOS is solaris)
-H windows (only in 6l/8l)
Write Windows PE32+ Console binaries (default when $GOOS is windows)
-H windowsgui (only in 6l/8l)
@@ -58,6 +60,8 @@ Options new in this version:
Omit the symbol table and debug information.
-V
Print the linker version.
+ -w
+ Omit the DWARF symbol table.
-X symbol value
Set the value of an otherwise uninitialized string variable.
The symbol name should be of the form importpath.name,
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index c832bcc94..cc77b45cd 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -27,19 +27,19 @@
static vlong abbrevo;
static vlong abbrevsize;
-static Sym* abbrevsym;
+static LSym* abbrevsym;
static vlong abbrevsympos;
static vlong lineo;
static vlong linesize;
-static Sym* linesym;
+static LSym* linesym;
static vlong linesympos;
static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize;
-static Sym* infosym;
+static LSym* infosym;
static vlong infosympos;
static vlong frameo;
static vlong framesize;
-static Sym* framesym;
+static LSym* framesym;
static vlong framesympos;
static vlong pubnameso;
static vlong pubnamessize;
@@ -50,19 +50,19 @@ static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
-static Sym *infosec;
+static LSym *infosec;
static vlong inforeloco;
static vlong inforelocsize;
-static Sym *arangessec;
+static LSym *arangessec;
static vlong arangesreloco;
static vlong arangesrelocsize;
-static Sym *linesec;
+static LSym *linesec;
static vlong linereloco;
static vlong linerelocsize;
-static Sym *framesec;
+static LSym *framesec;
static vlong framereloco;
static vlong framerelocsize;
@@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name)
}
static void
-adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend)
+adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
{
Reloc *r;
@@ -603,7 +603,7 @@ adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend)
r->xsym = sym;
r->off = cpos() - offsetbase;
r->siz = siz;
- r->type = D_ADDR;
+ r->type = R_ADDR;
r->add = addend;
r->xadd = addend;
if(iself && thechar == '6')
@@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
switch(form) {
case DW_FORM_addr: // address
if(linkmode == LinkExternal) {
- value -= ((Sym*)data)->value;
- adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ value -= ((LSym*)data)->value;
+ adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
cput(1+PtrSize);
cput(DW_OP_addr);
if(linkmode == LinkExternal) {
- value -= ((Sym*)data)->value;
- adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ value -= ((LSym*)data)->value;
+ adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs)
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
// location expression that evals to a const.
static void
-newabslocexprattr(DWDie *die, vlong addr, Sym *sym)
+newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
{
newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
@@ -864,12 +864,12 @@ enum {
static DWDie* defptrto(DWDie *dwtype); // below
// Lookup predefined types
-static Sym*
+static LSym*
lookup_or_diag(char *n)
{
- Sym *s;
+ LSym *s;
- s = rlookup(n, 0);
+ s = linkrlookup(ctxt, n, 0);
if (s == nil || s->size == 0) {
diag("dwarf: missing type: %s", n);
errorexit();
@@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def)
// Define gotype, for composite ones recurse into constituents.
static DWDie*
-defgotype(Sym *gotype)
+defgotype(LSym *gotype)
{
DWDie *die, *fld;
- Sym *s;
+ LSym *s;
char *name, *f;
uint8 kind;
vlong bytesize;
@@ -1099,21 +1099,29 @@ defptrto(DWDie *dwtype)
}
// Copies src's children into dst. Copies attributes by value.
-// DWAttr.data is copied as pointer only.
+// DWAttr.data is copied as pointer only. If except is one of
+// the top-level children, it will not be copied.
static void
-copychildren(DWDie *dst, DWDie *src)
+copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except)
{
DWDie *c;
DWAttr *a;
for (src = src->child; src != nil; src = src->link) {
+ if(src == except)
+ continue;
c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
for (a = src->attr; a != nil; a = a->link)
newattr(c, a->atr, a->cls, a->value, a->data);
- copychildren(c, src);
+ copychildrenexcept(c, src, nil);
}
reverselist(&dst->child);
}
+static void
+copychildren(DWDie *dst, DWDie *src)
+{
+ copychildrenexcept(dst, src, nil);
+}
// Search children (assumed to have DW_TAG_member) for the one named
// field and set its DW_AT_type to dwtype
@@ -1253,7 +1261,10 @@ synthesizemaptypes(DWDie *die)
mkinternaltypename("bucket",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
- copychildren(dwhb, bucket);
+ // Copy over all fields except the field "data" from the generic bucket.
+ // "data" will be replaced with keys/values below.
+ copychildrenexcept(dwhb, bucket, find(bucket, "data"));
+
fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys");
newrefattr(fld, DW_AT_type, dwhk);
newmemberoffsetattr(fld, BucketSize + PtrSize);
@@ -1335,7 +1346,7 @@ synthesizechantypes(DWDie *die)
// For use with pass.c::genasmsym
static void
-defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
+defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
{
DWDie *dv, *dt;
@@ -1371,284 +1382,37 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
newrefattr(dv, DW_AT_type, dt);
}
-// TODO(lvd) For now, just append them all to the first compilation
-// unit (that should be main), in the future distribute them to the
-// appropriate compilation units.
static void
movetomodule(DWDie *parent)
{
DWDie *die;
- for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
+ die = dwroot.child->child;
+ while(die->link != nil)
+ die = die->link;
die->link = parent->child;
}
-/*
- * Filename fragments for the line history stack.
- */
-
-static char **ftab;
-static int ftabsize;
-
-void
-dwarfaddfrag(int n, char *frag)
-{
- int s;
-
- if (n >= ftabsize) {
- s = ftabsize;
- ftabsize = 1 + n + (n >> 2);
- ftab = erealloc(ftab, ftabsize * sizeof(ftab[0]));
- memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
- }
-
- if (*frag == '<')
- frag++;
- ftab[n] = frag;
-}
-
-// Returns a malloc'ed string, piecewise copied from the ftab.
-static char *
-decodez(char *s)
-{
- int len, o;
- char *ss, *f;
- char *r, *rb, *re;
-
- len = 0;
- ss = s + 1; // first is 0
- while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
- if (o < 0 || o >= ftabsize) {
- diag("dwarf: corrupt z entry");
- return 0;
- }
- f = ftab[o];
- if (f == nil) {
- diag("dwarf: corrupt z entry");
- return 0;
- }
- len += strlen(f) + 1; // for the '/'
- ss += 2;
- }
-
- if (len == 0)
- return 0;
-
- r = malloc(len + 1);
- if(r == nil) {
- diag("out of memory");
- errorexit();
- }
- rb = r;
- re = rb + len + 1;
-
- s++;
- while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
- f = ftab[o];
- if (rb == r || rb[-1] == '/')
- rb = seprint(rb, re, "%s", f);
- else
- rb = seprint(rb, re, "/%s", f);
- s += 2;
- }
- return r;
-}
-
-/*
- * The line history itself
- */
-
-static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
-static int histfilesize;
-static int histfilecap;
-
+// If the pcln table contains runtime/string.goc, use that to set gdbscript path.
static void
-clearhistfile(void)
+finddebugruntimepath(LSym *s)
{
int i;
+ char *p;
+ LSym *f;
+
+ if(gdbscript[0] != '\0')
+ return;
- // [0] holds "<eof>"
- for (i = 1; i < histfilesize; i++)
- free(histfile[i]);
- histfilesize = 0;
-}
-
-static int
-addhistfile(char *zentry)
-{
- char *fname;
-
- if (histfilesize == histfilecap) {
- histfilecap = 2 * histfilecap + 2;
- histfile = erealloc(histfile, histfilecap * sizeof(char*));
- }
- if (histfilesize == 0)
- histfile[histfilesize++] = "<eof>";
-
- fname = decodez(zentry);
-// print("addhistfile %d: %s\n", histfilesize, fname);
- if (fname == 0)
- return -1;
-
- // Don't fill with duplicates (check only top one).
- if (strcmp(fname, histfile[histfilesize-1]) == 0) {
- free(fname);
- return histfilesize - 1;
- }
-
- histfile[histfilesize++] = fname;
- return histfilesize - 1;
-}
-
-// if the histfile stack contains ..../runtime/runtime_defs.go
-// use that to set gdbscript
-static void
-finddebugruntimepath(void)
-{
- int i, l;
- char *c;
-
- for (i = 1; i < histfilesize; i++) {
- if ((c = strstr(histfile[i], "runtime/zruntime_defs")) != nil) {
- l = c - histfile[i];
- memmove(gdbscript, histfile[i], l);
- memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1);
- break;
- }
- }
-}
-
-// Go's runtime C sources are sane, and Go sources nest only 1 level,
-// so a handful would be plenty, if it weren't for the fact that line
-// directives can push an unlimited number of them.
-static struct {
- int file;
- vlong line;
-} *includestack;
-static int includestacksize;
-static int includetop;
-static vlong absline;
-
-typedef struct Linehist Linehist;
-struct Linehist {
- Linehist *link;
- vlong absline;
- vlong line;
- int file;
-};
-
-static Linehist *linehist;
-
-static void
-checknesting(void)
-{
- if (includetop < 0) {
- diag("dwarf: corrupt z stack");
- errorexit();
- }
- if (includetop >= includestacksize) {
- includestacksize += 1;
- includestacksize <<= 2;
-// print("checknesting: growing to %d\n", includestacksize);
- includestack = erealloc(includestack, includestacksize * sizeof *includestack);
- }
-}
-
-/*
- * Return false if the a->link chain contains no history, otherwise
- * returns true and finds z and Z entries in the Auto list (of a
- * Prog), and resets the history stack
- */
-static int
-inithist(Auto *a)
-{
- Linehist *lh;
-
- for (; a; a = a->link)
- if (a->type == D_FILE)
+ for(i=0; i<s->pcln->nfile; i++) {
+ f = s->pcln->file[i];
+ if((p = strstr(f->name, "runtime/string.goc")) != nil) {
+ *p = '\0';
+ snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name);
+ *p = 'r';
break;
- if (a==nil)
- return 0;
-
- // We have a new history. They are guaranteed to come completely
- // at the beginning of the compilation unit.
- if (a->aoffset != 1) {
- diag("dwarf: stray 'z' with offset %d", a->aoffset);
- return 0;
- }
-
- // Clear the history.
- clearhistfile();
- includetop = 0;
- checknesting();
- includestack[includetop].file = 0;
- includestack[includetop].line = -1;
- absline = 0;
- while (linehist != nil) {
- lh = linehist->link;
- free(linehist);
- linehist = lh;
- }
-
- // Construct the new one.
- for (; a; a = a->link) {
- if (a->type == D_FILE) { // 'z'
- int f = addhistfile(a->asym->name);
- if (f < 0) { // pop file
- includetop--;
- checknesting();
- } else { // pushed a file (potentially same)
- includestack[includetop].line += a->aoffset - absline;
- includetop++;
- checknesting();
- includestack[includetop].file = f;
- includestack[includetop].line = 1;
- }
- absline = a->aoffset;
- } else if (a->type == D_FILE1) { // 'Z'
- // We could just fixup the current
- // linehist->line, but there doesn't appear to
- // be a guarantee that every 'Z' is preceded
- // by its own 'z', so do the safe thing and
- // update the stack and push a new Linehist
- // entry
- includestack[includetop].line = a->aoffset;
- } else
- continue;
- if (linehist == 0 || linehist->absline != absline) {
- Linehist* lh = malloc(sizeof *lh);
- if(lh == nil) {
- diag("out of memory");
- errorexit();
- }
- lh->link = linehist;
- lh->absline = absline;
- linehist = lh;
}
- linehist->file = includestack[includetop].file;
- linehist->line = includestack[includetop].line;
}
- return 1;
-}
-
-static Linehist *
-searchhist(vlong absline)
-{
- Linehist *lh;
-
- for (lh = linehist; lh; lh = lh->link)
- if (lh->absline <= absline)
- break;
- return lh;
-}
-
-static int
-guesslang(char *s)
-{
- if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
- return DW_LANG_Go;
-
- return DW_LANG_C;
}
/*
@@ -1659,7 +1423,7 @@ guesslang(char *s)
enum {
LINE_BASE = -1,
LINE_RANGE = 4,
- OPCODE_BASE = 5
+ OPCODE_BASE = 10
};
static void
@@ -1719,7 +1483,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length)
+flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
@@ -1744,147 +1508,129 @@ flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_len
static void
writelines(void)
{
- Prog *q;
- Sym *s, *epcs;
+ LSym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
- vlong pc, epc, lc, llc, lline;
- int currfile;
- int i, lang, da, dt;
- Linehist *lh;
+ vlong pc, epc;
+ int i, lang, da, dt, line, file;
DWDie *dwinfo, *dwfunc, *dwvar, **dws;
DWDie *varhash[HASHSIZE];
char *n, *nn;
+ Pciter pcfile, pcline;
+ LSym **files, *f;
if(linesec == S)
- linesec = lookup(".dwarfline", 0);
+ linesec = linklookup(ctxt, ".dwarfline", 0);
linesec->nr = 0;
unitstart = -1;
headerend = -1;
- pc = 0;
epc = 0;
epcs = S;
- lc = 1;
- llc = 1;
- currfile = -1;
lineo = cpos();
dwinfo = nil;
+
+ flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
+ unitstart = cpos();
+
+ lang = DW_LANG_Go;
+
+ s = ctxt->textp;
+
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go"));
+ newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
+ newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
+ newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
+
+ // Write .debug_line Line Number Program Header (sec 6.2.4)
+ // Fields marked with (*) must be changed for 64-bit dwarf
+ LPUT(0); // unit_length (*), will be filled in by flushunit.
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(0); // header_length (*), filled in by flushunit.
+ // cpos == unitstart + 4 + 2 + 4
+ cput(1); // minimum_instruction_length
+ cput(1); // default_is_stmt
+ cput(LINE_BASE); // line_base
+ cput(LINE_RANGE); // line_range
+ cput(OPCODE_BASE); // opcode_base
+ cput(0); // standard_opcode_lengths[1]
+ cput(1); // standard_opcode_lengths[2]
+ cput(1); // standard_opcode_lengths[3]
+ cput(1); // standard_opcode_lengths[4]
+ cput(1); // standard_opcode_lengths[5]
+ cput(0); // standard_opcode_lengths[6]
+ cput(0); // standard_opcode_lengths[7]
+ cput(0); // standard_opcode_lengths[8]
+ cput(1); // standard_opcode_lengths[9]
+ cput(0); // include_directories (empty)
+
+ files = emallocz(ctxt->nhistfile*sizeof files[0]);
+ for(f = ctxt->filesyms; f != nil; f = f->next)
+ files[f->value-1] = f;
+
+ for(i=0; i<ctxt->nhistfile; i++) {
+ strnput(files[i]->name, strlen(files[i]->name) + 4);
+ // 4 zeros: the string termination + 3 fields.
+ }
+
+ cput(0); // terminate file_names.
+ headerend = cpos();
+
+ cput(0); // start extended opcode
+ uleb128put(1 + PtrSize);
+ cput(DW_LNE_set_address);
+
+ pc = s->value;
+ line = 1;
+ file = 1;
+ if(linkmode == LinkExternal)
+ adddwarfrel(linesec, s, lineo, PtrSize, 0);
+ else
+ addrput(pc);
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
- if(s->text == P)
- continue;
-
- // Look for history stack. If we find one,
- // we're entering a new compilation unit
-
- if (inithist(s->autom)) {
- flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
- unitstart = cpos();
-
- if(debug['v'] > 1) {
- print("dwarf writelines found %s\n", histfile[1]);
- Linehist* lh;
- for (lh = linehist; lh; lh = lh->link)
- print("\t%8lld: [%4lld]%s\n",
- lh->absline, lh->line, histfile[lh->file]);
- }
-
- lang = guesslang(histfile[1]);
- finddebugruntimepath();
-
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup(histfile[1]));
- newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
- newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
- newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, (char*)s);
-
- // Write .debug_line Line Number Program Header (sec 6.2.4)
- // Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in by flushunit.
- WPUT(2); // dwarf version (appendix F)
- LPUT(0); // header_length (*), filled in by flushunit.
- // cpos == unitstart + 4 + 2 + 4
- cput(1); // minimum_instruction_length
- cput(1); // default_is_stmt
- cput(LINE_BASE); // line_base
- cput(LINE_RANGE); // line_range
- cput(OPCODE_BASE); // opcode_base (we only use 1..4)
- cput(0); // standard_opcode_lengths[1]
- cput(1); // standard_opcode_lengths[2]
- cput(1); // standard_opcode_lengths[3]
- cput(1); // standard_opcode_lengths[4]
- cput(0); // include_directories (empty)
-
- for (i=1; i < histfilesize; i++) {
- strnput(histfile[i], strlen(histfile[i]) + 4);
- // 4 zeros: the string termination + 3 fields.
- }
-
- cput(0); // terminate file_names.
- headerend = cpos();
-
- pc = s->text->pc;
- epc = pc;
- epcs = s;
- currfile = 1;
- lc = 1;
- llc = 1;
-
- cput(0); // start extended opcode
- uleb128put(1 + PtrSize);
- cput(DW_LNE_set_address);
-
- if(linkmode == LinkExternal)
- adddwarfrel(linesec, s, lineo, PtrSize, 0);
- else
- addrput(pc);
- }
- if(s->text == nil)
- continue;
-
- if (unitstart < 0) {
- diag("dwarf: reachable code before seeing any history: %P", s->text);
- continue;
- }
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ s = ctxt->cursym;
dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
epc = s->value + s->size;
+ epcs = s;
newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s);
if (s->version == 0)
newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
- if(s->text->link == nil)
+ if(s->pcln == nil)
continue;
- for(q = s->text; q != P; q = q->link) {
- lh = searchhist(q->line);
- if (lh == nil) {
- diag("dwarf: corrupt history or bad absolute line: %P", q);
+ finddebugruntimepath(s);
+
+ pciterinit(ctxt, &pcfile, &s->pcln->pcfile);
+ pciterinit(ctxt, &pcline, &s->pcln->pcline);
+ epc = pc;
+ while(!pcfile.done && !pcline.done) {
+ if(epc - s->value >= pcfile.nextpc) {
+ pciternext(&pcfile);
continue;
}
-
- if (lh->file < 1) { // 0 is the past-EOF entry.
- // diag("instruction with line number past EOF in %s: %P", histfile[1], q);
+ if(epc - s->value >= pcline.nextpc) {
+ pciternext(&pcline);
continue;
}
- lline = lh->line + q->line - lh->absline;
- if (debug['v'] > 1)
- print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
-
- if (q->line == lc)
- continue;
- if (currfile != lh->file) {
- currfile = lh->file;
+ if(file != pcfile.value) {
cput(DW_LNS_set_file);
- uleb128put(currfile);
+ uleb128put(pcfile.value);
+ file = pcfile.value;
}
- putpclcdelta(q->pc - pc, lline - llc);
- pc = q->pc;
- lc = q->line;
- llc = lline;
+ putpclcdelta(s->value + pcline.pc - pc, pcline.value - line);
+
+ pc = s->value + pcline.pc;
+ line = pcline.value;
+ if(pcfile.nextpc < pcline.nextpc)
+ epc = pcfile.nextpc;
+ else
+ epc = pcline.nextpc;
+ epc += s->value;
}
da = 0;
@@ -1892,11 +1638,11 @@ writelines(void)
memset(varhash, 0, sizeof varhash);
for(a = s->autom; a; a = a->link) {
switch (a->type) {
- case D_AUTO:
+ case A_AUTO:
dt = DW_ABRV_AUTO;
offs = a->aoffset - PtrSize;
break;
- case D_PARAM:
+ case A_PARAM:
dt = DW_ABRV_PARAM;
offs = a->aoffset;
break;
@@ -1970,12 +1716,12 @@ putpccfadelta(vlong deltapc, vlong cfa)
static void
writeframes(void)
{
- Prog *p, *q;
- Sym *s;
- vlong fdeo, fdesize, pad, cfa, pc;
+ LSym *s;
+ vlong fdeo, fdesize, pad;
+ Pciter pcsp;
if(framesec == S)
- framesec = lookup(".dwarfframe", 0);
+ framesec = linklookup(ctxt, ".dwarfframe", 0);
framesec->nr = 0;
frameo = cpos();
@@ -2003,9 +1749,9 @@ writeframes(void)
}
strnput("", pad);
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- s = cursym;
- if(s->text == nil)
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ s = ctxt->cursym;
+ if(s->pcln == nil)
continue;
fdeo = cpos();
@@ -2015,17 +1761,8 @@ writeframes(void)
addrput(0); // initial location
addrput(0); // address range
- cfa = PtrSize; // CFA starts at sp+PtrSize
- p = s->text;
- pc = p->pc;
-
- for(q = p; q->link != P; q = q->link) {
- if (q->spadj == 0)
- continue;
- cfa += q->spadj;
- putpccfadelta(q->link->pc - pc, cfa);
- pc = q->link->pc;
- }
+ for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp))
+ putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value);
fdesize = cpos() - fdeo - 4; // exclude the length field.
pad = rnd(fdesize, PtrSize) - fdesize;
@@ -2041,7 +1778,7 @@ writeframes(void)
}
else {
LPUT(0);
- addrput(p->pc);
+ addrput(s->value);
}
addrput(s->size);
cseek(fdeo + 4 + fdesize);
@@ -2067,11 +1804,11 @@ writeinfo(void)
fwdcount = 0;
if (infosec == S)
- infosec = lookup(".dwarfinfo", 0);
+ infosec = linklookup(ctxt, ".dwarfinfo", 0);
infosec->nr = 0;
if(arangessec == S)
- arangessec = lookup(".dwarfaranges", 0);
+ arangessec = linklookup(ctxt, ".dwarfaranges", 0);
arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
@@ -2204,7 +1941,7 @@ writearanges(void)
strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
if(linkmode == LinkExternal)
- adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value);
+ adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
else
addrput(b->value);
@@ -2239,7 +1976,7 @@ align(vlong size)
}
static vlong
-writedwarfreloc(Sym* s)
+writedwarfreloc(LSym* s)
{
int i;
vlong start;
@@ -2408,7 +2145,7 @@ enum
vlong elfstrdbg[NElfStrDbg];
void
-dwarfaddshstrings(Sym *shstrtab)
+dwarfaddshstrings(LSym *shstrtab)
{
if(debug['w']) // disable dwarf
return;
@@ -2438,16 +2175,16 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
}
- infosym = lookup(".debug_info", 0);
+ infosym = linklookup(ctxt, ".debug_info", 0);
infosym->hide = 1;
- abbrevsym = lookup(".debug_abbrev", 0);
+ abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
abbrevsym->hide = 1;
- linesym = lookup(".debug_line", 0);
+ linesym = linklookup(ctxt, ".debug_line", 0);
linesym->hide = 1;
- framesym = lookup(".debug_frame", 0);
+ framesym = linklookup(ctxt, ".debug_frame", 0);
framesym->hide = 1;
}
}
@@ -2616,31 +2353,37 @@ dwarfaddmachoheaders(void)
ms = newMachoSeg("__DWARF", nsect);
ms->fileoffset = fakestart;
ms->filesize = abbrevo-fakestart;
+ ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff;
msect = newMachoSect(ms, "__debug_abbrev", "__DWARF");
msect->off = abbrevo;
msect->size = abbrevsize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_line", "__DWARF");
msect->off = lineo;
msect->size = linesize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_frame", "__DWARF");
msect->off = frameo;
msect->size = framesize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_info", "__DWARF");
msect->off = infoo;
msect->size = infosize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
if (pubnamessize > 0) {
msect = newMachoSect(ms, "__debug_pubnames", "__DWARF");
msect->off = pubnameso;
msect->size = pubnamessize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
@@ -2648,6 +2391,7 @@ dwarfaddmachoheaders(void)
msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
msect->off = pubtypeso;
msect->size = pubtypessize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
@@ -2655,6 +2399,7 @@ dwarfaddmachoheaders(void)
msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
msect->off = arangeso;
msect->size = arangessize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
@@ -2663,6 +2408,7 @@ dwarfaddmachoheaders(void)
msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
msect->off = gdbscripto;
msect->size = gdbscriptsize;
+ msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
index f0df2f9b1..32db36dcd 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -3,12 +3,6 @@
// license that can be found in the LICENSE file.
/*
- * Register 'f' symbol file fragments. Doing this while parsing the
- * .6 input saves a pass over the symbol table later.
- */
-void dwarfaddfrag(int n, char* frag);
-
-/*
* Emit debug_abbrevs, debug_info and debug_line sections to current
* offset in cout.
*/
@@ -19,7 +13,7 @@ void dwarfemitdebugsections(void);
* s[ection]h[eader]str[ing]tab. Prerequisite for
* dwarfaddelfheaders().
*/
-void dwarfaddshstrings(Sym *shstrtab);
+void dwarfaddshstrings(LSym *shstrtab);
/*
* Add section headers pointing to the sections emitted in
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 6b3638ec5..0555cf46a 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -55,8 +55,8 @@ elfinit(void)
// 32-bit architectures
case '5':
- // we only use EABI on linux/arm
- if(HEADTYPE == Hlinux)
+ // we use EABI on both linux/arm and freebsd/arm.
+ if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd)
hdr.flags = 0x5000002; // has entry point, Version5 EABI
// fallthrough
default:
@@ -287,35 +287,35 @@ elfhash(uchar *name)
}
void
-elfwritedynent(Sym *s, int tag, uint64 val)
+elfwritedynent(LSym *s, int tag, uint64 val)
{
if(elf64) {
- adduint64(s, tag);
- adduint64(s, val);
+ adduint64(ctxt, s, tag);
+ adduint64(ctxt, s, val);
} else {
- adduint32(s, tag);
- adduint32(s, val);
+ adduint32(ctxt, s, tag);
+ adduint32(ctxt, s, val);
}
}
void
-elfwritedynentsym(Sym *s, int tag, Sym *t)
+elfwritedynentsym(LSym *s, int tag, LSym *t)
{
if(elf64)
- adduint64(s, tag);
+ adduint64(ctxt, s, tag);
else
- adduint32(s, tag);
- addaddr(s, t);
+ adduint32(ctxt, s, tag);
+ addaddr(ctxt, s, t);
}
void
-elfwritedynentsymsize(Sym *s, int tag, Sym *t)
+elfwritedynentsymsize(LSym *s, int tag, LSym *t)
{
if(elf64)
- adduint64(s, tag);
+ adduint64(ctxt, s, tag);
else
- adduint32(s, tag);
- addsize(s, t);
+ adduint32(ctxt, s, tag);
+ addsize(ctxt, s, t);
}
int
@@ -355,7 +355,7 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)
sh->addralign = 4;
sh->addr = startva + resoff - n;
sh->off = resoff - n;
- sh->size = n;
+ sh->size = n - resoff % 4;
return n;
}
@@ -388,7 +388,7 @@ elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
{
int n;
- n = ELF_NOTE_NETBSD_NAMESZ + ELF_NOTE_NETBSD_DESCSZ + 1;
+ n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4);
return elfnote(sh, startva, resoff, n);
}
@@ -561,7 +561,7 @@ haveaux:
void
elfdynhash(void)
{
- Sym *s, *sy, *dynstr;
+ LSym *s, *sy, *dynstr;
int i, j, nbucket, b, nfile;
uint32 hc, *chain, *buckets;
int nsym;
@@ -575,7 +575,7 @@ elfdynhash(void)
return;
nsym = nelfsym;
- s = lookup(".hash", 0);
+ s = linklookup(ctxt, ".hash", 0);
s->type = SELFROSECT;
s->reachable = 1;
@@ -591,14 +591,14 @@ elfdynhash(void)
chain = malloc(nsym * sizeof chain[0]);
buckets = malloc(nbucket * sizeof buckets[0]);
if(need == nil || chain == nil || buckets == nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("out of memory");
errorexit();
}
memset(need, 0, nsym * sizeof need[0]);
memset(chain, 0, nsym * sizeof chain[0]);
memset(buckets, 0, nbucket * sizeof buckets[0]);
- for(sy=allsym; sy!=S; sy=sy->allsym) {
+ for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
if (sy->dynid <= 0)
continue;
@@ -613,70 +613,87 @@ elfdynhash(void)
buckets[b] = sy->dynid;
}
- adduint32(s, nbucket);
- adduint32(s, nsym);
+ adduint32(ctxt, s, nbucket);
+ adduint32(ctxt, s, nsym);
for(i = 0; i<nbucket; i++)
- adduint32(s, buckets[i]);
+ adduint32(ctxt, s, buckets[i]);
for(i = 0; i<nsym; i++)
- adduint32(s, chain[i]);
+ adduint32(ctxt, s, chain[i]);
free(chain);
free(buckets);
// version symbols
- dynstr = lookup(".dynstr", 0);
- s = lookup(".gnu.version_r", 0);
+ dynstr = linklookup(ctxt, ".dynstr", 0);
+ s = linklookup(ctxt, ".gnu.version_r", 0);
i = 2;
nfile = 0;
for(l=needlib; l; l=l->next) {
nfile++;
// header
- adduint16(s, 1); // table version
+ adduint16(ctxt, s, 1); // table version
j = 0;
for(x=l->aux; x; x=x->next)
j++;
- adduint16(s, j); // aux count
- adduint32(s, addstring(dynstr, l->file)); // file string offset
- adduint32(s, 16); // offset from header to first aux
+ adduint16(ctxt, s, j); // aux count
+ adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset
+ adduint32(ctxt, s, 16); // offset from header to first aux
if(l->next)
- adduint32(s, 16+j*16); // offset from this header to next
+ adduint32(ctxt, s, 16+j*16); // offset from this header to next
else
- adduint32(s, 0);
+ adduint32(ctxt, s, 0);
for(x=l->aux; x; x=x->next) {
x->num = i++;
// aux struct
- adduint32(s, elfhash((uchar*)x->vers)); // hash
- adduint16(s, 0); // flags
- adduint16(s, x->num); // other - index we refer to this by
- adduint32(s, addstring(dynstr, x->vers)); // version string offset
+ adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash
+ adduint16(ctxt, s, 0); // flags
+ adduint16(ctxt, s, x->num); // other - index we refer to this by
+ adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset
if(x->next)
- adduint32(s, 16); // offset from this aux to next
+ adduint32(ctxt, s, 16); // offset from this aux to next
else
- adduint32(s, 0);
+ adduint32(ctxt, s, 0);
}
}
// version references
- s = lookup(".gnu.version", 0);
+ s = linklookup(ctxt, ".gnu.version", 0);
for(i=0; i<nsym; i++) {
if(i == 0)
- adduint16(s, 0); // first entry - no symbol
+ adduint16(ctxt, s, 0); // first entry - no symbol
else if(need[i] == nil)
- adduint16(s, 1); // global
+ adduint16(ctxt, s, 1); // global
else
- adduint16(s, need[i]->num);
+ adduint16(ctxt, s, need[i]->num);
}
free(need);
- s = lookup(".dynamic", 0);
+ s = linklookup(ctxt, ".dynamic", 0);
elfverneed = nfile;
if(elfverneed) {
- elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
+ elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
elfwritedynent(s, DT_VERNEEDNUM, nfile);
- elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
+ elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
+ }
+
+ if(thechar == '6') {
+ sy = linklookup(ctxt, ".rela.plt", 0);
+ if(sy->size > 0) {
+ elfwritedynent(s, DT_PLTREL, DT_RELA);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
+ elfwritedynentsym(s, DT_JMPREL, sy);
+ }
+ } else {
+ sy = linklookup(ctxt, ".rel.plt", 0);
+ if(sy->size > 0) {
+ elfwritedynent(s, DT_PLTREL, DT_REL);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
+ elfwritedynentsym(s, DT_JMPREL, sy);
+ }
}
+
elfwritedynent(s, DT_NULL, 0);
}
@@ -797,19 +814,19 @@ elfshreloc(Section *sect)
snprint(buf, sizeof buf, "%s%s", prefix, sect->name);
sh = elfshname(buf);
sh->type = typ;
- sh->entsize = PtrSize*(2+(typ==SHT_RELA));
+ sh->entsize = RegSize*(2+(typ==SHT_RELA));
sh->link = elfshname(".symtab")->shnum;
sh->info = sect->elfsect->shnum;
sh->off = sect->reloff;
sh->size = sect->rellen;
- sh->addralign = PtrSize;
+ sh->addralign = RegSize;
return sh;
}
void
-elfrelocsect(Section *sect, Sym *first)
+elfrelocsect(Section *sect, LSym *first)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
Reloc *r;
@@ -834,7 +851,7 @@ elfrelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
- cursym = sym;
+ ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@@ -861,7 +878,7 @@ elfemitreloc(void)
while(cpos()&7)
cput(0);
- elfrelocsect(segtext.sect, textp);
+ elfrelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
elfrelocsect(sect, datap);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
@@ -873,13 +890,13 @@ elfemitreloc(void)
void
doelf(void)
{
- Sym *s, *shstrtab, *dynstr;
+ LSym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
- shstrtab = lookup(".shstrtab", 0);
+ shstrtab = linklookup(ctxt, ".shstrtab", 0);
shstrtab->type = SELFROSECT;
shstrtab->reachable = 1;
@@ -969,7 +986,7 @@ doelf(void)
addstring(shstrtab, ".gnu.version_r");
/* dynamic symbol table - first entry all zeros */
- s = lookup(".dynsym", 0);
+ s = linklookup(ctxt, ".dynsym", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(thechar == '6')
@@ -978,7 +995,7 @@ doelf(void)
s->size += ELF32SYMSIZE;
/* dynamic string table */
- s = lookup(".dynstr", 0);
+ s = linklookup(ctxt, ".dynstr", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(s->size == 0)
@@ -987,87 +1004,81 @@ doelf(void)
/* relocation table */
if(thechar == '6')
- s = lookup(".rela", 0);
+ s = linklookup(ctxt, ".rela", 0);
else
- s = lookup(".rel", 0);
+ s = linklookup(ctxt, ".rel", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* global offset table */
- s = lookup(".got", 0);
+ s = linklookup(ctxt, ".got", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/* hash */
- s = lookup(".hash", 0);
+ s = linklookup(ctxt, ".hash", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".got.plt", 0);
+ s = linklookup(ctxt, ".got.plt", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
- s = lookup(".plt", 0);
+ s = linklookup(ctxt, ".plt", 0);
s->reachable = 1;
s->type = SELFRXSECT;
elfsetupplt();
if(thechar == '6')
- s = lookup(".rela.plt", 0);
+ s = linklookup(ctxt, ".rela.plt", 0);
else
- s = lookup(".rel.plt", 0);
+ s = linklookup(ctxt, ".rel.plt", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".gnu.version", 0);
+ s = linklookup(ctxt, ".gnu.version", 0);
s->reachable = 1;
s->type = SELFROSECT;
- s = lookup(".gnu.version_r", 0);
+ s = linklookup(ctxt, ".gnu.version_r", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* define dynamic elf table */
- s = lookup(".dynamic", 0);
+ s = linklookup(ctxt, ".dynamic", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/*
* .dynamic table
*/
- elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
- elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
+ elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
+ elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
if(thechar == '6')
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
else
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
- elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
- elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
+ elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
+ elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
if(thechar == '6') {
- elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
- elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
+ elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
+ elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
} else {
- elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
- elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
+ elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
+ elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
}
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
- if(thechar == '6') {
- elfwritedynent(s, DT_PLTREL, DT_RELA);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
- } else {
- elfwritedynent(s, DT_PLTREL, DT_REL);
- elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
- elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
- }
-
+ // Solaris dynamic linker can't handle an empty .rela.plt if
+ // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
+ // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
+ // size of .rel(a).plt section.
elfwritedynent(s, DT_DEBUG, 0);
// Do not write DT_NULL. elfdynhash will finish it.
@@ -1075,7 +1086,7 @@ doelf(void)
}
void
-shsym(ElfShdr *sh, Sym *s)
+shsym(ElfShdr *sh, LSym *s)
{
vlong addr;
addr = symaddr(s);
@@ -1152,7 +1163,7 @@ asmbelf(vlong symo)
/* program header info */
pph = newElfPhdr();
pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
+ pph->flags = PF_R;
pph->off = eh->ehsize;
pph->vaddr = INITTEXT - HEADR + pph->off;
pph->paddr = INITTEXT - HEADR + pph->off;
@@ -1161,13 +1172,16 @@ asmbelf(vlong symo)
/*
* PHDR must be in a loaded segment. Adjust the text
* segment boundaries downwards to include it.
+ * Except on NaCl where it must not be loaded.
*/
- o = segtext.vaddr - pph->vaddr;
- segtext.vaddr -= o;
- segtext.len += o;
- o = segtext.fileoff - pph->off;
- segtext.fileoff -= o;
- segtext.filelen += o;
+ if(HEADTYPE != Hnacl) {
+ o = segtext.vaddr - pph->vaddr;
+ segtext.vaddr -= o;
+ segtext.len += o;
+ o = segtext.fileoff - pph->off;
+ segtext.fileoff -= o;
+ segtext.filelen += o;
+ }
if(!debug['d']) {
/* interpreter */
@@ -1192,6 +1206,9 @@ asmbelf(vlong symo)
case Hdragonfly:
interpreter = dragonflydynld;
break;
+ case Hsolaris:
+ interpreter = solarisdynld;
+ break;
}
}
resoff -= elfinterp(sh, startva, resoff, interpreter);
@@ -1247,20 +1264,20 @@ asmbelf(vlong symo)
sh = elfshname(".dynsym");
sh->type = SHT_DYNSYM;
sh->flags = SHF_ALLOC;
- if(PtrSize == 8)
+ if(elf64)
sh->entsize = ELF64SYMSIZE;
else
sh->entsize = ELF32SYMSIZE;
- sh->addralign = PtrSize;
+ sh->addralign = RegSize;
sh->link = elfshname(".dynstr")->shnum;
// sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, lookup(".dynsym", 0));
+ shsym(sh, linklookup(ctxt, ".dynsym", 0));
sh = elfshname(".dynstr");
sh->type = SHT_STRTAB;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
- shsym(sh, lookup(".dynstr", 0));
+ shsym(sh, linklookup(ctxt, ".dynstr", 0));
if(elfverneed) {
sh = elfshname(".gnu.version");
@@ -1269,15 +1286,15 @@ asmbelf(vlong symo)
sh->addralign = 2;
sh->link = elfshname(".dynsym")->shnum;
sh->entsize = 2;
- shsym(sh, lookup(".gnu.version", 0));
+ shsym(sh, linklookup(ctxt, ".gnu.version", 0));
sh = elfshname(".gnu.version_r");
sh->type = SHT_GNU_VERNEED;
sh->flags = SHF_ALLOC;
- sh->addralign = PtrSize;
+ sh->addralign = RegSize;
sh->info = elfverneed;
sh->link = elfshname(".dynstr")->shnum;
- shsym(sh, lookup(".gnu.version_r", 0));
+ shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
}
switch(eh->machine) {
@@ -1286,10 +1303,10 @@ asmbelf(vlong symo)
sh->type = SHT_RELA;
sh->flags = SHF_ALLOC;
sh->entsize = ELF64RELASIZE;
- sh->addralign = PtrSize;
+ sh->addralign = RegSize;
sh->link = elfshname(".dynsym")->shnum;
sh->info = elfshname(".plt")->shnum;
- shsym(sh, lookup(".rela.plt", 0));
+ shsym(sh, linklookup(ctxt, ".rela.plt", 0));
sh = elfshname(".rela");
sh->type = SHT_RELA;
@@ -1297,7 +1314,7 @@ asmbelf(vlong symo)
sh->entsize = ELF64RELASIZE;
sh->addralign = 8;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rela", 0));
+ shsym(sh, linklookup(ctxt, ".rela", 0));
break;
default:
@@ -1306,7 +1323,7 @@ asmbelf(vlong symo)
sh->flags = SHF_ALLOC;
sh->entsize = ELF32RELSIZE;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rel.plt", 0));
+ shsym(sh, linklookup(ctxt, ".rel.plt", 0));
sh = elfshname(".rel");
sh->type = SHT_REL;
@@ -1314,7 +1331,7 @@ asmbelf(vlong symo)
sh->entsize = ELF32RELSIZE;
sh->addralign = 4;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".rel", 0));
+ shsym(sh, linklookup(ctxt, ".rel", 0));
break;
}
@@ -1326,38 +1343,38 @@ asmbelf(vlong symo)
else
sh->entsize = 4;
sh->addralign = 4;
- shsym(sh, lookup(".plt", 0));
+ shsym(sh, linklookup(ctxt, ".plt", 0));
sh = elfshname(".got");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = PtrSize;
- sh->addralign = PtrSize;
- shsym(sh, lookup(".got", 0));
+ sh->entsize = RegSize;
+ sh->addralign = RegSize;
+ shsym(sh, linklookup(ctxt, ".got", 0));
sh = elfshname(".got.plt");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = PtrSize;
- sh->addralign = PtrSize;
- shsym(sh, lookup(".got.plt", 0));
+ sh->entsize = RegSize;
+ sh->addralign = RegSize;
+ shsym(sh, linklookup(ctxt, ".got.plt", 0));
sh = elfshname(".hash");
sh->type = SHT_HASH;
sh->flags = SHF_ALLOC;
sh->entsize = 4;
- sh->addralign = PtrSize;
+ sh->addralign = RegSize;
sh->link = elfshname(".dynsym")->shnum;
- shsym(sh, lookup(".hash", 0));
+ shsym(sh, linklookup(ctxt, ".hash", 0));
/* sh and PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic");
sh->type = SHT_DYNAMIC;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 2*PtrSize;
- sh->addralign = PtrSize;
+ sh->entsize = 2*RegSize;
+ sh->addralign = RegSize;
sh->link = elfshname(".dynstr")->shnum;
- shsym(sh, lookup(".dynamic", 0));
+ shsym(sh, linklookup(ctxt, ".dynamic", 0));
ph = newElfPhdr();
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
@@ -1369,12 +1386,12 @@ asmbelf(vlong symo)
// Do not emit PT_TLS for OpenBSD since ld.so(1) does
// not currently support it. This is handled
// appropriately in runtime/cgo.
- if(tlsoffset != 0 && HEADTYPE != Hopenbsd) {
+ if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
ph = newElfPhdr();
ph->type = PT_TLS;
ph->flags = PF_R;
- ph->memsz = -tlsoffset;
- ph->align = PtrSize;
+ ph->memsz = -ctxt->tlsoffset;
+ ph->align = RegSize;
}
}
@@ -1382,19 +1399,19 @@ asmbelf(vlong symo)
ph = newElfPhdr();
ph->type = PT_GNU_STACK;
ph->flags = PF_W+PF_R;
- ph->align = PtrSize;
+ ph->align = RegSize;
ph = newElfPhdr();
ph->type = PT_PAX_FLAGS;
ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
- ph->align = PtrSize;
+ ph->align = RegSize;
}
elfobj:
sh = elfshname(".shstrtab");
sh->type = SHT_STRTAB;
sh->addralign = 1;
- shsym(sh, lookup(".shstrtab", 0));
+ shsym(sh, linklookup(ctxt, ".shstrtab", 0));
eh->shstrndx = sh->shnum;
// put these sections early in the list
@@ -1429,8 +1446,8 @@ elfobj:
if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
sh = elfshname(".tbss");
sh->type = SHT_NOBITS;
- sh->addralign = PtrSize;
- sh->size = -tlsoffset;
+ sh->addralign = RegSize;
+ sh->size = -ctxt->tlsoffset;
sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
}
@@ -1439,8 +1456,8 @@ elfobj:
sh->type = SHT_SYMTAB;
sh->off = symo;
sh->size = symsize;
- sh->addralign = PtrSize;
- sh->entsize = 8+2*PtrSize;
+ sh->addralign = RegSize;
+ sh->entsize = 8+2*RegSize;
sh->link = elfshname(".strtab")->shnum;
sh->info = elfglobalsymndx;
@@ -1466,7 +1483,7 @@ elfobj:
eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
else if(HEADTYPE == Hdragonfly)
eh->ident[EI_OSABI] = ELFOSABI_NONE;
- if(PtrSize == 8)
+ if(elf64)
eh->ident[EI_CLASS] = ELFCLASS64;
else
eh->ident[EI_CLASS] = ELFCLASS32;
@@ -1504,5 +1521,5 @@ elfobj:
a += elfwritebuildinfo();
}
if(a > ELFRESERVE)
- diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
+ diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 5b2ff041a..e84d996f2 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -858,7 +858,7 @@ struct Elf64_Shdr {
Elf64_Xword entsize; /* Size of each entry in section. */
int shnum; /* section number, not stored on disk */
- Sym* secsym; /* section symbol, if needed; not on disk */
+ LSym* secsym; /* section symbol, if needed; not on disk */
};
/*
@@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void);
uint32 elfwritehdr(void);
uint32 elfwritephdrs(void);
uint32 elfwriteshdrs(void);
-void elfwritedynent(Sym*, int, uint64);
-void elfwritedynentsym(Sym*, int, Sym*);
-void elfwritedynentsymsize(Sym*, int, Sym*);
+void elfwritedynent(LSym*, int, uint64);
+void elfwritedynentsym(LSym*, int, LSym*);
+void elfwritedynentsymsize(LSym*, int, LSym*);
uint32 elfhash(uchar*);
uint64 startelf(void);
uint64 endelf(void);
@@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*);
ElfShdr* elfshname(char*);
ElfShdr* elfshreloc(Section*);
void elfsetstring(char*, int);
-void elfaddverneed(Sym*);
+void elfaddverneed(LSym*);
void elfemitreloc(void);
-void shsym(ElfShdr*, Sym*);
+void shsym(ElfShdr*, LSym*);
void phsh(ElfPhdr*, ElfShdr*);
void doelf(void);
void elfsetupplt(void);
-void dwarfaddshstrings(Sym*);
+void dwarfaddshstrings(LSym*);
void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void);
void asmbelf(vlong symo);
@@ -1010,6 +1010,7 @@ extern char freebsddynld[];
extern char netbsddynld[];
extern char openbsddynld[];
extern char dragonflydynld[];
+extern char solarisdynld[];
int elfreloc1(Reloc*, vlong sectoff);
void putelfsectionsyms(void);
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 39ffa3d87..9c296b740 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -151,28 +151,11 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
}
loadpkgdata(filename, pkg, p0, p1 - p0);
}
-
- // The __.PKGDEF archive summary has no local types.
+
+ // __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
if(whence == Pkgdef)
return;
- // local types begin where exports end.
- // skip rest of line after $$ we found above
- p0 = p1 + 3;
- while(*p0 != '\n' && *p0 != '\0')
- p0++;
-
- // local types end at next \n$$.
- p1 = strstr(p0, "\n$$");
- if(p1 == nil) {
- fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename);
- if(debug['u'])
- errorexit();
- return;
- }
-
- loadpkgdata(filename, pkg, p0, p1 - p0);
-
// look for cgo section
p0 = strstr(p1, "\n$$ // cgo");
if(p0 != nil) {
@@ -228,39 +211,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
free(file);
}
-// replace all "". with pkg.
-char*
-expandpkg(char *t0, char *pkg)
-{
- int n;
- char *p;
- char *w, *w0, *t;
-
- n = 0;
- for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
- n++;
-
- if(n == 0)
- return estrdup(t0);
-
- // use malloc, not mal, so that caller can free
- w0 = malloc(strlen(t0) + strlen(pkg)*n);
- if(w0 == nil) {
- diag("out of memory");
- errorexit();
- }
- w = w0;
- for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
- memmove(w, t, p - t);
- w += p-t;
- strcpy(w, pkg);
- w += strlen(pkg);
- t = p+2;
- }
- strcpy(w, t);
- return w0;
-}
-
static int
parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
@@ -413,7 +363,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
char *pend, *next, *p0, *q;
char *f[10], *local, *remote, *lib;
int nf;
- Sym *s;
+ LSym *s;
USED(file);
pend = p + n;
@@ -459,7 +409,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
q = strchr(remote, '#');
if(q)
*q++ = '\0';
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
if(local != f[1])
free(local);
if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
@@ -477,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(nf != 2)
goto err;
local = f[1];
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
s->type = SHOSTOBJ;
s->size = 0;
continue;
@@ -496,9 +446,9 @@ loadcgo(char *file, char *pkg, char *p, int n)
else
remote = local;
local = expandpkg(local, pkg);
- s = lookup(local, 0);
+ s = linklookup(ctxt, local, 0);
- if(flag_shared && s == lookup("main", 0))
+ if(flag_shared && s == linklookup(ctxt, "main", 0))
continue;
// export overrides import, for openbsd/cgo.
@@ -562,11 +512,11 @@ err:
nerrors++;
}
-static Sym *markq;
-static Sym *emarkq;
+static LSym *markq;
+static LSym *emarkq;
static void
-mark1(Sym *s, Sym *parent)
+mark1(LSym *s, LSym *parent)
{
if(s == S || s->reachable)
return;
@@ -582,7 +532,7 @@ mark1(Sym *s, Sym *parent)
}
void
-mark(Sym *s)
+mark(LSym *s)
{
mark1(s, nil);
}
@@ -591,23 +541,22 @@ static void
markflood(void)
{
Auto *a;
- Prog *p;
- Sym *s;
+ LSym *s;
int i;
for(s=markq; s!=S; s=s->queue) {
- if(s->text) {
+ if(s->type == STEXT) {
if(debug['v'] > 1)
Bprint(&bso, "marktext %s\n", s->name);
for(a=s->autom; a; a=a->link)
mark1(a->gotype, s);
- for(p=s->text; p != P; p=p->link) {
- mark1(p->from.sym, s);
- mark1(p->to.sym, s);
- }
}
for(i=0; i<s->nr; i++)
mark1(s->r[i].sym, s);
+ if(s->pcln) {
+ for(i=0; i<s->pcln->nfuncdata; i++)
+ mark1(s->pcln->funcdata[i], s);
+ }
mark1(s->gotype, s);
mark1(s->sub, s);
mark1(s->outer, s);
@@ -639,51 +588,19 @@ markextra[] =
"_modu",
};
-static int
-isz(Auto *a)
-{
- for(; a; a=a->link)
- if(a->type == D_FILE || a->type == D_FILE1)
- return 1;
- return 0;
-}
-
-static void
-addz(Sym *s, Auto *z)
-{
- Auto *a, *last;
-
- // strip out non-z
- last = nil;
- for(a = z; a != nil; a = a->link) {
- if(a->type == D_FILE || a->type == D_FILE1) {
- if(last == nil)
- z = a;
- else
- last->link = a;
- last = a;
- }
- }
- if(last) {
- last->link = s->autom;
- s->autom = z;
- }
-}
-
void
deadcode(void)
{
int i;
- Sym *s, *last, *p;
- Auto *z;
+ LSym *s, *last, *p;
Fmt fmt;
if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime());
- mark(lookup(INITENTRY, 0));
+ mark(linklookup(ctxt, INITENTRY, 0));
for(i=0; i<nelem(markextra); i++)
- mark(lookup(markextra[i], 0));
+ mark(linklookup(ctxt, markextra[i], 0));
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
@@ -691,37 +608,29 @@ deadcode(void)
markflood();
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.typelink.", 12) == 0)
s->reachable = s->nr==1 && s->r[0].sym->reachable;
}
// remove dead text but keep file information (z symbols).
last = nil;
- z = nil;
- for(s = textp; s != nil; s = s->next) {
- if(!s->reachable) {
- if(isz(s->autom))
- z = s->autom;
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(!s->reachable)
continue;
- }
+ // NOTE: Removing s from old textp and adding to new, shorter textp.
if(last == nil)
- textp = s;
+ ctxt->textp = s;
else
last->next = s;
last = s;
- if(z != nil) {
- if(!isz(s->autom))
- addz(s, z);
- z = nil;
- }
}
if(last == nil)
- textp = nil;
+ ctxt->textp = nil;
else
last->next = nil;
- for(s = allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != S; s = s->allsym)
if(strncmp(s->name, "go.weak.", 8) == 0) {
s->special = 1; // do not lay out in data segment
s->reachable = 1;
@@ -730,7 +639,7 @@ deadcode(void)
// record field tracking references
fmtstrinit(&fmt);
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.track.", 9) == 0) {
s->special = 1; // do not lay out in data segment
s->hide = 1;
@@ -746,7 +655,7 @@ deadcode(void)
}
if(tracksym == nil)
return;
- s = lookup(tracksym, 0);
+ s = linklookup(ctxt, tracksym, 0);
if(!s->reachable)
return;
addstrdata(tracksym, fmtstrflush(&fmt));
@@ -755,13 +664,13 @@ deadcode(void)
void
doweak(void)
{
- Sym *s, *t;
+ LSym *s, *t;
// resolve weak references only if
// target symbol will be in binary anyway.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.weak.", 8) == 0) {
- t = rlookup(s->name+8, s->version);
+ t = linkrlookup(ctxt, s->name+8, s->version);
if(t && t->type != 0 && t->reachable) {
s->value = t->value;
s->type = t->type;
@@ -784,7 +693,7 @@ addexport(void)
return;
for(i=0; i<ndynexp; i++)
- adddynsym(dynexp[i]);
+ adddynsym(ctxt, dynexp[i]);
}
/* %Z from gc, for quoting import paths */
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 27041bc47..1d7c4c13e 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -258,7 +258,7 @@ struct ElfSect
uint64 align;
uint64 entsize;
uchar *base;
- Sym *sym;
+ LSym *sym;
};
struct ElfObj
@@ -301,7 +301,7 @@ struct ElfSym
uchar type;
uchar other;
uint16 shndx;
- Sym* sym;
+ LSym* sym;
};
uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
@@ -312,7 +312,7 @@ static int readsym(ElfObj*, int i, ElfSym*, int);
static int reltype(char*, int, uchar*);
int
-valuecmp(Sym *a, Sym *b)
+valuecmp(LSym *a, LSym *b)
{
if(a->value < b->value)
return -1;
@@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
ElfSym sym;
Endian *e;
Reloc *r, *rp;
- Sym *s;
- Sym **symbols;
+ LSym *s;
+ LSym **symbols;
symbols = nil;
if(debug['v'])
Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
- version++;
+ ctxt->version++;
base = Boffset(f);
if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
@@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
free(name);
switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
default:
@@ -601,24 +601,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->size = sym.size;
s->outer = sect->sym;
if(sect->sym->type == STEXT) {
- Prog *p;
-
- if(s->text != P) {
- if(!s->dupok)
+ if(s->external && !s->dupok)
diag("%s: duplicate definition of %s", pn, s->name);
- } else {
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
- }
+ s->external = 1;
}
}
@@ -629,16 +614,22 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
- etextp->next = s;
- etextp = s;
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ ctxt->etextp->next = s;
+ ctxt->etextp = s;
}
}
}
@@ -712,6 +703,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
else
diag("invalid rela size %d", rp->siz);
}
+ if(rp->siz == 4)
+ rp->add = (int32)rp->add;
+ //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
}
qsort(r, n, sizeof r[0], rbyoff); // just in case
@@ -761,7 +755,7 @@ map(ElfObj *obj, ElfSect *sect)
static int
readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
{
- Sym *s;
+ LSym *s;
if(i >= obj->nsymtab || i < 0) {
werrstr("invalid elf symbol index");
@@ -808,7 +802,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
switch(sym->bind) {
case ElfSymBindGlobal:
if(needSym) {
- s = lookup(sym->name, 0);
+ s = linklookup(ctxt, sym->name, 0);
// for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden.
// __i686.get_pc_thunk.bx is allowed to be duplicated, to
@@ -828,13 +822,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// local names and hidden visiblity global names are unique
// and should only reference by its index, not name, so we
// don't bother to add them into hash table
- s = newsym(sym->name, version);
+ s = linknewsym(ctxt, sym->name, ctxt->version);
s->type |= SHIDDEN;
}
break;
case ElfSymBindWeak:
if(needSym) {
- s = newsym(sym->name, 0);
+ s = linknewsym(ctxt, sym->name, 0);
if(sym->other == 2)
s->type |= SHIDDEN;
}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index e0f5405f6..413dedabd 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -102,7 +102,7 @@ struct MachoSect
uint32 flags;
uint32 res1;
uint32 res2;
- Sym *sym;
+ LSym *sym;
MachoRel *rel;
};
@@ -138,7 +138,7 @@ struct MachoSym
uint16 desc;
char kind;
uint64 value;
- Sym *sym;
+ LSym *sym;
};
struct MachoDysymtab
@@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
int64 base;
MachoSect *sect;
MachoRel *rel;
- Sym *s, *s1, *outer;
+ LSym *s, *s1, *outer;
MachoCmd *c;
MachoSymtab *symtab;
MachoDysymtab *dsymtab;
@@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
Reloc *r, *rp;
char *name;
- version++;
+ ctxt->version++;
base = Boffset(f);
if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
goto bad;
@@ -507,6 +507,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
c = nil;
symtab = nil;
dsymtab = nil;
+ USED(dsymtab);
for(i=0; i<ncmd; i++){
ty = e->e32(cmdp);
sz = e->e32(cmdp+4);
@@ -566,7 +567,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if(strcmp(sect->name, "__eh_frame") == 0)
continue;
name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
if(s->type != 0) {
werrstr("duplicate %s/%s", sect->segname, sect->name);
goto bad;
@@ -609,8 +610,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
name++;
v = 0;
if(!(sym->type&N_EXT))
- v = version;
- s = lookup(name, v);
+ v = ctxt->version;
+ s = linklookup(ctxt, name, v);
if(!(sym->type&N_EXT))
s->dupok = 1;
sym->sym = s;
@@ -640,22 +641,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if(!(s->cgoexport & CgoExportDynamic))
s->dynimplib = nil; // satisfy dynimport
if(outer->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
- diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- // TODO: this is too 6l-specific ?
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
+ if(s->external && !s->dupok)
+ diag("%s: duplicate definition of %s", pn, s->name);
+ s->external = 1;
}
sym->sym = s;
}
@@ -667,7 +655,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if((s = sect->sym) == S)
continue;
if(s->sub) {
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
// assign sizes, now that we know symbols in sorted order.
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
@@ -678,14 +666,20 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
}
}
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
- etextp->next = s1;
- etextp = s1;
+ if(s1->onlist)
+ sysfatal("symbol %s listed multiple times", s1->name);
+ s1->onlist = 1;
+ ctxt->etextp->next = s1;
+ ctxt->etextp = s1;
}
}
}
@@ -743,7 +737,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// want to make it pc-relative aka relative to rp->off+4
// but the scatter asks for relative to off = (rel+1)->value - sect->addr.
// adjust rp->add accordingly.
- rp->type = D_PCREL;
+ rp->type = R_PCREL;
rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
// now consider the desired symbol.
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 6bcda2cb6..f6eda900d 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -102,14 +102,14 @@ struct PeSym {
uint16 type;
uint8 sclass;
uint8 aux;
- Sym* sym;
+ LSym* sym;
};
struct PeSect {
char* name;
uchar* base;
uint64 size;
- Sym* sym;
+ LSym* sym;
IMAGE_SECTION_HEADER sh;
};
@@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
PeSect *sect, *rsect;
IMAGE_SECTION_HEADER sh;
uchar symbuf[18];
- Sym *s;
+ LSym *s;
Reloc *r, *rp;
PeSym *sym;
@@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
sect = nil;
- version++;
+ ctxt->version++;
base = Boffset(f);
obj = mal(sizeof *obj);
@@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
free(name);
switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
@@ -290,18 +290,18 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
case IMAGE_REL_AMD64_REL32:
case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
case IMAGE_REL_AMD64_ADDR32NB:
- rp->type = D_PCREL;
+ rp->type = R_PCREL;
rp->add = (int32)le32(rsect->base+rp->off);
break;
case IMAGE_REL_I386_DIR32NB:
case IMAGE_REL_I386_DIR32:
- rp->type = D_ADDR;
+ rp->type = R_ADDR;
// load addend from image
- rp->add = le32(rsect->base+rp->off);
+ rp->add = (int32)le32(rsect->base+rp->off);
break;
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
rp->siz = 8;
- rp->type = D_ADDR;
+ rp->type = R_ADDR;
// load addend from image
rp->add = le64(rsect->base+rp->off);
break;
@@ -366,21 +366,9 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
s->size = 4;
s->outer = sect->sym;
if(sect->sym->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
+ if(s->external && !s->dupok)
diag("%s: duplicate definition of %s", pn, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
+ s->external = 1;
}
}
@@ -391,16 +379,22 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
- s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
+ s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
else
- textp = s;
- etextp = s;
+ ctxt->textp = s;
+ ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
- etextp->next = s;
- etextp = s;
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ ctxt->etextp->next = s;
+ ctxt->etextp = s;
}
}
}
@@ -430,7 +424,7 @@ map(PeObj *obj, PeSect *sect)
static int
readsym(PeObj *obj, int i, PeSym **y)
{
- Sym *s;
+ LSym *s;
PeSym *sym;
char *name, *p;
@@ -464,12 +458,12 @@ readsym(PeObj *obj, int i, PeSym **y)
case IMAGE_SYM_DTYPE_NULL:
switch(sym->sclass) {
case IMAGE_SYM_CLASS_EXTERNAL: //global
- s = lookup(name, 0);
+ s = linklookup(ctxt, name, 0);
break;
case IMAGE_SYM_CLASS_NULL:
case IMAGE_SYM_CLASS_STATIC:
case IMAGE_SYM_CLASS_LABEL:
- s = lookup(name, version);
+ s = linklookup(ctxt, name, ctxt->version);
s->dupok = 1;
break;
default:
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index da522dc0c..da6194e4f 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -32,10 +32,14 @@
#include "l.h"
#include "lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../../pkg/runtime/stack.h"
#include "../../pkg/runtime/funcdata.h"
#include <ar.h>
+#if !(defined(_WIN32) || defined(PLAN9))
+#include <sys/stat.h>
+#endif
enum
{
@@ -48,18 +52,9 @@ int iconv(Fmt*);
char symname[] = SYMDEF;
char pkgname[] = "__.PKGDEF";
-char** libdir;
-int nlibdir = 0;
-static int maxlibdir = 0;
static int cout = -1;
-// symbol version, incremented each time a file is loaded.
-// version==1 is reserved for savehist.
-enum
-{
- HistVersion = 1,
-};
-int version = HistVersion;
+extern int version;
// Set if we see an object compiled by the host compiler that is not
// from a package that is known to support internal linking mode.
@@ -77,15 +72,32 @@ Lflag(char *arg)
{
char **p;
- if(nlibdir >= maxlibdir) {
- if (maxlibdir == 0)
- maxlibdir = 8;
+ if(ctxt->nlibdir >= ctxt->maxlibdir) {
+ if (ctxt->maxlibdir == 0)
+ ctxt->maxlibdir = 8;
else
- maxlibdir *= 2;
- p = erealloc(libdir, maxlibdir * sizeof(*p));
- libdir = p;
+ ctxt->maxlibdir *= 2;
+ p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p));
+ ctxt->libdir = p;
}
- libdir[nlibdir++] = arg;
+ ctxt->libdir[ctxt->nlibdir++] = arg;
+}
+
+/*
+ * Unix doesn't like it when we write to a running (or, sometimes,
+ * recently run) binary, so remove the output file before writing it.
+ * On Windows 7, remove() can force a subsequent create() to fail.
+ * S_ISREG() does not exist on Plan 9.
+ */
+static void
+mayberemoveoutfile(void)
+{
+#if !(defined(_WIN32) || defined(PLAN9))
+ struct stat st;
+ if(lstat(outfile, &st) == 0 && !S_ISREG(st.st_mode))
+ return;
+#endif
+ remove(outfile);
}
void
@@ -93,12 +105,11 @@ libinit(void)
{
char *suffix, *suffixsep;
+ funcalign = FuncAlign;
fmtinstall('i', iconv);
fmtinstall('Y', Yconv);
fmtinstall('Z', Zconv);
mywhatsys(); // get goroot, goarch, goos
- if(strcmp(goarch, thestring) != 0)
- print("goarch is not known: %s\n", goarch);
// add goroot to the end of the libdir list.
suffix = "";
@@ -112,12 +123,7 @@ libinit(void)
}
Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix));
- // Unix doesn't like it when we write to a running (or, sometimes,
- // recently run) binary, so remove the output file before writing it.
- // On Windows 7, remove() can force the following create() to fail.
-#ifndef _WIN32
- remove(outfile);
-#endif
+ mayberemoveoutfile();
cout = create(outfile, 1, 0775);
if(cout < 0) {
diag("cannot create %s: %r", outfile);
@@ -132,7 +138,7 @@ libinit(void)
sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
}
}
- lookup(INITENTRY, 0)->type = SXREF;
+ linklookup(ctxt, INITENTRY, 0)->type = SXREF;
}
void
@@ -140,165 +146,25 @@ errorexit(void)
{
if(nerrors) {
if(cout >= 0)
- remove(outfile);
+ mayberemoveoutfile();
exits("error");
}
exits(0);
}
void
-addlib(char *src, char *obj)
-{
- char name[1024], pname[1024], comp[256], *p;
- int i, search;
-
- if(histfrogp <= 0)
- return;
-
- search = 0;
- if(histfrog[0]->name[1] == '/') {
- sprint(name, "");
- i = 1;
- } else
- if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
- strcpy(name, histfrog[0]->name+1);
- i = 1;
- } else
- if(histfrog[0]->name[1] == '.') {
- sprint(name, ".");
- i = 0;
- } else {
- sprint(name, "");
- i = 0;
- search = 1;
- }
-
- for(; i<histfrogp; i++) {
- snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
- for(;;) {
- p = strstr(comp, "$O");
- if(p == 0)
- break;
- memmove(p+1, p+2, strlen(p+2)+1);
- p[0] = thechar;
- }
- for(;;) {
- p = strstr(comp, "$M");
- if(p == 0)
- break;
- if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
- diag("library component too long");
- return;
- }
- memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
- memmove(p, thestring, strlen(thestring));
- }
- if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
- diag("library component too long");
- return;
- }
- if(i > 0 || !search)
- strcat(name, "/");
- strcat(name, comp);
- }
- cleanname(name);
-
- // runtime.a -> runtime
- p = nil;
- if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
- p = name+strlen(name)-2;
- *p = '\0';
- }
-
- // already loaded?
- for(i=0; i<libraryp; i++)
- if(strcmp(library[i].pkg, name) == 0)
- return;
-
- // runtime -> runtime.a for search
- if(p != nil)
- *p = '.';
-
- if(search) {
- // try dot, -L "libdir", and then goroot.
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
- if(access(pname, AEXIST) >= 0)
- break;
- }
- }else
- strcpy(pname, name);
- cleanname(pname);
-
- /* runtime.a -> runtime */
- if(p != nil)
- *p = '\0';
-
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
-
- addlibpath(src, obj, pname, name);
-}
-
-/*
- * add library to library list.
- * srcref: src file referring to package
- * objref: object file referring to package
- * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
- * pkg: package import path, e.g. container/vector
- */
-void
-addlibpath(char *srcref, char *objref, char *file, char *pkg)
-{
- int i;
- Library *l;
- char *p;
-
- for(i=0; i<libraryp; i++)
- if(strcmp(file, library[i].file) == 0)
- return;
-
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
- cputime(), srcref, objref, file, pkg);
-
- if(libraryp == nlibrary){
- nlibrary = 50 + 2*libraryp;
- library = erealloc(library, sizeof library[0] * nlibrary);
- }
-
- l = &library[libraryp++];
-
- p = mal(strlen(objref) + 1);
- strcpy(p, objref);
- l->objref = p;
-
- p = mal(strlen(srcref) + 1);
- strcpy(p, srcref);
- l->srcref = p;
-
- p = mal(strlen(file) + 1);
- strcpy(p, file);
- l->file = p;
-
- p = mal(strlen(pkg) + 1);
- strcpy(p, pkg);
- l->pkg = p;
-}
-
-void
loadinternal(char *name)
{
char pname[1024];
int i, found;
found = 0;
- for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
+ for(i=0; i<ctxt->nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name);
if(debug['v'])
Bprint(&bso, "searching for %s.a in %s\n", name, pname);
if(access(pname, AEXIST) >= 0) {
- addlibpath("internal", "internal", pname, name);
+ addlibpath(ctxt, "internal", "internal", pname, name);
found = 1;
break;
}
@@ -311,12 +177,13 @@ void
loadlib(void)
{
int i, w, x;
- Sym *s, *gmsym;
+ LSym *s, *gmsym;
+ char* cgostrsym;
if(flag_shared) {
- s = lookup("runtime.islibrary", 0);
+ s = linklookup(ctxt, "runtime.islibrary", 0);
s->dupok = 1;
- adduint8(s, 1);
+ adduint8(ctxt, s, 1);
}
loadinternal("runtime");
@@ -324,27 +191,36 @@ loadlib(void)
loadinternal("math");
if(flag_race)
loadinternal("runtime/race");
- if(linkmode == LinkExternal) {
+
+ for(i=0; i<ctxt->libraryp; i++) {
+ if(debug['v'] > 1)
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref);
+ iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0;
+ objfile(ctxt->library[i].file, ctxt->library[i].pkg);
+ }
+
+ if(linkmode == LinkExternal && !iscgo) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
// whether to initialize the TLS. So give it one. This could
// be handled differently but it's an unusual case.
loadinternal("runtime/cgo");
+ if(i < ctxt->libraryp)
+ objfile(ctxt->library[i].file, ctxt->library[i].pkg);
+
// Pretend that we really imported the package.
- // This will do no harm if we did in fact import it.
- s = lookup("go.importpath.runtime/cgo.", 0);
+ s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0);
s->type = SDATA;
s->dupok = 1;
s->reachable = 1;
- }
- for(i=0; i<libraryp; i++) {
- if(debug['v'] > 1)
- Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
- iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
- objfile(library[i].file, library[i].pkg);
+ // Provided by the code that imports the package.
+ // Since we are simulating the import, we have to provide this string.
+ cgostrsym = "go.string.\"runtime/cgo\"";
+ if(linkrlookup(ctxt, cgostrsym, 0) == nil)
+ addstrdata(cgostrsym, "runtime/cgo");
}
-
+
if(linkmode == LinkAuto) {
if(iscgo && externalobj)
linkmode = LinkExternal;
@@ -355,7 +231,7 @@ loadlib(void)
if(linkmode == LinkInternal) {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
- for(s = allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != S; s = s->allsym)
if(s->type == SHOSTOBJ) {
// If a symbol was marked both
// cgo_import_static and cgo_import_dynamic,
@@ -368,14 +244,12 @@ loadlib(void)
}
}
- gmsym = lookup("runtime.tlsgm", 0);
+ gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
gmsym->type = STLSBSS;
gmsym->size = 2*PtrSize;
gmsym->hide = 1;
- if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd)
- gmsym->reachable = 1;
- else
- gmsym->reachable = 0;
+ gmsym->reachable = 1;
+ ctxt->gmsym = gmsym;
// Now that we know the link mode, trim the dynexp list.
x = CgoExportDynamic;
@@ -402,7 +276,9 @@ loadlib(void)
//
// Exception: on OS X, programs such as Shark only work with dynamic
// binaries, so leave it enabled on OS X (Mach-O) binaries.
- if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin)
+ // Also leave it enabled on Solaris which doesn't support
+ // statically linked binaries.
+ if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris)
debug['d'] = 1;
importcycles();
@@ -412,8 +288,8 @@ loadlib(void)
* look for the next file in an archive.
* adapted from libmach.
*/
-int
-nextar(Biobuf *bp, int off, struct ar_hdr *a)
+static vlong
+nextar(Biobuf *bp, vlong off, struct ar_hdr *a)
{
int r;
int32 arsize;
@@ -443,7 +319,7 @@ nextar(Biobuf *bp, int off, struct ar_hdr *a)
void
objfile(char *file, char *pkg)
{
- int32 off, l;
+ vlong off, l;
Biobuf *f;
char magbuf[SARMAG];
char pname[150];
@@ -470,25 +346,24 @@ objfile(char *file, char *pkg)
return;
}
- /* skip over __.GOSYMDEF */
+ /* skip over optional __.GOSYMDEF and process __.PKGDEF */
off = Boffset(f);
- if((l = nextar(f, off, &arhdr)) <= 0) {
+ l = nextar(f, off, &arhdr);
+ if(l <= 0) {
diag("%s: short read on archive file symbol header", file);
goto out;
}
- if(strncmp(arhdr.name, symname, strlen(symname))) {
- diag("%s: first entry not symbol header", file);
- goto out;
- }
- off += l;
-
- /* skip over (or process) __.PKGDEF */
- if((l = nextar(f, off, &arhdr)) <= 0) {
- diag("%s: short read on archive file symbol header", file);
- goto out;
+ if(strncmp(arhdr.name, symname, strlen(symname)) == 0) {
+ off += l;
+ l = nextar(f, off, &arhdr);
+ if(l <= 0) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
}
+
if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
- diag("%s: second entry not package header", file);
+ diag("%s: cannot find package header", file);
goto out;
}
off += l;
@@ -539,7 +414,7 @@ dowrite(int fd, char *p, int n)
while(n > 0) {
m = write(fd, p, n);
if(m <= 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("write error: %r");
errorexit();
}
@@ -628,7 +503,7 @@ hostobjs(void)
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -697,7 +572,7 @@ hostlink(void)
p = strchr(p + 1, ' ');
}
- argv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]);
+ argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]);
argc = 0;
if(extld == nil)
extld = "gcc";
@@ -720,6 +595,8 @@ hostlink(void)
}
if(HEADTYPE == Hdarwin)
argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000";
+ if(HEADTYPE == Hopenbsd)
+ argv[argc++] = "-Wl,-nopie";
if(iself && AssumeGoldLinker)
argv[argc++] = "-Wl,--rosegment";
@@ -738,13 +615,16 @@ hostlink(void)
if(iself)
argv[argc++] = "-rdynamic";
+ if(strstr(argv[0], "clang") != nil)
+ argv[argc++] = "-Qunused-arguments";
+
// already wrote main object file
// copy host objects to temporary directory
for(i=0; i<nhostobj; i++) {
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -753,7 +633,7 @@ hostlink(void)
argv[argc++] = p;
w = create(p, 1, 0775);
if(w < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot create %s: %r", p);
errorexit();
}
@@ -765,7 +645,7 @@ hostlink(void)
len -= n;
}
if(close(w) < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("cannot write %s: %r", p);
errorexit();
}
@@ -783,6 +663,20 @@ hostlink(void)
if(*p == '\0')
break;
argv[argc++] = p;
+
+ // clang, unlike GCC, passes -rdynamic to the linker
+ // even when linking with -static, causing a linker
+ // error when using GNU ld. So take out -rdynamic if
+ // we added it. We do it in this order, rather than
+ // only adding -rdynamic later, so that -extldflags
+ // can override -rdynamic without using -static.
+ if(iself && strncmp(p, "-static", 7) == 0 && (p[7]==' ' || p[7]=='\0')) {
+ for(i=0; i<argc; i++) {
+ if(strcmp(argv[i], "-rdynamic") == 0)
+ argv[i] = "-static";
+ }
+ }
+
p = strchr(p + 1, ' ');
}
@@ -798,7 +692,7 @@ hostlink(void)
}
if(runcmd(argv) < 0) {
- cursym = S;
+ ctxt->cursym = S;
diag("%s: running %s failed: %r", argv0, argv[0]);
errorexit();
}
@@ -866,8 +760,8 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
return;
}
- // First, check that the basic goos, string, and version match.
- t = smprint("%s %s %s ", goos, thestring, getgoversion());
+ // First, check that the basic goos, goarch, and version match.
+ t = smprint("%s %s %s ", goos, getgoarch(), getgoversion());
line[n] = ' ';
if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
line[n] = '\0';
@@ -913,7 +807,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n
Bseek(f, import1, 0);
- ldobj1(f, pkg, eof - Boffset(f), pn);
+ ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn);
free(pn);
return;
@@ -922,318 +816,12 @@ eof:
free(pn);
}
-Sym*
-newsym(char *symb, int v)
-{
- Sym *s;
- int l;
-
- l = strlen(symb) + 1;
- s = mal(sizeof(*s));
- if(debug['v'] > 1)
- Bprint(&bso, "newsym %s\n", symb);
-
- s->dynid = -1;
- s->plt = -1;
- s->got = -1;
- s->name = mal(l + 1);
- memmove(s->name, symb, l);
-
- s->type = 0;
- s->version = v;
- s->value = 0;
- s->sig = 0;
- s->size = 0;
- nsymbol++;
-
- s->allsym = allsym;
- allsym = s;
-
- return s;
-}
-
-static Sym*
-_lookup(char *symb, int v, int creat)
-{
- Sym *s;
- char *p;
- uint32 h;
- int c;
-
- h = v;
- for(p=symb; c = *p; p++)
- h = h+h+h + c;
- // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
- h &= 0xffffff;
- h %= NHASH;
- for(s = hash[h]; s != S; s = s->hash)
- if(strcmp(s->name, symb) == 0)
- return s;
- if(!creat)
- return nil;
-
- s = newsym(symb, v);
- s->extname = s->name;
- s->hash = hash[h];
- hash[h] = s;
-
- return s;
-}
-
-Sym*
-lookup(char *name, int v)
-{
- return _lookup(name, v, 1);
-}
-
-// read-only lookup
-Sym*
-rlookup(char *name, int v)
-{
- return _lookup(name, v, 0);
-}
-
-void
-copyhistfrog(char *buf, int nbuf)
-{
- char *p, *ep;
- int i;
-
- p = buf;
- ep = buf + nbuf;
- for(i=0; i<histfrogp; i++) {
- p = seprint(p, ep, "%s", histfrog[i]->name+1);
- if(i+1<histfrogp && (p == buf || p[-1] != '/'))
- p = seprint(p, ep, "/");
- }
-}
-
-void
-addhist(int32 line, int type)
-{
- Auto *u;
- Sym *s;
- int i, j, k;
-
- u = mal(sizeof(Auto));
- s = mal(sizeof(Sym));
- s->name = mal(2*(histfrogp+1) + 1);
-
- u->asym = s;
- u->type = type;
- u->aoffset = line;
- u->link = curhist;
- curhist = u;
-
- s->name[0] = 0;
- j = 1;
- for(i=0; i<histfrogp; i++) {
- k = histfrog[i]->value;
- s->name[j+0] = k>>8;
- s->name[j+1] = k;
- j += 2;
- }
- s->name[j] = 0;
- s->name[j+1] = 0;
-}
-
-void
-histtoauto(void)
-{
- Auto *l;
-
- while(l = curhist) {
- curhist = l->link;
- l->link = curauto;
- curauto = l;
- }
-}
-
-void
-collapsefrog(Sym *s)
-{
- int i;
-
- /*
- * bad encoding of path components only allows
- * MAXHIST components. if there is an overflow,
- * first try to collapse xxx/..
- */
- for(i=1; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, "..") == 0) {
- memmove(histfrog+i-1, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- histfrogp--;
- goto out;
- }
-
- /*
- * next try to collapse .
- */
- for(i=0; i<histfrogp; i++)
- if(strcmp(histfrog[i]->name+1, ".") == 0) {
- memmove(histfrog+i, histfrog+i+1,
- (histfrogp-i-1)*sizeof(histfrog[0]));
- goto out;
- }
-
- /*
- * last chance, just truncate from front
- */
- memmove(histfrog+0, histfrog+1,
- (histfrogp-1)*sizeof(histfrog[0]));
-
-out:
- histfrog[histfrogp-1] = s;
-}
-
-void
-nuxiinit(void)
-{
- int i, c;
-
- for(i=0; i<4; i++) {
- c = find1(0x04030201L, i+1);
- if(i < 2)
- inuxi2[i] = c;
- if(i < 1)
- inuxi1[i] = c;
- inuxi4[i] = c;
- if(c == i) {
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
- } else {
- inuxi8[i] = c+4;
- inuxi8[i+4] = c;
- }
- fnuxi4[i] = c;
- fnuxi8[i] = c;
- fnuxi8[i+4] = c+4;
- }
- if(debug['v']) {
- Bprint(&bso, "inuxi = ");
- for(i=0; i<1; i++)
- Bprint(&bso, "%d", inuxi1[i]);
- Bprint(&bso, " ");
- for(i=0; i<2; i++)
- Bprint(&bso, "%d", inuxi2[i]);
- Bprint(&bso, " ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", inuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", inuxi8[i]);
- Bprint(&bso, "\nfnuxi = ");
- for(i=0; i<4; i++)
- Bprint(&bso, "%d", fnuxi4[i]);
- Bprint(&bso, " ");
- for(i=0; i<8; i++)
- Bprint(&bso, "%d", fnuxi8[i]);
- Bprint(&bso, "\n");
- }
- Bflush(&bso);
-}
-
-int
-find1(int32 l, int c)
-{
- char *p;
- int i;
-
- p = (char*)&l;
- for(i=0; i<4; i++)
- if(*p++ == c)
- return i;
- return 0;
-}
-
-int
-find2(int32 l, int c)
-{
- union {
- int32 l;
- short p[2];
- } u;
- short *p;
- int i;
-
- u.l = l;
- p = u.p;
- for(i=0; i<4; i+=2) {
- if(((*p >> 8) & 0xff) == c)
- return i;
- if((*p++ & 0xff) == c)
- return i+1;
- }
- return 0;
-}
-
-int32
-ieeedtof(Ieee *e)
-{
- int exp;
- int32 v;
-
- if(e->h == 0)
- return 0;
- exp = (e->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- v = (e->h & 0xfffffL) << 3;
- v |= (e->l >> 29) & 0x7L;
- if((e->l >> 28) & 1) {
- v++;
- if(v & 0x800000L) {
- v = (v & 0x7fffffL) >> 1;
- exp++;
- }
- }
- if(-148 <= exp && exp <= -126) {
- v |= 1<<23;
- v >>= -125 - exp;
- exp = -126;
- }
- else if(exp < -148 || exp >= 130)
- diag("double fp to single fp overflow: %.17g", ieeedtod(e));
- v |= ((exp + 126) & 0xffL) << 23;
- v |= e->h & 0x80000000L;
- return v;
-}
-
-double
-ieeedtod(Ieee *ieeep)
-{
- Ieee e;
- double fr;
- int exp;
-
- if(ieeep->h & (1L<<31)) {
- e.h = ieeep->h & ~(1L<<31);
- e.l = ieeep->l;
- return -ieeedtod(&e);
- }
- if(ieeep->l == 0 && ieeep->h == 0)
- return 0;
- exp = (ieeep->h>>20) & ((1L<<11)-1L);
- exp -= (1L<<10) - 2L;
- fr = ieeep->l & ((1L<<16)-1L);
- fr /= 1L<<16;
- fr += (ieeep->l>>16) & ((1L<<16)-1L);
- fr /= 1L<<16;
- if(exp == -(1L<<10) - 2L) {
- fr += (ieeep->h & (1L<<20)-1L);
- exp++;
- } else
- fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
- fr /= 1L<<21;
- return ldexp(fr, exp);
-}
-
void
zerosig(char *sp)
{
- Sym *s;
+ LSym *s;
- s = lookup(sp, 0);
+ s = linklookup(ctxt, sp, 0);
s->sig = 0;
}
@@ -1242,7 +830,10 @@ mywhatsys(void)
{
goroot = getgoroot();
goos = getgoos();
- goarch = thestring; // ignore $GOARCH - we know who we are
+ goarch = getgoarch();
+
+ if(strncmp(goarch, thestring, strlen(thestring)) != 0)
+ sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch);
}
int
@@ -1303,7 +894,8 @@ unmal(void *v, uint32 n)
* Invalid bytes turn into %xx. Right now the only bytes that need
* escaping are %, ., and ", but we escape all control characters too.
*
- * Must be same as ../gc/subr.c:/^pathtoprefix.
+ * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
+ * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too.
*/
static char*
pathtoprefix(char *s)
@@ -1357,13 +949,6 @@ iconv(Fmt *fp)
return 0;
}
-void
-mangle(char *file)
-{
- fprint(2, "%s: mangled input file\n", file);
- errorexit();
-}
-
Section*
addsection(Segment *seg, char *name, int rwx)
{
@@ -1381,235 +966,6 @@ addsection(Segment *seg, char *name, int rwx)
return sect;
}
-void
-addvarint(Sym *s, uint32 val)
-{
- int32 n;
- uint32 v;
- uchar *p;
-
- n = 0;
- for(v = val; v >= 0x80; v >>= 7)
- n++;
- n++;
-
- symgrow(s, s->np+n);
-
- p = s->p + s->np - n;
- for(v = val; v >= 0x80; v >>= 7)
- *p++ = v | 0x80;
- *p = v;
-}
-
-// funcpctab appends to dst a pc-value table mapping the code in func to the values
-// returned by valfunc parameterized by arg. The invocation of valfunc to update the
-// current value is, for each p,
-//
-// val = valfunc(func, val, p, 0, arg);
-// record val as value at p->pc;
-// val = valfunc(func, val, p, 1, arg);
-//
-// where func is the function, val is the current value, p is the instruction being
-// considered, and arg can be used to further parameterize valfunc.
-void
-funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg)
-{
- int dbg, i, start;
- int32 oldval, val, started;
- uint32 delta;
- vlong pc;
- Prog *p;
-
- // To debug a specific function, uncomment second line and change name.
- dbg = 0;
- //dbg = strcmp(func->name, "main.main") == 0;
-
- debug['O'] += dbg;
-
- start = dst->np;
-
- if(debug['O'])
- Bprint(&bso, "funcpctab %s -> %s [valfunc=%s]\n", func->name, dst->name, desc);
-
- val = -1;
- oldval = val;
- pc = func->value;
-
- if(debug['O'])
- Bprint(&bso, "%6llux %6d %P\n", pc, val, func->text);
-
- started = 0;
- for(p=func->text; p != P; p = p->link) {
- // Update val. If it's not changing, keep going.
- val = valfunc(func, val, p, 0, arg);
- if(val == oldval && started) {
- val = valfunc(func, val, p, 1, arg);
- if(debug['O'])
- Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
- continue;
- }
-
- // If the pc of the next instruction is the same as the
- // pc of this instruction, this instruction is not a real
- // instruction. Keep going, so that we only emit a delta
- // for a true instruction boundary in the program.
- if(p->link && p->link->pc == p->pc) {
- val = valfunc(func, val, p, 1, arg);
- if(debug['O'])
- Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
- continue;
- }
-
- // The table is a sequence of (value, pc) pairs, where each
- // pair states that the given value is in effect from the current position
- // up to the given pc, which becomes the new current position.
- // To generate the table as we scan over the program instructions,
- // we emit a "(value" when pc == func->value, and then
- // each time we observe a change in value we emit ", pc) (value".
- // When the scan is over, we emit the closing ", pc)".
- //
- // The table is delta-encoded. The value deltas are signed and
- // transmitted in zig-zag form, where a complement bit is placed in bit 0,
- // and the pc deltas are unsigned. Both kinds of deltas are sent
- // as variable-length little-endian base-128 integers,
- // where the 0x80 bit indicates that the integer continues.
-
- if(debug['O'])
- Bprint(&bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
-
- if(started) {
- addvarint(dst, (p->pc - pc) / MINLC);
- pc = p->pc;
- }
- delta = val - oldval;
- if(delta>>31)
- delta = 1 | ~(delta<<1);
- else
- delta <<= 1;
- addvarint(dst, delta);
- oldval = val;
- started = 1;
- val = valfunc(func, val, p, 1, arg);
- }
-
- if(started) {
- if(debug['O'])
- Bprint(&bso, "%6llux done\n", (vlong)func->value+func->size);
- addvarint(dst, (func->value+func->size - pc) / MINLC);
- addvarint(dst, 0); // terminator
- }
-
- if(debug['O']) {
- Bprint(&bso, "wrote %d bytes\n", dst->np - start);
- for(i=start; i<dst->np; i++)
- Bprint(&bso, " %02ux", dst->p[i]);
- Bprint(&bso, "\n");
- }
-
- debug['O'] -= dbg;
-}
-
-// pctofileline computes either the file number (arg == 0)
-// or the line number (arg == 1) to use at p.
-// Because p->lineno applies to p, phase == 0 (before p)
-// takes care of the update.
-static int32
-pctofileline(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- int32 f, l;
-
- if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->line == 0 || phase == 1)
- return oldval;
- getline(sym->hist, p->line, &f, &l);
- if(f == 0) {
- // print("getline failed for %s %P\n", cursym->name, p);
- return oldval;
- }
- if(arg == 0)
- return f;
- return l;
-}
-
-// pctospadj computes the sp adjustment in effect.
-// It is oldval plus any adjustment made by p itself.
-// The adjustment by p takes effect only after p, so we
-// apply the change during phase == 1.
-static int32
-pctospadj(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- USED(arg);
- USED(sym);
-
- if(oldval == -1) // starting
- oldval = 0;
- if(phase == 0)
- return oldval;
- if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
- diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
- errorexit();
- }
- return oldval + p->spadj;
-}
-
-// pctopcdata computes the pcdata value in effect at p.
-// A PCDATA instruction sets the value in effect at future
-// non-PCDATA instructions.
-// Since PCDATA instructions have no width in the final code,
-// it does not matter which phase we use for the update.
-static int32
-pctopcdata(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg)
-{
- USED(sym);
-
- if(phase == 0 || p->as != APCDATA || p->from.offset != arg)
- return oldval;
- if((int32)p->to.offset != p->to.offset) {
- diag("overflow in PCDATA instruction: %P", p);
- errorexit();
- }
- return p->to.offset;
-}
-
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1;
- else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- for(p = cursym->text; p != P; p = p->link) {
- if(p->link == P) {
- if(cursym->next)
- p->forwd = cursym->next->text;
- break;
- }
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
- }
-}
-
uint16
le16(uchar *b)
{
@@ -1652,7 +1008,7 @@ Endian le = { le16, le32, le64 };
typedef struct Chain Chain;
struct Chain
{
- Sym *sym;
+ LSym *sym;
Chain *up;
int limit; // limit on entry to sym
};
@@ -1660,67 +1016,87 @@ struct Chain
static int stkcheck(Chain*, int);
static void stkprint(Chain*, int);
static void stkbroke(Chain*, int);
-static Sym *morestack;
-static Sym *newstack;
+static LSym *morestack;
+static LSym *newstack;
enum
{
HasLinkRegister = (thechar == '5'),
- CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
};
+// TODO: Record enough information in new object files to
+// allow stack checks here.
+
+static int
+callsize(void)
+{
+ if(thechar == '5')
+ return 0;
+ return RegSize;
+}
+
void
dostkcheck(void)
{
Chain ch;
- Sym *s;
+ LSym *s;
- morestack = lookup("runtime.morestack", 0);
- newstack = lookup("runtime.newstack", 0);
-
- // First the nosplits on their own.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0)
+ morestack = linklookup(ctxt, "runtime.morestack", 0);
+ newstack = linklookup(ctxt, "runtime.newstack", 0);
+
+ // Every splitting function ensures that there are at least StackLimit
+ // bytes available below SP when the splitting prologue finishes.
+ // If the splitting function calls F, then F begins execution with
+ // at least StackLimit - callsize() bytes available.
+ // Check that every function behaves correctly with this amount
+ // of stack, following direct calls in order to piece together chains
+ // of non-splitting functions.
+ ch.up = nil;
+ ch.limit = StackLimit - callsize();
+
+ // Check every function, but do the nosplit functions in a first pass,
+ // to make the printed failure chains as short as possible.
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ // runtime.racesymbolizethunk is called from gcc-compiled C
+ // code running on the operating system thread stack.
+ // It uses more than the usual amount of stack but that's okay.
+ if(strcmp(s->name, "runtime.racesymbolizethunk") == 0)
continue;
- cursym = s;
- ch.up = nil;
+
+ if(s->nosplit) {
+ ctxt->cursym = s;
ch.sym = s;
- ch.limit = StackLimit - CallSize;
stkcheck(&ch, 0);
- s->stkcheck = 1;
}
-
- // Check calling contexts.
- // Some nosplits get called a little further down,
- // like newproc and deferproc. We could hard-code
- // that knowledge but it's more robust to look at
- // the actual call sites.
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0)
- continue;
- cursym = s;
- ch.up = nil;
+ }
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(!s->nosplit) {
+ ctxt->cursym = s;
ch.sym = s;
- ch.limit = StackLimit - CallSize;
stkcheck(&ch, 0);
}
}
+}
static int
stkcheck(Chain *up, int depth)
{
Chain ch, ch1;
- Prog *p;
- Sym *s;
- int limit, prolog;
+ LSym *s;
+ int limit;
+ Reloc *r, *endr;
+ Pciter pcsp;
limit = up->limit;
s = up->sym;
- p = s->text;
- // Small optimization: don't repeat work at top.
- if(s->stkcheck && limit == StackLimit-CallSize)
+ // Don't duplicate work: only need to consider each
+ // function at top of safe zone once.
+ if(limit == StackLimit-callsize()) {
+ if(s->stkcheck)
return 0;
+ s->stkcheck = 1;
+ }
if(depth > 100) {
diag("nosplit stack check too deep");
@@ -1728,11 +1104,11 @@ stkcheck(Chain *up, int depth)
return -1;
}
- if(p == nil || p->link == nil) {
+ if(s->external || s->pcln == nil) {
// external function.
// should never be called directly.
// only diagnose the direct caller.
- if(depth == 1)
+ if(depth == 1 && s->type != SXREF)
diag("call to external function %s", s->name);
return -1;
}
@@ -1748,50 +1124,56 @@ stkcheck(Chain *up, int depth)
return 0;
ch.up = up;
- prolog = (s->text->textflag & NOSPLIT) == 0;
- for(p = s->text; p != P; p = p->link) {
- limit -= p->spadj;
- if(prolog && p->spadj != 0) {
- // The first stack adjustment in a function with a
- // split-checking prologue marks the end of the
- // prologue. Assuming the split check is correct,
- // after the adjustment there should still be at least
- // StackLimit bytes available below the stack pointer.
- // If this is not the top call in the chain, no need
- // to duplicate effort, so just stop.
- if(depth > 0)
- return 0;
- prolog = 0;
- limit = StackLimit;
- }
- if(limit < 0) {
- stkbroke(up, limit);
+
+ // Walk through sp adjustments in function, consuming relocs.
+ r = s->r;
+ endr = r + s->nr;
+ for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) {
+ // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
+
+ // Check stack size in effect for this span.
+ if(limit - pcsp.value < 0) {
+ stkbroke(up, limit - pcsp.value);
return -1;
}
- if(iscall(p)) {
- limit -= CallSize;
- ch.limit = limit;
- if(p->to.type == D_BRANCH) {
+
+ // Process calls in this span.
+ for(; r < endr && r->off < pcsp.nextpc; r++) {
+ switch(r->type) {
+ case R_CALL:
+ case R_CALLARM:
// Direct call.
- ch.sym = p->to.sym;
+ ch.limit = limit - pcsp.value - callsize();
+ ch.sym = r->sym;
if(stkcheck(&ch, depth+1) < 0)
return -1;
- } else {
- // Indirect call. Assume it is a splitting function,
+
+ // If this is a call to morestack, we've just raised our limit back
+ // to StackLimit beyond the frame size.
+ if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) {
+ limit = StackLimit + s->locals;
+ if(thechar == '5')
+ limit += 4; // saved LR
+ }
+ break;
+
+ case R_CALLIND:
+ // Indirect call. Assume it is a call to a splitting function,
// so we have to make sure it can call morestack.
- limit -= CallSize;
+ // Arrange the data structures to report both calls, so that
+ // if there is an error, stkprint shows all the steps involved.
+ ch.limit = limit - pcsp.value - callsize();
ch.sym = nil;
- ch1.limit = limit;
+ ch1.limit = ch.limit - callsize(); // for morestack in called prologue
ch1.up = &ch;
ch1.sym = morestack;
if(stkcheck(&ch1, depth+2) < 0)
return -1;
- limit += CallSize;
+ break;
}
- limit += CallSize;
+ }
}
- }
return 0;
}
@@ -1814,7 +1196,7 @@ stkprint(Chain *ch, int limit)
if(ch->up == nil) {
// top of chain. ch->sym != nil.
- if(ch->sym->text->textflag & NOSPLIT)
+ if(ch->sym->nosplit)
print("\t%d\tassumed on entry to %s\n", ch->limit, name);
else
print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
@@ -1828,52 +1210,14 @@ stkprint(Chain *ch, int limit)
}
int
-headtype(char *name)
-{
- int i;
-
- for(i=0; headers[i].name; i++)
- if(strcmp(name, headers[i].name) == 0) {
- headstring = headers[i].name;
- return headers[i].val;
- }
- fprint(2, "unknown header type -H %s\n", name);
- errorexit();
- return -1; // not reached
-}
-
-char*
-headstr(int v)
-{
- static char buf[20];
- int i;
-
- for(i=0; headers[i].name; i++)
- if(v == headers[i].val)
- return headers[i].name;
- snprint(buf, sizeof buf, "%d", v);
- return buf;
-}
-
-void
-undef(void)
-{
- Sym *s;
-
- for(s = allsym; s != S; s = s->allsym)
- if(s->type == SXREF)
- diag("%s(%d): not defined", s->name, s->version);
-}
-
-int
Yconv(Fmt *fp)
{
- Sym *s;
+ LSym *s;
Fmt fmt;
int i;
char *str;
- s = va_arg(fp->args, Sym*);
+ s = va_arg(fp->args, LSym*);
if (s == S) {
fmtprint(fp, "<nil>");
} else {
@@ -1967,6 +1311,14 @@ usage(void)
void
setheadtype(char *s)
{
+ int h;
+
+ h = headtype(s);
+ if(h < 0) {
+ fprint(2, "unknown header type -H %s\n", s);
+ errorexit();
+ }
+ headstring = s;
HEADTYPE = headtype(s);
}
@@ -1985,22 +1337,22 @@ doversion(void)
}
void
-genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
{
Auto *a;
- Sym *s;
+ LSym *s;
int32 off;
// These symbols won't show up in the first loop below because we
// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
- s = lookup("text", 0);
+ s = linklookup(ctxt, "text", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- s = lookup("etext", 0);
+ s = linklookup(ctxt, "etext", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- for(s=allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
continue;
switch(s->type&SMASK) {
@@ -2036,20 +1388,20 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
}
}
- for(s = textp; s != nil; s = s->next) {
- if(s->text == nil)
- continue;
-
+ for(s = ctxt->textp; s != nil; s = s->next) {
put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+ // NOTE(ality): acid can't produce a stack trace without .frame symbols
+ put(nil, ".frame", 'm', s->locals+PtrSize, 0, 0, 0);
+
for(a=s->autom; a; a=a->link) {
// Emit a or p according to actual offset, even if label is wrong.
// This avoids negative offsets, which cannot be encoded.
- if(a->type != D_AUTO && a->type != D_PARAM)
+ if(a->type != A_AUTO && a->type != A_PARAM)
continue;
// compute offset relative to FP
- if(a->type == D_PARAM)
+ if(a->type == A_PARAM)
off = a->aoffset;
else
off = a->aoffset - PtrSize;
@@ -2075,461 +1427,126 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bflush(&bso);
}
-char*
-estrdup(char *p)
-{
- p = strdup(p);
- if(p == nil) {
- cursym = S;
- diag("out of memory");
- errorexit();
- }
- return p;
-}
-
-void*
-erealloc(void *p, long n)
+vlong
+symaddr(LSym *s)
{
- p = realloc(p, n);
- if(p == nil) {
- cursym = S;
- diag("out of memory");
- errorexit();
- }
- return p;
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-// Saved history stacks encountered while reading archives.
-// Keeping them allows us to answer virtual lineno -> file:line
-// queries.
-//
-// The history stack is a complex data structure, described best at the
-// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
-// One of the key benefits of interpreting it here is that the runtime
-// does not have to. Perhaps some day the compilers could generate
-// a simpler linker input too.
-
-struct Hist
-{
- int32 line;
- int32 off;
- Sym *file;
-};
-
-static Hist *histcopy;
-static Hist *hist;
-static int32 nhist;
-static int32 maxhist;
-static int32 histdepth;
-static int32 nhistfile;
-static Sym *filesyms;
-
-// savehist processes a single line, off history directive
-// found in the input object file.
void
-savehist(int32 line, int32 off)
+xdefine(char *p, int t, vlong v)
{
- char tmp[1024];
- Sym *file;
- Hist *h;
-
- // NOTE(rsc): We used to do the copyhistfrog first and this
- // condition was if(tmp[0] != '\0') to check for an empty string,
- // implying that histfrogp == 0, implying that this is a history pop.
- // However, on Windows in the misc/cgo test, the linker is
- // presented with an ANAME corresponding to an empty string,
- // that ANAME ends up being the only histfrog, and thus we have
- // a situation where histfrogp > 0 (not a pop) but the path we find
- // is the empty string. Really that shouldn't happen, but it doesn't
- // seem to be bothering anyone yet, and it's easier to fix the condition
- // to test histfrogp than to track down where that empty string is
- // coming from. Probably it is coming from go tool pack's P command.
- if(histfrogp > 0) {
- tmp[0] = '\0';
- copyhistfrog(tmp, sizeof tmp);
- file = lookup(tmp, HistVersion);
- if(file->type != SFILEPATH) {
- file->value = ++nhistfile;
- file->type = SFILEPATH;
- file->next = filesyms;
- filesyms = file;
- }
- } else
- file = nil;
+ LSym *s;
- if(file != nil && line == 1 && off == 0) {
- // start of new stack
- if(histdepth != 0) {
- diag("history stack phase error: unexpected start of new stack depth=%d file=%s", histdepth, tmp);
- errorexit();
- }
- nhist = 0;
- histcopy = nil;
- }
-
- if(nhist >= maxhist) {
- if(maxhist == 0)
- maxhist = 1;
- maxhist *= 2;
- hist = erealloc(hist, maxhist*sizeof hist[0]);
- }
- h = &hist[nhist++];
- h->line = line;
- h->off = off;
- h->file = file;
-
- if(file != nil) {
- if(off == 0)
- histdepth++;
- } else {
- if(off != 0) {
- diag("history stack phase error: bad offset in pop");
- errorexit();
- }
- histdepth--;
- }
+ s = linklookup(ctxt, p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
-// gethist returns the history stack currently in effect.
-// The result is valid indefinitely.
-Hist*
-gethist(void)
+vlong
+datoff(vlong addr)
{
- if(histcopy == nil) {
- if(nhist == 0)
- return nil;
- histcopy = mal((nhist+1)*sizeof hist[0]);
- memmove(histcopy, hist, nhist*sizeof hist[0]);
- histcopy[nhist].line = -1;
- }
- return histcopy;
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
+ diag("datoff %#llx", addr);
+ return 0;
}
-typedef struct Hstack Hstack;
-struct Hstack
-{
- Hist *h;
- int delta;
-};
-
-// getline sets *f to the file number and *l to the line number
-// of the virtual line number line according to the history stack h.
-void
-getline(Hist *h, int32 line, int32 *f, int32 *l)
+vlong
+entryvalue(void)
{
- Hstack stk[100];
- int nstk, start;
- Hist *top, *h0;
- static Hist *lasth;
- static int32 laststart, lastend, lastdelta, lastfile;
-
- h0 = h;
- *f = 0;
- *l = 0;
- start = 0;
- if(h == nil || line == 0) {
- print("%s: getline: h=%p line=%d\n", cursym->name, h, line);
- return;
- }
-
- // Cache span used during last lookup, so that sequential
- // translation of line numbers in compiled code is efficient.
- if(!debug['O'] && lasth == h && laststart <= line && line < lastend) {
- *f = lastfile;
- *l = line - lastdelta;
- return;
- }
-
- if(debug['O'])
- print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
-
- nstk = 0;
- for(; h->line != -1; h++) {
- if(debug['O'])
- print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
-
- if(h->line > line) {
- if(nstk == 0) {
- diag("history stack phase error: empty stack at line %d", (int)line);
- errorexit();
- }
- top = stk[nstk-1].h;
- lasth = h;
- lastfile = top->file->value;
- laststart = start;
- lastend = h->line;
- lastdelta = stk[nstk-1].delta;
- *f = lastfile;
- *l = line - lastdelta;
- if(debug['O'])
- print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
- return;
- }
- if(h->file == nil) {
- // pop included file
- if(nstk == 0) {
- diag("history stack phase error: stack underflow");
- errorexit();
- }
- nstk--;
- if(nstk > 0)
- stk[nstk-1].delta += h->line - stk[nstk].h->line;
- start = h->line;
- } else if(h->off == 0) {
- // push included file
- if(nstk >= nelem(stk)) {
- diag("history stack phase error: stack overflow");
- errorexit();
- }
- start = h->line;
- stk[nstk].h = h;
- stk[nstk].delta = h->line - 1;
- nstk++;
- } else {
- // #line directive
- if(nstk == 0) {
- diag("history stack phase error: stack underflow");
- errorexit();
- }
- stk[nstk-1].h = h;
- stk[nstk-1].delta = h->line - h->off;
- start = h->line;
- }
- if(debug['O'])
- print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
- }
+ char *a;
+ LSym *s;
- diag("history stack phase error: cannot find line for %d", line);
- nstk = 0;
- for(h = h0; h->line != -1; h++) {
- print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
- if(h->file == nil)
- nstk--;
- else if(h->off == 0)
- nstk++;
- }
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = linklookup(ctxt, a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT)
+ diag("entry not text: %s", s->name);
+ return s->value;
}
-// defgostring returns a symbol for the Go string containing text.
-Sym*
-defgostring(char *text)
+static void
+undefsym(LSym *s)
{
- char *p;
- Sym *s;
- int32 n;
-
- n = strlen(text);
- p = smprint("go.string.\"%Z\"", text);
- s = lookup(p, 0);
- if(s->size == 0) {
- s->type = SGOSTRING;
- s->reachable = 1;
- s->size = 2*PtrSize+n;
- symgrow(s, 2*PtrSize+n);
- setaddrplus(s, 0, s, 2*PtrSize);
- setuintxx(s, PtrSize, n, PtrSize);
- memmove(s->p+2*PtrSize, text, n);
- }
- s->reachable = 1;
- return s;
-}
+ int i;
+ Reloc *r;
-// addpctab appends to f a pc-value table, storing its offset at off.
-// The pc-value table is for func and reports the value of valfunc
-// parameterized by arg.
-static int32
-addpctab(Sym *f, int32 off, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg)
-{
- int32 start;
-
- start = f->np;
- funcpctab(f, func, desc, valfunc, arg);
- if(start == f->np) {
- // no table
- return setuint32(f, off, 0);
- }
- if((int32)start > (int32)f->np) {
- diag("overflow adding pc-table: symbol too large");
- errorexit();
+ ctxt->cursym = s;
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ if(r->sym == nil) // happens for some external ARM relocs
+ continue;
+ if(r->sym->type == Sxxx || r->sym->type == SXREF)
+ diag("undefined: %s", r->sym->name);
+ if(!r->sym->reachable)
+ diag("use of unreachable symbol: %s", r->sym->name);
}
- return setuint32(f, off, start);
}
-static int32
-ftabaddstring(Sym *ftab, char *s)
+void
+undef(void)
{
- int32 n, start;
+ LSym *s;
- n = strlen(s)+1;
- start = ftab->np;
- symgrow(ftab, start+n+1);
- strcpy((char*)ftab->p + start, s);
- return start;
+ for(s = ctxt->textp; s != nil; s = s->next)
+ undefsym(s);
+ for(s = datap; s != nil; s = s->next)
+ undefsym(s);
+ if(nerrors > 0)
+ errorexit();
}
-// pclntab initializes the pclntab symbol with
-// runtime function and file name information.
void
-pclntab(void)
+callgraph(void)
{
- Prog *p;
- int32 i, n, nfunc, start, funcstart;
- uint32 *havepc, *havefunc;
- Sym *ftab, *s;
- int32 npcdata, nfuncdata, off, end;
- int64 funcdata_bytes;
-
- funcdata_bytes = 0;
- ftab = lookup("pclntab", 0);
- ftab->type = SPCLNTAB;
- ftab->reachable = 1;
-
- // See golang.org/s/go12symtab for the format. Briefly:
- // 8-byte header
- // nfunc [PtrSize bytes]
- // function table, alternating PC and offset to func struct [each entry PtrSize bytes]
- // end PC [PtrSize bytes]
- // offset to file table [4 bytes]
- nfunc = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next)
- nfunc++;
- symgrow(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
- setuint32(ftab, 0, 0xfffffffb);
- setuint8(ftab, 6, MINLC);
- setuint8(ftab, 7, PtrSize);
- setuintxx(ftab, 8, nfunc, PtrSize);
-
- nfunc = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next, nfunc++) {
- funcstart = ftab->np;
- funcstart += -ftab->np & (PtrSize-1);
-
- setaddr(ftab, 8+PtrSize+nfunc*2*PtrSize, cursym);
- setuintxx(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
-
- npcdata = 0;
- nfuncdata = 0;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == APCDATA && p->from.offset >= npcdata)
- npcdata = p->from.offset+1;
- if(p->as == AFUNCDATA && p->from.offset >= nfuncdata)
- nfuncdata = p->from.offset+1;
- }
-
- // fixed size of struct, checked below
- off = funcstart;
- end = funcstart + PtrSize + 3*4 + 5*4 + npcdata*4 + nfuncdata*PtrSize;
- if(nfuncdata > 0 && (end&(PtrSize-1)))
- end += 4;
- symgrow(ftab, end);
-
- // entry uintptr
- off = setaddr(ftab, off, cursym);
-
- // name int32
- off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name));
-
- // args int32
- // TODO: Move into funcinfo.
- if(cursym->text == nil)
- off = setuint32(ftab, off, ArgsSizeUnknown);
- else
- off = setuint32(ftab, off, cursym->args);
-
- // frame int32
- // TODO: Remove entirely. The pcsp table is more precise.
- // This is only used by a fallback case during stack walking
- // when a called function doesn't have argument information.
- // We need to make sure everything has argument information
- // and then remove this.
- if(cursym->text == nil)
- off = setuint32(ftab, off, 0);
- else
- off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize);
-
- // pcsp table (offset int32)
- off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0);
-
- // pcfile table (offset int32)
- off = addpctab(ftab, off, cursym, "pctofileline file", pctofileline, 0);
+ LSym *s;
+ Reloc *r;
+ int i;
- // pcln table (offset int32)
- off = addpctab(ftab, off, cursym, "pctofileline line", pctofileline, 1);
-
- // npcdata int32
- off = setuint32(ftab, off, npcdata);
-
- // nfuncdata int32
- off = setuint32(ftab, off, nfuncdata);
-
- // tabulate which pc and func data we have.
- n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
- havepc = mal(n);
- havefunc = havepc + (npcdata+31)/32;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == AFUNCDATA) {
- if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
- diag("multiple definitions for FUNCDATA $%d", p->from.offset);
- havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
- }
- if(p->as == APCDATA)
- havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
- }
+ if(!debug['c'])
+ return;
- // pcdata.
- for(i=0; i<npcdata; i++) {
- if(!(havepc[i/32]>>(i%32))&1) {
- off = setuint32(ftab, off, 0);
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ if(r->sym == nil)
continue;
- }
- off = addpctab(ftab, off, cursym, "pctopcdata", pctopcdata, i);
- }
-
- unmal(havepc, n);
-
- // funcdata, must be pointer-aligned and we're only int32-aligned.
- // Unlike pcdata, can gather in a single pass.
- // Missing funcdata will be 0 (nil pointer).
- if(nfuncdata > 0) {
- if(off&(PtrSize-1))
- off += 4;
- for(p = cursym->text; p != P; p = p->link) {
- if(p->as == AFUNCDATA) {
- i = p->from.offset;
- if(p->to.type == D_CONST)
- setuintxx(ftab, off+PtrSize*i, p->to.offset, PtrSize);
- else {
- // TODO: Dedup.
- funcdata_bytes += p->to.sym->size;
- setaddrplus(ftab, off+PtrSize*i, p->to.sym, p->to.offset);
- }
- }
- }
- off += nfuncdata*PtrSize;
- }
-
- if(off != end) {
- diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, npcdata, nfuncdata);
- errorexit();
+ if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT)
+ Bprint(&bso, "%s calls %s\n", s->name, r->sym->name);
}
-
- // Final entry of table is just end pc.
- if(cursym->next == nil)
- setaddrplus(ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, cursym, cursym->size);
}
-
- // Start file table.
- start = ftab->np;
- start += -ftab->np & (PtrSize-1);
- setuint32(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
+}
- symgrow(ftab, start+(nhistfile+1)*4);
- setuint32(ftab, start, nhistfile);
- for(s = filesyms; s != S; s = s->next)
- setuint32(ftab, start + s->value*4, ftabaddstring(ftab, s->name));
+void
+diag(char *fmt, ...)
+{
+ char buf[1024], *tn, *sep;
+ va_list arg;
- ftab->size = ftab->np;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
-}
+ tn = "";
+ sep = "";
+ if(ctxt->cursym != S) {
+ tn = ctxt->cursym->name;
+ sep = ": ";
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s%s%s\n", tn, sep, buf);
+
+ nerrors++;
+ if(nerrors > 20) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index be95bb46e..7267c6371 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -28,68 +28,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-enum
-{
- Sxxx,
-
- /* order here is order in output file */
- /* readonly, executable */
- STEXT,
- SELFRXSECT,
-
- /* readonly, non-executable */
- STYPE,
- SSTRING,
- SGOSTRING,
- SGOFUNC,
- SRODATA,
- SFUNCTAB,
- STYPELINK,
- SSYMTAB, // TODO: move to unmapped section
- SPCLNTAB,
- SELFROSECT,
-
- /* writable, non-executable */
- SMACHOPLT,
- SELFSECT,
- SMACHO, /* Mach-O __nl_symbol_ptr */
- SMACHOGOT,
- SNOPTRDATA,
- SINITARR,
- SDATA,
- SWINDOWS,
- SBSS,
- SNOPTRBSS,
- STLSBSS,
-
- /* not mapped */
- SXREF,
- SMACHOSYMSTR,
- SMACHOSYMTAB,
- SMACHOINDIRECTPLT,
- SMACHOINDIRECTGOT,
- SFILE,
- SFILEPATH,
- SCONST,
- SDYNIMPORT,
- SHOSTOBJ,
-
- SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
- SMASK = SSUB - 1,
- SHIDDEN = 1<<9, // hidden or local symbol
-
- NHASH = 100003,
-};
-
-typedef struct Library Library;
-struct Library
-{
- char *objref; // object where we found the reference
- char *srcref; // src file where we found the reference
- char *file; // object file
- char *pkg; // import path
-};
-
// Terrible but standard terminology.
// A segment describes a block of file to load into memory.
// A section further describes the pieces of that block for
@@ -125,39 +63,18 @@ struct Section
uvlong rellen;
};
-typedef struct Hist Hist;
-
-#pragma incomplete struct Hist
-
extern char symname[];
-extern char **libdir;
-extern int nlibdir;
-extern int version;
EXTERN char* INITENTRY;
-EXTERN char* thestring;
-EXTERN Library* library;
-EXTERN int libraryp;
-EXTERN int nlibrary;
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* allsym;
-EXTERN Sym* histfrog[MAXHIST];
-EXTERN uchar fnuxi8[8];
-EXTERN uchar fnuxi4[4];
-EXTERN int histfrogp;
-EXTERN int histgen;
-EXTERN uchar inuxi1[1];
-EXTERN uchar inuxi2[2];
-EXTERN uchar inuxi4[4];
-EXTERN uchar inuxi8[8];
+extern char* thestring;
+extern LinkArch* thelinkarch;
EXTERN char* outfile;
-EXTERN int32 nsymbol;
-EXTERN char* thestring;
EXTERN int ndynexp;
-EXTERN Sym** dynexp;
+EXTERN LSym** dynexp;
EXTERN int nldflag;
EXTERN char** ldflag;
EXTERN int havedynamic;
+EXTERN int funcalign;
EXTERN int iscgo;
EXTERN int elfglobalsymndx;
EXTERN char* flag_installsuffix;
@@ -169,16 +86,21 @@ EXTERN char* tmpdir;
EXTERN char* extld;
EXTERN char* extldflags;
EXTERN int debug_s; // backup old value of debug['s']
+EXTERN Link* ctxt;
+EXTERN int32 HEADR;
+EXTERN int32 HEADTYPE;
+EXTERN int32 INITRND;
+EXTERN int64 INITTEXT;
+EXTERN int64 INITDAT;
+EXTERN char* INITENTRY; /* entry point */
+EXTERN char* noname;
+EXTERN char* paramspace;
+EXTERN int nerrors;
-enum
-{
- LinkAuto = 0,
- LinkInternal,
- LinkExternal,
-};
EXTERN int linkmode;
+EXTERN int64 liveness;
-// for dynexport field of Sym
+// for dynexport field of LSym
enum
{
CgoExportDynamic = 1<<0,
@@ -190,119 +112,6 @@ EXTERN Segment segrodata;
EXTERN Segment segdata;
EXTERN Segment segdwarf;
-void setlinkmode(char*);
-void addlib(char *src, char *obj);
-void addlibpath(char *srcref, char *objref, char *file, char *pkg);
-Section* addsection(Segment*, char*, int);
-void copyhistfrog(char *buf, int nbuf);
-void addhist(int32 line, int type);
-void savehist(int32 line, int32 off);
-Hist* gethist(void);
-void getline(Hist*, int32 line, int32 *f, int32 *l);
-void asmlc(void);
-void histtoauto(void);
-void collapsefrog(Sym *s);
-Sym* newsym(char *symb, int v);
-Sym* lookup(char *symb, int v);
-Sym* rlookup(char *symb, int v);
-void nuxiinit(void);
-int find1(int32 l, int c);
-int find2(int32 l, int c);
-int32 ieeedtof(Ieee *e);
-double ieeedtod(Ieee *e);
-void undefsym(Sym *s);
-void zerosig(char *sp);
-void readundefs(char *f, int t);
-void loadlib(void);
-void errorexit(void);
-void mangle(char*);
-void objfile(char *file, char *pkg);
-void libinit(void);
-void pclntab(void);
-void symtab(void);
-void Lflag(char *arg);
-void usage(void);
-void adddynrel(Sym*, Reloc*);
-void adddynrela(Sym*, Sym*, Reloc*);
-void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, char*, int);
-void ldelf(Biobuf*, char*, int64, char*);
-void ldmacho(Biobuf*, char*, int64, char*);
-void ldpe(Biobuf*, char*, int64, char*);
-void ldpkg(Biobuf*, char*, int64, char*, int);
-void mark(Sym *s);
-void mkfwd(void);
-char* expandpkg(char*, char*);
-void deadcode(void);
-Reloc* addrel(Sym*);
-void codeblk(int32, int32);
-void datblk(int32, int32);
-void reloc(void);
-void relocsym(Sym*);
-void savedata(Sym*, Prog*, char*);
-void symgrow(Sym*, int32);
-void addstrdata(char*, char*);
-vlong addstring(Sym*, char*);
-vlong adduint8(Sym*, uint8);
-vlong adduint16(Sym*, uint16);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong adduintxx(Sym*, uint64, int);
-vlong addaddr(Sym*, Sym*);
-vlong addaddrplus(Sym*, Sym*, vlong);
-vlong addpcrelplus(Sym*, Sym*, vlong);
-vlong addsize(Sym*, Sym*);
-vlong setaddrplus(Sym*, vlong, Sym*, vlong);
-vlong setaddr(Sym*, vlong, Sym*);
-vlong setuint8(Sym*, vlong, uint8);
-vlong setuint16(Sym*, vlong, uint16);
-vlong setuint32(Sym*, vlong, uint32);
-vlong setuint64(Sym*, vlong, uint64);
-vlong setuintxx(Sym*, vlong, uint64, vlong);
-void asmsym(void);
-void asmelfsym(void);
-void asmplan9sym(void);
-void putelfsectionsym(Sym*, int);
-void putelfsymshndx(vlong, int);
-void strnput(char*, int);
-void dodata(void);
-void dosymtype(void);
-void address(void);
-void textaddress(void);
-void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
-vlong datoff(vlong);
-void adddynlib(char*);
-int archreloc(Reloc*, Sym*, vlong*);
-void adddynsym(Sym*);
-void addexport(void);
-void dostkcheck(void);
-void undef(void);
-void doweak(void);
-void setpersrc(Sym*);
-void doversion(void);
-void usage(void);
-void setinterp(char*);
-Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
-int valuecmp(Sym*, Sym*);
-void hostobjs(void);
-void hostlink(void);
-char* estrdup(char*);
-void* erealloc(void*, long);
-Sym* defgostring(char*);
-
-int pathchar(void);
-void* mal(uint32);
-void unmal(void*, uint32);
-void mywhatsys(void);
-int rbyoff(const void*, const void*);
-
-uint16 le16(uchar*);
-uint32 le32(uchar*);
-uint64 le64(uchar*);
-uint16 be16(uchar*);
-uint32 be32(uchar*);
-uint64 be64(uchar*);
-
typedef struct Endian Endian;
struct Endian
{
@@ -325,28 +134,6 @@ enum {
Pkgdef
};
-/* executable header types */
-enum {
- Hgarbunix = 0, // garbage unix
- Hnoheader, // no header
- Hunixcoff, // unix coff
- Hrisc, // aif for risc os
- Hplan9x32, // plan 9 32-bit format
- Hplan9x64, // plan 9 64-bit format
- Hmsdoscom, // MS-DOS .COM
- Hnetbsd, // NetBSD
- Hmsdosexe, // fake MS-DOS .EXE
- Hixp1200, // IXP1200 (raw)
- Helf, // ELF32
- Hipaq, // ipaq
- Hdarwin, // Apple Mach-O
- Hlinux, // Linux ELF
- Hfreebsd, // FreeBSD ELF
- Hwindows, // MS Windows PE
- Hopenbsd, // OpenBSD ELF
- Hdragonfly, // DragonFly ELF
-};
-
typedef struct Header Header;
struct Header {
char *name;
@@ -356,14 +143,9 @@ struct Header {
EXTERN char* headstring;
extern Header headers[];
-int headtype(char*);
-char* headstr(int);
-void setheadtype(char*);
-
-int Yconv(Fmt*);
-
-#pragma varargck type "O" int
-#pragma varargck type "Y" Sym*
+#pragma varargck type "Y" LSym*
+#pragma varargck type "Z" char*
+#pragma varargck type "i" char*
// buffered output
@@ -383,29 +165,117 @@ EXTERN char* cbpmax;
if(--cbc <= 0)\
cflush(); }
+void Lflag(char *arg);
+int Yconv(Fmt *fp);
+int Zconv(Fmt *fp);
+void addexport(void);
+void address(void);
+Section*addsection(Segment *seg, char *name, int rwx);
+void addstrdata(char *name, char *value);
+vlong addstring(LSym *s, char *str);
+void asmelfsym(void);
+void asmplan9sym(void);
+uint16 be16(uchar *b);
+uint32 be32(uchar *b);
+uint64 be64(uchar *b);
+void callgraph(void);
void cflush(void);
+void codeblk(int32 addr, int32 size);
vlong cpos(void);
-void cseek(vlong);
-void cwrite(void*, int);
+void cseek(vlong p);
+void cwrite(void *buf, int n);
+void datblk(int32 addr, int32 size);
+int datcmp(LSym *s1, LSym *s2);
+vlong datoff(vlong addr);
+void deadcode(void);
+LSym* decodetype_arrayelem(LSym *s);
+vlong decodetype_arraylen(LSym *s);
+LSym* decodetype_chanelem(LSym *s);
+int decodetype_funcdotdotdot(LSym *s);
+int decodetype_funcincount(LSym *s);
+LSym* decodetype_funcintype(LSym *s, int i);
+int decodetype_funcoutcount(LSym *s);
+LSym* decodetype_funcouttype(LSym *s, int i);
+LSym* decodetype_gc(LSym *s);
+vlong decodetype_ifacemethodcount(LSym *s);
+uint8 decodetype_kind(LSym *s);
+LSym* decodetype_mapkey(LSym *s);
+LSym* decodetype_mapvalue(LSym *s);
+LSym* decodetype_ptrelem(LSym *s);
+vlong decodetype_size(LSym *s);
+int decodetype_structfieldcount(LSym *s);
+char* decodetype_structfieldname(LSym *s, int i);
+vlong decodetype_structfieldoffs(LSym *s, int i);
+LSym* decodetype_structfieldtype(LSym *s, int i);
+void dodata(void);
+void dostkcheck(void);
+void dostkoff(void);
+void dosymtype(void);
+void doversion(void);
+void doweak(void);
+void dynreloc(void);
+void dynrelocsym(LSym *s);
+vlong entryvalue(void);
+void errorexit(void);
+void follow(void);
+void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*));
+void growdatsize(vlong *datsizep, LSym *s);
+char* headstr(int v);
+int headtype(char *name);
+void hostlink(void);
+void hostobjs(void);
+int iconv(Fmt *fp);
void importcycles(void);
-int Zconv(Fmt*);
+void linkarchinit(void);
+void ldelf(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file);
+void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence);
+void ldpe(Biobuf *f, char *pkg, int64 len, char *pn);
+void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence);
+uint16 le16(uchar *b);
+uint32 le32(uchar *b);
+uint64 le64(uchar *b);
+void libinit(void);
+LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off);
+void loadinternal(char *name);
+void loadlib(void);
+void lputb(int32 l);
+void lputl(int32 l);
+void* mal(uint32 n);
+void mark(LSym *s);
+void mywhatsys(void);
+struct ar_hdr;
+void objfile(char *file, char *pkg);
+void patch(void);
+int pathchar(void);
+void pcln(void);
+void pclntab(void);
+void putelfsectionsym(LSym* s, int shndx);
+void putelfsymshndx(vlong sympos, int shndx);
+void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);
+int rbyoff(const void *va, const void *vb);
+void reloc(void);
+void relocsym(LSym *s);
+void setheadtype(char *s);
+void setinterp(char *s);
+void setlinkmode(char *arg);
+void span(void);
+void strnput(char *s, int n);
+vlong symaddr(LSym *s);
+void symtab(void);
+void textaddress(void);
+void undef(void);
+void unmal(void *v, uint32 n);
+void usage(void);
+void vputb(uint64 v);
+int valuecmp(LSym *a, LSym *b);
+void vputl(uint64 v);
+void wputb(ushort w);
+void wputl(ushort w);
+void xdefine(char *p, int t, vlong v);
+void zerosig(char *sp);
+void archinit(void);
+void diag(char *fmt, ...);
-uint8 decodetype_kind(Sym*);
-vlong decodetype_size(Sym*);
-Sym* decodetype_gc(Sym*);
-Sym* decodetype_arrayelem(Sym*);
-vlong decodetype_arraylen(Sym*);
-Sym* decodetype_ptrelem(Sym*);
-Sym* decodetype_mapkey(Sym*);
-Sym* decodetype_mapvalue(Sym*);
-Sym* decodetype_chanelem(Sym*);
-int decodetype_funcdotdotdot(Sym*);
-int decodetype_funcincount(Sym*);
-int decodetype_funcoutcount(Sym*);
-Sym* decodetype_funcintype(Sym*, int);
-Sym* decodetype_funcouttype(Sym*, int);
-int decodetype_structfieldcount(Sym*);
-char* decodetype_structfieldname(Sym*, int);
-Sym* decodetype_structfieldtype(Sym*, int);
-vlong decodetype_structfieldoffs(Sym*, int);
-vlong decodetype_ifacemethodcount(Sym*);
+#pragma varargck argpos diag 1
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index d135a92da..61306bb7c 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -25,7 +25,7 @@ enum
};
static int nkind[NumSymKind];
-static Sym** sortsym;
+static LSym** sortsym;
static int nsortsym;
// Amount of space left for adding load commands
@@ -232,37 +232,37 @@ machowrite(void)
void
domacho(void)
{
- Sym *s;
+ LSym *s;
if(debug['d'])
return;
// empirically, string table must begin with " \x00".
- s = lookup(".machosymstr", 0);
+ s = linklookup(ctxt, ".machosymstr", 0);
s->type = SMACHOSYMSTR;
s->reachable = 1;
- adduint8(s, ' ');
- adduint8(s, '\0');
+ adduint8(ctxt, s, ' ');
+ adduint8(ctxt, s, '\0');
- s = lookup(".machosymtab", 0);
+ s = linklookup(ctxt, ".machosymtab", 0);
s->type = SMACHOSYMTAB;
s->reachable = 1;
if(linkmode != LinkExternal) {
- s = lookup(".plt", 0); // will be __symbol_stub
+ s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub
s->type = SMACHOPLT;
s->reachable = 1;
- s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr
s->type = SMACHOGOT;
s->reachable = 1;
s->align = 4;
- s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt
s->type = SMACHOINDIRECTPLT;
s->reachable = 1;
- s = lookup(".linkedit.got", 0); // indirect table for .got
+ s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got
s->type = SMACHOINDIRECTGOT;
s->reachable = 1;
}
@@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname)
if(strcmp(sect->name, ".got") == 0) {
msect->name = "__nl_symbol_ptr";
msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
}
}
@@ -432,13 +432,13 @@ asmbmacho(void)
}
if(!debug['d']) {
- Sym *s1, *s2, *s3, *s4;
+ LSym *s1, *s2, *s3, *s4;
// must match domacholink below
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".machosymstr", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
+ s4 = linklookup(ctxt, ".machosymstr", 0);
if(linkmode != LinkExternal) {
ms = newMachoSeg("__LINKEDIT", 0);
@@ -484,7 +484,7 @@ asmbmacho(void)
}
static int
-symkind(Sym *s)
+symkind(LSym *s)
{
if(s->type == SDYNIMPORT)
return SymKindUndef;
@@ -494,7 +494,7 @@ symkind(Sym *s)
}
static void
-addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype)
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
{
USED(name);
USED(addr);
@@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp
static int
scmp(const void *p1, const void *p2)
{
- Sym *s1, *s2;
+ LSym *s1, *s2;
int k1, k2;
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
+ s1 = *(LSym**)p1;
+ s2 = *(LSym**)p2;
k1 = symkind(s1);
k2 = symkind(s2);
@@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2)
}
static void
-machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
{
- Sym *s;
+ LSym *s;
genasmsym(put);
- for(s=allsym; s; s=s->allsym)
+ for(s=ctxt->allsym; s; s=s->allsym)
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
if(s->reachable)
put(s, nil, 'D', 0, 0, 0, nil);
@@ -573,39 +573,54 @@ static void
machosymtab(void)
{
int i;
- Sym *symtab, *symstr, *s, *o;
+ LSym *symtab, *symstr, *s, *o;
+ char *p;
- symtab = lookup(".machosymtab", 0);
- symstr = lookup(".machosymstr", 0);
+ symtab = linklookup(ctxt, ".machosymtab", 0);
+ symstr = linklookup(ctxt, ".machosymstr", 0);
for(i=0; i<nsortsym; i++) {
s = sortsym[i];
- adduint32(symtab, symstr->size);
+ adduint32(ctxt, symtab, symstr->size);
// Only add _ to C symbols. Go symbols have dot in the name.
if(strstr(s->extname, ".") == nil)
- adduint8(symstr, '_');
- addstring(symstr, s->extname);
+ adduint8(ctxt, symstr, '_');
+ // replace "·" as ".", because DTrace cannot handle it.
+ if(strstr(s->extname, "·") == nil) {
+ addstring(symstr, s->extname);
+ } else {
+ p = s->extname;
+ while (*p++ != '\0') {
+ if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) {
+ adduint8(ctxt, symstr, '.');
+ p++;
+ } else {
+ adduint8(ctxt, symstr, *p);
+ }
+ }
+ adduint8(ctxt, symstr, '\0');
+ }
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
- adduint8(symtab, 0x01); // type N_EXT, external symbol
- adduint8(symtab, 0); // no section
- adduint16(symtab, 0); // desc
- adduintxx(symtab, 0, PtrSize); // no value
+ adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
+ adduint8(ctxt, symtab, 0); // no section
+ adduint16(ctxt, symtab, 0); // desc
+ adduintxx(ctxt, symtab, 0, PtrSize); // no value
} else {
if(s->cgoexport)
- adduint8(symtab, 0x0f);
+ adduint8(ctxt, symtab, 0x0f);
else
- adduint8(symtab, 0x0e);
+ adduint8(ctxt, symtab, 0x0e);
o = s;
while(o->outer != nil)
o = o->outer;
if(o->sect == nil) {
diag("missing section for %s", s->name);
- adduint8(symtab, 0);
+ adduint8(ctxt, symtab, 0);
} else
- adduint8(symtab, o->sect->extnum);
- adduint16(symtab, 0); // desc
- adduintxx(symtab, symaddr(s), PtrSize);
+ adduint8(ctxt, symtab, o->sect->extnum);
+ adduint16(ctxt, symtab, 0); // desc
+ adduintxx(ctxt, symtab, symaddr(s), PtrSize);
}
}
}
@@ -615,7 +630,7 @@ machodysymtab(void)
{
int n;
MachoLoad *ml;
- Sym *s1, *s2, *s3;
+ LSym *s1, *s2, *s3;
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
@@ -639,9 +654,9 @@ machodysymtab(void)
ml->data[11] = 0; /* nextrefsyms */
// must match domacholink below
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
ml->data[12] = linkoff + s1->size; /* indirectsymoff */
ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
@@ -655,15 +670,15 @@ vlong
domacholink(void)
{
int size;
- Sym *s1, *s2, *s3, *s4;
+ LSym *s1, *s2, *s3, *s4;
machosymtab();
// write data that will be linkedit section
- s1 = lookup(".machosymtab", 0);
- s2 = lookup(".linkedit.plt", 0);
- s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".machosymstr", 0);
+ s1 = linklookup(ctxt, ".machosymtab", 0);
+ s2 = linklookup(ctxt, ".linkedit.plt", 0);
+ s3 = linklookup(ctxt, ".linkedit.got", 0);
+ s4 = linklookup(ctxt, ".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -683,7 +698,7 @@ domacholink(void)
// any alignment padding itself, working around the
// issue.
while(s4->size%16)
- adduint8(s4, 0);
+ adduint8(ctxt, s4, 0);
size = s1->size + s2->size + s3->size + s4->size;
@@ -702,9 +717,9 @@ domacholink(void)
void
-machorelocsect(Section *sect, Sym *first)
+machorelocsect(Section *sect, LSym *first)
{
- Sym *sym;
+ LSym *sym;
int32 eaddr;
Reloc *r;
@@ -726,7 +741,7 @@ machorelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
- cursym = sym;
+ ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@@ -747,7 +762,7 @@ machoemitreloc(void)
while(cpos()&7)
cput(0);
- machorelocsect(segtext.sect, textp);
+ machorelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
machorelocsect(sect, datap);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c
new file mode 100644
index 000000000..788b7c75a
--- /dev/null
+++ b/src/cmd/ld/pass.c
@@ -0,0 +1,104 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Code and data passes.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../../pkg/runtime/stack.h"
+
+void
+follow(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->follow(ctxt, s);
+}
+
+void
+patch(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f mkfwd\n", cputime());
+ Bflush(&bso);
+ for(s = ctxt->textp; s != nil; s = s->next)
+ mkfwd(s);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+
+ if(flag_shared) {
+ s = linklookup(ctxt, "init_array", 0);
+ s->type = SINITARR;
+ s->reachable = 1;
+ s->hide = 1;
+ addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0));
+ }
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ linkpatch(ctxt, s);
+}
+
+void
+dostkoff(void)
+{
+ LSym *s;
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->addstacksplit(ctxt, s);
+}
+
+void
+span(void)
+{
+ LSym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ ctxt->arch->assemble(ctxt, s);
+}
+
+void
+pcln(void)
+{
+ LSym *s;
+
+ for(s = ctxt->textp; s != nil; s = s->next)
+ linkpcln(ctxt, s);
+}
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
new file mode 100644
index 000000000..4c2ffa78e
--- /dev/null
+++ b/src/cmd/ld/pcln.c
@@ -0,0 +1,244 @@
+// 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 "l.h"
+#include "lib.h"
+#include "../../pkg/runtime/funcdata.h"
+
+static void
+addvarint(Pcdata *d, uint32 val)
+{
+ int32 n;
+ uint32 v;
+ uchar *p;
+
+ n = 0;
+ for(v = val; v >= 0x80; v >>= 7)
+ n++;
+ n++;
+
+ if(d->n + n > d->m) {
+ d->m = (d->n + n)*2;
+ d->p = erealloc(d->p, d->m);
+ }
+
+ p = d->p + d->n;
+ for(v = val; v >= 0x80; v >>= 7)
+ *p++ = v | 0x80;
+ *p = v;
+ d->n += n;
+}
+
+static int32
+addpctab(LSym *ftab, int32 off, Pcdata *d)
+{
+ int32 start;
+
+ start = ftab->np;
+ symgrow(ctxt, ftab, start + d->n);
+ memmove(ftab->p + start, d->p, d->n);
+
+ return setuint32(ctxt, ftab, off, start);
+}
+
+static int32
+ftabaddstring(LSym *ftab, char *s)
+{
+ int32 n, start;
+
+ n = strlen(s)+1;
+ start = ftab->np;
+ symgrow(ctxt, ftab, start+n+1);
+ strcpy((char*)ftab->p + start, s);
+ return start;
+}
+
+static void
+renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d)
+{
+ int i;
+ LSym *f;
+ Pcdata out;
+ Pciter it;
+ uint32 v;
+ int32 oldval, newval, val, dv;
+
+ // Give files numbers.
+ for(i=0; i<nfiles; i++) {
+ f = files[i];
+ if(f->type != SFILEPATH) {
+ f->value = ++ctxt->nhistfile;
+ f->type = SFILEPATH;
+ f->next = ctxt->filesyms;
+ ctxt->filesyms = f;
+ }
+ }
+
+ newval = -1;
+ memset(&out, 0, sizeof out);
+
+ for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) {
+ // value delta
+ oldval = it.value;
+ if(oldval == -1)
+ val = -1;
+ else {
+ if(oldval < 0 || oldval >= nfiles)
+ sysfatal("bad pcdata %d", oldval);
+ val = files[oldval]->value;
+ }
+ dv = val - newval;
+ newval = val;
+ v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31);
+ addvarint(&out, v);
+
+ // pc delta
+ addvarint(&out, (it.nextpc - it.pc) / it.pcscale);
+ }
+
+ // terminating value delta
+ addvarint(&out, 0);
+
+ free(d->p);
+ *d = out;
+}
+
+
+// pclntab initializes the pclntab symbol with
+// runtime function and file name information.
+void
+pclntab(void)
+{
+ int32 i, nfunc, start, funcstart;
+ LSym *ftab, *s;
+ int32 off, end, frameptrsize;
+ int64 funcdata_bytes;
+ Pcln *pcln;
+ Pciter it;
+ static Pcln zpcln;
+
+ funcdata_bytes = 0;
+ ftab = linklookup(ctxt, "pclntab", 0);
+ ftab->type = SPCLNTAB;
+ ftab->reachable = 1;
+
+ // See golang.org/s/go12symtab for the format. Briefly:
+ // 8-byte header
+ // nfunc [PtrSize bytes]
+ // function table, alternating PC and offset to func struct [each entry PtrSize bytes]
+ // end PC [PtrSize bytes]
+ // offset to file table [4 bytes]
+ nfunc = 0;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next)
+ nfunc++;
+ symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
+ setuint32(ctxt, ftab, 0, 0xfffffffb);
+ setuint8(ctxt, ftab, 6, MINLC);
+ setuint8(ctxt, ftab, 7, PtrSize);
+ setuintxx(ctxt, ftab, 8, nfunc, PtrSize);
+
+ nfunc = 0;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) {
+ pcln = ctxt->cursym->pcln;
+ if(pcln == nil)
+ pcln = &zpcln;
+
+ funcstart = ftab->np;
+ funcstart += -ftab->np & (PtrSize-1);
+
+ setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym);
+ setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
+
+ // fixed size of struct, checked below
+ off = funcstart;
+ end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize;
+ if(pcln->nfuncdata > 0 && (end&(PtrSize-1)))
+ end += 4;
+ symgrow(ctxt, ftab, end);
+
+ // entry uintptr
+ off = setaddr(ctxt, ftab, off, ctxt->cursym);
+
+ // name int32
+ off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name));
+
+ // args int32
+ // TODO: Move into funcinfo.
+ off = setuint32(ctxt, ftab, off, ctxt->cursym->args);
+
+ // frame int32
+ // TODO: Remove entirely. The pcsp table is more precise.
+ // This is only used by a fallback case during stack walking
+ // when a called function doesn't have argument information.
+ // We need to make sure everything has argument information
+ // and then remove this.
+ frameptrsize = PtrSize;
+ if(ctxt->cursym->leaf)
+ frameptrsize = 0;
+ off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize);
+
+ if(pcln != &zpcln) {
+ renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile);
+ if(0) {
+ // Sanity check the new numbering
+ for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) {
+ if(it.value < 1 || it.value > ctxt->nhistfile) {
+ diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile);
+ errorexit();
+ }
+ }
+ }
+ }
+
+ // pcdata
+ off = addpctab(ftab, off, &pcln->pcsp);
+ off = addpctab(ftab, off, &pcln->pcfile);
+ off = addpctab(ftab, off, &pcln->pcline);
+ off = setuint32(ctxt, ftab, off, pcln->npcdata);
+ off = setuint32(ctxt, ftab, off, pcln->nfuncdata);
+ for(i=0; i<pcln->npcdata; i++)
+ off = addpctab(ftab, off, &pcln->pcdata[i]);
+
+ // funcdata, must be pointer-aligned and we're only int32-aligned.
+ // Missing funcdata will be 0 (nil pointer).
+ if(pcln->nfuncdata > 0) {
+ if(off&(PtrSize-1))
+ off += 4;
+ for(i=0; i<pcln->nfuncdata; i++) {
+ if(pcln->funcdata[i] == nil)
+ setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize);
+ else {
+ // TODO: Dedup.
+ funcdata_bytes += pcln->funcdata[i]->size;
+ setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
+ }
+ }
+ off += pcln->nfuncdata*PtrSize;
+ }
+
+ if(off != end) {
+ diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize);
+ errorexit();
+ }
+
+ // Final entry of table is just end pc.
+ if(ctxt->cursym->next == nil)
+ setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size);
+ }
+
+ // Start file table.
+ start = ftab->np;
+ start += -ftab->np & (PtrSize-1);
+ setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
+
+ symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4);
+ setuint32(ctxt, ftab, start, ctxt->nhistfile);
+ for(s = ctxt->filesyms; s != S; s = s->next)
+ setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name));
+
+ ftab->size = ftab->np;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
+}
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 7b9a596fc..c26cd5264 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -32,15 +32,11 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-// Note: currently only up to 8 chars plus \0.
-static char *symlabels[] = {
- "symtab", "esymtab", "pclntab", "epclntab"
-};
-
-static Sym *rsrcsym;
+static LSym *rsrcsym;
-static char symnames[256];
-static int nextsymoff;
+static char* strtbl;
+static int strtblnextoff;
+static int strtblsize;
int32 PESECTHEADR;
int32 PEFILEHEADR;
@@ -50,6 +46,7 @@ static int nsect;
static int nextsectoff;
static int nextfileoff;
static int textsect;
+static int datasect;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
@@ -62,7 +59,7 @@ static IMAGE_DATA_DIRECTORY* dd;
typedef struct Imp Imp;
struct Imp {
- Sym* s;
+ LSym* s;
uvlong off;
Imp* next;
};
@@ -78,9 +75,21 @@ struct Dll {
static Dll* dr;
-static Sym *dexport[1024];
+static LSym *dexport[1024];
static int nexport;
+typedef struct COFFSym COFFSym;
+struct COFFSym
+{
+ LSym* sym;
+ int strtbloff;
+ int sect;
+ vlong value;
+};
+
+static COFFSym* coffsym;
+static int ncoffsym;
+
static IMAGE_SECTION_HEADER*
addpesection(char *name, int sectsize, int filesize)
{
@@ -191,11 +200,11 @@ initdynimport(void)
{
Imp *m;
Dll *d;
- Sym *s, *dynamic;
+ LSym *s, *dynamic;
dr = nil;
m = nil;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
@@ -216,7 +225,7 @@ initdynimport(void)
d->ms = m;
}
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
for(d = dr; d != nil; d = d->next) {
@@ -241,10 +250,10 @@ addimports(IMAGE_SECTION_HEADER *datsect)
vlong startoff, endoff;
Imp *m;
Dll *d;
- Sym* dynamic;
+ LSym* dynamic;
startoff = cpos();
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
// skip import descriptor table (will write it later)
n = 0;
@@ -322,20 +331,20 @@ addimports(IMAGE_SECTION_HEADER *datsect)
static int
scmp(const void *p1, const void *p2)
{
- Sym *s1, *s2;
+ LSym *s1, *s2;
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
+ s1 = *(LSym**)p1;
+ s2 = *(LSym**)p2;
return strcmp(s1->extname, s2->extname);
}
static void
initdynexport(void)
{
- Sym *s;
+ LSym *s;
nexport = 0;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
@@ -410,10 +419,10 @@ addexports(void)
void
dope(void)
{
- Sym *rel;
+ LSym *rel;
/* relocation table */
- rel = lookup(".rel", 0);
+ rel = linklookup(ctxt, ".rel", 0);
rel->reachable = 1;
rel->type = SELFROSECT;
@@ -421,6 +430,24 @@ dope(void)
initdynexport();
}
+static int
+strtbladd(char *name)
+{
+ int newsize, thisoff;
+
+ newsize = strtblnextoff + strlen(name) + 1;
+ if(newsize > strtblsize) {
+ strtblsize = 2 * (newsize + (1<<18));
+ strtbl = realloc(strtbl, strtblsize);
+ }
+ thisoff = strtblnextoff+4; // first string starts at offset=4
+ strcpy(&strtbl[strtblnextoff], name);
+ strtblnextoff += strlen(name);
+ strtbl[strtblnextoff] = 0;
+ strtblnextoff++;
+ return thisoff;
+}
+
/*
* For more than 8 characters section names, name contains a slash (/) that is
* followed by an ASCII representation of a decimal number that is an offset into
@@ -433,20 +460,13 @@ newPEDWARFSection(char *name, vlong size)
{
IMAGE_SECTION_HEADER *h;
char s[8];
+ int off;
if(size == 0)
return nil;
- if(nextsymoff+strlen(name)+1 > sizeof(symnames)) {
- diag("pe string table is full");
- errorexit();
- }
-
- strcpy(&symnames[nextsymoff], name);
- sprint(s, "/%d\0", nextsymoff+4);
- nextsymoff += strlen(name);
- symnames[nextsymoff] = 0;
- nextsymoff ++;
+ off = strtbladd(name);
+ sprint(s, "/%d\0", off);
h = addpesection(s, size, size);
h->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_MEM_DISCARDABLE;
@@ -455,40 +475,97 @@ newPEDWARFSection(char *name, vlong size)
}
static void
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
+{
+ COFFSym *cs;
+ USED(name);
+ USED(addr);
+ USED(size);
+ USED(ver);
+ USED(gotype);
+
+ if(s == nil)
+ return;
+
+ if(s->sect == nil)
+ return;
+
+ switch(type) {
+ default:
+ return;
+ case 'D':
+ case 'B':
+ case 'T':
+ break;
+ }
+
+ if(coffsym) {
+ cs = &coffsym[ncoffsym];
+ cs->sym = s;
+ if(strlen(s->name) > 8)
+ cs->strtbloff = strtbladd(s->name);
+ if(s->value >= segdata.vaddr) {
+ cs->value = s->value - segdata.vaddr;
+ cs->sect = datasect;
+ } else if(s->value >= segtext.vaddr) {
+ cs->value = s->value - segtext.vaddr;
+ cs->sect = textsect;
+ } else {
+ cs->value = 0;
+ cs->sect = 0;
+ diag("addsym %#llx", addr);
+ }
+ }
+ ncoffsym++;
+}
+
+static void
addsymtable(void)
{
IMAGE_SECTION_HEADER *h;
int i, size;
- Sym *s;
-
- fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
- size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
+ COFFSym *s;
+
+ if(!debug['s']) {
+ genasmsym(addsym);
+ coffsym = mal(ncoffsym * sizeof coffsym[0]);
+ ncoffsym = 0;
+ genasmsym(addsym);
+ }
+
+ size = strtblnextoff + 4 + 18*ncoffsym;
h = addpesection(".symtab", size, size);
h->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_MEM_DISCARDABLE;
chksectoff(h, cpos());
fh.PointerToSymbolTable = cpos();
+ fh.NumberOfSymbols = ncoffsym;
// put COFF symbol table
- for (i=0; i<fh.NumberOfSymbols; i++) {
- s = rlookup(symlabels[i], 0);
- strnput(s->name, 8);
- lputl(datoff(s->value));
- wputl(textsect);
+ for (i=0; i<ncoffsym; i++) {
+ s = &coffsym[i];
+ if(s->strtbloff == 0)
+ strnput(s->sym->name, 8);
+ else {
+ lputl(0);
+ lputl(s->strtbloff);
+ }
+ lputl(s->value);
+ wputl(s->sect);
wputl(0x0308); // "array of structs"
cput(2); // storage class: external
cput(0); // no aux entries
}
// put COFF string table
- lputl(nextsymoff + 4);
- for (i=0; i<nextsymoff; i++)
- cput(symnames[i]);
+ lputl(strtblnextoff + 4);
+ for (i=0; i<strtblnextoff; i++)
+ cput(strtbl[i]);
strnput("", h->SizeOfRawData - size);
}
void
-setpersrc(Sym *sym)
+setpersrc(LSym *sym)
{
if(rsrcsym != nil)
diag("too many .rsrc sections");
@@ -529,49 +606,6 @@ addpersrc(void)
dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
}
-static void
-addexcept(IMAGE_SECTION_HEADER *text)
-{
- IMAGE_SECTION_HEADER *pdata, *xdata;
- vlong startoff;
- uvlong n;
- Sym *sym;
-
- USED(text);
- if(thechar != '6')
- return;
-
- // write unwind info
- sym = lookup("runtime.sigtramp", 0);
- startoff = cpos();
- lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0
- lputl(sym->value - PEBASE);
- lputl(0);
-
- n = cpos() - startoff;
- xdata = addpesection(".xdata", n, n);
- xdata->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_CNT_INITIALIZED_DATA;
- chksectoff(xdata, startoff);
- strnput("", xdata->SizeOfRawData - n);
-
- // write a function table entry for the whole text segment
- startoff = cpos();
- lputl(text->VirtualAddress);
- lputl(text->VirtualAddress + text->VirtualSize);
- lputl(xdata->VirtualAddress);
-
- n = cpos() - startoff;
- pdata = addpesection(".pdata", n, n);
- pdata->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_CNT_INITIALIZED_DATA;
- chksectoff(pdata, startoff);
- strnput("", pdata->SizeOfRawData - n);
-
- dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
- dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
-}
-
void
asmbpe(void)
{
@@ -600,6 +634,7 @@ asmbpe(void)
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
chksectseg(d, &segdata);
+ datasect = nsect;
if(!debug['s'])
dwarfaddpeheaders();
@@ -609,7 +644,6 @@ asmbpe(void)
addexports();
addsymtable();
addpersrc();
- addexcept(t);
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index 7aa938829..03ed8d830 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -176,4 +176,4 @@ typedef struct {
IMAGE_DATA_DIRECTORY DataDirectory[16];
} PE64_IMAGE_OPTIONAL_HEADER;
-void setpersrc(Sym *sym);
+void setpersrc(LSym *sym);
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
new file mode 100644
index 000000000..819c37954
--- /dev/null
+++ b/src/cmd/ld/pobj.c
@@ -0,0 +1,197 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Reading object files.
+
+#define EXTERN
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/macho.h"
+#include "../ld/dwarf.h"
+#include "../ld/pe.h"
+#include <ar.h>
+
+char *noname = "<none>";
+char* paramspace = "FP";
+
+void
+main(int argc, char *argv[])
+{
+ linkarchinit();
+ ctxt = linknew(thelinkarch);
+ ctxt->thechar = thechar;
+ ctxt->thestring = thestring;
+ ctxt->diag = diag;
+ ctxt->bso = &bso;
+
+ Binit(&bso, 1, OWRITE);
+ listinit();
+ memset(debug, 0, sizeof(debug));
+ nerrors = 0;
+ outfile = nil;
+ HEADTYPE = -1;
+ INITTEXT = -1;
+ INITDAT = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+ linkmode = LinkAuto;
+ nuxiinit();
+
+ if(thechar == '5' && ctxt->goarm == 5)
+ debug['F'] = 1;
+
+ flagcount("1", "use alternate profiling code", &debug['1']);
+ if(thechar == '6')
+ flagcount("8", "assume 64-bit addresses", &debug['8']);
+ flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
+ flagint64("D", "addr: data address", &INITDAT);
+ flagstr("E", "sym: entry symbol", &INITENTRY);
+ if(thechar == '5')
+ flagcount("G", "debug pseudo-ops", &debug['G']);
+ flagfn1("I", "interp: set ELF interp", setinterp);
+ flagfn1("L", "dir: add dir to library path", Lflag);
+ flagfn1("H", "head: header type", setheadtype);
+ flagcount("K", "add stack underflow checks", &debug['K']);
+ if(thechar == '5')
+ flagcount("M", "disable software div/mod", &debug['M']);
+ flagcount("O", "print pc-line tables", &debug['O']);
+ flagcount("Q", "debug byte-register code gen", &debug['Q']);
+ if(thechar == '5')
+ flagcount("P", "debug code generation", &debug['P']);
+ flagint32("R", "rnd: address rounding", &INITRND);
+ flagcount("S", "check type signatures", &debug['S']);
+ flagint64("T", "addr: text address", &INITTEXT);
+ flagfn0("V", "print version and exit", doversion);
+ flagcount("W", "disassemble input", &debug['W']);
+ flagfn2("X", "name value: define string data", addstrdata);
+ flagcount("Z", "clear stack frame on entry", &debug['Z']);
+ flagcount("a", "disassemble output", &debug['a']);
+ flagcount("c", "dump call graph", &debug['c']);
+ flagcount("d", "disable dynamic executable", &debug['d']);
+ flagstr("extld", "linker to run in external mode", &extld);
+ flagstr("extldflags", "flags for external linker", &extldflags);
+ flagcount("f", "ignore version mismatch", &debug['f']);
+ flagcount("g", "disable go package data checks", &debug['g']);
+ flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
+ flagstr("k", "sym: set field tracking symbol", &tracksym);
+ flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
+ flagcount("n", "dump symbol table", &debug['n']);
+ flagstr("o", "outfile: set output file", &outfile);
+ flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
+ flagcount("race", "enable race detector", &flag_race);
+ flagcount("s", "disable symbol table", &debug['s']);
+ if(thechar == '5' || thechar == '6')
+ flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
+ flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
+ flagcount("u", "reject unsafe packages", &debug['u']);
+ flagcount("v", "print link trace", &debug['v']);
+ flagcount("w", "disable DWARF generation", &debug['w']);
+
+ flagparse(&argc, &argv, usage);
+ ctxt->bso = &bso;
+ ctxt->debugdivmod = debug['M'];
+ ctxt->debugfloat = debug['F'];
+ ctxt->debughist = debug['O'];
+ ctxt->debugpcln = debug['O'];
+ ctxt->debugread = debug['W'];
+ ctxt->debugstack = debug['K'];
+ ctxt->debugvlog = debug['v'];
+
+ if(argc != 1)
+ usage();
+
+ if(outfile == nil) {
+ if(HEADTYPE == Hwindows)
+ outfile = smprint("%c.out.exe", thechar);
+ else
+ outfile = smprint("%c.out", thechar);
+ }
+ libinit(); // creates outfile
+
+ if(HEADTYPE == -1)
+ HEADTYPE = headtype(goos);
+ ctxt->headtype = HEADTYPE;
+ if (headstring == nil)
+ headstring = headstr(HEADTYPE);
+
+ archinit();
+ ctxt->debugfloat = debug['F'];
+
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+
+ addlibpath(ctxt, "command line", "command line", argv[0], "main");
+ loadlib();
+
+ if(thechar == '5') {
+ // mark some functions that are only referenced after linker code editing
+ if(debug['F'])
+ mark(linkrlookup(ctxt, "_sfloat", 0));
+ mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
+ }
+
+ deadcode();
+ callgraph();
+ paramspace = "SP"; /* (FP) now (SP) on output */
+
+ doelf();
+ if(HEADTYPE == Hdarwin)
+ domacho();
+ dostkcheck();
+ if(HEADTYPE == Hwindows)
+ dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ doweak();
+ reloc();
+ asmb();
+ undef();
+ hostlink();
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d symbols\n", ctxt->nsymbol);
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Addr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ Bprint(&bso, "%lld liveness data\n", liveness);
+ }
+ Bflush(&bso);
+
+ errorexit();
+}
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index c9b4657f7..6d321c0bb 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -40,6 +40,7 @@ static int
putelfstr(char *s)
{
int off, n;
+ char *p, *q;
if(elfstrsize == 0 && s[0] != 0) {
// first entry must be empty string
@@ -54,6 +55,21 @@ putelfstr(char *s)
off = elfstrsize;
elfstrsize += n;
memmove(elfstrdat+off, s, n);
+ // replace "·" as ".", because DTrace cannot handle it.
+ p = strstr(s, "·");
+ if(p != nil) {
+ p = q = elfstrdat+off;
+ while (*q != '\0') {
+ if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) {
+ q += 2;
+ *p++ = '.';
+ elfstrsize--;
+ } else {
+ *p++ = *q++;
+ }
+ }
+ *p = '\0';
+ }
return off;
}
@@ -86,10 +102,10 @@ static int numelfsym = 1; // 0 is reserved
static int elfbind;
static void
-putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int bind, type, off;
- Sym *xo;
+ LSym *xo;
USED(go);
switch(t) {
@@ -109,12 +125,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
while(xo->outer != nil)
xo = xo->outer;
if(xo->sect == nil) {
- cursym = x;
+ ctxt->cursym = x;
diag("missing section in putelfsym");
return;
}
if(xo->sect->elfsect == nil) {
- cursym = x;
+ ctxt->cursym = x;
diag("missing ELF section in putelfsym");
return;
}
@@ -143,7 +159,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
}
void
-putelfsectionsym(Sym* s, int shndx)
+putelfsectionsym(LSym* s, int shndx)
{
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
s->elfsym = numelfsym++;
@@ -170,7 +186,8 @@ putelfsymshndx(vlong sympos, int shndx)
void
asmelfsym(void)
{
- Sym *s;
+ LSym *s;
+ char *name;
// the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
@@ -181,9 +198,9 @@ asmelfsym(void)
genasmsym(putelfsym);
if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
- s = lookup("runtime.tlsgm", 0);
+ s = linklookup(ctxt, "runtime.tlsgm", 0);
if(s->sect == nil) {
- cursym = nil;
+ ctxt->cursym = nil;
diag("missing section for %s", s->name);
errorexit();
}
@@ -195,16 +212,20 @@ asmelfsym(void)
elfglobalsymndx = numelfsym;
genasmsym(putelfsym);
- for(s=allsym; s!=S; s=s->allsym) {
- if(s->type != SHOSTOBJ)
+ for(s=ctxt->allsym; s!=S; s=s->allsym) {
+ if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable))
continue;
- putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
+ if(s->type == SDYNIMPORT)
+ name = s->extname;
+ else
+ name = s->name;
+ putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
s->elfsym = numelfsym++;
}
}
static void
-putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int i, l;
@@ -226,7 +247,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
case 'Z':
case 'm':
l = 4;
- if(HEADTYPE == Hplan9x64 && !debug['8']) {
+ if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
lputb(addr>>32);
l = 8;
}
@@ -263,48 +284,7 @@ asmplan9sym(void)
genasmsym(putplan9sym);
}
-static Sym *symt;
-
-static void
-scput(int b)
-{
- uchar *p;
-
- symgrow(symt, symt->size+1);
- p = symt->p + symt->size;
- *p = b;
- symt->size++;
-}
-
-static void
-slputb(int32 v)
-{
- uchar *p;
-
- symgrow(symt, symt->size+4);
- p = symt->p + symt->size;
- *p++ = v>>24;
- *p++ = v>>16;
- *p++ = v>>8;
- *p = v;
- symt->size += 4;
-}
-
-static void
-slputl(int32 v)
-{
- uchar *p;
-
- symgrow(symt, symt->size+4);
- p = symt->p + symt->size;
- *p++ = v;
- *p++ = v>>8;
- *p++ = v>>16;
- *p = v>>24;
- symt->size += 4;
-}
-
-static void (*slput)(int32);
+static LSym *symt;
void
wputl(ushort w)
@@ -352,112 +332,10 @@ vputl(uint64 v)
lputl(v >> 32);
}
-// Emit symbol table entry.
-// The table format is described at the top of ../../pkg/runtime/symtab.c.
-void
-putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
-{
- int i, f, c;
- vlong v1;
- Reloc *rel;
-
- USED(size);
-
- // type byte
- if('A' <= t && t <= 'Z')
- c = t - 'A' + (ver ? 26 : 0);
- else if('a' <= t && t <= 'z')
- c = t - 'a' + 26;
- else {
- diag("invalid symbol table type %c", t);
- errorexit();
- return;
- }
-
- if(s != nil)
- c |= 0x40; // wide value
- if(typ != nil)
- c |= 0x80; // has go type
- scput(c);
-
- // value
- if(s != nil) {
- // full width
- rel = addrel(symt);
- rel->siz = PtrSize;
- rel->sym = s;
- rel->type = D_ADDR;
- rel->off = symt->size;
- if(PtrSize == 8)
- slput(0);
- slput(0);
- } else {
- // varint
- if(v < 0) {
- diag("negative value in symbol table: %s %lld", name, v);
- errorexit();
- }
- v1 = v;
- while(v1 >= 0x80) {
- scput(v1 | 0x80);
- v1 >>= 7;
- }
- scput(v1);
- }
-
- // go type if present
- if(typ != nil) {
- if(!typ->reachable)
- diag("unreachable type %s", typ->name);
- rel = addrel(symt);
- rel->siz = PtrSize;
- rel->sym = typ;
- rel->type = D_ADDR;
- rel->off = symt->size;
- if(PtrSize == 8)
- slput(0);
- slput(0);
- }
-
- // name
- if(t == 'f')
- name++;
-
- if(t == 'Z' || t == 'z') {
- scput(name[0]);
- for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) {
- scput(name[i]);
- scput(name[i+1]);
- }
- scput(0);
- scput(0);
- } else {
- for(i=0; name[i]; i++)
- scput(name[i]);
- scput(0);
- }
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", t, v);
- for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) {
- f = ((name[i]&0xff) << 8) | (name[i+1]&0xff);
- Bprint(&bso, "/%x", f);
- }
- Bprint(&bso, "\n");
- return;
- }
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, name, ver, typ ? typ->name : "");
- else
- Bprint(&bso, "%c %.8llux %s %s\n", t, v, name, typ ? typ->name : "");
- }
-}
-
void
symtab(void)
{
- Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
+ LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
dosymtype();
@@ -482,40 +360,40 @@ symtab(void)
xdefine("esymtab", SRODATA, 0);
// garbage collection symbols
- s = lookup("gcdata", 0);
+ s = linklookup(ctxt, "gcdata", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcdata", SRODATA, 0);
- s = lookup("gcbss", 0);
+ s = linklookup(ctxt, "gcbss", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcbss", SRODATA, 0);
// pseudo-symbols to mark locations of type, string, and go string data.
- s = lookup("type.*", 0);
+ s = linklookup(ctxt, "type.*", 0);
s->type = STYPE;
s->size = 0;
s->reachable = 1;
symtype = s;
- s = lookup("go.string.*", 0);
+ s = linklookup(ctxt, "go.string.*", 0);
s->type = SGOSTRING;
s->size = 0;
s->reachable = 1;
symgostring = s;
- s = lookup("go.func.*", 0);
+ s = linklookup(ctxt, "go.func.*", 0);
s->type = SGOFUNC;
s->size = 0;
s->reachable = 1;
symgofunc = s;
- symtypelink = lookup("typelink", 0);
+ symtypelink = linklookup(ctxt, "typelink", 0);
- symt = lookup("symtab", 0);
+ symt = linklookup(ctxt, "symtab", 0);
symt->type = SSYMTAB;
symt->size = 0;
symt->reachable = 1;
@@ -524,7 +402,7 @@ symtab(void)
// within a type they sort by size, so the .* symbols
// just defined above will be first.
// hide the specific symbols.
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->special || s->type != SRODATA)
continue;
if(strncmp(s->name, "type.", 5) == 0) {
@@ -547,32 +425,12 @@ symtab(void)
s->hide = 1;
s->outer = symgofunc;
}
+ if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) {
+ s->type = SGOFUNC;
+ s->hide = 1;
+ s->outer = symgofunc;
+ s->align = 4;
+ liveness += (s->size+s->align-1)&~(s->align-1);
+ }
}
-
- if(debug['s'])
- return;
-
- switch(thechar) {
- default:
- diag("unknown architecture %c", thechar);
- errorexit();
- case '5':
- case '6':
- case '8':
- // little-endian symbol table
- slput = slputl;
- break;
- case 'v':
- // big-endian symbol table
- slput = slputb;
- break;
- }
- // new symbol table header.
- slput(0xfffffffd);
- scput(0);
- scput(0);
- scput(0);
- scput(PtrSize);
-
- genasmsym(putsymb);
}
diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h
index 1d62db736..2a76e76c2 100644
--- a/src/cmd/ld/textflag.h
+++ b/src/cmd/ld/textflag.h
@@ -19,3 +19,5 @@
#define NOPTR 16
// This is a wrapper function and should not count as disabling 'recover'.
#define WRAPPER 32
+// This function uses its incoming context register.
+#define NEEDCTXT 64
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/nm/Makefile
+++ /dev/null
@@ -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
diff --git a/src/cmd/nm/debug_goobj.go b/src/cmd/nm/debug_goobj.go
new file mode 100644
index 000000000..9a067e2b9
--- /dev/null
+++ b/src/cmd/nm/debug_goobj.go
@@ -0,0 +1,670 @@
+// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle
+// bundle -p main -x goobj_ debug/goobj
+
+/* read.go */
+
+// 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 goobj implements reading of Go object files and archives.
+//
+// TODO(rsc): Decide where this package should live. (golang.org/issue/6932)
+// TODO(rsc): Decide the appropriate integer types for various fields.
+// TODO(rsc): Write tests. (File format still up in the air a little.)
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// A SymKind describes the kind of memory represented by a symbol.
+type goobj_SymKind int
+
+// This list is taken from include/link.h.
+
+// Defined SymKind values.
+// TODO(rsc): Give idiomatic Go names.
+// TODO(rsc): Reduce the number of symbol types in the object files.
+const (
+ _ goobj_SymKind = iota
+
+ // readonly, executable
+ goobj_STEXT
+ goobj_SELFRXSECT
+
+ // readonly, non-executable
+ goobj_STYPE
+ goobj_SSTRING
+ goobj_SGOSTRING
+ goobj_SGOFUNC
+ goobj_SRODATA
+ goobj_SFUNCTAB
+ goobj_STYPELINK
+ goobj_SSYMTAB // TODO: move to unmapped section
+ goobj_SPCLNTAB
+ goobj_SELFROSECT
+
+ // writable, non-executable
+ goobj_SMACHOPLT
+ goobj_SELFSECT
+ goobj_SMACHO // Mach-O __nl_symbol_ptr
+ goobj_SMACHOGOT
+ goobj_SNOPTRDATA
+ goobj_SINITARR
+ goobj_SDATA
+ goobj_SWINDOWS
+ goobj_SBSS
+ goobj_SNOPTRBSS
+ goobj_STLSBSS
+
+ // not mapped
+ goobj_SXREF
+ goobj_SMACHOSYMSTR
+ goobj_SMACHOSYMTAB
+ goobj_SMACHOINDIRECTPLT
+ goobj_SMACHOINDIRECTGOT
+ goobj_SFILE
+ goobj_SFILEPATH
+ goobj_SCONST
+ goobj_SDYNIMPORT
+ goobj_SHOSTOBJ
+)
+
+var goobj_symKindStrings = []string{
+ goobj_SBSS: "SBSS",
+ goobj_SCONST: "SCONST",
+ goobj_SDATA: "SDATA",
+ goobj_SDYNIMPORT: "SDYNIMPORT",
+ goobj_SELFROSECT: "SELFROSECT",
+ goobj_SELFRXSECT: "SELFRXSECT",
+ goobj_SELFSECT: "SELFSECT",
+ goobj_SFILE: "SFILE",
+ goobj_SFILEPATH: "SFILEPATH",
+ goobj_SFUNCTAB: "SFUNCTAB",
+ goobj_SGOFUNC: "SGOFUNC",
+ goobj_SGOSTRING: "SGOSTRING",
+ goobj_SHOSTOBJ: "SHOSTOBJ",
+ goobj_SINITARR: "SINITARR",
+ goobj_SMACHO: "SMACHO",
+ goobj_SMACHOGOT: "SMACHOGOT",
+ goobj_SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
+ goobj_SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
+ goobj_SMACHOPLT: "SMACHOPLT",
+ goobj_SMACHOSYMSTR: "SMACHOSYMSTR",
+ goobj_SMACHOSYMTAB: "SMACHOSYMTAB",
+ goobj_SNOPTRBSS: "SNOPTRBSS",
+ goobj_SNOPTRDATA: "SNOPTRDATA",
+ goobj_SPCLNTAB: "SPCLNTAB",
+ goobj_SRODATA: "SRODATA",
+ goobj_SSTRING: "SSTRING",
+ goobj_SSYMTAB: "SSYMTAB",
+ goobj_STEXT: "STEXT",
+ goobj_STLSBSS: "STLSBSS",
+ goobj_STYPE: "STYPE",
+ goobj_STYPELINK: "STYPELINK",
+ goobj_SWINDOWS: "SWINDOWS",
+ goobj_SXREF: "SXREF",
+}
+
+func (k goobj_SymKind) String() string {
+ if k < 0 || int(k) >= len(goobj_symKindStrings) {
+ return fmt.Sprintf("SymKind(%d)", k)
+ }
+ return goobj_symKindStrings[k]
+}
+
+// A Sym is a named symbol in an object file.
+type goobj_Sym struct {
+ goobj_SymID // symbol identifier (name and version)
+ Kind goobj_SymKind // kind of symbol
+ DupOK bool // are duplicate definitions okay?
+ Size int // size of corresponding data
+ Type goobj_SymID // symbol for Go type information
+ Data goobj_Data // memory image of symbol
+ Reloc []goobj_Reloc // relocations to apply to Data
+ Func *goobj_Func // additional data for functions
+}
+
+// A SymID - the combination of Name and Version - uniquely identifies
+// a symbol within a package.
+type goobj_SymID struct {
+ // Name is the name of a symbol.
+ Name string
+
+ // Version is zero for symbols with global visibility.
+ // Symbols with only file visibility (such as file-level static
+ // declarations in C) have a non-zero version distinguishing
+ // a symbol in one file from a symbol of the same name
+ // in another file
+ Version int
+}
+
+func (s goobj_SymID) String() string {
+ if s.Version == 0 {
+ return s.Name
+ }
+ return fmt.Sprintf("%s<%d>", s.Name, s.Version)
+}
+
+// A Data is a reference to data stored in an object file.
+// It records the offset and size of the data, so that a client can
+// read the data only if necessary.
+type goobj_Data struct {
+ Offset int64
+ Size int64
+}
+
+// A Reloc describes a relocation applied to a memory image to refer
+// to an address within a particular symbol.
+type goobj_Reloc struct {
+ // The bytes at [Offset, Offset+Size) within the memory image
+ // should be updated to refer to the address Add bytes after the start
+ // of the symbol Sym.
+ Offset int
+ Size int
+ Sym goobj_SymID
+ Add int
+
+ // The Type records the form of address expected in the bytes
+ // described by the previous fields: absolute, PC-relative, and so on.
+ // TODO(rsc): The interpretation of Type is not exposed by this package.
+ Type int
+}
+
+// A Var describes a variable in a function stack frame: a declared
+// local variable, an input argument, or an output result.
+type goobj_Var struct {
+ // The combination of Name, Kind, and Offset uniquely
+ // identifies a variable in a function stack frame.
+ // Using fewer of these - in particular, using only Name - does not.
+ Name string // Name of variable.
+ Kind int // TODO(rsc): Define meaning.
+ Offset int // Frame offset. TODO(rsc): Define meaning.
+
+ Type goobj_SymID // Go type for variable.
+}
+
+// Func contains additional per-symbol information specific to functions.
+type goobj_Func struct {
+ Args int // size in bytes of argument frame: inputs and outputs
+ Frame int // size in bytes of local variable frame
+ Leaf bool // function omits save of link register (ARM)
+ NoSplit bool // function omits stack split prologue
+ Var []goobj_Var // detail about local variables
+ PCSP goobj_Data // PC → SP offset map
+ PCFile goobj_Data // PC → file number map (index into File)
+ PCLine goobj_Data // PC → line number map
+ PCData []goobj_Data // PC → runtime support data map
+ FuncData []goobj_FuncData // non-PC-specific runtime support data
+ File []string // paths indexed by PCFile
+}
+
+// TODO: Add PCData []byte and PCDataIter (similar to liblink).
+
+// A FuncData is a single function-specific data value.
+type goobj_FuncData struct {
+ Sym goobj_SymID // symbol holding data
+ Offset int64 // offset into symbol for funcdata pointer
+}
+
+// A Package is a parsed Go object file or archive defining a Go package.
+type goobj_Package struct {
+ ImportPath string // import path denoting this package
+ Imports []string // packages imported by this package
+ Syms []*goobj_Sym // symbols defined by this package
+ MaxVersion int // maximum Version in any SymID in Syms
+}
+
+var (
+ goobj_archiveHeader = []byte("!<arch>\n")
+ goobj_archiveMagic = []byte("`\n")
+ goobj_goobjHeader = []byte("go objec") // truncated to size of archiveHeader
+
+ goobj_errCorruptArchive = errors.New("corrupt archive")
+ goobj_errTruncatedArchive = errors.New("truncated archive")
+ goobj_errNotArchive = errors.New("unrecognized archive format")
+
+ goobj_errCorruptObject = errors.New("corrupt object file")
+ goobj_errTruncatedObject = errors.New("truncated object file")
+ goobj_errNotObject = errors.New("unrecognized object file format")
+)
+
+// An objReader is an object file reader.
+type goobj_objReader struct {
+ p *goobj_Package
+ b *bufio.Reader
+ f io.ReadSeeker
+ err error
+ offset int64
+ limit int64
+ tmp [256]byte
+ pkg string
+ pkgprefix string
+}
+
+// importPathToPrefix returns the prefix that will be used in the
+// final symbol table for the given import path.
+// We escape '%', '"', all control characters and non-ASCII bytes,
+// and any '.' after the final slash.
+//
+// See ../../../cmd/ld/lib.c:/^pathtoprefix and
+// ../../../cmd/gc/subr.c:/^pathtoprefix.
+func goobj_importPathToPrefix(s string) string {
+ // find index of last slash, if any, or else -1.
+ // used for determining whether an index is after the last slash.
+ slash := strings.LastIndex(s, "/")
+
+ // check for chars that need escaping
+ n := 0
+ for r := 0; r < len(s); r++ {
+ if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+ n++
+ }
+ }
+
+ // quick exit
+ if n == 0 {
+ return s
+ }
+
+ // escape
+ const hex = "0123456789abcdef"
+ p := make([]byte, 0, len(s)+2*n)
+ for r := 0; r < len(s); r++ {
+ if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
+ p = append(p, '%', hex[c>>4], hex[c&0xF])
+ } else {
+ p = append(p, c)
+ }
+ }
+
+ return string(p)
+}
+
+// init initializes r to read package p from f.
+func (r *goobj_objReader) init(f io.ReadSeeker, p *goobj_Package) {
+ r.f = f
+ r.p = p
+ r.offset, _ = f.Seek(0, 1)
+ r.limit, _ = f.Seek(0, 2)
+ f.Seek(r.offset, 0)
+ r.b = bufio.NewReader(f)
+ r.pkgprefix = goobj_importPathToPrefix(p.ImportPath) + "."
+}
+
+// error records that an error occurred.
+// It returns only the first error, so that an error
+// caused by an earlier error does not discard information
+// about the earlier error.
+func (r *goobj_objReader) error(err error) error {
+ if r.err == nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ r.err = err
+ }
+ // panic("corrupt") // useful for debugging
+ return r.err
+}
+
+// readByte reads and returns a byte from the input file.
+// On I/O error or EOF, it records the error but returns byte 0.
+// A sequence of 0 bytes will eventually terminate any
+// parsing state in the object file. In particular, it ends the
+// reading of a varint.
+func (r *goobj_objReader) readByte() byte {
+ if r.err != nil {
+ return 0
+ }
+ if r.offset >= r.limit {
+ r.error(io.ErrUnexpectedEOF)
+ return 0
+ }
+ b, err := r.b.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ r.error(err)
+ b = 0
+ } else {
+ r.offset++
+ }
+ return b
+}
+
+// read reads exactly len(b) bytes from the input file.
+// If an error occurs, read returns the error but also
+// records it, so it is safe for callers to ignore the result
+// as long as delaying the report is not a problem.
+func (r *goobj_objReader) readFull(b []byte) error {
+ if r.err != nil {
+ return r.err
+ }
+ if r.offset+int64(len(b)) > r.limit {
+ return r.error(io.ErrUnexpectedEOF)
+ }
+ n, err := io.ReadFull(r.b, b)
+ r.offset += int64(n)
+ if err != nil {
+ return r.error(err)
+ }
+ return nil
+}
+
+// readInt reads a zigzag varint from the input file.
+func (r *goobj_objReader) readInt() int {
+ var u uint64
+
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ r.error(goobj_errCorruptObject)
+ return 0
+ }
+ c := r.readByte()
+ u |= uint64(c&0x7F) << shift
+ if c&0x80 == 0 {
+ break
+ }
+ }
+
+ v := int64(u>>1) ^ (int64(u) << 63 >> 63)
+ if int64(int(v)) != v {
+ r.error(goobj_errCorruptObject) // TODO
+ return 0
+ }
+ return int(v)
+}
+
+// readString reads a length-delimited string from the input file.
+func (r *goobj_objReader) readString() string {
+ n := r.readInt()
+ buf := make([]byte, n)
+ r.readFull(buf)
+ return string(buf)
+}
+
+// readSymID reads a SymID from the input file.
+func (r *goobj_objReader) readSymID() goobj_SymID {
+ name, vers := r.readString(), r.readInt()
+
+ // In a symbol name in an object file, "". denotes the
+ // prefix for the package in which the object file has been found.
+ // Expand it.
+ name = strings.Replace(name, `"".`, r.pkgprefix, -1)
+
+ // An individual object file only records version 0 (extern) or 1 (static).
+ // To make static symbols unique across all files being read, we
+ // replace version 1 with the version corresponding to the current
+ // file number. The number is incremented on each call to parseObject.
+ if vers != 0 {
+ vers = r.p.MaxVersion
+ }
+
+ return goobj_SymID{name, vers}
+}
+
+// readData reads a data reference from the input file.
+func (r *goobj_objReader) readData() goobj_Data {
+ n := r.readInt()
+ d := goobj_Data{Offset: r.offset, Size: int64(n)}
+ r.skip(int64(n))
+ return d
+}
+
+// skip skips n bytes in the input.
+func (r *goobj_objReader) skip(n int64) {
+ if n < 0 {
+ r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
+ }
+ if n < int64(len(r.tmp)) {
+ // Since the data is so small, a just reading from the buffered
+ // reader is better than flushing the buffer and seeking.
+ r.readFull(r.tmp[:n])
+ } else if n <= int64(r.b.Buffered()) {
+ // Even though the data is not small, it has already been read.
+ // Advance the buffer instead of seeking.
+ for n > int64(len(r.tmp)) {
+ r.readFull(r.tmp[:])
+ n -= int64(len(r.tmp))
+ }
+ r.readFull(r.tmp[:n])
+ } else {
+ // Seek, giving up buffered data.
+ _, err := r.f.Seek(r.offset+n, 0)
+ if err != nil {
+ r.error(err)
+ }
+ r.offset += n
+ r.b.Reset(r.f)
+ }
+}
+
+// Parse parses an object file or archive from r,
+// assuming that its import path is pkgpath.
+func goobj_Parse(r io.ReadSeeker, pkgpath string) (*goobj_Package, error) {
+ if pkgpath == "" {
+ pkgpath = `""`
+ }
+ p := new(goobj_Package)
+ p.ImportPath = pkgpath
+
+ var rd goobj_objReader
+ rd.init(r, p)
+ err := rd.readFull(rd.tmp[:8])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+
+ switch {
+ default:
+ return nil, goobj_errNotObject
+
+ case bytes.Equal(rd.tmp[:8], goobj_archiveHeader):
+ if err := rd.parseArchive(); err != nil {
+ return nil, err
+ }
+ case bytes.Equal(rd.tmp[:8], goobj_goobjHeader):
+ if err := rd.parseObject(goobj_goobjHeader); err != nil {
+ return nil, err
+ }
+ }
+
+ return p, nil
+}
+
+// trimSpace removes trailing spaces from b and returns the corresponding string.
+// This effectively parses the form used in archive headers.
+func goobj_trimSpace(b []byte) string {
+ return string(bytes.TrimRight(b, " "))
+}
+
+// parseArchive parses a Unix archive of Go object files.
+// TODO(rsc): Need to skip non-Go object files.
+// TODO(rsc): Maybe record table of contents in r.p so that
+// linker can avoid having code to parse archives too.
+func (r *goobj_objReader) parseArchive() error {
+ for r.offset < r.limit {
+ if err := r.readFull(r.tmp[:60]); err != nil {
+ return err
+ }
+ data := r.tmp[:60]
+
+ // Each file is preceded by this text header (slice indices in first column):
+ // 0:16 name
+ // 16:28 date
+ // 28:34 uid
+ // 34:40 gid
+ // 40:48 mode
+ // 48:58 size
+ // 58:60 magic - `\n
+ // We only care about name, size, and magic.
+ // The fields are space-padded on the right.
+ // The size is in decimal.
+ // The file data - size bytes - follows the header.
+ // Headers are 2-byte aligned, so if size is odd, an extra padding
+ // byte sits between the file data and the next header.
+ // The file data that follows is padded to an even number of bytes:
+ // if size is odd, an extra padding byte is inserted betw the next header.
+ if len(data) < 60 {
+ return goobj_errTruncatedArchive
+ }
+ if !bytes.Equal(data[58:60], goobj_archiveMagic) {
+ return goobj_errCorruptArchive
+ }
+ name := goobj_trimSpace(data[0:16])
+ size, err := strconv.ParseInt(goobj_trimSpace(data[48:58]), 10, 64)
+ if err != nil {
+ return goobj_errCorruptArchive
+ }
+ data = data[60:]
+ fsize := size + size&1
+ if fsize < 0 || fsize < size {
+ return goobj_errCorruptArchive
+ }
+ switch name {
+ case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF":
+ r.skip(size)
+ default:
+ oldLimit := r.limit
+ r.limit = r.offset + size
+ if err := r.parseObject(nil); err != nil {
+ return fmt.Errorf("parsing archive member %q: %v", name, err)
+ }
+ r.skip(r.limit - r.offset)
+ r.limit = oldLimit
+ }
+ if size&1 != 0 {
+ r.skip(1)
+ }
+ }
+ return nil
+}
+
+// parseObject parses a single Go object file.
+// The prefix is the bytes already read from the file,
+// typically in order to detect that this is an object file.
+// The object file consists of a textual header ending in "\n!\n"
+// and then the part we want to parse begins.
+// The format of that part is defined in a comment at the top
+// of src/liblink/objfile.c.
+func (r *goobj_objReader) parseObject(prefix []byte) error {
+ // TODO(rsc): Maybe use prefix and the initial input to
+ // record the header line from the file, which would
+ // give the architecture and other version information.
+
+ r.p.MaxVersion++
+ var c1, c2, c3 byte
+ for {
+ c1, c2, c3 = c2, c3, r.readByte()
+ if c3 == 0 { // NUL or EOF, either is bad
+ return goobj_errCorruptObject
+ }
+ if c1 == '\n' && c2 == '!' && c3 == '\n' {
+ break
+ }
+ }
+
+ r.readFull(r.tmp[:8])
+ if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) {
+ return r.error(goobj_errCorruptObject)
+ }
+
+ b := r.readByte()
+ if b != 1 {
+ return r.error(goobj_errCorruptObject)
+ }
+
+ // Direct package dependencies.
+ for {
+ s := r.readString()
+ if s == "" {
+ break
+ }
+ r.p.Imports = append(r.p.Imports, s)
+ }
+
+ // Symbols.
+ for {
+ if b := r.readByte(); b != 0xfe {
+ if b != 0xff {
+ return r.error(goobj_errCorruptObject)
+ }
+ break
+ }
+
+ typ := r.readInt()
+ s := &goobj_Sym{goobj_SymID: r.readSymID()}
+ r.p.Syms = append(r.p.Syms, s)
+ s.Kind = goobj_SymKind(typ)
+ s.DupOK = r.readInt() != 0
+ s.Size = r.readInt()
+ s.Type = r.readSymID()
+ s.Data = r.readData()
+ s.Reloc = make([]goobj_Reloc, r.readInt())
+ for i := range s.Reloc {
+ rel := &s.Reloc[i]
+ rel.Offset = r.readInt()
+ rel.Size = r.readInt()
+ rel.Type = r.readInt()
+ rel.Add = r.readInt()
+ r.readInt() // Xadd - ignored
+ rel.Sym = r.readSymID()
+ r.readSymID() // Xsym - ignored
+ }
+
+ if s.Kind == goobj_STEXT {
+ f := new(goobj_Func)
+ s.Func = f
+ f.Args = r.readInt()
+ f.Frame = r.readInt()
+ f.Leaf = r.readInt() != 0
+ f.NoSplit = r.readInt() != 0
+ f.Var = make([]goobj_Var, r.readInt())
+ for i := range f.Var {
+ v := &f.Var[i]
+ v.Name = r.readSymID().Name
+ v.Offset = r.readInt()
+ v.Kind = r.readInt()
+ v.Type = r.readSymID()
+ }
+
+ f.PCSP = r.readData()
+ f.PCFile = r.readData()
+ f.PCLine = r.readData()
+ f.PCData = make([]goobj_Data, r.readInt())
+ for i := range f.PCData {
+ f.PCData[i] = r.readData()
+ }
+ f.FuncData = make([]goobj_FuncData, r.readInt())
+ for i := range f.FuncData {
+ f.FuncData[i].Sym = r.readSymID()
+ }
+ for i := range f.FuncData {
+ f.FuncData[i].Offset = int64(r.readInt()) // TODO
+ }
+ f.File = make([]string, r.readInt())
+ for i := range f.File {
+ f.File[i] = r.readSymID().Name
+ }
+ }
+ }
+
+ r.readFull(r.tmp[:7])
+ if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) {
+ return r.error(goobj_errCorruptObject)
+ }
+
+ return nil
+}
diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go
index 8e88e2e63..b62da47c0 100644
--- a/src/cmd/nm/doc.go
+++ b/src/cmd/nm/doc.go
@@ -1,23 +1,41 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// 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.
-// +build ignore
-
-/*
-
-Nm is a version of the Plan 9 nm command. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/nm
-
-It prints the name list (symbol table) for programs compiled by gc as well as the
-Plan 9 C compiler.
-
-This implementation adds the flag -S, which prints each symbol's size
-in decimal after its address.
-
-Usage:
- go tool nm [-aghnsSTu] file
-
-*/
+// Nm lists the symbols defined or used by an object file, archive, or executable.
+//
+// Usage:
+// go tool nm [options] file...
+//
+// The default output prints one line per symbol, with three space-separated
+// fields giving the address (in hexadecimal), type (a character), and name of
+// the symbol. The types are:
+//
+// T text (code) segment symbol
+// t static text segment symbol
+// R read-only data segment symbol
+// r static read-only data segment symbol
+// D data segment symbol
+// d static data segment symbol
+// B bss segment symbol
+// b static bss segment symbol
+// C constant address
+// U referenced but undefined symbol
+//
+// Following established convention, the address is omitted for undefined
+// symbols (type U).
+//
+// The options control the printed output:
+//
+// -n
+// an alias for -sort address (numeric),
+// for compatibility with other nm commands
+// -size
+// print symbol size in decimal between address and type
+// -sort {address,name,none,size}
+// sort output in the given order (default name)
+// size orders from largest to smallest
+// -type
+// print symbol type after name
+//
package main
diff --git a/src/cmd/nm/elf.go b/src/cmd/nm/elf.go
new file mode 100644
index 000000000..5aaa194dd
--- /dev/null
+++ b/src/cmd/nm/elf.go
@@ -0,0 +1,57 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of ELF executables (Linux, FreeBSD, and so on).
+
+package main
+
+import (
+ "debug/elf"
+ "os"
+)
+
+func elfSymbols(f *os.File) []Sym {
+ p, err := elf.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ elfSyms, err := p.Symbols()
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ var syms []Sym
+ for _, s := range elfSyms {
+ sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
+ switch s.Section {
+ case elf.SHN_UNDEF:
+ sym.Code = 'U'
+ case elf.SHN_COMMON:
+ sym.Code = 'B'
+ default:
+ i := int(s.Section)
+ if i < 0 || i >= len(p.Sections) {
+ break
+ }
+ sect := p.Sections[i]
+ switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
+ case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
+ sym.Code = 'T'
+ case elf.SHF_ALLOC:
+ sym.Code = 'R'
+ case elf.SHF_ALLOC | elf.SHF_WRITE:
+ sym.Code = 'D'
+ }
+ }
+ if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
+ sym.Code += 'a' - 'A'
+ }
+ syms = append(syms, sym)
+ }
+
+ return syms
+}
diff --git a/src/cmd/nm/goobj.go b/src/cmd/nm/goobj.go
new file mode 100644
index 000000000..5e0817d95
--- /dev/null
+++ b/src/cmd/nm/goobj.go
@@ -0,0 +1,67 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Go intermediate object files and archives.
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func goobjName(id goobj_SymID) string {
+ if id.Version == 0 {
+ return id.Name
+ }
+ return fmt.Sprintf("%s<%d>", id.Name, id.Version)
+}
+
+func goobjSymbols(f *os.File) []Sym {
+ pkg, err := goobj_Parse(f, `""`)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ seen := make(map[goobj_SymID]bool)
+
+ var syms []Sym
+ for _, s := range pkg.Syms {
+ seen[s.goobj_SymID] = true
+ sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.goobj_SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'}
+ switch s.Kind {
+ case goobj_STEXT, goobj_SELFRXSECT:
+ sym.Code = 'T'
+ case goobj_STYPE, goobj_SSTRING, goobj_SGOSTRING, goobj_SGOFUNC, goobj_SRODATA, goobj_SFUNCTAB, goobj_STYPELINK, goobj_SSYMTAB, goobj_SPCLNTAB, goobj_SELFROSECT:
+ sym.Code = 'R'
+ case goobj_SMACHOPLT, goobj_SELFSECT, goobj_SMACHO, goobj_SMACHOGOT, goobj_SNOPTRDATA, goobj_SINITARR, goobj_SDATA, goobj_SWINDOWS:
+ sym.Code = 'D'
+ case goobj_SBSS, goobj_SNOPTRBSS, goobj_STLSBSS:
+ sym.Code = 'B'
+ case goobj_SXREF, goobj_SMACHOSYMSTR, goobj_SMACHOSYMTAB, goobj_SMACHOINDIRECTPLT, goobj_SMACHOINDIRECTGOT, goobj_SFILE, goobj_SFILEPATH, goobj_SCONST, goobj_SDYNIMPORT, goobj_SHOSTOBJ:
+ sym.Code = 'X' // should not see
+ }
+ if s.Version != 0 {
+ sym.Code += 'a' - 'A'
+ }
+ syms = append(syms, sym)
+ }
+
+ for _, s := range pkg.Syms {
+ for _, r := range s.Reloc {
+ if !seen[r.Sym] {
+ seen[r.Sym] = true
+ sym := Sym{Name: goobjName(r.Sym), Code: 'U'}
+ if s.Version != 0 {
+ // should not happen but handle anyway
+ sym.Code = 'u'
+ }
+ syms = append(syms, sym)
+ }
+ }
+ }
+
+ return syms
+}
diff --git a/src/cmd/nm/macho.go b/src/cmd/nm/macho.go
new file mode 100644
index 000000000..c60bde55b
--- /dev/null
+++ b/src/cmd/nm/macho.go
@@ -0,0 +1,69 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Mach-O executables (OS X).
+
+package main
+
+import (
+ "debug/macho"
+ "os"
+ "sort"
+)
+
+func machoSymbols(f *os.File) []Sym {
+ p, err := macho.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ if p.Symtab == nil {
+ errorf("%s: no symbol table", f.Name())
+ return nil
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+ for _, s := range p.Symtab.Syms {
+ addrs = append(addrs, s.Value)
+ }
+ sort.Sort(uint64s(addrs))
+
+ var syms []Sym
+ for _, s := range p.Symtab.Syms {
+ sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
+ i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
+ if i < len(addrs) {
+ sym.Size = int64(addrs[i] - s.Value)
+ }
+ if s.Sect == 0 {
+ sym.Code = 'U'
+ } else if int(s.Sect) <= len(p.Sections) {
+ sect := p.Sections[s.Sect-1]
+ switch sect.Seg {
+ case "__TEXT":
+ sym.Code = 'R'
+ case "__DATA":
+ sym.Code = 'D'
+ }
+ switch sect.Seg + " " + sect.Name {
+ case "__TEXT __text":
+ sym.Code = 'T'
+ case "__DATA __bss", "__DATA __noptrbss":
+ sym.Code = 'B'
+ }
+ }
+ syms = append(syms, sym)
+ }
+
+ return syms
+}
+
+type uint64s []uint64
+
+func (x uint64s) Len() int { return len(x) }
+func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
deleted file mode 100644
index 820942426..000000000
--- a/src/cmd/nm/nm.c
+++ /dev/null
@@ -1,401 +0,0 @@
-// Inferno utils/nm/nm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/nm/nm.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-/*
- * nm.c -- drive nm
- */
-#include <u.h>
-#include <libc.h>
-#include <ar.h>
-#include <bio.h>
-#include <mach.h>
-
-enum{
- CHUNK = 256 /* must be power of 2 */
-};
-
-char *errs; /* exit status */
-char *filename; /* current file */
-char symname[]="__.GOSYMDEF"; /* table of contents file name */
-int multifile; /* processing multiple files */
-int aflag;
-int gflag;
-int hflag;
-int nflag;
-int sflag;
-int Sflag;
-int uflag;
-int Tflag;
-int tflag;
-
-Sym **fnames; /* file path translation table */
-Sym **symptr;
-int nsym;
-Biobuf bout;
-
-int cmp(void*, void*);
-void error(char*, ...);
-void execsyms(int);
-void psym(Sym*, void*);
-void printsyms(Sym**, long);
-void doar(Biobuf*);
-void dofile(Biobuf*);
-void zenter(Sym*);
-
-void
-usage(void)
-{
- fprint(2, "usage: nm [-aghnsSTu] file ...\n");
- exits("usage");
-}
-
-void
-main(int argc, char *argv[])
-{
- int i;
- Biobuf *bin;
-
- Binit(&bout, 1, OWRITE);
- argv0 = argv[0];
- ARGBEGIN {
- default: usage();
- case 'a': aflag = 1; break;
- case 'g': gflag = 1; break;
- case 'h': hflag = 1; break;
- case 'n': nflag = 1; break;
- case 's': sflag = 1; break;
- case 'S': nflag = Sflag = 1; break;
- case 'u': uflag = 1; break;
- case 't': tflag = 1; break;
- case 'T': Tflag = 1; break;
- } ARGEND
- if (argc == 0)
- usage();
- if (argc > 1)
- multifile++;
- for(i=0; i<argc; i++){
- filename = argv[i];
- bin = Bopen(filename, OREAD);
- if(bin == 0){
- error("cannot open %s", filename);
- continue;
- }
- if (isar(bin))
- doar(bin);
- else{
- Bseek(bin, 0, 0);
- dofile(bin);
- }
- Bterm(bin);
- }
- exits(errs);
-}
-
-/*
- * read an archive file,
- * processing the symbols for each intermediate file in it.
- */
-void
-doar(Biobuf *bp)
-{
- int offset, size, obj;
- char name[SARNAME];
-
- multifile = 1;
- for (offset = Boffset(bp);;offset += size) {
- size = nextar(bp, offset, name);
- if (size < 0) {
- error("phase error on ar header %d", offset);
- return;
- }
- if (size == 0)
- return;
- if (strcmp(name, symname) == 0)
- continue;
- obj = objtype(bp, 0);
- if (obj < 0) {
- // perhaps foreign object
- if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
- return;
- error("inconsistent file %s in %s",
- name, filename);
- return;
- }
- if (!readar(bp, obj, offset+size, 1)) {
- error("invalid symbol reference in file %s",
- name);
- return;
- }
- filename = name;
- nsym=0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
-}
-
-/*
- * process symbols in a file
- */
-void
-dofile(Biobuf *bp)
-{
- int obj;
-
- obj = objtype(bp, 0);
- if (obj < 0)
- execsyms(Bfildes(bp));
- else
- if (readobj(bp, obj)) {
- nsym = 0;
- objtraverse(psym, 0);
- printsyms(symptr, nsym);
- }
-}
-
-/*
- * comparison routine for sorting the symbol table
- * this screws up on 'z' records when aflag == 1
- */
-int
-cmp(void *vs, void *vt)
-{
- Sym **s, **t;
-
- s = vs;
- t = vt;
- if(nflag) // sort on address (numeric) order
- if((*s)->value < (*t)->value)
- return -1;
- else
- return (*s)->value > (*t)->value;
- if(sflag) // sort on file order (sequence)
- return (*s)->sequence - (*t)->sequence;
- return strcmp((*s)->name, (*t)->name);
-}
-/*
- * enter a symbol in the table of filename elements
- */
-void
-zenter(Sym *s)
-{
- static int maxf = 0;
-
- if (s->value > maxf) {
- maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
- fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
- if(fnames == 0) {
- error("out of memory", argv0);
- exits("memory");
- }
- }
- fnames[s->value] = s;
-}
-
-/*
- * get the symbol table from an executable file, if it has one
- */
-void
-execsyms(int fd)
-{
- Fhdr f;
- Sym *s;
- int32 n;
-
- seek(fd, 0, 0);
- if (crackhdr(fd, &f) == 0) {
- error("Can't read header for %s", filename);
- return;
- }
- if (syminit(fd, &f) < 0)
- return;
- s = symbase(&n);
- nsym = 0;
- while(n--)
- psym(s++, 0);
-
- printsyms(symptr, nsym);
-}
-
-void
-psym(Sym *s, void* p)
-{
- USED(p);
- switch(s->type) {
- case 'T':
- case 'L':
- case 'D':
- case 'B':
- if (uflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'b':
- case 'd':
- case 'l':
- case 't':
- if (uflag || gflag)
- return;
- if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
- return;
- break;
- case 'U':
- if (gflag)
- return;
- break;
- case 'Z':
- if (!aflag)
- return;
- break;
- case 'm':
- if(!aflag || uflag || gflag)
- return;
- break;
- case 'f': /* we only see a 'z' when the following is true*/
- if(!aflag || uflag || gflag)
- return;
- zenter(s);
- break;
- case 'a':
- case 'p':
- case 'z':
- default:
- if(!aflag || uflag || gflag)
- return;
- break;
- }
- symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
- if (symptr == 0) {
- error("out of memory");
- exits("memory");
- }
- symptr[nsym++] = s;
-}
-
-const char *skipnames[] = {
- "bss",
- "data",
- "ebss",
- "edata",
- "egcbss",
- "egcdata",
- "enoptrbss",
- "enoptrdata",
- "epclntab",
- "erodata",
- "esymtab",
- "etext",
- "etypelink",
- "noptrbss",
- "noptrdata",
- "rodata",
- "text",
-};
-
-int
-skipsize(char *name)
-{
- int i;
-
- for(i=0; i<nelem(skipnames); i++)
- if(strcmp(skipnames[i], name) == 0)
- return 1;
- return 0;
-}
-
-void
-printsyms(Sym **symptr, long nsym)
-{
- int i, j, wid;
- Sym *s;
- char *cp;
- char path[512];
-
- qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
-
- wid = 0;
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (s->value && wid == 0)
- wid = 8;
- else if (s->value >= 0x100000000LL && wid == 8)
- wid = 16;
- }
- for (i=0; i<nsym; i++) {
- s = symptr[i];
- if (multifile && !hflag)
- Bprint(&bout, "%s:", filename);
- if (s->type == 'z') {
- fileelem(fnames, (uchar *) s->name, path, 512);
- cp = path;
- } else
- cp = s->name;
- if (Tflag)
- Bprint(&bout, "%8ux ", s->sig);
- if (s->value || s->type == 'a' || s->type == 'p')
- Bprint(&bout, "%*llux ", wid, s->value);
- else
- Bprint(&bout, "%*s ", wid, "");
- if(Sflag && !skipsize(cp)) {
- vlong siz;
-
- siz = 0;
- for(j=i+1; j<nsym; j++) {
- if(!skipsize(symptr[j]->name) && symptr[j]->type != 'a' && symptr[j]->type != 'p') {
- siz = symptr[j]->value - s->value;
- break;
- }
- }
- if(siz > 0)
- Bprint(&bout, "%*llud ", wid, siz);
- }
- Bprint(&bout, "%c %s", s->type, cp);
- if(tflag && s->gotype)
- Bprint(&bout, " %*llux", wid, s->gotype);
- Bprint(&bout, "\n");
- }
-}
-
-void
-error(char *fmt, ...)
-{
- Fmt f;
- char buf[128];
- va_list arg;
-
- fmtfdinit(&f, 2, buf, sizeof buf);
- fmtprint(&f, "%s: ", argv0);
- va_start(arg, fmt);
- fmtvprint(&f, fmt, arg);
- va_end(arg);
- fmtprint(&f, "\n");
- fmtfdflush(&f);
- errs = "errors";
-}
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
new file mode 100644
index 000000000..a4036184e
--- /dev/null
+++ b/src/cmd/nm/nm.go
@@ -0,0 +1,184 @@
+// 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 (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "sort"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go tool nm [-n] [-size] [-sort order] [-type] file...\n")
+ os.Exit(2)
+}
+
+var (
+ sortOrder = flag.String("sort", "name", "")
+ printSize = flag.Bool("size", false, "")
+ printType = flag.Bool("type", false, "")
+
+ filePrefix = false
+)
+
+func init() {
+ flag.Var(nflag(0), "n", "") // alias for -sort address
+}
+
+type nflag int
+
+func (nflag) IsBoolFlag() bool {
+ return true
+}
+
+func (nflag) Set(value string) error {
+ if value == "true" {
+ *sortOrder = "address"
+ }
+ return nil
+}
+
+func (nflag) String() string {
+ if *sortOrder == "address" {
+ return "true"
+ }
+ return "false"
+}
+
+func main() {
+ log.SetFlags(0)
+ flag.Usage = usage
+ flag.Parse()
+
+ switch *sortOrder {
+ case "address", "name", "none", "size":
+ // ok
+ default:
+ fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder)
+ os.Exit(2)
+ }
+
+ args := flag.Args()
+ filePrefix = len(args) > 1
+ if len(args) == 0 {
+ flag.Usage()
+ }
+
+ for _, file := range args {
+ nm(file)
+ }
+
+ os.Exit(exitCode)
+}
+
+var exitCode = 0
+
+func errorf(format string, args ...interface{}) {
+ log.Printf(format, args...)
+ exitCode = 1
+}
+
+type Sym struct {
+ Addr uint64
+ Size int64
+ Code rune
+ Name string
+ Type string
+}
+
+var parsers = []struct {
+ prefix []byte
+ parse func(*os.File) []Sym
+}{
+ {[]byte("!<arch>\n"), goobjSymbols},
+ {[]byte("go object "), goobjSymbols},
+ {[]byte("\x7FELF"), elfSymbols},
+ {[]byte("\xFE\xED\xFA\xCE"), machoSymbols},
+ {[]byte("\xFE\xED\xFA\xCF"), machoSymbols},
+ {[]byte("\xCE\xFA\xED\xFE"), machoSymbols},
+ {[]byte("\xCF\xFA\xED\xFE"), machoSymbols},
+ {[]byte("MZ"), peSymbols},
+ {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386
+ {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips
+ {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm
+ {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64
+}
+
+func nm(file string) {
+ f, err := os.Open(file)
+ if err != nil {
+ errorf("%v", err)
+ return
+ }
+ defer f.Close()
+
+ buf := make([]byte, 16)
+ io.ReadFull(f, buf)
+ f.Seek(0, 0)
+
+ var syms []Sym
+ for _, p := range parsers {
+ if bytes.HasPrefix(buf, p.prefix) {
+ syms = p.parse(f)
+ goto HaveSyms
+ }
+ }
+ errorf("%v: unknown file format", file)
+ return
+
+HaveSyms:
+ switch *sortOrder {
+ case "address":
+ sort.Sort(byAddr(syms))
+ case "name":
+ sort.Sort(byName(syms))
+ case "size":
+ sort.Sort(bySize(syms))
+ }
+
+ w := bufio.NewWriter(os.Stdout)
+ for _, sym := range syms {
+ if filePrefix {
+ fmt.Fprintf(w, "%s:\t", file)
+ }
+ if sym.Code == 'U' {
+ fmt.Fprintf(w, "%8s", "")
+ } else {
+ fmt.Fprintf(w, "%8x", sym.Addr)
+ }
+ if *printSize {
+ fmt.Fprintf(w, " %10d", sym.Size)
+ }
+ fmt.Fprintf(w, " %c %s", sym.Code, sym.Name)
+ if *printType && sym.Type != "" {
+ fmt.Fprintf(w, " %s", sym.Type)
+ }
+ fmt.Fprintf(w, "\n")
+ }
+ w.Flush()
+}
+
+type byAddr []Sym
+
+func (x byAddr) Len() int { return len(x) }
+func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
+
+type byName []Sym
+
+func (x byName) Len() int { return len(x) }
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name }
+
+type bySize []Sym
+
+func (x bySize) Len() int { return len(x) }
+func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x bySize) Less(i, j int) bool { return x[i].Size > x[j].Size }
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
new file mode 100644
index 000000000..f4e47a42d
--- /dev/null
+++ b/src/cmd/nm/nm_test.go
@@ -0,0 +1,99 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var testData uint32
+
+func checkSymbols(t *testing.T, nmoutput []byte) {
+ var checkSymbolsFound, testDataFound bool
+ scanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))
+ for scanner.Scan() {
+ f := strings.Fields(scanner.Text())
+ if len(f) < 3 {
+ continue
+ }
+ switch f[2] {
+ case "cmd/nm.checkSymbols":
+ checkSymbolsFound = true
+ addr := "0x" + f[0]
+ if addr != fmt.Sprintf("%p", checkSymbols) {
+ t.Errorf("nm shows wrong address %v for checkSymbols (%p)", addr, checkSymbols)
+ }
+ case "cmd/nm.testData":
+ testDataFound = true
+ addr := "0x" + f[0]
+ if addr != fmt.Sprintf("%p", &testData) {
+ t.Errorf("nm shows wrong address %v for testData (%p)", addr, &testData)
+ }
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ t.Errorf("error while reading symbols: %v", err)
+ return
+ }
+ if !checkSymbolsFound {
+ t.Error("nm shows no checkSymbols symbol")
+ }
+ if !testDataFound {
+ t.Error("nm shows no testData symbol")
+ }
+}
+
+func TestNM(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ tmpDir, err := ioutil.TempDir("", "TestNM")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ testnmpath := filepath.Join(tmpDir, "testnm.exe")
+ out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
+ if err != nil {
+ t.Fatalf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
+ }
+
+ testfiles := []string{
+ "elf/testdata/gcc-386-freebsd-exec",
+ "elf/testdata/gcc-amd64-linux-exec",
+ "macho/testdata/gcc-386-darwin-exec",
+ "macho/testdata/gcc-amd64-darwin-exec",
+ "pe/testdata/gcc-amd64-mingw-exec",
+ "pe/testdata/gcc-386-mingw-exec",
+ "plan9obj/testdata/amd64-plan9-exec",
+ "plan9obj/testdata/386-plan9-exec",
+ }
+ for _, f := range testfiles {
+ exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f)
+ cmd := exec.Command(testnmpath, exepath)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out))
+ }
+ }
+
+ cmd := exec.Command(testnmpath, os.Args[0])
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
+ }
+ checkSymbols(t, out)
+}
diff --git a/src/cmd/nm/pe.go b/src/cmd/nm/pe.go
new file mode 100644
index 000000000..52d05e51d
--- /dev/null
+++ b/src/cmd/nm/pe.go
@@ -0,0 +1,98 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of PE executables (Microsoft Windows).
+
+package main
+
+import (
+ "debug/pe"
+ "os"
+ "sort"
+)
+
+func peSymbols(f *os.File) []Sym {
+ p, err := pe.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+
+ var imageBase uint64
+ switch oh := p.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ default:
+ errorf("parsing %s: file format not recognized", f.Name())
+ return nil
+ }
+
+ var syms []Sym
+ for _, s := range p.Symbols {
+ const (
+ N_UNDEF = 0 // An undefined (extern) symbol
+ N_ABS = -1 // An absolute symbol (e_value is a constant, not an address)
+ N_DEBUG = -2 // A debugging symbol
+ )
+ sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
+ switch s.SectionNumber {
+ case N_UNDEF:
+ sym.Code = 'U'
+ case N_ABS:
+ sym.Code = 'C'
+ case N_DEBUG:
+ sym.Code = '?'
+ default:
+ if s.SectionNumber < 0 {
+ errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber)
+ return nil
+ }
+ if len(p.Sections) < int(s.SectionNumber) {
+ errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections))
+ return nil
+ }
+ sect := p.Sections[s.SectionNumber-1]
+ const (
+ text = 0x20
+ data = 0x40
+ bss = 0x80
+ permX = 0x20000000
+ permR = 0x40000000
+ permW = 0x80000000
+ )
+ ch := sect.Characteristics
+ switch {
+ case ch&text != 0:
+ sym.Code = 'T'
+ case ch&data != 0:
+ if ch&permW == 0 {
+ sym.Code = 'R'
+ } else {
+ sym.Code = 'D'
+ }
+ case ch&bss != 0:
+ sym.Code = 'B'
+ }
+ sym.Addr += imageBase + uint64(sect.VirtualAddress)
+ }
+ syms = append(syms, sym)
+ addrs = append(addrs, sym.Addr)
+ }
+
+ sort.Sort(uint64s(addrs))
+ for i := range syms {
+ j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
+ if j < len(addrs) {
+ syms[i].Size = int64(addrs[j] - syms[i].Addr)
+ }
+ }
+
+ return syms
+}
diff --git a/src/cmd/nm/plan9obj.go b/src/cmd/nm/plan9obj.go
new file mode 100644
index 000000000..006c66ebf
--- /dev/null
+++ b/src/cmd/nm/plan9obj.go
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Plan 9 a.out executables.
+
+package main
+
+import (
+ "debug/plan9obj"
+ "os"
+ "sort"
+)
+
+func plan9Symbols(f *os.File) []Sym {
+ p, err := plan9obj.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ plan9Syms, err := p.Symbols()
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return nil
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+ for _, s := range plan9Syms {
+ addrs = append(addrs, s.Value)
+ }
+ sort.Sort(uint64s(addrs))
+
+ var syms []Sym
+
+ for _, s := range plan9Syms {
+ sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
+ i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
+ if i < len(addrs) {
+ sym.Size = int64(addrs[i] - s.Value)
+ }
+ syms = append(syms, sym)
+ }
+
+ return syms
+}
diff --git a/src/cmd/objdump/Makefile b/src/cmd/objdump/Makefile
new file mode 100644
index 000000000..1b66c26ba
--- /dev/null
+++ b/src/cmd/objdump/Makefile
@@ -0,0 +1,10 @@
+all: x86.go armasm.go
+
+x86.go: bundle
+ ./bundle -p main -x x86_ rsc.io/x86/x86asm | gofmt >x86.go
+
+armasm.go: bundle
+ ./bundle -p main -x arm_ rsc.io/arm/armasm | gofmt >armasm.go
+
+bundle:
+ go build -o bundle code.google.com/p/rsc/cmd/bundle
diff --git a/src/cmd/objdump/armasm.go b/src/cmd/objdump/armasm.go
new file mode 100644
index 000000000..764a3689e
--- /dev/null
+++ b/src/cmd/objdump/armasm.go
@@ -0,0 +1,10821 @@
+// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle
+// bundle -p main -x arm_ rsc.io/arm/armasm
+
+/* decode.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// An instFormat describes the format of an instruction encoding.
+// An instruction with 32-bit value x matches the format if x&mask == value
+// and the condition matches.
+// The condition matches if x>>28 == 0xF && value>>28==0xF
+// or if x>>28 != 0xF and value>>28 == 0.
+// If x matches the format, then the rest of the fields describe how to interpret x.
+// The opBits describe bits that should be extracted from x and added to the opcode.
+// For example opBits = 0x1234 means that the value
+// (2 bits at offset 1) followed by (4 bits at offset 3)
+// should be added to op.
+// Finally the args describe how to decode the instruction arguments.
+// args is stored as a fixed-size array; if there are fewer than len(args) arguments,
+// args[i] == 0 marks the end of the argument list.
+type arm_instFormat struct {
+ mask uint32
+ value uint32
+ priority int8
+ op arm_Op
+ opBits uint64
+ args arm_instArgs
+}
+
+type arm_instArgs [4]arm_instArg
+
+var (
+ arm_errMode = fmt.Errorf("unsupported execution mode")
+ arm_errShort = fmt.Errorf("truncated instruction")
+ arm_errUnknown = fmt.Errorf("unknown instruction")
+)
+
+var arm_decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction.
+func arm_Decode(src []byte, mode arm_Mode) (inst arm_Inst, err error) {
+ if mode != arm_ModeARM {
+ return arm_Inst{}, arm_errMode
+ }
+ if len(src) < 4 {
+ return arm_Inst{}, arm_errShort
+ }
+
+ if arm_decoderCover == nil {
+ arm_decoderCover = make([]bool, len(arm_instFormats))
+ }
+
+ x := binary.LittleEndian.Uint32(src)
+
+ // The instFormat table contains both conditional and unconditional instructions.
+ // Considering only the top 4 bits, the conditional instructions use mask=0, value=0,
+ // while the unconditional instructions use mask=f, value=f.
+ // Prepare a version of x with the condition cleared to 0 in conditional instructions
+ // and then assume mask=f during matching.
+ const condMask = 0xf0000000
+ xNoCond := x
+ if x&condMask != condMask {
+ xNoCond &^= condMask
+ }
+ var priority int8
+Search:
+ for i := range arm_instFormats {
+ f := &arm_instFormats[i]
+ if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority {
+ continue
+ }
+ delta := uint32(0)
+ deltaShift := uint(0)
+ for opBits := f.opBits; opBits != 0; opBits >>= 16 {
+ n := uint(opBits & 0xFF)
+ off := uint((opBits >> 8) & 0xFF)
+ delta |= (x >> off) & (1<<n - 1) << deltaShift
+ deltaShift += n
+ }
+ op := f.op + arm_Op(delta)
+
+ // Special case: BKPT encodes with condition but cannot have one.
+ if op&^15 == arm_BKPT_EQ && op != arm_BKPT {
+ continue Search
+ }
+
+ var args arm_Args
+ for j, aop := range f.args {
+ if aop == 0 {
+ break
+ }
+ arg := arm_decodeArg(aop, x)
+ if arg == nil { // cannot decode argument
+ continue Search
+ }
+ args[j] = arg
+ }
+
+ arm_decoderCover[i] = true
+
+ inst = arm_Inst{
+ Op: op,
+ Args: args,
+ Enc: x,
+ Len: 4,
+ }
+ priority = f.priority
+ continue Search
+ }
+ if inst.Op != 0 {
+ return inst, nil
+ }
+ return arm_Inst{}, arm_errUnknown
+}
+
+// An instArg describes the encoding of a single argument.
+// In the names used for arguments, _p_ means +, _m_ means -,
+// _pm_ means ± (usually keyed by the U bit).
+// The _W suffix indicates a general addressing mode based on the P and W bits.
+// The _offset and _postindex suffixes force the given addressing mode.
+// The rest should be somewhat self-explanatory, at least given
+// the decodeArg function.
+type arm_instArg uint8
+
+const (
+ _ arm_instArg = iota
+ arm_arg_APSR
+ arm_arg_FPSCR
+ arm_arg_Dn_half
+ arm_arg_R1_0
+ arm_arg_R1_12
+ arm_arg_R2_0
+ arm_arg_R2_12
+ arm_arg_R_0
+ arm_arg_R_12
+ arm_arg_R_12_nzcv
+ arm_arg_R_16
+ arm_arg_R_16_WB
+ arm_arg_R_8
+ arm_arg_R_rotate
+ arm_arg_R_shift_R
+ arm_arg_R_shift_imm
+ arm_arg_SP
+ arm_arg_Sd
+ arm_arg_Sd_Dd
+ arm_arg_Dd_Sd
+ arm_arg_Sm
+ arm_arg_Sm_Dm
+ arm_arg_Sn
+ arm_arg_Sn_Dn
+ arm_arg_const
+ arm_arg_endian
+ arm_arg_fbits
+ arm_arg_fp_0
+ arm_arg_imm24
+ arm_arg_imm5
+ arm_arg_imm5_32
+ arm_arg_imm5_nz
+ arm_arg_imm_12at8_4at0
+ arm_arg_imm_4at16_12at0
+ arm_arg_imm_vfp
+ arm_arg_label24
+ arm_arg_label24H
+ arm_arg_label_m_12
+ arm_arg_label_p_12
+ arm_arg_label_pm_12
+ arm_arg_label_pm_4_4
+ arm_arg_lsb_width
+ arm_arg_mem_R
+ arm_arg_mem_R_pm_R_W
+ arm_arg_mem_R_pm_R_postindex
+ arm_arg_mem_R_pm_R_shift_imm_W
+ arm_arg_mem_R_pm_R_shift_imm_offset
+ arm_arg_mem_R_pm_R_shift_imm_postindex
+ arm_arg_mem_R_pm_imm12_W
+ arm_arg_mem_R_pm_imm12_offset
+ arm_arg_mem_R_pm_imm12_postindex
+ arm_arg_mem_R_pm_imm8_W
+ arm_arg_mem_R_pm_imm8_postindex
+ arm_arg_mem_R_pm_imm8at0_offset
+ arm_arg_option
+ arm_arg_registers
+ arm_arg_registers1
+ arm_arg_registers2
+ arm_arg_satimm4
+ arm_arg_satimm5
+ arm_arg_satimm4m1
+ arm_arg_satimm5m1
+ arm_arg_widthm1
+)
+
+// decodeArg decodes the arg described by aop from the instruction bits x.
+// It returns nil if x cannot be decoded according to aop.
+func arm_decodeArg(aop arm_instArg, x uint32) arm_Arg {
+ switch aop {
+ default:
+ return nil
+
+ case arm_arg_APSR:
+ return arm_APSR
+ case arm_arg_FPSCR:
+ return arm_FPSCR
+
+ case arm_arg_R_0:
+ return arm_Reg(x & (1<<4 - 1))
+ case arm_arg_R_8:
+ return arm_Reg((x >> 8) & (1<<4 - 1))
+ case arm_arg_R_12:
+ return arm_Reg((x >> 12) & (1<<4 - 1))
+ case arm_arg_R_16:
+ return arm_Reg((x >> 16) & (1<<4 - 1))
+
+ case arm_arg_R_12_nzcv:
+ r := arm_Reg((x >> 12) & (1<<4 - 1))
+ if r == arm_R15 {
+ return arm_APSR_nzcv
+ }
+ return r
+
+ case arm_arg_R_16_WB:
+ mode := arm_AddrLDM
+ if (x>>21)&1 != 0 {
+ mode = arm_AddrLDM_WB
+ }
+ return arm_Mem{Base: arm_Reg((x >> 16) & (1<<4 - 1)), Mode: mode}
+
+ case arm_arg_R_rotate:
+ Rm := arm_Reg(x & (1<<4 - 1))
+ typ, count := arm_decodeShift(x)
+ // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1.
+ if typ == arm_RotateRightExt {
+ return arm_Reg(Rm)
+ }
+ return arm_RegShift{Rm, typ, uint8(count)}
+
+ case arm_arg_R_shift_R:
+ Rm := arm_Reg(x & (1<<4 - 1))
+ Rs := arm_Reg((x >> 8) & (1<<4 - 1))
+ typ := arm_Shift((x >> 5) & (1<<2 - 1))
+ return arm_RegShiftReg{Rm, typ, Rs}
+
+ case arm_arg_R_shift_imm:
+ Rm := arm_Reg(x & (1<<4 - 1))
+ typ, count := arm_decodeShift(x)
+ if typ == arm_ShiftLeft && count == 0 {
+ return arm_Reg(Rm)
+ }
+ return arm_RegShift{Rm, typ, uint8(count)}
+
+ case arm_arg_R1_0:
+ return arm_Reg((x & (1<<4 - 1)))
+ case arm_arg_R1_12:
+ return arm_Reg(((x >> 12) & (1<<4 - 1)))
+ case arm_arg_R2_0:
+ return arm_Reg((x & (1<<4 - 1)) | 1)
+ case arm_arg_R2_12:
+ return arm_Reg(((x >> 12) & (1<<4 - 1)) | 1)
+
+ case arm_arg_SP:
+ return arm_SP
+
+ case arm_arg_Sd_Dd:
+ v := (x >> 12) & (1<<4 - 1)
+ vx := (x >> 22) & 1
+ sz := (x >> 8) & 1
+ if sz != 0 {
+ return arm_D0 + arm_Reg(vx<<4+v)
+ } else {
+ return arm_S0 + arm_Reg(v<<1+vx)
+ }
+
+ case arm_arg_Dd_Sd:
+ return arm_decodeArg(arm_arg_Sd_Dd, x^(1<<8))
+
+ case arm_arg_Sd:
+ v := (x >> 12) & (1<<4 - 1)
+ vx := (x >> 22) & 1
+ return arm_S0 + arm_Reg(v<<1+vx)
+
+ case arm_arg_Sm_Dm:
+ v := (x >> 0) & (1<<4 - 1)
+ vx := (x >> 5) & 1
+ sz := (x >> 8) & 1
+ if sz != 0 {
+ return arm_D0 + arm_Reg(vx<<4+v)
+ } else {
+ return arm_S0 + arm_Reg(v<<1+vx)
+ }
+
+ case arm_arg_Sm:
+ v := (x >> 0) & (1<<4 - 1)
+ vx := (x >> 5) & 1
+ return arm_S0 + arm_Reg(v<<1+vx)
+
+ case arm_arg_Dn_half:
+ v := (x >> 16) & (1<<4 - 1)
+ vx := (x >> 7) & 1
+ return arm_RegX{arm_D0 + arm_Reg(vx<<4+v), int((x >> 21) & 1)}
+
+ case arm_arg_Sn_Dn:
+ v := (x >> 16) & (1<<4 - 1)
+ vx := (x >> 7) & 1
+ sz := (x >> 8) & 1
+ if sz != 0 {
+ return arm_D0 + arm_Reg(vx<<4+v)
+ } else {
+ return arm_S0 + arm_Reg(v<<1+vx)
+ }
+
+ case arm_arg_Sn:
+ v := (x >> 16) & (1<<4 - 1)
+ vx := (x >> 7) & 1
+ return arm_S0 + arm_Reg(v<<1+vx)
+
+ case arm_arg_const:
+ v := x & (1<<8 - 1)
+ rot := (x >> 8) & (1<<4 - 1) * 2
+ if rot > 0 && v&3 == 0 {
+ // could rotate less
+ return arm_ImmAlt{uint8(v), uint8(rot)}
+ }
+ if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v {
+ // could wrap around to rot==0.
+ return arm_ImmAlt{uint8(v), uint8(rot)}
+ }
+ return arm_Imm(v>>rot | v<<(32-rot))
+
+ case arm_arg_endian:
+ return arm_Endian((x >> 9) & 1)
+
+ case arm_arg_fbits:
+ return arm_Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1))
+
+ case arm_arg_fp_0:
+ return arm_Imm(0)
+
+ case arm_arg_imm24:
+ return arm_Imm(x & (1<<24 - 1))
+
+ case arm_arg_imm5:
+ return arm_Imm((x >> 7) & (1<<5 - 1))
+
+ case arm_arg_imm5_32:
+ x = (x >> 7) & (1<<5 - 1)
+ if x == 0 {
+ x = 32
+ }
+ return arm_Imm(x)
+
+ case arm_arg_imm5_nz:
+ x = (x >> 7) & (1<<5 - 1)
+ if x == 0 {
+ return nil
+ }
+ return arm_Imm(x)
+
+ case arm_arg_imm_4at16_12at0:
+ return arm_Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1))
+
+ case arm_arg_imm_12at8_4at0:
+ return arm_Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1))
+
+ case arm_arg_imm_vfp:
+ x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1)
+ return arm_Imm(x)
+
+ case arm_arg_label24:
+ imm := (x & (1<<24 - 1)) << 2
+ return arm_PCRel(int32(imm<<6) >> 6)
+
+ case arm_arg_label24H:
+ h := (x >> 24) & 1
+ imm := (x&(1<<24-1))<<2 | h<<1
+ return arm_PCRel(int32(imm<<6) >> 6)
+
+ case arm_arg_label_m_12:
+ d := int32(x & (1<<12 - 1))
+ return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(-d)}
+
+ case arm_arg_label_p_12:
+ d := int32(x & (1<<12 - 1))
+ return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(d)}
+
+ case arm_arg_label_pm_12:
+ d := int32(x & (1<<12 - 1))
+ u := (x >> 23) & 1
+ if u == 0 {
+ d = -d
+ }
+ return arm_Mem{Base: arm_PC, Mode: arm_AddrOffset, Offset: int16(d)}
+
+ case arm_arg_label_pm_4_4:
+ d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
+ u := (x >> 23) & 1
+ if u == 0 {
+ d = -d
+ }
+ return arm_PCRel(d)
+
+ case arm_arg_lsb_width:
+ lsb := (x >> 7) & (1<<5 - 1)
+ msb := (x >> 16) & (1<<5 - 1)
+ if msb < lsb || msb >= 32 {
+ return nil
+ }
+ return arm_Imm(msb + 1 - lsb)
+
+ case arm_arg_mem_R:
+ Rn := arm_Reg((x >> 16) & (1<<4 - 1))
+ return arm_Mem{Base: Rn, Mode: arm_AddrOffset}
+
+ case arm_arg_mem_R_pm_R_postindex:
+ // Treat [<Rn>],+/-<Rm> like [<Rn>,+/-<Rm>{,<shift>}]{!}
+ // by forcing shift bits to <<0 and P=0, W=0 (postindex=true).
+ return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21))
+
+ case arm_arg_mem_R_pm_R_W:
+ // Treat [<Rn>,+/-<Rm>]{!} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+ // by forcing shift bits to <<0.
+ return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5))
+
+ case arm_arg_mem_R_pm_R_shift_imm_offset:
+ // Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+ // by forcing P=1, W=0 (index=false, wback=false).
+ return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24)
+
+ case arm_arg_mem_R_pm_R_shift_imm_postindex:
+ // Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+ // by forcing P=0, W=0 (postindex=true).
+ return arm_decodeArg(arm_arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21))
+
+ case arm_arg_mem_R_pm_R_shift_imm_W:
+ Rn := arm_Reg((x >> 16) & (1<<4 - 1))
+ Rm := arm_Reg(x & (1<<4 - 1))
+ typ, count := arm_decodeShift(x)
+ u := (x >> 23) & 1
+ w := (x >> 21) & 1
+ p := (x >> 24) & 1
+ if p == 0 && w == 1 {
+ return nil
+ }
+ sign := int8(+1)
+ if u == 0 {
+ sign = -1
+ }
+ mode := arm_AddrMode(uint8(p<<1) | uint8(w^1))
+ return arm_Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count}
+
+ case arm_arg_mem_R_pm_imm12_offset:
+ // Treat [<Rn>,#+/-<imm12>] like [<Rn>{,#+/-<imm12>}]{!}
+ // by forcing P=1, W=0 (index=false, wback=false).
+ return arm_decodeArg(arm_arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24)
+
+ case arm_arg_mem_R_pm_imm12_postindex:
+ // Treat [<Rn>],#+/-<imm12> like [<Rn>{,#+/-<imm12>}]{!}
+ // by forcing P=0, W=0 (postindex=true).
+ return arm_decodeArg(arm_arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21))
+
+ case arm_arg_mem_R_pm_imm12_W:
+ Rn := arm_Reg((x >> 16) & (1<<4 - 1))
+ u := (x >> 23) & 1
+ w := (x >> 21) & 1
+ p := (x >> 24) & 1
+ if p == 0 && w == 1 {
+ return nil
+ }
+ sign := int8(+1)
+ if u == 0 {
+ sign = -1
+ }
+ imm := int16(x & (1<<12 - 1))
+ mode := arm_AddrMode(uint8(p<<1) | uint8(w^1))
+ return arm_Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
+
+ case arm_arg_mem_R_pm_imm8_postindex:
+ // Treat [<Rn>],#+/-<imm8> like [<Rn>{,#+/-<imm8>}]{!}
+ // by forcing P=0, W=0 (postindex=true).
+ return arm_decodeArg(arm_arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21))
+
+ case arm_arg_mem_R_pm_imm8_W:
+ Rn := arm_Reg((x >> 16) & (1<<4 - 1))
+ u := (x >> 23) & 1
+ w := (x >> 21) & 1
+ p := (x >> 24) & 1
+ if p == 0 && w == 1 {
+ return nil
+ }
+ sign := int8(+1)
+ if u == 0 {
+ sign = -1
+ }
+ imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
+ mode := arm_AddrMode(uint8(p<<1) | uint8(w^1))
+ return arm_Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
+
+ case arm_arg_mem_R_pm_imm8at0_offset:
+ Rn := arm_Reg((x >> 16) & (1<<4 - 1))
+ u := (x >> 23) & 1
+ sign := int8(+1)
+ if u == 0 {
+ sign = -1
+ }
+ imm := int16(x&(1<<8-1)) << 2
+ return arm_Mem{Base: Rn, Mode: arm_AddrOffset, Offset: int16(sign) * imm}
+
+ case arm_arg_option:
+ return arm_Imm(x & (1<<4 - 1))
+
+ case arm_arg_registers:
+ return arm_RegList(x & (1<<16 - 1))
+
+ case arm_arg_registers2:
+ x &= 1<<16 - 1
+ n := 0
+ for i := 0; i < 16; i++ {
+ if x>>uint(i)&1 != 0 {
+ n++
+ }
+ }
+ if n < 2 {
+ return nil
+ }
+ return arm_RegList(x)
+
+ case arm_arg_registers1:
+ Rt := (x >> 12) & (1<<4 - 1)
+ return arm_RegList(1 << Rt)
+
+ case arm_arg_satimm4:
+ return arm_Imm((x >> 16) & (1<<4 - 1))
+
+ case arm_arg_satimm5:
+ return arm_Imm((x >> 16) & (1<<5 - 1))
+
+ case arm_arg_satimm4m1:
+ return arm_Imm((x>>16)&(1<<4-1) + 1)
+
+ case arm_arg_satimm5m1:
+ return arm_Imm((x>>16)&(1<<5-1) + 1)
+
+ case arm_arg_widthm1:
+ return arm_Imm((x>>16)&(1<<5-1) + 1)
+
+ }
+}
+
+// decodeShift decodes the shift-by-immediate encoded in x.
+func arm_decodeShift(x uint32) (arm_Shift, uint8) {
+ count := (x >> 7) & (1<<5 - 1)
+ typ := arm_Shift((x >> 5) & (1<<2 - 1))
+ switch typ {
+ case arm_ShiftRight, arm_ShiftRightSigned:
+ if count == 0 {
+ count = 32
+ }
+ case arm_RotateRight:
+ if count == 0 {
+ typ = arm_RotateRightExt
+ count = 1
+ }
+ }
+ return typ, uint8(count)
+}
+
+/* gnu.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var arm_saveDot = strings.NewReplacer(
+ ".F16", "_dot_F16",
+ ".F32", "_dot_F32",
+ ".F64", "_dot_F64",
+ ".S32", "_dot_S32",
+ ".U32", "_dot_U32",
+ ".FXS", "_dot_S",
+ ".FXU", "_dot_U",
+ ".32", "_dot_32",
+)
+
+// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
+// This form typically matches the syntax defined in the ARM Reference Manual.
+func arm_GNUSyntax(inst arm_Inst) string {
+ var buf bytes.Buffer
+ op := inst.Op.String()
+ op = arm_saveDot.Replace(op)
+ op = strings.Replace(op, ".", "", -1)
+ op = strings.Replace(op, "_dot_", ".", -1)
+ op = strings.ToLower(op)
+ buf.WriteString(op)
+ sep := " "
+ for i, arg := range inst.Args {
+ if arg == nil {
+ break
+ }
+ text := arm_gnuArg(&inst, i, arg)
+ if text == "" {
+ continue
+ }
+ buf.WriteString(sep)
+ sep = ", "
+ buf.WriteString(text)
+ }
+ return buf.String()
+}
+
+func arm_gnuArg(inst *arm_Inst, argIndex int, arg arm_Arg) string {
+ switch inst.Op &^ 15 {
+ case arm_LDRD_EQ, arm_LDREXD_EQ, arm_STRD_EQ:
+ if argIndex == 1 {
+ // second argument in consecutive pair not printed
+ return ""
+ }
+ case arm_STREXD_EQ:
+ if argIndex == 2 {
+ // second argument in consecutive pair not printed
+ return ""
+ }
+ }
+
+ switch arg := arg.(type) {
+ case arm_Imm:
+ switch inst.Op &^ 15 {
+ case arm_BKPT_EQ:
+ return fmt.Sprintf("%#04x", uint32(arg))
+ case arm_SVC_EQ:
+ return fmt.Sprintf("%#08x", uint32(arg))
+ }
+ return fmt.Sprintf("#%d", int32(arg))
+
+ case arm_ImmAlt:
+ return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot)
+
+ case arm_Mem:
+ R := arm_gnuArg(inst, -1, arg.Base)
+ X := ""
+ if arg.Sign != 0 {
+ X = ""
+ if arg.Sign < 0 {
+ X = "-"
+ }
+ X += arm_gnuArg(inst, -1, arg.Index)
+ if arg.Shift == arm_ShiftLeft && arg.Count == 0 {
+ // nothing
+ } else if arg.Shift == arm_RotateRightExt {
+ X += ", rrx"
+ } else {
+ X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count)
+ }
+ } else {
+ X = fmt.Sprintf("#%d", arg.Offset)
+ }
+
+ switch arg.Mode {
+ case arm_AddrOffset:
+ if X == "#0" {
+ return fmt.Sprintf("[%s]", R)
+ }
+ return fmt.Sprintf("[%s, %s]", R, X)
+ case arm_AddrPreIndex:
+ return fmt.Sprintf("[%s, %s]!", R, X)
+ case arm_AddrPostIndex:
+ return fmt.Sprintf("[%s], %s", R, X)
+ case arm_AddrLDM:
+ if X == "#0" {
+ return R
+ }
+ case arm_AddrLDM_WB:
+ if X == "#0" {
+ return R + "!"
+ }
+ }
+ return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X)
+
+ case arm_PCRel:
+ return fmt.Sprintf(".%+#x", int32(arg)+4)
+
+ case arm_Reg:
+ switch inst.Op &^ 15 {
+ case arm_LDREX_EQ:
+ if argIndex == 0 {
+ return fmt.Sprintf("r%d", int32(arg))
+ }
+ }
+ switch arg {
+ case arm_R10:
+ return "sl"
+ case arm_R11:
+ return "fp"
+ case arm_R12:
+ return "ip"
+ }
+
+ case arm_RegList:
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "{")
+ sep := ""
+ for i := 0; i < 16; i++ {
+ if arg&(1<<uint(i)) != 0 {
+ fmt.Fprintf(&buf, "%s%s", sep, arm_gnuArg(inst, -1, arm_Reg(i)))
+ sep = ", "
+ }
+ }
+ fmt.Fprintf(&buf, "}")
+ return buf.String()
+
+ case arm_RegShift:
+ if arg.Shift == arm_ShiftLeft && arg.Count == 0 {
+ return arm_gnuArg(inst, -1, arg.Reg)
+ }
+ if arg.Shift == arm_RotateRightExt {
+ return arm_gnuArg(inst, -1, arg.Reg) + ", rrx"
+ }
+ return fmt.Sprintf("%s, %s #%d", arm_gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arg.Count)
+
+ case arm_RegShiftReg:
+ return fmt.Sprintf("%s, %s %s", arm_gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arm_gnuArg(inst, -1, arg.RegCount))
+
+ }
+ return strings.ToLower(arg.String())
+}
+
+/* inst.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A Mode is an instruction execution mode.
+type arm_Mode int
+
+const (
+ _ arm_Mode = iota
+ arm_ModeARM
+ arm_ModeThumb
+)
+
+func (m arm_Mode) String() string {
+ switch m {
+ case arm_ModeARM:
+ return "ARM"
+ case arm_ModeThumb:
+ return "Thumb"
+ }
+ return fmt.Sprintf("Mode(%d)", int(m))
+}
+
+// An Op is an ARM opcode.
+type arm_Op uint16
+
+// NOTE: The actual Op values are defined in tables.go.
+// They are chosen to simplify instruction decoding and
+// are not a dense packing from 0 to N, although the
+// density is high, probably at least 90%.
+
+func (op arm_Op) String() string {
+ if op >= arm_Op(len(arm_opstr)) || arm_opstr[op] == "" {
+ return fmt.Sprintf("Op(%d)", int(op))
+ }
+ return arm_opstr[op]
+}
+
+// An Inst is a single instruction.
+type arm_Inst struct {
+ Op arm_Op // Opcode mnemonic
+ Enc uint32 // Raw encoding bits.
+ Len int // Length of encoding in bytes.
+ Args arm_Args // Instruction arguments, in ARM manual order.
+}
+
+func (i arm_Inst) String() string {
+ var buf bytes.Buffer
+ buf.WriteString(i.Op.String())
+ for j, arg := range i.Args {
+ if arg == nil {
+ break
+ }
+ if j == 0 {
+ buf.WriteString(" ")
+ } else {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(arg.String())
+ }
+ return buf.String()
+}
+
+// An Args holds the instruction arguments.
+// If an instruction has fewer than 4 arguments,
+// the final elements in the array are nil.
+type arm_Args [4]arm_Arg
+
+// An Arg is a single instruction argument, one of these types:
+// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg.
+type arm_Arg interface {
+ IsArg()
+ String() string
+}
+
+type arm_Float32Imm float32
+
+func (arm_Float32Imm) IsArg() {}
+
+func (f arm_Float32Imm) String() string {
+ return fmt.Sprintf("#%v", float32(f))
+}
+
+type arm_Float64Imm float32
+
+func (arm_Float64Imm) IsArg() {}
+
+func (f arm_Float64Imm) String() string {
+ return fmt.Sprintf("#%v", float64(f))
+}
+
+// An Imm is an integer constant.
+type arm_Imm uint32
+
+func (arm_Imm) IsArg() {}
+
+func (i arm_Imm) String() string {
+ return fmt.Sprintf("#%#x", uint32(i))
+}
+
+// A ImmAlt is an alternate encoding of an integer constant.
+type arm_ImmAlt struct {
+ Val uint8
+ Rot uint8
+}
+
+func (arm_ImmAlt) IsArg() {}
+
+func (i arm_ImmAlt) Imm() arm_Imm {
+ v := uint32(i.Val)
+ r := uint(i.Rot)
+ return arm_Imm(v>>r | v<<(32-r))
+}
+
+func (i arm_ImmAlt) String() string {
+ return fmt.Sprintf("#%#x, %d", i.Val, i.Rot)
+}
+
+// A Label is a text (code) address.
+type arm_Label uint32
+
+func (arm_Label) IsArg() {}
+
+func (i arm_Label) String() string {
+ return fmt.Sprintf("%#x", uint32(i))
+}
+
+// A Reg is a single register.
+// The zero value denotes R0, not the absence of a register.
+type arm_Reg uint8
+
+const (
+ arm_R0 arm_Reg = iota
+ arm_R1
+ arm_R2
+ arm_R3
+ arm_R4
+ arm_R5
+ arm_R6
+ arm_R7
+ arm_R8
+ arm_R9
+ arm_R10
+ arm_R11
+ arm_R12
+ arm_R13
+ arm_R14
+ arm_R15
+
+ arm_S0
+ arm_S1
+ arm_S2
+ arm_S3
+ arm_S4
+ arm_S5
+ arm_S6
+ arm_S7
+ arm_S8
+ arm_S9
+ arm_S10
+ arm_S11
+ arm_S12
+ arm_S13
+ arm_S14
+ arm_S15
+ arm_S16
+ arm_S17
+ arm_S18
+ arm_S19
+ arm_S20
+ arm_S21
+ arm_S22
+ arm_S23
+ arm_S24
+ arm_S25
+ arm_S26
+ arm_S27
+ arm_S28
+ arm_S29
+ arm_S30
+ arm_S31
+
+ arm_D0
+ arm_D1
+ arm_D2
+ arm_D3
+ arm_D4
+ arm_D5
+ arm_D6
+ arm_D7
+ arm_D8
+ arm_D9
+ arm_D10
+ arm_D11
+ arm_D12
+ arm_D13
+ arm_D14
+ arm_D15
+ arm_D16
+ arm_D17
+ arm_D18
+ arm_D19
+ arm_D20
+ arm_D21
+ arm_D22
+ arm_D23
+ arm_D24
+ arm_D25
+ arm_D26
+ arm_D27
+ arm_D28
+ arm_D29
+ arm_D30
+ arm_D31
+
+ arm_APSR
+ arm_APSR_nzcv
+ arm_FPSCR
+
+ arm_SP = arm_R13
+ arm_LR = arm_R14
+ arm_PC = arm_R15
+)
+
+func (arm_Reg) IsArg() {}
+
+func (r arm_Reg) String() string {
+ switch r {
+ case arm_APSR:
+ return "APSR"
+ case arm_APSR_nzcv:
+ return "APSR_nzcv"
+ case arm_FPSCR:
+ return "FPSCR"
+ case arm_SP:
+ return "SP"
+ case arm_PC:
+ return "PC"
+ case arm_LR:
+ return "LR"
+ }
+ if arm_R0 <= r && r <= arm_R15 {
+ return fmt.Sprintf("R%d", int(r-arm_R0))
+ }
+ if arm_S0 <= r && r <= arm_S31 {
+ return fmt.Sprintf("S%d", int(r-arm_S0))
+ }
+ if arm_D0 <= r && r <= arm_D31 {
+ return fmt.Sprintf("D%d", int(r-arm_D0))
+ }
+ return fmt.Sprintf("Reg(%d)", int(r))
+}
+
+// A RegX represents a fraction of a multi-value register.
+// The Index field specifies the index number,
+// but the size of the fraction is not specified.
+// It must be inferred from the instruction and the register type.
+// For example, in a VMOV instruction, RegX{D5, 1} represents
+// the top 32 bits of the 64-bit D5 register.
+type arm_RegX struct {
+ Reg arm_Reg
+ Index int
+}
+
+func (arm_RegX) IsArg() {}
+
+func (r arm_RegX) String() string {
+ return fmt.Sprintf("%s[%d]", r.Reg, r.Index)
+}
+
+// A RegList is a register list.
+// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list.
+type arm_RegList uint16
+
+func (arm_RegList) IsArg() {}
+
+func (r arm_RegList) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "{")
+ sep := ""
+ for i := 0; i < 16; i++ {
+ if r&(1<<uint(i)) != 0 {
+ fmt.Fprintf(&buf, "%s%s", sep, arm_Reg(i).String())
+ sep = ","
+ }
+ }
+ fmt.Fprintf(&buf, "}")
+ return buf.String()
+}
+
+// An Endian is the argument to the SETEND instruction.
+type arm_Endian uint8
+
+const (
+ arm_LittleEndian arm_Endian = 0
+ arm_BigEndian arm_Endian = 1
+)
+
+func (arm_Endian) IsArg() {}
+
+func (e arm_Endian) String() string {
+ if e != 0 {
+ return "BE"
+ }
+ return "LE"
+}
+
+// A Shift describes an ARM shift operation.
+type arm_Shift uint8
+
+const (
+ arm_ShiftLeft arm_Shift = 0 // left shift
+ arm_ShiftRight arm_Shift = 1 // logical (unsigned) right shift
+ arm_ShiftRightSigned arm_Shift = 2 // arithmetic (signed) right shift
+ arm_RotateRight arm_Shift = 3 // right rotate
+ arm_RotateRightExt arm_Shift = 4 // right rotate through carry (Count will always be 1)
+)
+
+var arm_shiftName = [...]string{
+ "LSL", "LSR", "ASR", "ROR", "RRX",
+}
+
+func (s arm_Shift) String() string {
+ if s < 5 {
+ return arm_shiftName[s]
+ }
+ return fmt.Sprintf("Shift(%d)", int(s))
+}
+
+// A RegShift is a register shifted by a constant.
+type arm_RegShift struct {
+ Reg arm_Reg
+ Shift arm_Shift
+ Count uint8
+}
+
+func (arm_RegShift) IsArg() {}
+
+func (r arm_RegShift) String() string {
+ return fmt.Sprintf("%s %s #%d", r.Reg, r.Shift, r.Count)
+}
+
+// A RegShiftReg is a register shifted by a register.
+type arm_RegShiftReg struct {
+ Reg arm_Reg
+ Shift arm_Shift
+ RegCount arm_Reg
+}
+
+func (arm_RegShiftReg) IsArg() {}
+
+func (r arm_RegShiftReg) String() string {
+ return fmt.Sprintf("%s %s %s", r.Reg, r.Shift, r.RegCount)
+}
+
+// A PCRel describes a memory address (usually a code label)
+// as a distance relative to the program counter.
+// TODO(rsc): Define which program counter (PC+4? PC+8? PC?).
+type arm_PCRel int32
+
+func (arm_PCRel) IsArg() {}
+
+func (r arm_PCRel) String() string {
+ return fmt.Sprintf("PC%+#x", int32(r))
+}
+
+// An AddrMode is an ARM addressing mode.
+type arm_AddrMode uint8
+
+const (
+ _ arm_AddrMode = iota
+ arm_AddrPostIndex // [R], X – use address R, set R = R + X
+ arm_AddrPreIndex // [R, X]! – use address R + X, set R = R + X
+ arm_AddrOffset // [R, X] – use address R + X
+ arm_AddrLDM // R – [R] but formats as R, for LDM/STM only
+ arm_AddrLDM_WB // R! - [R], X where X is instruction-specific amount, for LDM/STM only
+)
+
+// A Mem is a memory reference made up of a base R and index expression X.
+// The effective memory address is R or R+X depending on AddrMode.
+// The index expression is X = Sign*(Index Shift Count) + Offset,
+// but in any instruction either Sign = 0 or Offset = 0.
+type arm_Mem struct {
+ Base arm_Reg
+ Mode arm_AddrMode
+ Sign int8
+ Index arm_Reg
+ Shift arm_Shift
+ Count uint8
+ Offset int16
+}
+
+func (arm_Mem) IsArg() {}
+
+func (m arm_Mem) String() string {
+ R := m.Base.String()
+ X := ""
+ if m.Sign != 0 {
+ X = "+"
+ if m.Sign < 0 {
+ X = "-"
+ }
+ X += m.Index.String()
+ if m.Shift != arm_ShiftLeft || m.Count != 0 {
+ X += fmt.Sprintf(", %s #%d", m.Shift, m.Count)
+ }
+ } else {
+ X = fmt.Sprintf("#%d", m.Offset)
+ }
+
+ switch m.Mode {
+ case arm_AddrOffset:
+ if X == "#0" {
+ return fmt.Sprintf("[%s]", R)
+ }
+ return fmt.Sprintf("[%s, %s]", R, X)
+ case arm_AddrPreIndex:
+ return fmt.Sprintf("[%s, %s]!", R, X)
+ case arm_AddrPostIndex:
+ return fmt.Sprintf("[%s], %s", R, X)
+ case arm_AddrLDM:
+ if X == "#0" {
+ return R
+ }
+ case arm_AddrLDM_WB:
+ if X == "#0" {
+ return R + "!"
+ }
+ }
+ return fmt.Sprintf("[%s Mode(%d) %s]", R, int(m.Mode), X)
+}
+
+/* plan9x.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// plan9Syntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name and base
+// address of the symbol containing the target, if any; otherwise it returns "", 0.
+// The reader r should read from the text segment using text addresses
+// as offsets; it is used to display pc-relative loads as constant loads.
+func arm_plan9Syntax(inst arm_Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
+ if symname == nil {
+ symname = func(uint64) (string, uint64) { return "", 0 }
+ }
+
+ var args []string
+ for _, a := range inst.Args {
+ if a == nil {
+ break
+ }
+ args = append(args, arm_plan9Arg(&inst, pc, symname, a))
+ }
+
+ op := inst.Op.String()
+
+ switch inst.Op &^ 15 {
+ case arm_LDR_EQ, arm_LDRB_EQ, arm_LDRH_EQ:
+ // Check for RET
+ reg, _ := inst.Args[0].(arm_Reg)
+ mem, _ := inst.Args[1].(arm_Mem)
+ if inst.Op&^15 == arm_LDR_EQ && reg == arm_R15 && mem.Base == arm_SP && mem.Sign == 0 && mem.Mode == arm_AddrPostIndex {
+ return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset)
+ }
+
+ // Check for PC-relative load.
+ if mem.Base == arm_PC && mem.Sign == 0 && mem.Mode == arm_AddrOffset && text != nil {
+ addr := uint32(pc) + 8 + uint32(mem.Offset)
+ buf := make([]byte, 4)
+ switch inst.Op &^ 15 {
+ case arm_LDRB_EQ:
+ if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil {
+ break
+ }
+ args[1] = fmt.Sprintf("$%#x", buf[0])
+
+ case arm_LDRH_EQ:
+ if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil {
+ break
+ }
+ args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf))
+
+ case arm_LDR_EQ:
+ if _, err := text.ReadAt(buf, int64(addr)); err != nil {
+ break
+ }
+ x := binary.LittleEndian.Uint32(buf)
+ if s, base := symname(uint64(x)); s != "" && uint64(x) == base {
+ args[1] = fmt.Sprintf("$%s(SB)", s)
+ } else {
+ args[1] = fmt.Sprintf("$%#x", x)
+ }
+ }
+ }
+ }
+
+ // Move addressing mode into opcode suffix.
+ suffix := ""
+ switch inst.Op &^ 15 {
+ case arm_LDR_EQ, arm_LDRB_EQ, arm_LDRH_EQ, arm_STR_EQ, arm_STRB_EQ, arm_STRH_EQ:
+ mem, _ := inst.Args[1].(arm_Mem)
+ switch mem.Mode {
+ case arm_AddrOffset, arm_AddrLDM:
+ // no suffix
+ case arm_AddrPreIndex, arm_AddrLDM_WB:
+ suffix = ".W"
+ case arm_AddrPostIndex:
+ suffix = ".P"
+ }
+ off := ""
+ if mem.Offset != 0 {
+ off = fmt.Sprintf("%#x", mem.Offset)
+ }
+ base := fmt.Sprintf("(R%d)", int(mem.Base))
+ index := ""
+ if mem.Sign != 0 {
+ sign := ""
+ if mem.Sign < 0 {
+ sign = ""
+ }
+ shift := ""
+ if mem.Count != 0 {
+ shift = fmt.Sprintf("%s%d", arm_plan9Shift[mem.Shift], mem.Count)
+ }
+ index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
+ }
+ args[1] = off + base + index
+ }
+
+ // Reverse args, placing dest last.
+ for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+ args[i], args[j] = args[j], args[i]
+ }
+
+ switch inst.Op &^ 15 {
+ case arm_MOV_EQ:
+ op = "MOVW" + op[3:]
+
+ case arm_LDR_EQ:
+ op = "MOVW" + op[3:] + suffix
+ case arm_LDRB_EQ:
+ op = "MOVB" + op[4:] + suffix
+ case arm_LDRH_EQ:
+ op = "MOVH" + op[4:] + suffix
+
+ case arm_STR_EQ:
+ op = "MOVW" + op[3:] + suffix
+ args[0], args[1] = args[1], args[0]
+ case arm_STRB_EQ:
+ op = "MOVB" + op[4:] + suffix
+ args[0], args[1] = args[1], args[0]
+ case arm_STRH_EQ:
+ op = "MOVH" + op[4:] + suffix
+ args[0], args[1] = args[1], args[0]
+ }
+
+ if args != nil {
+ op += " " + strings.Join(args, ", ")
+ }
+
+ return op
+}
+
+// assembler syntax for the various shifts.
+// @x> is a lie; the assembler uses @> 0
+// instead of @x> 1, but i wanted to be clear that it
+// was a different operation (rotate right extended, not rotate right).
+var arm_plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"}
+
+func arm_plan9Arg(inst *arm_Inst, pc uint64, symname func(uint64) (string, uint64), arg arm_Arg) string {
+ switch a := arg.(type) {
+ case arm_Endian:
+
+ case arm_Imm:
+ return fmt.Sprintf("$%d", int(a))
+
+ case arm_Mem:
+
+ case arm_PCRel:
+ addr := uint32(pc) + 8 + uint32(a)
+ if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ return fmt.Sprintf("%#x", addr)
+
+ case arm_Reg:
+ if a < 16 {
+ return fmt.Sprintf("R%d", int(a))
+ }
+
+ case arm_RegList:
+ var buf bytes.Buffer
+ start := -2
+ end := -2
+ fmt.Fprintf(&buf, "[")
+ flush := func() {
+ if start >= 0 {
+ if buf.Len() > 1 {
+ fmt.Fprintf(&buf, ",")
+ }
+ if start == end {
+ fmt.Fprintf(&buf, "R%d", start)
+ } else {
+ fmt.Fprintf(&buf, "R%d-R%d", start, end)
+ }
+ }
+ }
+ for i := 0; i < 16; i++ {
+ if a&(1<<uint(i)) != 0 {
+ if i == end+1 {
+ end++
+ continue
+ }
+ start = i
+ end = i
+ }
+ }
+ flush()
+ fmt.Fprintf(&buf, "]")
+ return buf.String()
+
+ case arm_RegShift:
+ return fmt.Sprintf("R%d%s$%d", int(a.Reg), arm_plan9Shift[a.Shift], int(a.Count))
+
+ case arm_RegShiftReg:
+ return fmt.Sprintf("R%d%sR%d", int(a.Reg), arm_plan9Shift[a.Shift], int(a.RegCount))
+ }
+ return strings.ToUpper(arg.String())
+}
+
+/* tables.go */
+
+const (
+ _ arm_Op = iota
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_ADC_EQ
+ arm_ADC_NE
+ arm_ADC_CS
+ arm_ADC_CC
+ arm_ADC_MI
+ arm_ADC_PL
+ arm_ADC_VS
+ arm_ADC_VC
+ arm_ADC_HI
+ arm_ADC_LS
+ arm_ADC_GE
+ arm_ADC_LT
+ arm_ADC_GT
+ arm_ADC_LE
+ arm_ADC
+ arm_ADC_ZZ
+ arm_ADC_S_EQ
+ arm_ADC_S_NE
+ arm_ADC_S_CS
+ arm_ADC_S_CC
+ arm_ADC_S_MI
+ arm_ADC_S_PL
+ arm_ADC_S_VS
+ arm_ADC_S_VC
+ arm_ADC_S_HI
+ arm_ADC_S_LS
+ arm_ADC_S_GE
+ arm_ADC_S_LT
+ arm_ADC_S_GT
+ arm_ADC_S_LE
+ arm_ADC_S
+ arm_ADC_S_ZZ
+ arm_ADD_EQ
+ arm_ADD_NE
+ arm_ADD_CS
+ arm_ADD_CC
+ arm_ADD_MI
+ arm_ADD_PL
+ arm_ADD_VS
+ arm_ADD_VC
+ arm_ADD_HI
+ arm_ADD_LS
+ arm_ADD_GE
+ arm_ADD_LT
+ arm_ADD_GT
+ arm_ADD_LE
+ arm_ADD
+ arm_ADD_ZZ
+ arm_ADD_S_EQ
+ arm_ADD_S_NE
+ arm_ADD_S_CS
+ arm_ADD_S_CC
+ arm_ADD_S_MI
+ arm_ADD_S_PL
+ arm_ADD_S_VS
+ arm_ADD_S_VC
+ arm_ADD_S_HI
+ arm_ADD_S_LS
+ arm_ADD_S_GE
+ arm_ADD_S_LT
+ arm_ADD_S_GT
+ arm_ADD_S_LE
+ arm_ADD_S
+ arm_ADD_S_ZZ
+ arm_AND_EQ
+ arm_AND_NE
+ arm_AND_CS
+ arm_AND_CC
+ arm_AND_MI
+ arm_AND_PL
+ arm_AND_VS
+ arm_AND_VC
+ arm_AND_HI
+ arm_AND_LS
+ arm_AND_GE
+ arm_AND_LT
+ arm_AND_GT
+ arm_AND_LE
+ arm_AND
+ arm_AND_ZZ
+ arm_AND_S_EQ
+ arm_AND_S_NE
+ arm_AND_S_CS
+ arm_AND_S_CC
+ arm_AND_S_MI
+ arm_AND_S_PL
+ arm_AND_S_VS
+ arm_AND_S_VC
+ arm_AND_S_HI
+ arm_AND_S_LS
+ arm_AND_S_GE
+ arm_AND_S_LT
+ arm_AND_S_GT
+ arm_AND_S_LE
+ arm_AND_S
+ arm_AND_S_ZZ
+ arm_ASR_EQ
+ arm_ASR_NE
+ arm_ASR_CS
+ arm_ASR_CC
+ arm_ASR_MI
+ arm_ASR_PL
+ arm_ASR_VS
+ arm_ASR_VC
+ arm_ASR_HI
+ arm_ASR_LS
+ arm_ASR_GE
+ arm_ASR_LT
+ arm_ASR_GT
+ arm_ASR_LE
+ arm_ASR
+ arm_ASR_ZZ
+ arm_ASR_S_EQ
+ arm_ASR_S_NE
+ arm_ASR_S_CS
+ arm_ASR_S_CC
+ arm_ASR_S_MI
+ arm_ASR_S_PL
+ arm_ASR_S_VS
+ arm_ASR_S_VC
+ arm_ASR_S_HI
+ arm_ASR_S_LS
+ arm_ASR_S_GE
+ arm_ASR_S_LT
+ arm_ASR_S_GT
+ arm_ASR_S_LE
+ arm_ASR_S
+ arm_ASR_S_ZZ
+ arm_B_EQ
+ arm_B_NE
+ arm_B_CS
+ arm_B_CC
+ arm_B_MI
+ arm_B_PL
+ arm_B_VS
+ arm_B_VC
+ arm_B_HI
+ arm_B_LS
+ arm_B_GE
+ arm_B_LT
+ arm_B_GT
+ arm_B_LE
+ arm_B
+ arm_B_ZZ
+ arm_BFC_EQ
+ arm_BFC_NE
+ arm_BFC_CS
+ arm_BFC_CC
+ arm_BFC_MI
+ arm_BFC_PL
+ arm_BFC_VS
+ arm_BFC_VC
+ arm_BFC_HI
+ arm_BFC_LS
+ arm_BFC_GE
+ arm_BFC_LT
+ arm_BFC_GT
+ arm_BFC_LE
+ arm_BFC
+ arm_BFC_ZZ
+ arm_BFI_EQ
+ arm_BFI_NE
+ arm_BFI_CS
+ arm_BFI_CC
+ arm_BFI_MI
+ arm_BFI_PL
+ arm_BFI_VS
+ arm_BFI_VC
+ arm_BFI_HI
+ arm_BFI_LS
+ arm_BFI_GE
+ arm_BFI_LT
+ arm_BFI_GT
+ arm_BFI_LE
+ arm_BFI
+ arm_BFI_ZZ
+ arm_BIC_EQ
+ arm_BIC_NE
+ arm_BIC_CS
+ arm_BIC_CC
+ arm_BIC_MI
+ arm_BIC_PL
+ arm_BIC_VS
+ arm_BIC_VC
+ arm_BIC_HI
+ arm_BIC_LS
+ arm_BIC_GE
+ arm_BIC_LT
+ arm_BIC_GT
+ arm_BIC_LE
+ arm_BIC
+ arm_BIC_ZZ
+ arm_BIC_S_EQ
+ arm_BIC_S_NE
+ arm_BIC_S_CS
+ arm_BIC_S_CC
+ arm_BIC_S_MI
+ arm_BIC_S_PL
+ arm_BIC_S_VS
+ arm_BIC_S_VC
+ arm_BIC_S_HI
+ arm_BIC_S_LS
+ arm_BIC_S_GE
+ arm_BIC_S_LT
+ arm_BIC_S_GT
+ arm_BIC_S_LE
+ arm_BIC_S
+ arm_BIC_S_ZZ
+ arm_BKPT_EQ
+ arm_BKPT_NE
+ arm_BKPT_CS
+ arm_BKPT_CC
+ arm_BKPT_MI
+ arm_BKPT_PL
+ arm_BKPT_VS
+ arm_BKPT_VC
+ arm_BKPT_HI
+ arm_BKPT_LS
+ arm_BKPT_GE
+ arm_BKPT_LT
+ arm_BKPT_GT
+ arm_BKPT_LE
+ arm_BKPT
+ arm_BKPT_ZZ
+ arm_BL_EQ
+ arm_BL_NE
+ arm_BL_CS
+ arm_BL_CC
+ arm_BL_MI
+ arm_BL_PL
+ arm_BL_VS
+ arm_BL_VC
+ arm_BL_HI
+ arm_BL_LS
+ arm_BL_GE
+ arm_BL_LT
+ arm_BL_GT
+ arm_BL_LE
+ arm_BL
+ arm_BL_ZZ
+ arm_BLX_EQ
+ arm_BLX_NE
+ arm_BLX_CS
+ arm_BLX_CC
+ arm_BLX_MI
+ arm_BLX_PL
+ arm_BLX_VS
+ arm_BLX_VC
+ arm_BLX_HI
+ arm_BLX_LS
+ arm_BLX_GE
+ arm_BLX_LT
+ arm_BLX_GT
+ arm_BLX_LE
+ arm_BLX
+ arm_BLX_ZZ
+ arm_BX_EQ
+ arm_BX_NE
+ arm_BX_CS
+ arm_BX_CC
+ arm_BX_MI
+ arm_BX_PL
+ arm_BX_VS
+ arm_BX_VC
+ arm_BX_HI
+ arm_BX_LS
+ arm_BX_GE
+ arm_BX_LT
+ arm_BX_GT
+ arm_BX_LE
+ arm_BX
+ arm_BX_ZZ
+ arm_BXJ_EQ
+ arm_BXJ_NE
+ arm_BXJ_CS
+ arm_BXJ_CC
+ arm_BXJ_MI
+ arm_BXJ_PL
+ arm_BXJ_VS
+ arm_BXJ_VC
+ arm_BXJ_HI
+ arm_BXJ_LS
+ arm_BXJ_GE
+ arm_BXJ_LT
+ arm_BXJ_GT
+ arm_BXJ_LE
+ arm_BXJ
+ arm_BXJ_ZZ
+ arm_CLREX
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_CLZ_EQ
+ arm_CLZ_NE
+ arm_CLZ_CS
+ arm_CLZ_CC
+ arm_CLZ_MI
+ arm_CLZ_PL
+ arm_CLZ_VS
+ arm_CLZ_VC
+ arm_CLZ_HI
+ arm_CLZ_LS
+ arm_CLZ_GE
+ arm_CLZ_LT
+ arm_CLZ_GT
+ arm_CLZ_LE
+ arm_CLZ
+ arm_CLZ_ZZ
+ arm_CMN_EQ
+ arm_CMN_NE
+ arm_CMN_CS
+ arm_CMN_CC
+ arm_CMN_MI
+ arm_CMN_PL
+ arm_CMN_VS
+ arm_CMN_VC
+ arm_CMN_HI
+ arm_CMN_LS
+ arm_CMN_GE
+ arm_CMN_LT
+ arm_CMN_GT
+ arm_CMN_LE
+ arm_CMN
+ arm_CMN_ZZ
+ arm_CMP_EQ
+ arm_CMP_NE
+ arm_CMP_CS
+ arm_CMP_CC
+ arm_CMP_MI
+ arm_CMP_PL
+ arm_CMP_VS
+ arm_CMP_VC
+ arm_CMP_HI
+ arm_CMP_LS
+ arm_CMP_GE
+ arm_CMP_LT
+ arm_CMP_GT
+ arm_CMP_LE
+ arm_CMP
+ arm_CMP_ZZ
+ arm_DBG_EQ
+ arm_DBG_NE
+ arm_DBG_CS
+ arm_DBG_CC
+ arm_DBG_MI
+ arm_DBG_PL
+ arm_DBG_VS
+ arm_DBG_VC
+ arm_DBG_HI
+ arm_DBG_LS
+ arm_DBG_GE
+ arm_DBG_LT
+ arm_DBG_GT
+ arm_DBG_LE
+ arm_DBG
+ arm_DBG_ZZ
+ arm_DMB
+ arm_DSB
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_EOR_EQ
+ arm_EOR_NE
+ arm_EOR_CS
+ arm_EOR_CC
+ arm_EOR_MI
+ arm_EOR_PL
+ arm_EOR_VS
+ arm_EOR_VC
+ arm_EOR_HI
+ arm_EOR_LS
+ arm_EOR_GE
+ arm_EOR_LT
+ arm_EOR_GT
+ arm_EOR_LE
+ arm_EOR
+ arm_EOR_ZZ
+ arm_EOR_S_EQ
+ arm_EOR_S_NE
+ arm_EOR_S_CS
+ arm_EOR_S_CC
+ arm_EOR_S_MI
+ arm_EOR_S_PL
+ arm_EOR_S_VS
+ arm_EOR_S_VC
+ arm_EOR_S_HI
+ arm_EOR_S_LS
+ arm_EOR_S_GE
+ arm_EOR_S_LT
+ arm_EOR_S_GT
+ arm_EOR_S_LE
+ arm_EOR_S
+ arm_EOR_S_ZZ
+ arm_ISB
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_LDM_EQ
+ arm_LDM_NE
+ arm_LDM_CS
+ arm_LDM_CC
+ arm_LDM_MI
+ arm_LDM_PL
+ arm_LDM_VS
+ arm_LDM_VC
+ arm_LDM_HI
+ arm_LDM_LS
+ arm_LDM_GE
+ arm_LDM_LT
+ arm_LDM_GT
+ arm_LDM_LE
+ arm_LDM
+ arm_LDM_ZZ
+ arm_LDMDA_EQ
+ arm_LDMDA_NE
+ arm_LDMDA_CS
+ arm_LDMDA_CC
+ arm_LDMDA_MI
+ arm_LDMDA_PL
+ arm_LDMDA_VS
+ arm_LDMDA_VC
+ arm_LDMDA_HI
+ arm_LDMDA_LS
+ arm_LDMDA_GE
+ arm_LDMDA_LT
+ arm_LDMDA_GT
+ arm_LDMDA_LE
+ arm_LDMDA
+ arm_LDMDA_ZZ
+ arm_LDMDB_EQ
+ arm_LDMDB_NE
+ arm_LDMDB_CS
+ arm_LDMDB_CC
+ arm_LDMDB_MI
+ arm_LDMDB_PL
+ arm_LDMDB_VS
+ arm_LDMDB_VC
+ arm_LDMDB_HI
+ arm_LDMDB_LS
+ arm_LDMDB_GE
+ arm_LDMDB_LT
+ arm_LDMDB_GT
+ arm_LDMDB_LE
+ arm_LDMDB
+ arm_LDMDB_ZZ
+ arm_LDMIB_EQ
+ arm_LDMIB_NE
+ arm_LDMIB_CS
+ arm_LDMIB_CC
+ arm_LDMIB_MI
+ arm_LDMIB_PL
+ arm_LDMIB_VS
+ arm_LDMIB_VC
+ arm_LDMIB_HI
+ arm_LDMIB_LS
+ arm_LDMIB_GE
+ arm_LDMIB_LT
+ arm_LDMIB_GT
+ arm_LDMIB_LE
+ arm_LDMIB
+ arm_LDMIB_ZZ
+ arm_LDR_EQ
+ arm_LDR_NE
+ arm_LDR_CS
+ arm_LDR_CC
+ arm_LDR_MI
+ arm_LDR_PL
+ arm_LDR_VS
+ arm_LDR_VC
+ arm_LDR_HI
+ arm_LDR_LS
+ arm_LDR_GE
+ arm_LDR_LT
+ arm_LDR_GT
+ arm_LDR_LE
+ arm_LDR
+ arm_LDR_ZZ
+ arm_LDRB_EQ
+ arm_LDRB_NE
+ arm_LDRB_CS
+ arm_LDRB_CC
+ arm_LDRB_MI
+ arm_LDRB_PL
+ arm_LDRB_VS
+ arm_LDRB_VC
+ arm_LDRB_HI
+ arm_LDRB_LS
+ arm_LDRB_GE
+ arm_LDRB_LT
+ arm_LDRB_GT
+ arm_LDRB_LE
+ arm_LDRB
+ arm_LDRB_ZZ
+ arm_LDRBT_EQ
+ arm_LDRBT_NE
+ arm_LDRBT_CS
+ arm_LDRBT_CC
+ arm_LDRBT_MI
+ arm_LDRBT_PL
+ arm_LDRBT_VS
+ arm_LDRBT_VC
+ arm_LDRBT_HI
+ arm_LDRBT_LS
+ arm_LDRBT_GE
+ arm_LDRBT_LT
+ arm_LDRBT_GT
+ arm_LDRBT_LE
+ arm_LDRBT
+ arm_LDRBT_ZZ
+ arm_LDRD_EQ
+ arm_LDRD_NE
+ arm_LDRD_CS
+ arm_LDRD_CC
+ arm_LDRD_MI
+ arm_LDRD_PL
+ arm_LDRD_VS
+ arm_LDRD_VC
+ arm_LDRD_HI
+ arm_LDRD_LS
+ arm_LDRD_GE
+ arm_LDRD_LT
+ arm_LDRD_GT
+ arm_LDRD_LE
+ arm_LDRD
+ arm_LDRD_ZZ
+ arm_LDREX_EQ
+ arm_LDREX_NE
+ arm_LDREX_CS
+ arm_LDREX_CC
+ arm_LDREX_MI
+ arm_LDREX_PL
+ arm_LDREX_VS
+ arm_LDREX_VC
+ arm_LDREX_HI
+ arm_LDREX_LS
+ arm_LDREX_GE
+ arm_LDREX_LT
+ arm_LDREX_GT
+ arm_LDREX_LE
+ arm_LDREX
+ arm_LDREX_ZZ
+ arm_LDREXB_EQ
+ arm_LDREXB_NE
+ arm_LDREXB_CS
+ arm_LDREXB_CC
+ arm_LDREXB_MI
+ arm_LDREXB_PL
+ arm_LDREXB_VS
+ arm_LDREXB_VC
+ arm_LDREXB_HI
+ arm_LDREXB_LS
+ arm_LDREXB_GE
+ arm_LDREXB_LT
+ arm_LDREXB_GT
+ arm_LDREXB_LE
+ arm_LDREXB
+ arm_LDREXB_ZZ
+ arm_LDREXD_EQ
+ arm_LDREXD_NE
+ arm_LDREXD_CS
+ arm_LDREXD_CC
+ arm_LDREXD_MI
+ arm_LDREXD_PL
+ arm_LDREXD_VS
+ arm_LDREXD_VC
+ arm_LDREXD_HI
+ arm_LDREXD_LS
+ arm_LDREXD_GE
+ arm_LDREXD_LT
+ arm_LDREXD_GT
+ arm_LDREXD_LE
+ arm_LDREXD
+ arm_LDREXD_ZZ
+ arm_LDREXH_EQ
+ arm_LDREXH_NE
+ arm_LDREXH_CS
+ arm_LDREXH_CC
+ arm_LDREXH_MI
+ arm_LDREXH_PL
+ arm_LDREXH_VS
+ arm_LDREXH_VC
+ arm_LDREXH_HI
+ arm_LDREXH_LS
+ arm_LDREXH_GE
+ arm_LDREXH_LT
+ arm_LDREXH_GT
+ arm_LDREXH_LE
+ arm_LDREXH
+ arm_LDREXH_ZZ
+ arm_LDRH_EQ
+ arm_LDRH_NE
+ arm_LDRH_CS
+ arm_LDRH_CC
+ arm_LDRH_MI
+ arm_LDRH_PL
+ arm_LDRH_VS
+ arm_LDRH_VC
+ arm_LDRH_HI
+ arm_LDRH_LS
+ arm_LDRH_GE
+ arm_LDRH_LT
+ arm_LDRH_GT
+ arm_LDRH_LE
+ arm_LDRH
+ arm_LDRH_ZZ
+ arm_LDRHT_EQ
+ arm_LDRHT_NE
+ arm_LDRHT_CS
+ arm_LDRHT_CC
+ arm_LDRHT_MI
+ arm_LDRHT_PL
+ arm_LDRHT_VS
+ arm_LDRHT_VC
+ arm_LDRHT_HI
+ arm_LDRHT_LS
+ arm_LDRHT_GE
+ arm_LDRHT_LT
+ arm_LDRHT_GT
+ arm_LDRHT_LE
+ arm_LDRHT
+ arm_LDRHT_ZZ
+ arm_LDRSB_EQ
+ arm_LDRSB_NE
+ arm_LDRSB_CS
+ arm_LDRSB_CC
+ arm_LDRSB_MI
+ arm_LDRSB_PL
+ arm_LDRSB_VS
+ arm_LDRSB_VC
+ arm_LDRSB_HI
+ arm_LDRSB_LS
+ arm_LDRSB_GE
+ arm_LDRSB_LT
+ arm_LDRSB_GT
+ arm_LDRSB_LE
+ arm_LDRSB
+ arm_LDRSB_ZZ
+ arm_LDRSBT_EQ
+ arm_LDRSBT_NE
+ arm_LDRSBT_CS
+ arm_LDRSBT_CC
+ arm_LDRSBT_MI
+ arm_LDRSBT_PL
+ arm_LDRSBT_VS
+ arm_LDRSBT_VC
+ arm_LDRSBT_HI
+ arm_LDRSBT_LS
+ arm_LDRSBT_GE
+ arm_LDRSBT_LT
+ arm_LDRSBT_GT
+ arm_LDRSBT_LE
+ arm_LDRSBT
+ arm_LDRSBT_ZZ
+ arm_LDRSH_EQ
+ arm_LDRSH_NE
+ arm_LDRSH_CS
+ arm_LDRSH_CC
+ arm_LDRSH_MI
+ arm_LDRSH_PL
+ arm_LDRSH_VS
+ arm_LDRSH_VC
+ arm_LDRSH_HI
+ arm_LDRSH_LS
+ arm_LDRSH_GE
+ arm_LDRSH_LT
+ arm_LDRSH_GT
+ arm_LDRSH_LE
+ arm_LDRSH
+ arm_LDRSH_ZZ
+ arm_LDRSHT_EQ
+ arm_LDRSHT_NE
+ arm_LDRSHT_CS
+ arm_LDRSHT_CC
+ arm_LDRSHT_MI
+ arm_LDRSHT_PL
+ arm_LDRSHT_VS
+ arm_LDRSHT_VC
+ arm_LDRSHT_HI
+ arm_LDRSHT_LS
+ arm_LDRSHT_GE
+ arm_LDRSHT_LT
+ arm_LDRSHT_GT
+ arm_LDRSHT_LE
+ arm_LDRSHT
+ arm_LDRSHT_ZZ
+ arm_LDRT_EQ
+ arm_LDRT_NE
+ arm_LDRT_CS
+ arm_LDRT_CC
+ arm_LDRT_MI
+ arm_LDRT_PL
+ arm_LDRT_VS
+ arm_LDRT_VC
+ arm_LDRT_HI
+ arm_LDRT_LS
+ arm_LDRT_GE
+ arm_LDRT_LT
+ arm_LDRT_GT
+ arm_LDRT_LE
+ arm_LDRT
+ arm_LDRT_ZZ
+ arm_LSL_EQ
+ arm_LSL_NE
+ arm_LSL_CS
+ arm_LSL_CC
+ arm_LSL_MI
+ arm_LSL_PL
+ arm_LSL_VS
+ arm_LSL_VC
+ arm_LSL_HI
+ arm_LSL_LS
+ arm_LSL_GE
+ arm_LSL_LT
+ arm_LSL_GT
+ arm_LSL_LE
+ arm_LSL
+ arm_LSL_ZZ
+ arm_LSL_S_EQ
+ arm_LSL_S_NE
+ arm_LSL_S_CS
+ arm_LSL_S_CC
+ arm_LSL_S_MI
+ arm_LSL_S_PL
+ arm_LSL_S_VS
+ arm_LSL_S_VC
+ arm_LSL_S_HI
+ arm_LSL_S_LS
+ arm_LSL_S_GE
+ arm_LSL_S_LT
+ arm_LSL_S_GT
+ arm_LSL_S_LE
+ arm_LSL_S
+ arm_LSL_S_ZZ
+ arm_LSR_EQ
+ arm_LSR_NE
+ arm_LSR_CS
+ arm_LSR_CC
+ arm_LSR_MI
+ arm_LSR_PL
+ arm_LSR_VS
+ arm_LSR_VC
+ arm_LSR_HI
+ arm_LSR_LS
+ arm_LSR_GE
+ arm_LSR_LT
+ arm_LSR_GT
+ arm_LSR_LE
+ arm_LSR
+ arm_LSR_ZZ
+ arm_LSR_S_EQ
+ arm_LSR_S_NE
+ arm_LSR_S_CS
+ arm_LSR_S_CC
+ arm_LSR_S_MI
+ arm_LSR_S_PL
+ arm_LSR_S_VS
+ arm_LSR_S_VC
+ arm_LSR_S_HI
+ arm_LSR_S_LS
+ arm_LSR_S_GE
+ arm_LSR_S_LT
+ arm_LSR_S_GT
+ arm_LSR_S_LE
+ arm_LSR_S
+ arm_LSR_S_ZZ
+ arm_MLA_EQ
+ arm_MLA_NE
+ arm_MLA_CS
+ arm_MLA_CC
+ arm_MLA_MI
+ arm_MLA_PL
+ arm_MLA_VS
+ arm_MLA_VC
+ arm_MLA_HI
+ arm_MLA_LS
+ arm_MLA_GE
+ arm_MLA_LT
+ arm_MLA_GT
+ arm_MLA_LE
+ arm_MLA
+ arm_MLA_ZZ
+ arm_MLA_S_EQ
+ arm_MLA_S_NE
+ arm_MLA_S_CS
+ arm_MLA_S_CC
+ arm_MLA_S_MI
+ arm_MLA_S_PL
+ arm_MLA_S_VS
+ arm_MLA_S_VC
+ arm_MLA_S_HI
+ arm_MLA_S_LS
+ arm_MLA_S_GE
+ arm_MLA_S_LT
+ arm_MLA_S_GT
+ arm_MLA_S_LE
+ arm_MLA_S
+ arm_MLA_S_ZZ
+ arm_MLS_EQ
+ arm_MLS_NE
+ arm_MLS_CS
+ arm_MLS_CC
+ arm_MLS_MI
+ arm_MLS_PL
+ arm_MLS_VS
+ arm_MLS_VC
+ arm_MLS_HI
+ arm_MLS_LS
+ arm_MLS_GE
+ arm_MLS_LT
+ arm_MLS_GT
+ arm_MLS_LE
+ arm_MLS
+ arm_MLS_ZZ
+ arm_MOV_EQ
+ arm_MOV_NE
+ arm_MOV_CS
+ arm_MOV_CC
+ arm_MOV_MI
+ arm_MOV_PL
+ arm_MOV_VS
+ arm_MOV_VC
+ arm_MOV_HI
+ arm_MOV_LS
+ arm_MOV_GE
+ arm_MOV_LT
+ arm_MOV_GT
+ arm_MOV_LE
+ arm_MOV
+ arm_MOV_ZZ
+ arm_MOV_S_EQ
+ arm_MOV_S_NE
+ arm_MOV_S_CS
+ arm_MOV_S_CC
+ arm_MOV_S_MI
+ arm_MOV_S_PL
+ arm_MOV_S_VS
+ arm_MOV_S_VC
+ arm_MOV_S_HI
+ arm_MOV_S_LS
+ arm_MOV_S_GE
+ arm_MOV_S_LT
+ arm_MOV_S_GT
+ arm_MOV_S_LE
+ arm_MOV_S
+ arm_MOV_S_ZZ
+ arm_MOVT_EQ
+ arm_MOVT_NE
+ arm_MOVT_CS
+ arm_MOVT_CC
+ arm_MOVT_MI
+ arm_MOVT_PL
+ arm_MOVT_VS
+ arm_MOVT_VC
+ arm_MOVT_HI
+ arm_MOVT_LS
+ arm_MOVT_GE
+ arm_MOVT_LT
+ arm_MOVT_GT
+ arm_MOVT_LE
+ arm_MOVT
+ arm_MOVT_ZZ
+ arm_MOVW_EQ
+ arm_MOVW_NE
+ arm_MOVW_CS
+ arm_MOVW_CC
+ arm_MOVW_MI
+ arm_MOVW_PL
+ arm_MOVW_VS
+ arm_MOVW_VC
+ arm_MOVW_HI
+ arm_MOVW_LS
+ arm_MOVW_GE
+ arm_MOVW_LT
+ arm_MOVW_GT
+ arm_MOVW_LE
+ arm_MOVW
+ arm_MOVW_ZZ
+ arm_MRS_EQ
+ arm_MRS_NE
+ arm_MRS_CS
+ arm_MRS_CC
+ arm_MRS_MI
+ arm_MRS_PL
+ arm_MRS_VS
+ arm_MRS_VC
+ arm_MRS_HI
+ arm_MRS_LS
+ arm_MRS_GE
+ arm_MRS_LT
+ arm_MRS_GT
+ arm_MRS_LE
+ arm_MRS
+ arm_MRS_ZZ
+ arm_MUL_EQ
+ arm_MUL_NE
+ arm_MUL_CS
+ arm_MUL_CC
+ arm_MUL_MI
+ arm_MUL_PL
+ arm_MUL_VS
+ arm_MUL_VC
+ arm_MUL_HI
+ arm_MUL_LS
+ arm_MUL_GE
+ arm_MUL_LT
+ arm_MUL_GT
+ arm_MUL_LE
+ arm_MUL
+ arm_MUL_ZZ
+ arm_MUL_S_EQ
+ arm_MUL_S_NE
+ arm_MUL_S_CS
+ arm_MUL_S_CC
+ arm_MUL_S_MI
+ arm_MUL_S_PL
+ arm_MUL_S_VS
+ arm_MUL_S_VC
+ arm_MUL_S_HI
+ arm_MUL_S_LS
+ arm_MUL_S_GE
+ arm_MUL_S_LT
+ arm_MUL_S_GT
+ arm_MUL_S_LE
+ arm_MUL_S
+ arm_MUL_S_ZZ
+ arm_MVN_EQ
+ arm_MVN_NE
+ arm_MVN_CS
+ arm_MVN_CC
+ arm_MVN_MI
+ arm_MVN_PL
+ arm_MVN_VS
+ arm_MVN_VC
+ arm_MVN_HI
+ arm_MVN_LS
+ arm_MVN_GE
+ arm_MVN_LT
+ arm_MVN_GT
+ arm_MVN_LE
+ arm_MVN
+ arm_MVN_ZZ
+ arm_MVN_S_EQ
+ arm_MVN_S_NE
+ arm_MVN_S_CS
+ arm_MVN_S_CC
+ arm_MVN_S_MI
+ arm_MVN_S_PL
+ arm_MVN_S_VS
+ arm_MVN_S_VC
+ arm_MVN_S_HI
+ arm_MVN_S_LS
+ arm_MVN_S_GE
+ arm_MVN_S_LT
+ arm_MVN_S_GT
+ arm_MVN_S_LE
+ arm_MVN_S
+ arm_MVN_S_ZZ
+ arm_NOP_EQ
+ arm_NOP_NE
+ arm_NOP_CS
+ arm_NOP_CC
+ arm_NOP_MI
+ arm_NOP_PL
+ arm_NOP_VS
+ arm_NOP_VC
+ arm_NOP_HI
+ arm_NOP_LS
+ arm_NOP_GE
+ arm_NOP_LT
+ arm_NOP_GT
+ arm_NOP_LE
+ arm_NOP
+ arm_NOP_ZZ
+ arm_ORR_EQ
+ arm_ORR_NE
+ arm_ORR_CS
+ arm_ORR_CC
+ arm_ORR_MI
+ arm_ORR_PL
+ arm_ORR_VS
+ arm_ORR_VC
+ arm_ORR_HI
+ arm_ORR_LS
+ arm_ORR_GE
+ arm_ORR_LT
+ arm_ORR_GT
+ arm_ORR_LE
+ arm_ORR
+ arm_ORR_ZZ
+ arm_ORR_S_EQ
+ arm_ORR_S_NE
+ arm_ORR_S_CS
+ arm_ORR_S_CC
+ arm_ORR_S_MI
+ arm_ORR_S_PL
+ arm_ORR_S_VS
+ arm_ORR_S_VC
+ arm_ORR_S_HI
+ arm_ORR_S_LS
+ arm_ORR_S_GE
+ arm_ORR_S_LT
+ arm_ORR_S_GT
+ arm_ORR_S_LE
+ arm_ORR_S
+ arm_ORR_S_ZZ
+ arm_PKHBT_EQ
+ arm_PKHBT_NE
+ arm_PKHBT_CS
+ arm_PKHBT_CC
+ arm_PKHBT_MI
+ arm_PKHBT_PL
+ arm_PKHBT_VS
+ arm_PKHBT_VC
+ arm_PKHBT_HI
+ arm_PKHBT_LS
+ arm_PKHBT_GE
+ arm_PKHBT_LT
+ arm_PKHBT_GT
+ arm_PKHBT_LE
+ arm_PKHBT
+ arm_PKHBT_ZZ
+ arm_PKHTB_EQ
+ arm_PKHTB_NE
+ arm_PKHTB_CS
+ arm_PKHTB_CC
+ arm_PKHTB_MI
+ arm_PKHTB_PL
+ arm_PKHTB_VS
+ arm_PKHTB_VC
+ arm_PKHTB_HI
+ arm_PKHTB_LS
+ arm_PKHTB_GE
+ arm_PKHTB_LT
+ arm_PKHTB_GT
+ arm_PKHTB_LE
+ arm_PKHTB
+ arm_PKHTB_ZZ
+ arm_PLD_W
+ arm_PLD
+ arm_PLI
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_POP_EQ
+ arm_POP_NE
+ arm_POP_CS
+ arm_POP_CC
+ arm_POP_MI
+ arm_POP_PL
+ arm_POP_VS
+ arm_POP_VC
+ arm_POP_HI
+ arm_POP_LS
+ arm_POP_GE
+ arm_POP_LT
+ arm_POP_GT
+ arm_POP_LE
+ arm_POP
+ arm_POP_ZZ
+ arm_PUSH_EQ
+ arm_PUSH_NE
+ arm_PUSH_CS
+ arm_PUSH_CC
+ arm_PUSH_MI
+ arm_PUSH_PL
+ arm_PUSH_VS
+ arm_PUSH_VC
+ arm_PUSH_HI
+ arm_PUSH_LS
+ arm_PUSH_GE
+ arm_PUSH_LT
+ arm_PUSH_GT
+ arm_PUSH_LE
+ arm_PUSH
+ arm_PUSH_ZZ
+ arm_QADD_EQ
+ arm_QADD_NE
+ arm_QADD_CS
+ arm_QADD_CC
+ arm_QADD_MI
+ arm_QADD_PL
+ arm_QADD_VS
+ arm_QADD_VC
+ arm_QADD_HI
+ arm_QADD_LS
+ arm_QADD_GE
+ arm_QADD_LT
+ arm_QADD_GT
+ arm_QADD_LE
+ arm_QADD
+ arm_QADD_ZZ
+ arm_QADD16_EQ
+ arm_QADD16_NE
+ arm_QADD16_CS
+ arm_QADD16_CC
+ arm_QADD16_MI
+ arm_QADD16_PL
+ arm_QADD16_VS
+ arm_QADD16_VC
+ arm_QADD16_HI
+ arm_QADD16_LS
+ arm_QADD16_GE
+ arm_QADD16_LT
+ arm_QADD16_GT
+ arm_QADD16_LE
+ arm_QADD16
+ arm_QADD16_ZZ
+ arm_QADD8_EQ
+ arm_QADD8_NE
+ arm_QADD8_CS
+ arm_QADD8_CC
+ arm_QADD8_MI
+ arm_QADD8_PL
+ arm_QADD8_VS
+ arm_QADD8_VC
+ arm_QADD8_HI
+ arm_QADD8_LS
+ arm_QADD8_GE
+ arm_QADD8_LT
+ arm_QADD8_GT
+ arm_QADD8_LE
+ arm_QADD8
+ arm_QADD8_ZZ
+ arm_QASX_EQ
+ arm_QASX_NE
+ arm_QASX_CS
+ arm_QASX_CC
+ arm_QASX_MI
+ arm_QASX_PL
+ arm_QASX_VS
+ arm_QASX_VC
+ arm_QASX_HI
+ arm_QASX_LS
+ arm_QASX_GE
+ arm_QASX_LT
+ arm_QASX_GT
+ arm_QASX_LE
+ arm_QASX
+ arm_QASX_ZZ
+ arm_QDADD_EQ
+ arm_QDADD_NE
+ arm_QDADD_CS
+ arm_QDADD_CC
+ arm_QDADD_MI
+ arm_QDADD_PL
+ arm_QDADD_VS
+ arm_QDADD_VC
+ arm_QDADD_HI
+ arm_QDADD_LS
+ arm_QDADD_GE
+ arm_QDADD_LT
+ arm_QDADD_GT
+ arm_QDADD_LE
+ arm_QDADD
+ arm_QDADD_ZZ
+ arm_QDSUB_EQ
+ arm_QDSUB_NE
+ arm_QDSUB_CS
+ arm_QDSUB_CC
+ arm_QDSUB_MI
+ arm_QDSUB_PL
+ arm_QDSUB_VS
+ arm_QDSUB_VC
+ arm_QDSUB_HI
+ arm_QDSUB_LS
+ arm_QDSUB_GE
+ arm_QDSUB_LT
+ arm_QDSUB_GT
+ arm_QDSUB_LE
+ arm_QDSUB
+ arm_QDSUB_ZZ
+ arm_QSAX_EQ
+ arm_QSAX_NE
+ arm_QSAX_CS
+ arm_QSAX_CC
+ arm_QSAX_MI
+ arm_QSAX_PL
+ arm_QSAX_VS
+ arm_QSAX_VC
+ arm_QSAX_HI
+ arm_QSAX_LS
+ arm_QSAX_GE
+ arm_QSAX_LT
+ arm_QSAX_GT
+ arm_QSAX_LE
+ arm_QSAX
+ arm_QSAX_ZZ
+ arm_QSUB_EQ
+ arm_QSUB_NE
+ arm_QSUB_CS
+ arm_QSUB_CC
+ arm_QSUB_MI
+ arm_QSUB_PL
+ arm_QSUB_VS
+ arm_QSUB_VC
+ arm_QSUB_HI
+ arm_QSUB_LS
+ arm_QSUB_GE
+ arm_QSUB_LT
+ arm_QSUB_GT
+ arm_QSUB_LE
+ arm_QSUB
+ arm_QSUB_ZZ
+ arm_QSUB16_EQ
+ arm_QSUB16_NE
+ arm_QSUB16_CS
+ arm_QSUB16_CC
+ arm_QSUB16_MI
+ arm_QSUB16_PL
+ arm_QSUB16_VS
+ arm_QSUB16_VC
+ arm_QSUB16_HI
+ arm_QSUB16_LS
+ arm_QSUB16_GE
+ arm_QSUB16_LT
+ arm_QSUB16_GT
+ arm_QSUB16_LE
+ arm_QSUB16
+ arm_QSUB16_ZZ
+ arm_QSUB8_EQ
+ arm_QSUB8_NE
+ arm_QSUB8_CS
+ arm_QSUB8_CC
+ arm_QSUB8_MI
+ arm_QSUB8_PL
+ arm_QSUB8_VS
+ arm_QSUB8_VC
+ arm_QSUB8_HI
+ arm_QSUB8_LS
+ arm_QSUB8_GE
+ arm_QSUB8_LT
+ arm_QSUB8_GT
+ arm_QSUB8_LE
+ arm_QSUB8
+ arm_QSUB8_ZZ
+ arm_RBIT_EQ
+ arm_RBIT_NE
+ arm_RBIT_CS
+ arm_RBIT_CC
+ arm_RBIT_MI
+ arm_RBIT_PL
+ arm_RBIT_VS
+ arm_RBIT_VC
+ arm_RBIT_HI
+ arm_RBIT_LS
+ arm_RBIT_GE
+ arm_RBIT_LT
+ arm_RBIT_GT
+ arm_RBIT_LE
+ arm_RBIT
+ arm_RBIT_ZZ
+ arm_REV_EQ
+ arm_REV_NE
+ arm_REV_CS
+ arm_REV_CC
+ arm_REV_MI
+ arm_REV_PL
+ arm_REV_VS
+ arm_REV_VC
+ arm_REV_HI
+ arm_REV_LS
+ arm_REV_GE
+ arm_REV_LT
+ arm_REV_GT
+ arm_REV_LE
+ arm_REV
+ arm_REV_ZZ
+ arm_REV16_EQ
+ arm_REV16_NE
+ arm_REV16_CS
+ arm_REV16_CC
+ arm_REV16_MI
+ arm_REV16_PL
+ arm_REV16_VS
+ arm_REV16_VC
+ arm_REV16_HI
+ arm_REV16_LS
+ arm_REV16_GE
+ arm_REV16_LT
+ arm_REV16_GT
+ arm_REV16_LE
+ arm_REV16
+ arm_REV16_ZZ
+ arm_REVSH_EQ
+ arm_REVSH_NE
+ arm_REVSH_CS
+ arm_REVSH_CC
+ arm_REVSH_MI
+ arm_REVSH_PL
+ arm_REVSH_VS
+ arm_REVSH_VC
+ arm_REVSH_HI
+ arm_REVSH_LS
+ arm_REVSH_GE
+ arm_REVSH_LT
+ arm_REVSH_GT
+ arm_REVSH_LE
+ arm_REVSH
+ arm_REVSH_ZZ
+ arm_ROR_EQ
+ arm_ROR_NE
+ arm_ROR_CS
+ arm_ROR_CC
+ arm_ROR_MI
+ arm_ROR_PL
+ arm_ROR_VS
+ arm_ROR_VC
+ arm_ROR_HI
+ arm_ROR_LS
+ arm_ROR_GE
+ arm_ROR_LT
+ arm_ROR_GT
+ arm_ROR_LE
+ arm_ROR
+ arm_ROR_ZZ
+ arm_ROR_S_EQ
+ arm_ROR_S_NE
+ arm_ROR_S_CS
+ arm_ROR_S_CC
+ arm_ROR_S_MI
+ arm_ROR_S_PL
+ arm_ROR_S_VS
+ arm_ROR_S_VC
+ arm_ROR_S_HI
+ arm_ROR_S_LS
+ arm_ROR_S_GE
+ arm_ROR_S_LT
+ arm_ROR_S_GT
+ arm_ROR_S_LE
+ arm_ROR_S
+ arm_ROR_S_ZZ
+ arm_RRX_EQ
+ arm_RRX_NE
+ arm_RRX_CS
+ arm_RRX_CC
+ arm_RRX_MI
+ arm_RRX_PL
+ arm_RRX_VS
+ arm_RRX_VC
+ arm_RRX_HI
+ arm_RRX_LS
+ arm_RRX_GE
+ arm_RRX_LT
+ arm_RRX_GT
+ arm_RRX_LE
+ arm_RRX
+ arm_RRX_ZZ
+ arm_RRX_S_EQ
+ arm_RRX_S_NE
+ arm_RRX_S_CS
+ arm_RRX_S_CC
+ arm_RRX_S_MI
+ arm_RRX_S_PL
+ arm_RRX_S_VS
+ arm_RRX_S_VC
+ arm_RRX_S_HI
+ arm_RRX_S_LS
+ arm_RRX_S_GE
+ arm_RRX_S_LT
+ arm_RRX_S_GT
+ arm_RRX_S_LE
+ arm_RRX_S
+ arm_RRX_S_ZZ
+ arm_RSB_EQ
+ arm_RSB_NE
+ arm_RSB_CS
+ arm_RSB_CC
+ arm_RSB_MI
+ arm_RSB_PL
+ arm_RSB_VS
+ arm_RSB_VC
+ arm_RSB_HI
+ arm_RSB_LS
+ arm_RSB_GE
+ arm_RSB_LT
+ arm_RSB_GT
+ arm_RSB_LE
+ arm_RSB
+ arm_RSB_ZZ
+ arm_RSB_S_EQ
+ arm_RSB_S_NE
+ arm_RSB_S_CS
+ arm_RSB_S_CC
+ arm_RSB_S_MI
+ arm_RSB_S_PL
+ arm_RSB_S_VS
+ arm_RSB_S_VC
+ arm_RSB_S_HI
+ arm_RSB_S_LS
+ arm_RSB_S_GE
+ arm_RSB_S_LT
+ arm_RSB_S_GT
+ arm_RSB_S_LE
+ arm_RSB_S
+ arm_RSB_S_ZZ
+ arm_RSC_EQ
+ arm_RSC_NE
+ arm_RSC_CS
+ arm_RSC_CC
+ arm_RSC_MI
+ arm_RSC_PL
+ arm_RSC_VS
+ arm_RSC_VC
+ arm_RSC_HI
+ arm_RSC_LS
+ arm_RSC_GE
+ arm_RSC_LT
+ arm_RSC_GT
+ arm_RSC_LE
+ arm_RSC
+ arm_RSC_ZZ
+ arm_RSC_S_EQ
+ arm_RSC_S_NE
+ arm_RSC_S_CS
+ arm_RSC_S_CC
+ arm_RSC_S_MI
+ arm_RSC_S_PL
+ arm_RSC_S_VS
+ arm_RSC_S_VC
+ arm_RSC_S_HI
+ arm_RSC_S_LS
+ arm_RSC_S_GE
+ arm_RSC_S_LT
+ arm_RSC_S_GT
+ arm_RSC_S_LE
+ arm_RSC_S
+ arm_RSC_S_ZZ
+ arm_SADD16_EQ
+ arm_SADD16_NE
+ arm_SADD16_CS
+ arm_SADD16_CC
+ arm_SADD16_MI
+ arm_SADD16_PL
+ arm_SADD16_VS
+ arm_SADD16_VC
+ arm_SADD16_HI
+ arm_SADD16_LS
+ arm_SADD16_GE
+ arm_SADD16_LT
+ arm_SADD16_GT
+ arm_SADD16_LE
+ arm_SADD16
+ arm_SADD16_ZZ
+ arm_SADD8_EQ
+ arm_SADD8_NE
+ arm_SADD8_CS
+ arm_SADD8_CC
+ arm_SADD8_MI
+ arm_SADD8_PL
+ arm_SADD8_VS
+ arm_SADD8_VC
+ arm_SADD8_HI
+ arm_SADD8_LS
+ arm_SADD8_GE
+ arm_SADD8_LT
+ arm_SADD8_GT
+ arm_SADD8_LE
+ arm_SADD8
+ arm_SADD8_ZZ
+ arm_SASX_EQ
+ arm_SASX_NE
+ arm_SASX_CS
+ arm_SASX_CC
+ arm_SASX_MI
+ arm_SASX_PL
+ arm_SASX_VS
+ arm_SASX_VC
+ arm_SASX_HI
+ arm_SASX_LS
+ arm_SASX_GE
+ arm_SASX_LT
+ arm_SASX_GT
+ arm_SASX_LE
+ arm_SASX
+ arm_SASX_ZZ
+ arm_SBC_EQ
+ arm_SBC_NE
+ arm_SBC_CS
+ arm_SBC_CC
+ arm_SBC_MI
+ arm_SBC_PL
+ arm_SBC_VS
+ arm_SBC_VC
+ arm_SBC_HI
+ arm_SBC_LS
+ arm_SBC_GE
+ arm_SBC_LT
+ arm_SBC_GT
+ arm_SBC_LE
+ arm_SBC
+ arm_SBC_ZZ
+ arm_SBC_S_EQ
+ arm_SBC_S_NE
+ arm_SBC_S_CS
+ arm_SBC_S_CC
+ arm_SBC_S_MI
+ arm_SBC_S_PL
+ arm_SBC_S_VS
+ arm_SBC_S_VC
+ arm_SBC_S_HI
+ arm_SBC_S_LS
+ arm_SBC_S_GE
+ arm_SBC_S_LT
+ arm_SBC_S_GT
+ arm_SBC_S_LE
+ arm_SBC_S
+ arm_SBC_S_ZZ
+ arm_SBFX_EQ
+ arm_SBFX_NE
+ arm_SBFX_CS
+ arm_SBFX_CC
+ arm_SBFX_MI
+ arm_SBFX_PL
+ arm_SBFX_VS
+ arm_SBFX_VC
+ arm_SBFX_HI
+ arm_SBFX_LS
+ arm_SBFX_GE
+ arm_SBFX_LT
+ arm_SBFX_GT
+ arm_SBFX_LE
+ arm_SBFX
+ arm_SBFX_ZZ
+ arm_SEL_EQ
+ arm_SEL_NE
+ arm_SEL_CS
+ arm_SEL_CC
+ arm_SEL_MI
+ arm_SEL_PL
+ arm_SEL_VS
+ arm_SEL_VC
+ arm_SEL_HI
+ arm_SEL_LS
+ arm_SEL_GE
+ arm_SEL_LT
+ arm_SEL_GT
+ arm_SEL_LE
+ arm_SEL
+ arm_SEL_ZZ
+ arm_SETEND
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_SEV_EQ
+ arm_SEV_NE
+ arm_SEV_CS
+ arm_SEV_CC
+ arm_SEV_MI
+ arm_SEV_PL
+ arm_SEV_VS
+ arm_SEV_VC
+ arm_SEV_HI
+ arm_SEV_LS
+ arm_SEV_GE
+ arm_SEV_LT
+ arm_SEV_GT
+ arm_SEV_LE
+ arm_SEV
+ arm_SEV_ZZ
+ arm_SHADD16_EQ
+ arm_SHADD16_NE
+ arm_SHADD16_CS
+ arm_SHADD16_CC
+ arm_SHADD16_MI
+ arm_SHADD16_PL
+ arm_SHADD16_VS
+ arm_SHADD16_VC
+ arm_SHADD16_HI
+ arm_SHADD16_LS
+ arm_SHADD16_GE
+ arm_SHADD16_LT
+ arm_SHADD16_GT
+ arm_SHADD16_LE
+ arm_SHADD16
+ arm_SHADD16_ZZ
+ arm_SHADD8_EQ
+ arm_SHADD8_NE
+ arm_SHADD8_CS
+ arm_SHADD8_CC
+ arm_SHADD8_MI
+ arm_SHADD8_PL
+ arm_SHADD8_VS
+ arm_SHADD8_VC
+ arm_SHADD8_HI
+ arm_SHADD8_LS
+ arm_SHADD8_GE
+ arm_SHADD8_LT
+ arm_SHADD8_GT
+ arm_SHADD8_LE
+ arm_SHADD8
+ arm_SHADD8_ZZ
+ arm_SHASX_EQ
+ arm_SHASX_NE
+ arm_SHASX_CS
+ arm_SHASX_CC
+ arm_SHASX_MI
+ arm_SHASX_PL
+ arm_SHASX_VS
+ arm_SHASX_VC
+ arm_SHASX_HI
+ arm_SHASX_LS
+ arm_SHASX_GE
+ arm_SHASX_LT
+ arm_SHASX_GT
+ arm_SHASX_LE
+ arm_SHASX
+ arm_SHASX_ZZ
+ arm_SHSAX_EQ
+ arm_SHSAX_NE
+ arm_SHSAX_CS
+ arm_SHSAX_CC
+ arm_SHSAX_MI
+ arm_SHSAX_PL
+ arm_SHSAX_VS
+ arm_SHSAX_VC
+ arm_SHSAX_HI
+ arm_SHSAX_LS
+ arm_SHSAX_GE
+ arm_SHSAX_LT
+ arm_SHSAX_GT
+ arm_SHSAX_LE
+ arm_SHSAX
+ arm_SHSAX_ZZ
+ arm_SHSUB16_EQ
+ arm_SHSUB16_NE
+ arm_SHSUB16_CS
+ arm_SHSUB16_CC
+ arm_SHSUB16_MI
+ arm_SHSUB16_PL
+ arm_SHSUB16_VS
+ arm_SHSUB16_VC
+ arm_SHSUB16_HI
+ arm_SHSUB16_LS
+ arm_SHSUB16_GE
+ arm_SHSUB16_LT
+ arm_SHSUB16_GT
+ arm_SHSUB16_LE
+ arm_SHSUB16
+ arm_SHSUB16_ZZ
+ arm_SHSUB8_EQ
+ arm_SHSUB8_NE
+ arm_SHSUB8_CS
+ arm_SHSUB8_CC
+ arm_SHSUB8_MI
+ arm_SHSUB8_PL
+ arm_SHSUB8_VS
+ arm_SHSUB8_VC
+ arm_SHSUB8_HI
+ arm_SHSUB8_LS
+ arm_SHSUB8_GE
+ arm_SHSUB8_LT
+ arm_SHSUB8_GT
+ arm_SHSUB8_LE
+ arm_SHSUB8
+ arm_SHSUB8_ZZ
+ arm_SMLABB_EQ
+ arm_SMLABB_NE
+ arm_SMLABB_CS
+ arm_SMLABB_CC
+ arm_SMLABB_MI
+ arm_SMLABB_PL
+ arm_SMLABB_VS
+ arm_SMLABB_VC
+ arm_SMLABB_HI
+ arm_SMLABB_LS
+ arm_SMLABB_GE
+ arm_SMLABB_LT
+ arm_SMLABB_GT
+ arm_SMLABB_LE
+ arm_SMLABB
+ arm_SMLABB_ZZ
+ arm_SMLABT_EQ
+ arm_SMLABT_NE
+ arm_SMLABT_CS
+ arm_SMLABT_CC
+ arm_SMLABT_MI
+ arm_SMLABT_PL
+ arm_SMLABT_VS
+ arm_SMLABT_VC
+ arm_SMLABT_HI
+ arm_SMLABT_LS
+ arm_SMLABT_GE
+ arm_SMLABT_LT
+ arm_SMLABT_GT
+ arm_SMLABT_LE
+ arm_SMLABT
+ arm_SMLABT_ZZ
+ arm_SMLATB_EQ
+ arm_SMLATB_NE
+ arm_SMLATB_CS
+ arm_SMLATB_CC
+ arm_SMLATB_MI
+ arm_SMLATB_PL
+ arm_SMLATB_VS
+ arm_SMLATB_VC
+ arm_SMLATB_HI
+ arm_SMLATB_LS
+ arm_SMLATB_GE
+ arm_SMLATB_LT
+ arm_SMLATB_GT
+ arm_SMLATB_LE
+ arm_SMLATB
+ arm_SMLATB_ZZ
+ arm_SMLATT_EQ
+ arm_SMLATT_NE
+ arm_SMLATT_CS
+ arm_SMLATT_CC
+ arm_SMLATT_MI
+ arm_SMLATT_PL
+ arm_SMLATT_VS
+ arm_SMLATT_VC
+ arm_SMLATT_HI
+ arm_SMLATT_LS
+ arm_SMLATT_GE
+ arm_SMLATT_LT
+ arm_SMLATT_GT
+ arm_SMLATT_LE
+ arm_SMLATT
+ arm_SMLATT_ZZ
+ arm_SMLAD_EQ
+ arm_SMLAD_NE
+ arm_SMLAD_CS
+ arm_SMLAD_CC
+ arm_SMLAD_MI
+ arm_SMLAD_PL
+ arm_SMLAD_VS
+ arm_SMLAD_VC
+ arm_SMLAD_HI
+ arm_SMLAD_LS
+ arm_SMLAD_GE
+ arm_SMLAD_LT
+ arm_SMLAD_GT
+ arm_SMLAD_LE
+ arm_SMLAD
+ arm_SMLAD_ZZ
+ arm_SMLAD_X_EQ
+ arm_SMLAD_X_NE
+ arm_SMLAD_X_CS
+ arm_SMLAD_X_CC
+ arm_SMLAD_X_MI
+ arm_SMLAD_X_PL
+ arm_SMLAD_X_VS
+ arm_SMLAD_X_VC
+ arm_SMLAD_X_HI
+ arm_SMLAD_X_LS
+ arm_SMLAD_X_GE
+ arm_SMLAD_X_LT
+ arm_SMLAD_X_GT
+ arm_SMLAD_X_LE
+ arm_SMLAD_X
+ arm_SMLAD_X_ZZ
+ arm_SMLAL_EQ
+ arm_SMLAL_NE
+ arm_SMLAL_CS
+ arm_SMLAL_CC
+ arm_SMLAL_MI
+ arm_SMLAL_PL
+ arm_SMLAL_VS
+ arm_SMLAL_VC
+ arm_SMLAL_HI
+ arm_SMLAL_LS
+ arm_SMLAL_GE
+ arm_SMLAL_LT
+ arm_SMLAL_GT
+ arm_SMLAL_LE
+ arm_SMLAL
+ arm_SMLAL_ZZ
+ arm_SMLAL_S_EQ
+ arm_SMLAL_S_NE
+ arm_SMLAL_S_CS
+ arm_SMLAL_S_CC
+ arm_SMLAL_S_MI
+ arm_SMLAL_S_PL
+ arm_SMLAL_S_VS
+ arm_SMLAL_S_VC
+ arm_SMLAL_S_HI
+ arm_SMLAL_S_LS
+ arm_SMLAL_S_GE
+ arm_SMLAL_S_LT
+ arm_SMLAL_S_GT
+ arm_SMLAL_S_LE
+ arm_SMLAL_S
+ arm_SMLAL_S_ZZ
+ arm_SMLALBB_EQ
+ arm_SMLALBB_NE
+ arm_SMLALBB_CS
+ arm_SMLALBB_CC
+ arm_SMLALBB_MI
+ arm_SMLALBB_PL
+ arm_SMLALBB_VS
+ arm_SMLALBB_VC
+ arm_SMLALBB_HI
+ arm_SMLALBB_LS
+ arm_SMLALBB_GE
+ arm_SMLALBB_LT
+ arm_SMLALBB_GT
+ arm_SMLALBB_LE
+ arm_SMLALBB
+ arm_SMLALBB_ZZ
+ arm_SMLALBT_EQ
+ arm_SMLALBT_NE
+ arm_SMLALBT_CS
+ arm_SMLALBT_CC
+ arm_SMLALBT_MI
+ arm_SMLALBT_PL
+ arm_SMLALBT_VS
+ arm_SMLALBT_VC
+ arm_SMLALBT_HI
+ arm_SMLALBT_LS
+ arm_SMLALBT_GE
+ arm_SMLALBT_LT
+ arm_SMLALBT_GT
+ arm_SMLALBT_LE
+ arm_SMLALBT
+ arm_SMLALBT_ZZ
+ arm_SMLALTB_EQ
+ arm_SMLALTB_NE
+ arm_SMLALTB_CS
+ arm_SMLALTB_CC
+ arm_SMLALTB_MI
+ arm_SMLALTB_PL
+ arm_SMLALTB_VS
+ arm_SMLALTB_VC
+ arm_SMLALTB_HI
+ arm_SMLALTB_LS
+ arm_SMLALTB_GE
+ arm_SMLALTB_LT
+ arm_SMLALTB_GT
+ arm_SMLALTB_LE
+ arm_SMLALTB
+ arm_SMLALTB_ZZ
+ arm_SMLALTT_EQ
+ arm_SMLALTT_NE
+ arm_SMLALTT_CS
+ arm_SMLALTT_CC
+ arm_SMLALTT_MI
+ arm_SMLALTT_PL
+ arm_SMLALTT_VS
+ arm_SMLALTT_VC
+ arm_SMLALTT_HI
+ arm_SMLALTT_LS
+ arm_SMLALTT_GE
+ arm_SMLALTT_LT
+ arm_SMLALTT_GT
+ arm_SMLALTT_LE
+ arm_SMLALTT
+ arm_SMLALTT_ZZ
+ arm_SMLALD_EQ
+ arm_SMLALD_NE
+ arm_SMLALD_CS
+ arm_SMLALD_CC
+ arm_SMLALD_MI
+ arm_SMLALD_PL
+ arm_SMLALD_VS
+ arm_SMLALD_VC
+ arm_SMLALD_HI
+ arm_SMLALD_LS
+ arm_SMLALD_GE
+ arm_SMLALD_LT
+ arm_SMLALD_GT
+ arm_SMLALD_LE
+ arm_SMLALD
+ arm_SMLALD_ZZ
+ arm_SMLALD_X_EQ
+ arm_SMLALD_X_NE
+ arm_SMLALD_X_CS
+ arm_SMLALD_X_CC
+ arm_SMLALD_X_MI
+ arm_SMLALD_X_PL
+ arm_SMLALD_X_VS
+ arm_SMLALD_X_VC
+ arm_SMLALD_X_HI
+ arm_SMLALD_X_LS
+ arm_SMLALD_X_GE
+ arm_SMLALD_X_LT
+ arm_SMLALD_X_GT
+ arm_SMLALD_X_LE
+ arm_SMLALD_X
+ arm_SMLALD_X_ZZ
+ arm_SMLAWB_EQ
+ arm_SMLAWB_NE
+ arm_SMLAWB_CS
+ arm_SMLAWB_CC
+ arm_SMLAWB_MI
+ arm_SMLAWB_PL
+ arm_SMLAWB_VS
+ arm_SMLAWB_VC
+ arm_SMLAWB_HI
+ arm_SMLAWB_LS
+ arm_SMLAWB_GE
+ arm_SMLAWB_LT
+ arm_SMLAWB_GT
+ arm_SMLAWB_LE
+ arm_SMLAWB
+ arm_SMLAWB_ZZ
+ arm_SMLAWT_EQ
+ arm_SMLAWT_NE
+ arm_SMLAWT_CS
+ arm_SMLAWT_CC
+ arm_SMLAWT_MI
+ arm_SMLAWT_PL
+ arm_SMLAWT_VS
+ arm_SMLAWT_VC
+ arm_SMLAWT_HI
+ arm_SMLAWT_LS
+ arm_SMLAWT_GE
+ arm_SMLAWT_LT
+ arm_SMLAWT_GT
+ arm_SMLAWT_LE
+ arm_SMLAWT
+ arm_SMLAWT_ZZ
+ arm_SMLSD_EQ
+ arm_SMLSD_NE
+ arm_SMLSD_CS
+ arm_SMLSD_CC
+ arm_SMLSD_MI
+ arm_SMLSD_PL
+ arm_SMLSD_VS
+ arm_SMLSD_VC
+ arm_SMLSD_HI
+ arm_SMLSD_LS
+ arm_SMLSD_GE
+ arm_SMLSD_LT
+ arm_SMLSD_GT
+ arm_SMLSD_LE
+ arm_SMLSD
+ arm_SMLSD_ZZ
+ arm_SMLSD_X_EQ
+ arm_SMLSD_X_NE
+ arm_SMLSD_X_CS
+ arm_SMLSD_X_CC
+ arm_SMLSD_X_MI
+ arm_SMLSD_X_PL
+ arm_SMLSD_X_VS
+ arm_SMLSD_X_VC
+ arm_SMLSD_X_HI
+ arm_SMLSD_X_LS
+ arm_SMLSD_X_GE
+ arm_SMLSD_X_LT
+ arm_SMLSD_X_GT
+ arm_SMLSD_X_LE
+ arm_SMLSD_X
+ arm_SMLSD_X_ZZ
+ arm_SMLSLD_EQ
+ arm_SMLSLD_NE
+ arm_SMLSLD_CS
+ arm_SMLSLD_CC
+ arm_SMLSLD_MI
+ arm_SMLSLD_PL
+ arm_SMLSLD_VS
+ arm_SMLSLD_VC
+ arm_SMLSLD_HI
+ arm_SMLSLD_LS
+ arm_SMLSLD_GE
+ arm_SMLSLD_LT
+ arm_SMLSLD_GT
+ arm_SMLSLD_LE
+ arm_SMLSLD
+ arm_SMLSLD_ZZ
+ arm_SMLSLD_X_EQ
+ arm_SMLSLD_X_NE
+ arm_SMLSLD_X_CS
+ arm_SMLSLD_X_CC
+ arm_SMLSLD_X_MI
+ arm_SMLSLD_X_PL
+ arm_SMLSLD_X_VS
+ arm_SMLSLD_X_VC
+ arm_SMLSLD_X_HI
+ arm_SMLSLD_X_LS
+ arm_SMLSLD_X_GE
+ arm_SMLSLD_X_LT
+ arm_SMLSLD_X_GT
+ arm_SMLSLD_X_LE
+ arm_SMLSLD_X
+ arm_SMLSLD_X_ZZ
+ arm_SMMLA_EQ
+ arm_SMMLA_NE
+ arm_SMMLA_CS
+ arm_SMMLA_CC
+ arm_SMMLA_MI
+ arm_SMMLA_PL
+ arm_SMMLA_VS
+ arm_SMMLA_VC
+ arm_SMMLA_HI
+ arm_SMMLA_LS
+ arm_SMMLA_GE
+ arm_SMMLA_LT
+ arm_SMMLA_GT
+ arm_SMMLA_LE
+ arm_SMMLA
+ arm_SMMLA_ZZ
+ arm_SMMLA_R_EQ
+ arm_SMMLA_R_NE
+ arm_SMMLA_R_CS
+ arm_SMMLA_R_CC
+ arm_SMMLA_R_MI
+ arm_SMMLA_R_PL
+ arm_SMMLA_R_VS
+ arm_SMMLA_R_VC
+ arm_SMMLA_R_HI
+ arm_SMMLA_R_LS
+ arm_SMMLA_R_GE
+ arm_SMMLA_R_LT
+ arm_SMMLA_R_GT
+ arm_SMMLA_R_LE
+ arm_SMMLA_R
+ arm_SMMLA_R_ZZ
+ arm_SMMLS_EQ
+ arm_SMMLS_NE
+ arm_SMMLS_CS
+ arm_SMMLS_CC
+ arm_SMMLS_MI
+ arm_SMMLS_PL
+ arm_SMMLS_VS
+ arm_SMMLS_VC
+ arm_SMMLS_HI
+ arm_SMMLS_LS
+ arm_SMMLS_GE
+ arm_SMMLS_LT
+ arm_SMMLS_GT
+ arm_SMMLS_LE
+ arm_SMMLS
+ arm_SMMLS_ZZ
+ arm_SMMLS_R_EQ
+ arm_SMMLS_R_NE
+ arm_SMMLS_R_CS
+ arm_SMMLS_R_CC
+ arm_SMMLS_R_MI
+ arm_SMMLS_R_PL
+ arm_SMMLS_R_VS
+ arm_SMMLS_R_VC
+ arm_SMMLS_R_HI
+ arm_SMMLS_R_LS
+ arm_SMMLS_R_GE
+ arm_SMMLS_R_LT
+ arm_SMMLS_R_GT
+ arm_SMMLS_R_LE
+ arm_SMMLS_R
+ arm_SMMLS_R_ZZ
+ arm_SMMUL_EQ
+ arm_SMMUL_NE
+ arm_SMMUL_CS
+ arm_SMMUL_CC
+ arm_SMMUL_MI
+ arm_SMMUL_PL
+ arm_SMMUL_VS
+ arm_SMMUL_VC
+ arm_SMMUL_HI
+ arm_SMMUL_LS
+ arm_SMMUL_GE
+ arm_SMMUL_LT
+ arm_SMMUL_GT
+ arm_SMMUL_LE
+ arm_SMMUL
+ arm_SMMUL_ZZ
+ arm_SMMUL_R_EQ
+ arm_SMMUL_R_NE
+ arm_SMMUL_R_CS
+ arm_SMMUL_R_CC
+ arm_SMMUL_R_MI
+ arm_SMMUL_R_PL
+ arm_SMMUL_R_VS
+ arm_SMMUL_R_VC
+ arm_SMMUL_R_HI
+ arm_SMMUL_R_LS
+ arm_SMMUL_R_GE
+ arm_SMMUL_R_LT
+ arm_SMMUL_R_GT
+ arm_SMMUL_R_LE
+ arm_SMMUL_R
+ arm_SMMUL_R_ZZ
+ arm_SMUAD_EQ
+ arm_SMUAD_NE
+ arm_SMUAD_CS
+ arm_SMUAD_CC
+ arm_SMUAD_MI
+ arm_SMUAD_PL
+ arm_SMUAD_VS
+ arm_SMUAD_VC
+ arm_SMUAD_HI
+ arm_SMUAD_LS
+ arm_SMUAD_GE
+ arm_SMUAD_LT
+ arm_SMUAD_GT
+ arm_SMUAD_LE
+ arm_SMUAD
+ arm_SMUAD_ZZ
+ arm_SMUAD_X_EQ
+ arm_SMUAD_X_NE
+ arm_SMUAD_X_CS
+ arm_SMUAD_X_CC
+ arm_SMUAD_X_MI
+ arm_SMUAD_X_PL
+ arm_SMUAD_X_VS
+ arm_SMUAD_X_VC
+ arm_SMUAD_X_HI
+ arm_SMUAD_X_LS
+ arm_SMUAD_X_GE
+ arm_SMUAD_X_LT
+ arm_SMUAD_X_GT
+ arm_SMUAD_X_LE
+ arm_SMUAD_X
+ arm_SMUAD_X_ZZ
+ arm_SMULBB_EQ
+ arm_SMULBB_NE
+ arm_SMULBB_CS
+ arm_SMULBB_CC
+ arm_SMULBB_MI
+ arm_SMULBB_PL
+ arm_SMULBB_VS
+ arm_SMULBB_VC
+ arm_SMULBB_HI
+ arm_SMULBB_LS
+ arm_SMULBB_GE
+ arm_SMULBB_LT
+ arm_SMULBB_GT
+ arm_SMULBB_LE
+ arm_SMULBB
+ arm_SMULBB_ZZ
+ arm_SMULBT_EQ
+ arm_SMULBT_NE
+ arm_SMULBT_CS
+ arm_SMULBT_CC
+ arm_SMULBT_MI
+ arm_SMULBT_PL
+ arm_SMULBT_VS
+ arm_SMULBT_VC
+ arm_SMULBT_HI
+ arm_SMULBT_LS
+ arm_SMULBT_GE
+ arm_SMULBT_LT
+ arm_SMULBT_GT
+ arm_SMULBT_LE
+ arm_SMULBT
+ arm_SMULBT_ZZ
+ arm_SMULTB_EQ
+ arm_SMULTB_NE
+ arm_SMULTB_CS
+ arm_SMULTB_CC
+ arm_SMULTB_MI
+ arm_SMULTB_PL
+ arm_SMULTB_VS
+ arm_SMULTB_VC
+ arm_SMULTB_HI
+ arm_SMULTB_LS
+ arm_SMULTB_GE
+ arm_SMULTB_LT
+ arm_SMULTB_GT
+ arm_SMULTB_LE
+ arm_SMULTB
+ arm_SMULTB_ZZ
+ arm_SMULTT_EQ
+ arm_SMULTT_NE
+ arm_SMULTT_CS
+ arm_SMULTT_CC
+ arm_SMULTT_MI
+ arm_SMULTT_PL
+ arm_SMULTT_VS
+ arm_SMULTT_VC
+ arm_SMULTT_HI
+ arm_SMULTT_LS
+ arm_SMULTT_GE
+ arm_SMULTT_LT
+ arm_SMULTT_GT
+ arm_SMULTT_LE
+ arm_SMULTT
+ arm_SMULTT_ZZ
+ arm_SMULL_EQ
+ arm_SMULL_NE
+ arm_SMULL_CS
+ arm_SMULL_CC
+ arm_SMULL_MI
+ arm_SMULL_PL
+ arm_SMULL_VS
+ arm_SMULL_VC
+ arm_SMULL_HI
+ arm_SMULL_LS
+ arm_SMULL_GE
+ arm_SMULL_LT
+ arm_SMULL_GT
+ arm_SMULL_LE
+ arm_SMULL
+ arm_SMULL_ZZ
+ arm_SMULL_S_EQ
+ arm_SMULL_S_NE
+ arm_SMULL_S_CS
+ arm_SMULL_S_CC
+ arm_SMULL_S_MI
+ arm_SMULL_S_PL
+ arm_SMULL_S_VS
+ arm_SMULL_S_VC
+ arm_SMULL_S_HI
+ arm_SMULL_S_LS
+ arm_SMULL_S_GE
+ arm_SMULL_S_LT
+ arm_SMULL_S_GT
+ arm_SMULL_S_LE
+ arm_SMULL_S
+ arm_SMULL_S_ZZ
+ arm_SMULWB_EQ
+ arm_SMULWB_NE
+ arm_SMULWB_CS
+ arm_SMULWB_CC
+ arm_SMULWB_MI
+ arm_SMULWB_PL
+ arm_SMULWB_VS
+ arm_SMULWB_VC
+ arm_SMULWB_HI
+ arm_SMULWB_LS
+ arm_SMULWB_GE
+ arm_SMULWB_LT
+ arm_SMULWB_GT
+ arm_SMULWB_LE
+ arm_SMULWB
+ arm_SMULWB_ZZ
+ arm_SMULWT_EQ
+ arm_SMULWT_NE
+ arm_SMULWT_CS
+ arm_SMULWT_CC
+ arm_SMULWT_MI
+ arm_SMULWT_PL
+ arm_SMULWT_VS
+ arm_SMULWT_VC
+ arm_SMULWT_HI
+ arm_SMULWT_LS
+ arm_SMULWT_GE
+ arm_SMULWT_LT
+ arm_SMULWT_GT
+ arm_SMULWT_LE
+ arm_SMULWT
+ arm_SMULWT_ZZ
+ arm_SMUSD_EQ
+ arm_SMUSD_NE
+ arm_SMUSD_CS
+ arm_SMUSD_CC
+ arm_SMUSD_MI
+ arm_SMUSD_PL
+ arm_SMUSD_VS
+ arm_SMUSD_VC
+ arm_SMUSD_HI
+ arm_SMUSD_LS
+ arm_SMUSD_GE
+ arm_SMUSD_LT
+ arm_SMUSD_GT
+ arm_SMUSD_LE
+ arm_SMUSD
+ arm_SMUSD_ZZ
+ arm_SMUSD_X_EQ
+ arm_SMUSD_X_NE
+ arm_SMUSD_X_CS
+ arm_SMUSD_X_CC
+ arm_SMUSD_X_MI
+ arm_SMUSD_X_PL
+ arm_SMUSD_X_VS
+ arm_SMUSD_X_VC
+ arm_SMUSD_X_HI
+ arm_SMUSD_X_LS
+ arm_SMUSD_X_GE
+ arm_SMUSD_X_LT
+ arm_SMUSD_X_GT
+ arm_SMUSD_X_LE
+ arm_SMUSD_X
+ arm_SMUSD_X_ZZ
+ arm_SSAT_EQ
+ arm_SSAT_NE
+ arm_SSAT_CS
+ arm_SSAT_CC
+ arm_SSAT_MI
+ arm_SSAT_PL
+ arm_SSAT_VS
+ arm_SSAT_VC
+ arm_SSAT_HI
+ arm_SSAT_LS
+ arm_SSAT_GE
+ arm_SSAT_LT
+ arm_SSAT_GT
+ arm_SSAT_LE
+ arm_SSAT
+ arm_SSAT_ZZ
+ arm_SSAT16_EQ
+ arm_SSAT16_NE
+ arm_SSAT16_CS
+ arm_SSAT16_CC
+ arm_SSAT16_MI
+ arm_SSAT16_PL
+ arm_SSAT16_VS
+ arm_SSAT16_VC
+ arm_SSAT16_HI
+ arm_SSAT16_LS
+ arm_SSAT16_GE
+ arm_SSAT16_LT
+ arm_SSAT16_GT
+ arm_SSAT16_LE
+ arm_SSAT16
+ arm_SSAT16_ZZ
+ arm_SSAX_EQ
+ arm_SSAX_NE
+ arm_SSAX_CS
+ arm_SSAX_CC
+ arm_SSAX_MI
+ arm_SSAX_PL
+ arm_SSAX_VS
+ arm_SSAX_VC
+ arm_SSAX_HI
+ arm_SSAX_LS
+ arm_SSAX_GE
+ arm_SSAX_LT
+ arm_SSAX_GT
+ arm_SSAX_LE
+ arm_SSAX
+ arm_SSAX_ZZ
+ arm_SSUB16_EQ
+ arm_SSUB16_NE
+ arm_SSUB16_CS
+ arm_SSUB16_CC
+ arm_SSUB16_MI
+ arm_SSUB16_PL
+ arm_SSUB16_VS
+ arm_SSUB16_VC
+ arm_SSUB16_HI
+ arm_SSUB16_LS
+ arm_SSUB16_GE
+ arm_SSUB16_LT
+ arm_SSUB16_GT
+ arm_SSUB16_LE
+ arm_SSUB16
+ arm_SSUB16_ZZ
+ arm_SSUB8_EQ
+ arm_SSUB8_NE
+ arm_SSUB8_CS
+ arm_SSUB8_CC
+ arm_SSUB8_MI
+ arm_SSUB8_PL
+ arm_SSUB8_VS
+ arm_SSUB8_VC
+ arm_SSUB8_HI
+ arm_SSUB8_LS
+ arm_SSUB8_GE
+ arm_SSUB8_LT
+ arm_SSUB8_GT
+ arm_SSUB8_LE
+ arm_SSUB8
+ arm_SSUB8_ZZ
+ arm_STM_EQ
+ arm_STM_NE
+ arm_STM_CS
+ arm_STM_CC
+ arm_STM_MI
+ arm_STM_PL
+ arm_STM_VS
+ arm_STM_VC
+ arm_STM_HI
+ arm_STM_LS
+ arm_STM_GE
+ arm_STM_LT
+ arm_STM_GT
+ arm_STM_LE
+ arm_STM
+ arm_STM_ZZ
+ arm_STMDA_EQ
+ arm_STMDA_NE
+ arm_STMDA_CS
+ arm_STMDA_CC
+ arm_STMDA_MI
+ arm_STMDA_PL
+ arm_STMDA_VS
+ arm_STMDA_VC
+ arm_STMDA_HI
+ arm_STMDA_LS
+ arm_STMDA_GE
+ arm_STMDA_LT
+ arm_STMDA_GT
+ arm_STMDA_LE
+ arm_STMDA
+ arm_STMDA_ZZ
+ arm_STMDB_EQ
+ arm_STMDB_NE
+ arm_STMDB_CS
+ arm_STMDB_CC
+ arm_STMDB_MI
+ arm_STMDB_PL
+ arm_STMDB_VS
+ arm_STMDB_VC
+ arm_STMDB_HI
+ arm_STMDB_LS
+ arm_STMDB_GE
+ arm_STMDB_LT
+ arm_STMDB_GT
+ arm_STMDB_LE
+ arm_STMDB
+ arm_STMDB_ZZ
+ arm_STMIB_EQ
+ arm_STMIB_NE
+ arm_STMIB_CS
+ arm_STMIB_CC
+ arm_STMIB_MI
+ arm_STMIB_PL
+ arm_STMIB_VS
+ arm_STMIB_VC
+ arm_STMIB_HI
+ arm_STMIB_LS
+ arm_STMIB_GE
+ arm_STMIB_LT
+ arm_STMIB_GT
+ arm_STMIB_LE
+ arm_STMIB
+ arm_STMIB_ZZ
+ arm_STR_EQ
+ arm_STR_NE
+ arm_STR_CS
+ arm_STR_CC
+ arm_STR_MI
+ arm_STR_PL
+ arm_STR_VS
+ arm_STR_VC
+ arm_STR_HI
+ arm_STR_LS
+ arm_STR_GE
+ arm_STR_LT
+ arm_STR_GT
+ arm_STR_LE
+ arm_STR
+ arm_STR_ZZ
+ arm_STRB_EQ
+ arm_STRB_NE
+ arm_STRB_CS
+ arm_STRB_CC
+ arm_STRB_MI
+ arm_STRB_PL
+ arm_STRB_VS
+ arm_STRB_VC
+ arm_STRB_HI
+ arm_STRB_LS
+ arm_STRB_GE
+ arm_STRB_LT
+ arm_STRB_GT
+ arm_STRB_LE
+ arm_STRB
+ arm_STRB_ZZ
+ arm_STRBT_EQ
+ arm_STRBT_NE
+ arm_STRBT_CS
+ arm_STRBT_CC
+ arm_STRBT_MI
+ arm_STRBT_PL
+ arm_STRBT_VS
+ arm_STRBT_VC
+ arm_STRBT_HI
+ arm_STRBT_LS
+ arm_STRBT_GE
+ arm_STRBT_LT
+ arm_STRBT_GT
+ arm_STRBT_LE
+ arm_STRBT
+ arm_STRBT_ZZ
+ arm_STRD_EQ
+ arm_STRD_NE
+ arm_STRD_CS
+ arm_STRD_CC
+ arm_STRD_MI
+ arm_STRD_PL
+ arm_STRD_VS
+ arm_STRD_VC
+ arm_STRD_HI
+ arm_STRD_LS
+ arm_STRD_GE
+ arm_STRD_LT
+ arm_STRD_GT
+ arm_STRD_LE
+ arm_STRD
+ arm_STRD_ZZ
+ arm_STREX_EQ
+ arm_STREX_NE
+ arm_STREX_CS
+ arm_STREX_CC
+ arm_STREX_MI
+ arm_STREX_PL
+ arm_STREX_VS
+ arm_STREX_VC
+ arm_STREX_HI
+ arm_STREX_LS
+ arm_STREX_GE
+ arm_STREX_LT
+ arm_STREX_GT
+ arm_STREX_LE
+ arm_STREX
+ arm_STREX_ZZ
+ arm_STREXB_EQ
+ arm_STREXB_NE
+ arm_STREXB_CS
+ arm_STREXB_CC
+ arm_STREXB_MI
+ arm_STREXB_PL
+ arm_STREXB_VS
+ arm_STREXB_VC
+ arm_STREXB_HI
+ arm_STREXB_LS
+ arm_STREXB_GE
+ arm_STREXB_LT
+ arm_STREXB_GT
+ arm_STREXB_LE
+ arm_STREXB
+ arm_STREXB_ZZ
+ arm_STREXD_EQ
+ arm_STREXD_NE
+ arm_STREXD_CS
+ arm_STREXD_CC
+ arm_STREXD_MI
+ arm_STREXD_PL
+ arm_STREXD_VS
+ arm_STREXD_VC
+ arm_STREXD_HI
+ arm_STREXD_LS
+ arm_STREXD_GE
+ arm_STREXD_LT
+ arm_STREXD_GT
+ arm_STREXD_LE
+ arm_STREXD
+ arm_STREXD_ZZ
+ arm_STREXH_EQ
+ arm_STREXH_NE
+ arm_STREXH_CS
+ arm_STREXH_CC
+ arm_STREXH_MI
+ arm_STREXH_PL
+ arm_STREXH_VS
+ arm_STREXH_VC
+ arm_STREXH_HI
+ arm_STREXH_LS
+ arm_STREXH_GE
+ arm_STREXH_LT
+ arm_STREXH_GT
+ arm_STREXH_LE
+ arm_STREXH
+ arm_STREXH_ZZ
+ arm_STRH_EQ
+ arm_STRH_NE
+ arm_STRH_CS
+ arm_STRH_CC
+ arm_STRH_MI
+ arm_STRH_PL
+ arm_STRH_VS
+ arm_STRH_VC
+ arm_STRH_HI
+ arm_STRH_LS
+ arm_STRH_GE
+ arm_STRH_LT
+ arm_STRH_GT
+ arm_STRH_LE
+ arm_STRH
+ arm_STRH_ZZ
+ arm_STRHT_EQ
+ arm_STRHT_NE
+ arm_STRHT_CS
+ arm_STRHT_CC
+ arm_STRHT_MI
+ arm_STRHT_PL
+ arm_STRHT_VS
+ arm_STRHT_VC
+ arm_STRHT_HI
+ arm_STRHT_LS
+ arm_STRHT_GE
+ arm_STRHT_LT
+ arm_STRHT_GT
+ arm_STRHT_LE
+ arm_STRHT
+ arm_STRHT_ZZ
+ arm_STRT_EQ
+ arm_STRT_NE
+ arm_STRT_CS
+ arm_STRT_CC
+ arm_STRT_MI
+ arm_STRT_PL
+ arm_STRT_VS
+ arm_STRT_VC
+ arm_STRT_HI
+ arm_STRT_LS
+ arm_STRT_GE
+ arm_STRT_LT
+ arm_STRT_GT
+ arm_STRT_LE
+ arm_STRT
+ arm_STRT_ZZ
+ arm_SUB_EQ
+ arm_SUB_NE
+ arm_SUB_CS
+ arm_SUB_CC
+ arm_SUB_MI
+ arm_SUB_PL
+ arm_SUB_VS
+ arm_SUB_VC
+ arm_SUB_HI
+ arm_SUB_LS
+ arm_SUB_GE
+ arm_SUB_LT
+ arm_SUB_GT
+ arm_SUB_LE
+ arm_SUB
+ arm_SUB_ZZ
+ arm_SUB_S_EQ
+ arm_SUB_S_NE
+ arm_SUB_S_CS
+ arm_SUB_S_CC
+ arm_SUB_S_MI
+ arm_SUB_S_PL
+ arm_SUB_S_VS
+ arm_SUB_S_VC
+ arm_SUB_S_HI
+ arm_SUB_S_LS
+ arm_SUB_S_GE
+ arm_SUB_S_LT
+ arm_SUB_S_GT
+ arm_SUB_S_LE
+ arm_SUB_S
+ arm_SUB_S_ZZ
+ arm_SVC_EQ
+ arm_SVC_NE
+ arm_SVC_CS
+ arm_SVC_CC
+ arm_SVC_MI
+ arm_SVC_PL
+ arm_SVC_VS
+ arm_SVC_VC
+ arm_SVC_HI
+ arm_SVC_LS
+ arm_SVC_GE
+ arm_SVC_LT
+ arm_SVC_GT
+ arm_SVC_LE
+ arm_SVC
+ arm_SVC_ZZ
+ arm_SWP_EQ
+ arm_SWP_NE
+ arm_SWP_CS
+ arm_SWP_CC
+ arm_SWP_MI
+ arm_SWP_PL
+ arm_SWP_VS
+ arm_SWP_VC
+ arm_SWP_HI
+ arm_SWP_LS
+ arm_SWP_GE
+ arm_SWP_LT
+ arm_SWP_GT
+ arm_SWP_LE
+ arm_SWP
+ arm_SWP_ZZ
+ arm_SWP_B_EQ
+ arm_SWP_B_NE
+ arm_SWP_B_CS
+ arm_SWP_B_CC
+ arm_SWP_B_MI
+ arm_SWP_B_PL
+ arm_SWP_B_VS
+ arm_SWP_B_VC
+ arm_SWP_B_HI
+ arm_SWP_B_LS
+ arm_SWP_B_GE
+ arm_SWP_B_LT
+ arm_SWP_B_GT
+ arm_SWP_B_LE
+ arm_SWP_B
+ arm_SWP_B_ZZ
+ arm_SXTAB_EQ
+ arm_SXTAB_NE
+ arm_SXTAB_CS
+ arm_SXTAB_CC
+ arm_SXTAB_MI
+ arm_SXTAB_PL
+ arm_SXTAB_VS
+ arm_SXTAB_VC
+ arm_SXTAB_HI
+ arm_SXTAB_LS
+ arm_SXTAB_GE
+ arm_SXTAB_LT
+ arm_SXTAB_GT
+ arm_SXTAB_LE
+ arm_SXTAB
+ arm_SXTAB_ZZ
+ arm_SXTAB16_EQ
+ arm_SXTAB16_NE
+ arm_SXTAB16_CS
+ arm_SXTAB16_CC
+ arm_SXTAB16_MI
+ arm_SXTAB16_PL
+ arm_SXTAB16_VS
+ arm_SXTAB16_VC
+ arm_SXTAB16_HI
+ arm_SXTAB16_LS
+ arm_SXTAB16_GE
+ arm_SXTAB16_LT
+ arm_SXTAB16_GT
+ arm_SXTAB16_LE
+ arm_SXTAB16
+ arm_SXTAB16_ZZ
+ arm_SXTAH_EQ
+ arm_SXTAH_NE
+ arm_SXTAH_CS
+ arm_SXTAH_CC
+ arm_SXTAH_MI
+ arm_SXTAH_PL
+ arm_SXTAH_VS
+ arm_SXTAH_VC
+ arm_SXTAH_HI
+ arm_SXTAH_LS
+ arm_SXTAH_GE
+ arm_SXTAH_LT
+ arm_SXTAH_GT
+ arm_SXTAH_LE
+ arm_SXTAH
+ arm_SXTAH_ZZ
+ arm_SXTB_EQ
+ arm_SXTB_NE
+ arm_SXTB_CS
+ arm_SXTB_CC
+ arm_SXTB_MI
+ arm_SXTB_PL
+ arm_SXTB_VS
+ arm_SXTB_VC
+ arm_SXTB_HI
+ arm_SXTB_LS
+ arm_SXTB_GE
+ arm_SXTB_LT
+ arm_SXTB_GT
+ arm_SXTB_LE
+ arm_SXTB
+ arm_SXTB_ZZ
+ arm_SXTB16_EQ
+ arm_SXTB16_NE
+ arm_SXTB16_CS
+ arm_SXTB16_CC
+ arm_SXTB16_MI
+ arm_SXTB16_PL
+ arm_SXTB16_VS
+ arm_SXTB16_VC
+ arm_SXTB16_HI
+ arm_SXTB16_LS
+ arm_SXTB16_GE
+ arm_SXTB16_LT
+ arm_SXTB16_GT
+ arm_SXTB16_LE
+ arm_SXTB16
+ arm_SXTB16_ZZ
+ arm_SXTH_EQ
+ arm_SXTH_NE
+ arm_SXTH_CS
+ arm_SXTH_CC
+ arm_SXTH_MI
+ arm_SXTH_PL
+ arm_SXTH_VS
+ arm_SXTH_VC
+ arm_SXTH_HI
+ arm_SXTH_LS
+ arm_SXTH_GE
+ arm_SXTH_LT
+ arm_SXTH_GT
+ arm_SXTH_LE
+ arm_SXTH
+ arm_SXTH_ZZ
+ arm_TEQ_EQ
+ arm_TEQ_NE
+ arm_TEQ_CS
+ arm_TEQ_CC
+ arm_TEQ_MI
+ arm_TEQ_PL
+ arm_TEQ_VS
+ arm_TEQ_VC
+ arm_TEQ_HI
+ arm_TEQ_LS
+ arm_TEQ_GE
+ arm_TEQ_LT
+ arm_TEQ_GT
+ arm_TEQ_LE
+ arm_TEQ
+ arm_TEQ_ZZ
+ arm_TST_EQ
+ arm_TST_NE
+ arm_TST_CS
+ arm_TST_CC
+ arm_TST_MI
+ arm_TST_PL
+ arm_TST_VS
+ arm_TST_VC
+ arm_TST_HI
+ arm_TST_LS
+ arm_TST_GE
+ arm_TST_LT
+ arm_TST_GT
+ arm_TST_LE
+ arm_TST
+ arm_TST_ZZ
+ arm_UADD16_EQ
+ arm_UADD16_NE
+ arm_UADD16_CS
+ arm_UADD16_CC
+ arm_UADD16_MI
+ arm_UADD16_PL
+ arm_UADD16_VS
+ arm_UADD16_VC
+ arm_UADD16_HI
+ arm_UADD16_LS
+ arm_UADD16_GE
+ arm_UADD16_LT
+ arm_UADD16_GT
+ arm_UADD16_LE
+ arm_UADD16
+ arm_UADD16_ZZ
+ arm_UADD8_EQ
+ arm_UADD8_NE
+ arm_UADD8_CS
+ arm_UADD8_CC
+ arm_UADD8_MI
+ arm_UADD8_PL
+ arm_UADD8_VS
+ arm_UADD8_VC
+ arm_UADD8_HI
+ arm_UADD8_LS
+ arm_UADD8_GE
+ arm_UADD8_LT
+ arm_UADD8_GT
+ arm_UADD8_LE
+ arm_UADD8
+ arm_UADD8_ZZ
+ arm_UASX_EQ
+ arm_UASX_NE
+ arm_UASX_CS
+ arm_UASX_CC
+ arm_UASX_MI
+ arm_UASX_PL
+ arm_UASX_VS
+ arm_UASX_VC
+ arm_UASX_HI
+ arm_UASX_LS
+ arm_UASX_GE
+ arm_UASX_LT
+ arm_UASX_GT
+ arm_UASX_LE
+ arm_UASX
+ arm_UASX_ZZ
+ arm_UBFX_EQ
+ arm_UBFX_NE
+ arm_UBFX_CS
+ arm_UBFX_CC
+ arm_UBFX_MI
+ arm_UBFX_PL
+ arm_UBFX_VS
+ arm_UBFX_VC
+ arm_UBFX_HI
+ arm_UBFX_LS
+ arm_UBFX_GE
+ arm_UBFX_LT
+ arm_UBFX_GT
+ arm_UBFX_LE
+ arm_UBFX
+ arm_UBFX_ZZ
+ arm_UHADD16_EQ
+ arm_UHADD16_NE
+ arm_UHADD16_CS
+ arm_UHADD16_CC
+ arm_UHADD16_MI
+ arm_UHADD16_PL
+ arm_UHADD16_VS
+ arm_UHADD16_VC
+ arm_UHADD16_HI
+ arm_UHADD16_LS
+ arm_UHADD16_GE
+ arm_UHADD16_LT
+ arm_UHADD16_GT
+ arm_UHADD16_LE
+ arm_UHADD16
+ arm_UHADD16_ZZ
+ arm_UHADD8_EQ
+ arm_UHADD8_NE
+ arm_UHADD8_CS
+ arm_UHADD8_CC
+ arm_UHADD8_MI
+ arm_UHADD8_PL
+ arm_UHADD8_VS
+ arm_UHADD8_VC
+ arm_UHADD8_HI
+ arm_UHADD8_LS
+ arm_UHADD8_GE
+ arm_UHADD8_LT
+ arm_UHADD8_GT
+ arm_UHADD8_LE
+ arm_UHADD8
+ arm_UHADD8_ZZ
+ arm_UHASX_EQ
+ arm_UHASX_NE
+ arm_UHASX_CS
+ arm_UHASX_CC
+ arm_UHASX_MI
+ arm_UHASX_PL
+ arm_UHASX_VS
+ arm_UHASX_VC
+ arm_UHASX_HI
+ arm_UHASX_LS
+ arm_UHASX_GE
+ arm_UHASX_LT
+ arm_UHASX_GT
+ arm_UHASX_LE
+ arm_UHASX
+ arm_UHASX_ZZ
+ arm_UHSAX_EQ
+ arm_UHSAX_NE
+ arm_UHSAX_CS
+ arm_UHSAX_CC
+ arm_UHSAX_MI
+ arm_UHSAX_PL
+ arm_UHSAX_VS
+ arm_UHSAX_VC
+ arm_UHSAX_HI
+ arm_UHSAX_LS
+ arm_UHSAX_GE
+ arm_UHSAX_LT
+ arm_UHSAX_GT
+ arm_UHSAX_LE
+ arm_UHSAX
+ arm_UHSAX_ZZ
+ arm_UHSUB16_EQ
+ arm_UHSUB16_NE
+ arm_UHSUB16_CS
+ arm_UHSUB16_CC
+ arm_UHSUB16_MI
+ arm_UHSUB16_PL
+ arm_UHSUB16_VS
+ arm_UHSUB16_VC
+ arm_UHSUB16_HI
+ arm_UHSUB16_LS
+ arm_UHSUB16_GE
+ arm_UHSUB16_LT
+ arm_UHSUB16_GT
+ arm_UHSUB16_LE
+ arm_UHSUB16
+ arm_UHSUB16_ZZ
+ arm_UHSUB8_EQ
+ arm_UHSUB8_NE
+ arm_UHSUB8_CS
+ arm_UHSUB8_CC
+ arm_UHSUB8_MI
+ arm_UHSUB8_PL
+ arm_UHSUB8_VS
+ arm_UHSUB8_VC
+ arm_UHSUB8_HI
+ arm_UHSUB8_LS
+ arm_UHSUB8_GE
+ arm_UHSUB8_LT
+ arm_UHSUB8_GT
+ arm_UHSUB8_LE
+ arm_UHSUB8
+ arm_UHSUB8_ZZ
+ arm_UMAAL_EQ
+ arm_UMAAL_NE
+ arm_UMAAL_CS
+ arm_UMAAL_CC
+ arm_UMAAL_MI
+ arm_UMAAL_PL
+ arm_UMAAL_VS
+ arm_UMAAL_VC
+ arm_UMAAL_HI
+ arm_UMAAL_LS
+ arm_UMAAL_GE
+ arm_UMAAL_LT
+ arm_UMAAL_GT
+ arm_UMAAL_LE
+ arm_UMAAL
+ arm_UMAAL_ZZ
+ arm_UMLAL_EQ
+ arm_UMLAL_NE
+ arm_UMLAL_CS
+ arm_UMLAL_CC
+ arm_UMLAL_MI
+ arm_UMLAL_PL
+ arm_UMLAL_VS
+ arm_UMLAL_VC
+ arm_UMLAL_HI
+ arm_UMLAL_LS
+ arm_UMLAL_GE
+ arm_UMLAL_LT
+ arm_UMLAL_GT
+ arm_UMLAL_LE
+ arm_UMLAL
+ arm_UMLAL_ZZ
+ arm_UMLAL_S_EQ
+ arm_UMLAL_S_NE
+ arm_UMLAL_S_CS
+ arm_UMLAL_S_CC
+ arm_UMLAL_S_MI
+ arm_UMLAL_S_PL
+ arm_UMLAL_S_VS
+ arm_UMLAL_S_VC
+ arm_UMLAL_S_HI
+ arm_UMLAL_S_LS
+ arm_UMLAL_S_GE
+ arm_UMLAL_S_LT
+ arm_UMLAL_S_GT
+ arm_UMLAL_S_LE
+ arm_UMLAL_S
+ arm_UMLAL_S_ZZ
+ arm_UMULL_EQ
+ arm_UMULL_NE
+ arm_UMULL_CS
+ arm_UMULL_CC
+ arm_UMULL_MI
+ arm_UMULL_PL
+ arm_UMULL_VS
+ arm_UMULL_VC
+ arm_UMULL_HI
+ arm_UMULL_LS
+ arm_UMULL_GE
+ arm_UMULL_LT
+ arm_UMULL_GT
+ arm_UMULL_LE
+ arm_UMULL
+ arm_UMULL_ZZ
+ arm_UMULL_S_EQ
+ arm_UMULL_S_NE
+ arm_UMULL_S_CS
+ arm_UMULL_S_CC
+ arm_UMULL_S_MI
+ arm_UMULL_S_PL
+ arm_UMULL_S_VS
+ arm_UMULL_S_VC
+ arm_UMULL_S_HI
+ arm_UMULL_S_LS
+ arm_UMULL_S_GE
+ arm_UMULL_S_LT
+ arm_UMULL_S_GT
+ arm_UMULL_S_LE
+ arm_UMULL_S
+ arm_UMULL_S_ZZ
+ arm_UNDEF
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ _
+ arm_UQADD16_EQ
+ arm_UQADD16_NE
+ arm_UQADD16_CS
+ arm_UQADD16_CC
+ arm_UQADD16_MI
+ arm_UQADD16_PL
+ arm_UQADD16_VS
+ arm_UQADD16_VC
+ arm_UQADD16_HI
+ arm_UQADD16_LS
+ arm_UQADD16_GE
+ arm_UQADD16_LT
+ arm_UQADD16_GT
+ arm_UQADD16_LE
+ arm_UQADD16
+ arm_UQADD16_ZZ
+ arm_UQADD8_EQ
+ arm_UQADD8_NE
+ arm_UQADD8_CS
+ arm_UQADD8_CC
+ arm_UQADD8_MI
+ arm_UQADD8_PL
+ arm_UQADD8_VS
+ arm_UQADD8_VC
+ arm_UQADD8_HI
+ arm_UQADD8_LS
+ arm_UQADD8_GE
+ arm_UQADD8_LT
+ arm_UQADD8_GT
+ arm_UQADD8_LE
+ arm_UQADD8
+ arm_UQADD8_ZZ
+ arm_UQASX_EQ
+ arm_UQASX_NE
+ arm_UQASX_CS
+ arm_UQASX_CC
+ arm_UQASX_MI
+ arm_UQASX_PL
+ arm_UQASX_VS
+ arm_UQASX_VC
+ arm_UQASX_HI
+ arm_UQASX_LS
+ arm_UQASX_GE
+ arm_UQASX_LT
+ arm_UQASX_GT
+ arm_UQASX_LE
+ arm_UQASX
+ arm_UQASX_ZZ
+ arm_UQSAX_EQ
+ arm_UQSAX_NE
+ arm_UQSAX_CS
+ arm_UQSAX_CC
+ arm_UQSAX_MI
+ arm_UQSAX_PL
+ arm_UQSAX_VS
+ arm_UQSAX_VC
+ arm_UQSAX_HI
+ arm_UQSAX_LS
+ arm_UQSAX_GE
+ arm_UQSAX_LT
+ arm_UQSAX_GT
+ arm_UQSAX_LE
+ arm_UQSAX
+ arm_UQSAX_ZZ
+ arm_UQSUB16_EQ
+ arm_UQSUB16_NE
+ arm_UQSUB16_CS
+ arm_UQSUB16_CC
+ arm_UQSUB16_MI
+ arm_UQSUB16_PL
+ arm_UQSUB16_VS
+ arm_UQSUB16_VC
+ arm_UQSUB16_HI
+ arm_UQSUB16_LS
+ arm_UQSUB16_GE
+ arm_UQSUB16_LT
+ arm_UQSUB16_GT
+ arm_UQSUB16_LE
+ arm_UQSUB16
+ arm_UQSUB16_ZZ
+ arm_UQSUB8_EQ
+ arm_UQSUB8_NE
+ arm_UQSUB8_CS
+ arm_UQSUB8_CC
+ arm_UQSUB8_MI
+ arm_UQSUB8_PL
+ arm_UQSUB8_VS
+ arm_UQSUB8_VC
+ arm_UQSUB8_HI
+ arm_UQSUB8_LS
+ arm_UQSUB8_GE
+ arm_UQSUB8_LT
+ arm_UQSUB8_GT
+ arm_UQSUB8_LE
+ arm_UQSUB8
+ arm_UQSUB8_ZZ
+ arm_USAD8_EQ
+ arm_USAD8_NE
+ arm_USAD8_CS
+ arm_USAD8_CC
+ arm_USAD8_MI
+ arm_USAD8_PL
+ arm_USAD8_VS
+ arm_USAD8_VC
+ arm_USAD8_HI
+ arm_USAD8_LS
+ arm_USAD8_GE
+ arm_USAD8_LT
+ arm_USAD8_GT
+ arm_USAD8_LE
+ arm_USAD8
+ arm_USAD8_ZZ
+ arm_USADA8_EQ
+ arm_USADA8_NE
+ arm_USADA8_CS
+ arm_USADA8_CC
+ arm_USADA8_MI
+ arm_USADA8_PL
+ arm_USADA8_VS
+ arm_USADA8_VC
+ arm_USADA8_HI
+ arm_USADA8_LS
+ arm_USADA8_GE
+ arm_USADA8_LT
+ arm_USADA8_GT
+ arm_USADA8_LE
+ arm_USADA8
+ arm_USADA8_ZZ
+ arm_USAT_EQ
+ arm_USAT_NE
+ arm_USAT_CS
+ arm_USAT_CC
+ arm_USAT_MI
+ arm_USAT_PL
+ arm_USAT_VS
+ arm_USAT_VC
+ arm_USAT_HI
+ arm_USAT_LS
+ arm_USAT_GE
+ arm_USAT_LT
+ arm_USAT_GT
+ arm_USAT_LE
+ arm_USAT
+ arm_USAT_ZZ
+ arm_USAT16_EQ
+ arm_USAT16_NE
+ arm_USAT16_CS
+ arm_USAT16_CC
+ arm_USAT16_MI
+ arm_USAT16_PL
+ arm_USAT16_VS
+ arm_USAT16_VC
+ arm_USAT16_HI
+ arm_USAT16_LS
+ arm_USAT16_GE
+ arm_USAT16_LT
+ arm_USAT16_GT
+ arm_USAT16_LE
+ arm_USAT16
+ arm_USAT16_ZZ
+ arm_USAX_EQ
+ arm_USAX_NE
+ arm_USAX_CS
+ arm_USAX_CC
+ arm_USAX_MI
+ arm_USAX_PL
+ arm_USAX_VS
+ arm_USAX_VC
+ arm_USAX_HI
+ arm_USAX_LS
+ arm_USAX_GE
+ arm_USAX_LT
+ arm_USAX_GT
+ arm_USAX_LE
+ arm_USAX
+ arm_USAX_ZZ
+ arm_USUB16_EQ
+ arm_USUB16_NE
+ arm_USUB16_CS
+ arm_USUB16_CC
+ arm_USUB16_MI
+ arm_USUB16_PL
+ arm_USUB16_VS
+ arm_USUB16_VC
+ arm_USUB16_HI
+ arm_USUB16_LS
+ arm_USUB16_GE
+ arm_USUB16_LT
+ arm_USUB16_GT
+ arm_USUB16_LE
+ arm_USUB16
+ arm_USUB16_ZZ
+ arm_USUB8_EQ
+ arm_USUB8_NE
+ arm_USUB8_CS
+ arm_USUB8_CC
+ arm_USUB8_MI
+ arm_USUB8_PL
+ arm_USUB8_VS
+ arm_USUB8_VC
+ arm_USUB8_HI
+ arm_USUB8_LS
+ arm_USUB8_GE
+ arm_USUB8_LT
+ arm_USUB8_GT
+ arm_USUB8_LE
+ arm_USUB8
+ arm_USUB8_ZZ
+ arm_UXTAB_EQ
+ arm_UXTAB_NE
+ arm_UXTAB_CS
+ arm_UXTAB_CC
+ arm_UXTAB_MI
+ arm_UXTAB_PL
+ arm_UXTAB_VS
+ arm_UXTAB_VC
+ arm_UXTAB_HI
+ arm_UXTAB_LS
+ arm_UXTAB_GE
+ arm_UXTAB_LT
+ arm_UXTAB_GT
+ arm_UXTAB_LE
+ arm_UXTAB
+ arm_UXTAB_ZZ
+ arm_UXTAB16_EQ
+ arm_UXTAB16_NE
+ arm_UXTAB16_CS
+ arm_UXTAB16_CC
+ arm_UXTAB16_MI
+ arm_UXTAB16_PL
+ arm_UXTAB16_VS
+ arm_UXTAB16_VC
+ arm_UXTAB16_HI
+ arm_UXTAB16_LS
+ arm_UXTAB16_GE
+ arm_UXTAB16_LT
+ arm_UXTAB16_GT
+ arm_UXTAB16_LE
+ arm_UXTAB16
+ arm_UXTAB16_ZZ
+ arm_UXTAH_EQ
+ arm_UXTAH_NE
+ arm_UXTAH_CS
+ arm_UXTAH_CC
+ arm_UXTAH_MI
+ arm_UXTAH_PL
+ arm_UXTAH_VS
+ arm_UXTAH_VC
+ arm_UXTAH_HI
+ arm_UXTAH_LS
+ arm_UXTAH_GE
+ arm_UXTAH_LT
+ arm_UXTAH_GT
+ arm_UXTAH_LE
+ arm_UXTAH
+ arm_UXTAH_ZZ
+ arm_UXTB_EQ
+ arm_UXTB_NE
+ arm_UXTB_CS
+ arm_UXTB_CC
+ arm_UXTB_MI
+ arm_UXTB_PL
+ arm_UXTB_VS
+ arm_UXTB_VC
+ arm_UXTB_HI
+ arm_UXTB_LS
+ arm_UXTB_GE
+ arm_UXTB_LT
+ arm_UXTB_GT
+ arm_UXTB_LE
+ arm_UXTB
+ arm_UXTB_ZZ
+ arm_UXTB16_EQ
+ arm_UXTB16_NE
+ arm_UXTB16_CS
+ arm_UXTB16_CC
+ arm_UXTB16_MI
+ arm_UXTB16_PL
+ arm_UXTB16_VS
+ arm_UXTB16_VC
+ arm_UXTB16_HI
+ arm_UXTB16_LS
+ arm_UXTB16_GE
+ arm_UXTB16_LT
+ arm_UXTB16_GT
+ arm_UXTB16_LE
+ arm_UXTB16
+ arm_UXTB16_ZZ
+ arm_UXTH_EQ
+ arm_UXTH_NE
+ arm_UXTH_CS
+ arm_UXTH_CC
+ arm_UXTH_MI
+ arm_UXTH_PL
+ arm_UXTH_VS
+ arm_UXTH_VC
+ arm_UXTH_HI
+ arm_UXTH_LS
+ arm_UXTH_GE
+ arm_UXTH_LT
+ arm_UXTH_GT
+ arm_UXTH_LE
+ arm_UXTH
+ arm_UXTH_ZZ
+ arm_VABS_EQ_F32
+ arm_VABS_NE_F32
+ arm_VABS_CS_F32
+ arm_VABS_CC_F32
+ arm_VABS_MI_F32
+ arm_VABS_PL_F32
+ arm_VABS_VS_F32
+ arm_VABS_VC_F32
+ arm_VABS_HI_F32
+ arm_VABS_LS_F32
+ arm_VABS_GE_F32
+ arm_VABS_LT_F32
+ arm_VABS_GT_F32
+ arm_VABS_LE_F32
+ arm_VABS_F32
+ arm_VABS_ZZ_F32
+ arm_VABS_EQ_F64
+ arm_VABS_NE_F64
+ arm_VABS_CS_F64
+ arm_VABS_CC_F64
+ arm_VABS_MI_F64
+ arm_VABS_PL_F64
+ arm_VABS_VS_F64
+ arm_VABS_VC_F64
+ arm_VABS_HI_F64
+ arm_VABS_LS_F64
+ arm_VABS_GE_F64
+ arm_VABS_LT_F64
+ arm_VABS_GT_F64
+ arm_VABS_LE_F64
+ arm_VABS_F64
+ arm_VABS_ZZ_F64
+ arm_VADD_EQ_F32
+ arm_VADD_NE_F32
+ arm_VADD_CS_F32
+ arm_VADD_CC_F32
+ arm_VADD_MI_F32
+ arm_VADD_PL_F32
+ arm_VADD_VS_F32
+ arm_VADD_VC_F32
+ arm_VADD_HI_F32
+ arm_VADD_LS_F32
+ arm_VADD_GE_F32
+ arm_VADD_LT_F32
+ arm_VADD_GT_F32
+ arm_VADD_LE_F32
+ arm_VADD_F32
+ arm_VADD_ZZ_F32
+ arm_VADD_EQ_F64
+ arm_VADD_NE_F64
+ arm_VADD_CS_F64
+ arm_VADD_CC_F64
+ arm_VADD_MI_F64
+ arm_VADD_PL_F64
+ arm_VADD_VS_F64
+ arm_VADD_VC_F64
+ arm_VADD_HI_F64
+ arm_VADD_LS_F64
+ arm_VADD_GE_F64
+ arm_VADD_LT_F64
+ arm_VADD_GT_F64
+ arm_VADD_LE_F64
+ arm_VADD_F64
+ arm_VADD_ZZ_F64
+ arm_VCMP_EQ_F32
+ arm_VCMP_NE_F32
+ arm_VCMP_CS_F32
+ arm_VCMP_CC_F32
+ arm_VCMP_MI_F32
+ arm_VCMP_PL_F32
+ arm_VCMP_VS_F32
+ arm_VCMP_VC_F32
+ arm_VCMP_HI_F32
+ arm_VCMP_LS_F32
+ arm_VCMP_GE_F32
+ arm_VCMP_LT_F32
+ arm_VCMP_GT_F32
+ arm_VCMP_LE_F32
+ arm_VCMP_F32
+ arm_VCMP_ZZ_F32
+ arm_VCMP_EQ_F64
+ arm_VCMP_NE_F64
+ arm_VCMP_CS_F64
+ arm_VCMP_CC_F64
+ arm_VCMP_MI_F64
+ arm_VCMP_PL_F64
+ arm_VCMP_VS_F64
+ arm_VCMP_VC_F64
+ arm_VCMP_HI_F64
+ arm_VCMP_LS_F64
+ arm_VCMP_GE_F64
+ arm_VCMP_LT_F64
+ arm_VCMP_GT_F64
+ arm_VCMP_LE_F64
+ arm_VCMP_F64
+ arm_VCMP_ZZ_F64
+ arm_VCMP_E_EQ_F32
+ arm_VCMP_E_NE_F32
+ arm_VCMP_E_CS_F32
+ arm_VCMP_E_CC_F32
+ arm_VCMP_E_MI_F32
+ arm_VCMP_E_PL_F32
+ arm_VCMP_E_VS_F32
+ arm_VCMP_E_VC_F32
+ arm_VCMP_E_HI_F32
+ arm_VCMP_E_LS_F32
+ arm_VCMP_E_GE_F32
+ arm_VCMP_E_LT_F32
+ arm_VCMP_E_GT_F32
+ arm_VCMP_E_LE_F32
+ arm_VCMP_E_F32
+ arm_VCMP_E_ZZ_F32
+ arm_VCMP_E_EQ_F64
+ arm_VCMP_E_NE_F64
+ arm_VCMP_E_CS_F64
+ arm_VCMP_E_CC_F64
+ arm_VCMP_E_MI_F64
+ arm_VCMP_E_PL_F64
+ arm_VCMP_E_VS_F64
+ arm_VCMP_E_VC_F64
+ arm_VCMP_E_HI_F64
+ arm_VCMP_E_LS_F64
+ arm_VCMP_E_GE_F64
+ arm_VCMP_E_LT_F64
+ arm_VCMP_E_GT_F64
+ arm_VCMP_E_LE_F64
+ arm_VCMP_E_F64
+ arm_VCMP_E_ZZ_F64
+ arm_VCVT_EQ_F32_FXS16
+ arm_VCVT_NE_F32_FXS16
+ arm_VCVT_CS_F32_FXS16
+ arm_VCVT_CC_F32_FXS16
+ arm_VCVT_MI_F32_FXS16
+ arm_VCVT_PL_F32_FXS16
+ arm_VCVT_VS_F32_FXS16
+ arm_VCVT_VC_F32_FXS16
+ arm_VCVT_HI_F32_FXS16
+ arm_VCVT_LS_F32_FXS16
+ arm_VCVT_GE_F32_FXS16
+ arm_VCVT_LT_F32_FXS16
+ arm_VCVT_GT_F32_FXS16
+ arm_VCVT_LE_F32_FXS16
+ arm_VCVT_F32_FXS16
+ arm_VCVT_ZZ_F32_FXS16
+ arm_VCVT_EQ_F32_FXS32
+ arm_VCVT_NE_F32_FXS32
+ arm_VCVT_CS_F32_FXS32
+ arm_VCVT_CC_F32_FXS32
+ arm_VCVT_MI_F32_FXS32
+ arm_VCVT_PL_F32_FXS32
+ arm_VCVT_VS_F32_FXS32
+ arm_VCVT_VC_F32_FXS32
+ arm_VCVT_HI_F32_FXS32
+ arm_VCVT_LS_F32_FXS32
+ arm_VCVT_GE_F32_FXS32
+ arm_VCVT_LT_F32_FXS32
+ arm_VCVT_GT_F32_FXS32
+ arm_VCVT_LE_F32_FXS32
+ arm_VCVT_F32_FXS32
+ arm_VCVT_ZZ_F32_FXS32
+ arm_VCVT_EQ_F32_FXU16
+ arm_VCVT_NE_F32_FXU16
+ arm_VCVT_CS_F32_FXU16
+ arm_VCVT_CC_F32_FXU16
+ arm_VCVT_MI_F32_FXU16
+ arm_VCVT_PL_F32_FXU16
+ arm_VCVT_VS_F32_FXU16
+ arm_VCVT_VC_F32_FXU16
+ arm_VCVT_HI_F32_FXU16
+ arm_VCVT_LS_F32_FXU16
+ arm_VCVT_GE_F32_FXU16
+ arm_VCVT_LT_F32_FXU16
+ arm_VCVT_GT_F32_FXU16
+ arm_VCVT_LE_F32_FXU16
+ arm_VCVT_F32_FXU16
+ arm_VCVT_ZZ_F32_FXU16
+ arm_VCVT_EQ_F32_FXU32
+ arm_VCVT_NE_F32_FXU32
+ arm_VCVT_CS_F32_FXU32
+ arm_VCVT_CC_F32_FXU32
+ arm_VCVT_MI_F32_FXU32
+ arm_VCVT_PL_F32_FXU32
+ arm_VCVT_VS_F32_FXU32
+ arm_VCVT_VC_F32_FXU32
+ arm_VCVT_HI_F32_FXU32
+ arm_VCVT_LS_F32_FXU32
+ arm_VCVT_GE_F32_FXU32
+ arm_VCVT_LT_F32_FXU32
+ arm_VCVT_GT_F32_FXU32
+ arm_VCVT_LE_F32_FXU32
+ arm_VCVT_F32_FXU32
+ arm_VCVT_ZZ_F32_FXU32
+ arm_VCVT_EQ_F64_FXS16
+ arm_VCVT_NE_F64_FXS16
+ arm_VCVT_CS_F64_FXS16
+ arm_VCVT_CC_F64_FXS16
+ arm_VCVT_MI_F64_FXS16
+ arm_VCVT_PL_F64_FXS16
+ arm_VCVT_VS_F64_FXS16
+ arm_VCVT_VC_F64_FXS16
+ arm_VCVT_HI_F64_FXS16
+ arm_VCVT_LS_F64_FXS16
+ arm_VCVT_GE_F64_FXS16
+ arm_VCVT_LT_F64_FXS16
+ arm_VCVT_GT_F64_FXS16
+ arm_VCVT_LE_F64_FXS16
+ arm_VCVT_F64_FXS16
+ arm_VCVT_ZZ_F64_FXS16
+ arm_VCVT_EQ_F64_FXS32
+ arm_VCVT_NE_F64_FXS32
+ arm_VCVT_CS_F64_FXS32
+ arm_VCVT_CC_F64_FXS32
+ arm_VCVT_MI_F64_FXS32
+ arm_VCVT_PL_F64_FXS32
+ arm_VCVT_VS_F64_FXS32
+ arm_VCVT_VC_F64_FXS32
+ arm_VCVT_HI_F64_FXS32
+ arm_VCVT_LS_F64_FXS32
+ arm_VCVT_GE_F64_FXS32
+ arm_VCVT_LT_F64_FXS32
+ arm_VCVT_GT_F64_FXS32
+ arm_VCVT_LE_F64_FXS32
+ arm_VCVT_F64_FXS32
+ arm_VCVT_ZZ_F64_FXS32
+ arm_VCVT_EQ_F64_FXU16
+ arm_VCVT_NE_F64_FXU16
+ arm_VCVT_CS_F64_FXU16
+ arm_VCVT_CC_F64_FXU16
+ arm_VCVT_MI_F64_FXU16
+ arm_VCVT_PL_F64_FXU16
+ arm_VCVT_VS_F64_FXU16
+ arm_VCVT_VC_F64_FXU16
+ arm_VCVT_HI_F64_FXU16
+ arm_VCVT_LS_F64_FXU16
+ arm_VCVT_GE_F64_FXU16
+ arm_VCVT_LT_F64_FXU16
+ arm_VCVT_GT_F64_FXU16
+ arm_VCVT_LE_F64_FXU16
+ arm_VCVT_F64_FXU16
+ arm_VCVT_ZZ_F64_FXU16
+ arm_VCVT_EQ_F64_FXU32
+ arm_VCVT_NE_F64_FXU32
+ arm_VCVT_CS_F64_FXU32
+ arm_VCVT_CC_F64_FXU32
+ arm_VCVT_MI_F64_FXU32
+ arm_VCVT_PL_F64_FXU32
+ arm_VCVT_VS_F64_FXU32
+ arm_VCVT_VC_F64_FXU32
+ arm_VCVT_HI_F64_FXU32
+ arm_VCVT_LS_F64_FXU32
+ arm_VCVT_GE_F64_FXU32
+ arm_VCVT_LT_F64_FXU32
+ arm_VCVT_GT_F64_FXU32
+ arm_VCVT_LE_F64_FXU32
+ arm_VCVT_F64_FXU32
+ arm_VCVT_ZZ_F64_FXU32
+ arm_VCVT_EQ_F32_U32
+ arm_VCVT_NE_F32_U32
+ arm_VCVT_CS_F32_U32
+ arm_VCVT_CC_F32_U32
+ arm_VCVT_MI_F32_U32
+ arm_VCVT_PL_F32_U32
+ arm_VCVT_VS_F32_U32
+ arm_VCVT_VC_F32_U32
+ arm_VCVT_HI_F32_U32
+ arm_VCVT_LS_F32_U32
+ arm_VCVT_GE_F32_U32
+ arm_VCVT_LT_F32_U32
+ arm_VCVT_GT_F32_U32
+ arm_VCVT_LE_F32_U32
+ arm_VCVT_F32_U32
+ arm_VCVT_ZZ_F32_U32
+ arm_VCVT_EQ_F32_S32
+ arm_VCVT_NE_F32_S32
+ arm_VCVT_CS_F32_S32
+ arm_VCVT_CC_F32_S32
+ arm_VCVT_MI_F32_S32
+ arm_VCVT_PL_F32_S32
+ arm_VCVT_VS_F32_S32
+ arm_VCVT_VC_F32_S32
+ arm_VCVT_HI_F32_S32
+ arm_VCVT_LS_F32_S32
+ arm_VCVT_GE_F32_S32
+ arm_VCVT_LT_F32_S32
+ arm_VCVT_GT_F32_S32
+ arm_VCVT_LE_F32_S32
+ arm_VCVT_F32_S32
+ arm_VCVT_ZZ_F32_S32
+ arm_VCVT_EQ_F64_U32
+ arm_VCVT_NE_F64_U32
+ arm_VCVT_CS_F64_U32
+ arm_VCVT_CC_F64_U32
+ arm_VCVT_MI_F64_U32
+ arm_VCVT_PL_F64_U32
+ arm_VCVT_VS_F64_U32
+ arm_VCVT_VC_F64_U32
+ arm_VCVT_HI_F64_U32
+ arm_VCVT_LS_F64_U32
+ arm_VCVT_GE_F64_U32
+ arm_VCVT_LT_F64_U32
+ arm_VCVT_GT_F64_U32
+ arm_VCVT_LE_F64_U32
+ arm_VCVT_F64_U32
+ arm_VCVT_ZZ_F64_U32
+ arm_VCVT_EQ_F64_S32
+ arm_VCVT_NE_F64_S32
+ arm_VCVT_CS_F64_S32
+ arm_VCVT_CC_F64_S32
+ arm_VCVT_MI_F64_S32
+ arm_VCVT_PL_F64_S32
+ arm_VCVT_VS_F64_S32
+ arm_VCVT_VC_F64_S32
+ arm_VCVT_HI_F64_S32
+ arm_VCVT_LS_F64_S32
+ arm_VCVT_GE_F64_S32
+ arm_VCVT_LT_F64_S32
+ arm_VCVT_GT_F64_S32
+ arm_VCVT_LE_F64_S32
+ arm_VCVT_F64_S32
+ arm_VCVT_ZZ_F64_S32
+ arm_VCVT_EQ_F64_F32
+ arm_VCVT_NE_F64_F32
+ arm_VCVT_CS_F64_F32
+ arm_VCVT_CC_F64_F32
+ arm_VCVT_MI_F64_F32
+ arm_VCVT_PL_F64_F32
+ arm_VCVT_VS_F64_F32
+ arm_VCVT_VC_F64_F32
+ arm_VCVT_HI_F64_F32
+ arm_VCVT_LS_F64_F32
+ arm_VCVT_GE_F64_F32
+ arm_VCVT_LT_F64_F32
+ arm_VCVT_GT_F64_F32
+ arm_VCVT_LE_F64_F32
+ arm_VCVT_F64_F32
+ arm_VCVT_ZZ_F64_F32
+ arm_VCVT_EQ_F32_F64
+ arm_VCVT_NE_F32_F64
+ arm_VCVT_CS_F32_F64
+ arm_VCVT_CC_F32_F64
+ arm_VCVT_MI_F32_F64
+ arm_VCVT_PL_F32_F64
+ arm_VCVT_VS_F32_F64
+ arm_VCVT_VC_F32_F64
+ arm_VCVT_HI_F32_F64
+ arm_VCVT_LS_F32_F64
+ arm_VCVT_GE_F32_F64
+ arm_VCVT_LT_F32_F64
+ arm_VCVT_GT_F32_F64
+ arm_VCVT_LE_F32_F64
+ arm_VCVT_F32_F64
+ arm_VCVT_ZZ_F32_F64
+ arm_VCVT_EQ_FXS16_F32
+ arm_VCVT_NE_FXS16_F32
+ arm_VCVT_CS_FXS16_F32
+ arm_VCVT_CC_FXS16_F32
+ arm_VCVT_MI_FXS16_F32
+ arm_VCVT_PL_FXS16_F32
+ arm_VCVT_VS_FXS16_F32
+ arm_VCVT_VC_FXS16_F32
+ arm_VCVT_HI_FXS16_F32
+ arm_VCVT_LS_FXS16_F32
+ arm_VCVT_GE_FXS16_F32
+ arm_VCVT_LT_FXS16_F32
+ arm_VCVT_GT_FXS16_F32
+ arm_VCVT_LE_FXS16_F32
+ arm_VCVT_FXS16_F32
+ arm_VCVT_ZZ_FXS16_F32
+ arm_VCVT_EQ_FXS16_F64
+ arm_VCVT_NE_FXS16_F64
+ arm_VCVT_CS_FXS16_F64
+ arm_VCVT_CC_FXS16_F64
+ arm_VCVT_MI_FXS16_F64
+ arm_VCVT_PL_FXS16_F64
+ arm_VCVT_VS_FXS16_F64
+ arm_VCVT_VC_FXS16_F64
+ arm_VCVT_HI_FXS16_F64
+ arm_VCVT_LS_FXS16_F64
+ arm_VCVT_GE_FXS16_F64
+ arm_VCVT_LT_FXS16_F64
+ arm_VCVT_GT_FXS16_F64
+ arm_VCVT_LE_FXS16_F64
+ arm_VCVT_FXS16_F64
+ arm_VCVT_ZZ_FXS16_F64
+ arm_VCVT_EQ_FXS32_F32
+ arm_VCVT_NE_FXS32_F32
+ arm_VCVT_CS_FXS32_F32
+ arm_VCVT_CC_FXS32_F32
+ arm_VCVT_MI_FXS32_F32
+ arm_VCVT_PL_FXS32_F32
+ arm_VCVT_VS_FXS32_F32
+ arm_VCVT_VC_FXS32_F32
+ arm_VCVT_HI_FXS32_F32
+ arm_VCVT_LS_FXS32_F32
+ arm_VCVT_GE_FXS32_F32
+ arm_VCVT_LT_FXS32_F32
+ arm_VCVT_GT_FXS32_F32
+ arm_VCVT_LE_FXS32_F32
+ arm_VCVT_FXS32_F32
+ arm_VCVT_ZZ_FXS32_F32
+ arm_VCVT_EQ_FXS32_F64
+ arm_VCVT_NE_FXS32_F64
+ arm_VCVT_CS_FXS32_F64
+ arm_VCVT_CC_FXS32_F64
+ arm_VCVT_MI_FXS32_F64
+ arm_VCVT_PL_FXS32_F64
+ arm_VCVT_VS_FXS32_F64
+ arm_VCVT_VC_FXS32_F64
+ arm_VCVT_HI_FXS32_F64
+ arm_VCVT_LS_FXS32_F64
+ arm_VCVT_GE_FXS32_F64
+ arm_VCVT_LT_FXS32_F64
+ arm_VCVT_GT_FXS32_F64
+ arm_VCVT_LE_FXS32_F64
+ arm_VCVT_FXS32_F64
+ arm_VCVT_ZZ_FXS32_F64
+ arm_VCVT_EQ_FXU16_F32
+ arm_VCVT_NE_FXU16_F32
+ arm_VCVT_CS_FXU16_F32
+ arm_VCVT_CC_FXU16_F32
+ arm_VCVT_MI_FXU16_F32
+ arm_VCVT_PL_FXU16_F32
+ arm_VCVT_VS_FXU16_F32
+ arm_VCVT_VC_FXU16_F32
+ arm_VCVT_HI_FXU16_F32
+ arm_VCVT_LS_FXU16_F32
+ arm_VCVT_GE_FXU16_F32
+ arm_VCVT_LT_FXU16_F32
+ arm_VCVT_GT_FXU16_F32
+ arm_VCVT_LE_FXU16_F32
+ arm_VCVT_FXU16_F32
+ arm_VCVT_ZZ_FXU16_F32
+ arm_VCVT_EQ_FXU16_F64
+ arm_VCVT_NE_FXU16_F64
+ arm_VCVT_CS_FXU16_F64
+ arm_VCVT_CC_FXU16_F64
+ arm_VCVT_MI_FXU16_F64
+ arm_VCVT_PL_FXU16_F64
+ arm_VCVT_VS_FXU16_F64
+ arm_VCVT_VC_FXU16_F64
+ arm_VCVT_HI_FXU16_F64
+ arm_VCVT_LS_FXU16_F64
+ arm_VCVT_GE_FXU16_F64
+ arm_VCVT_LT_FXU16_F64
+ arm_VCVT_GT_FXU16_F64
+ arm_VCVT_LE_FXU16_F64
+ arm_VCVT_FXU16_F64
+ arm_VCVT_ZZ_FXU16_F64
+ arm_VCVT_EQ_FXU32_F32
+ arm_VCVT_NE_FXU32_F32
+ arm_VCVT_CS_FXU32_F32
+ arm_VCVT_CC_FXU32_F32
+ arm_VCVT_MI_FXU32_F32
+ arm_VCVT_PL_FXU32_F32
+ arm_VCVT_VS_FXU32_F32
+ arm_VCVT_VC_FXU32_F32
+ arm_VCVT_HI_FXU32_F32
+ arm_VCVT_LS_FXU32_F32
+ arm_VCVT_GE_FXU32_F32
+ arm_VCVT_LT_FXU32_F32
+ arm_VCVT_GT_FXU32_F32
+ arm_VCVT_LE_FXU32_F32
+ arm_VCVT_FXU32_F32
+ arm_VCVT_ZZ_FXU32_F32
+ arm_VCVT_EQ_FXU32_F64
+ arm_VCVT_NE_FXU32_F64
+ arm_VCVT_CS_FXU32_F64
+ arm_VCVT_CC_FXU32_F64
+ arm_VCVT_MI_FXU32_F64
+ arm_VCVT_PL_FXU32_F64
+ arm_VCVT_VS_FXU32_F64
+ arm_VCVT_VC_FXU32_F64
+ arm_VCVT_HI_FXU32_F64
+ arm_VCVT_LS_FXU32_F64
+ arm_VCVT_GE_FXU32_F64
+ arm_VCVT_LT_FXU32_F64
+ arm_VCVT_GT_FXU32_F64
+ arm_VCVT_LE_FXU32_F64
+ arm_VCVT_FXU32_F64
+ arm_VCVT_ZZ_FXU32_F64
+ arm_VCVTB_EQ_F32_F16
+ arm_VCVTB_NE_F32_F16
+ arm_VCVTB_CS_F32_F16
+ arm_VCVTB_CC_F32_F16
+ arm_VCVTB_MI_F32_F16
+ arm_VCVTB_PL_F32_F16
+ arm_VCVTB_VS_F32_F16
+ arm_VCVTB_VC_F32_F16
+ arm_VCVTB_HI_F32_F16
+ arm_VCVTB_LS_F32_F16
+ arm_VCVTB_GE_F32_F16
+ arm_VCVTB_LT_F32_F16
+ arm_VCVTB_GT_F32_F16
+ arm_VCVTB_LE_F32_F16
+ arm_VCVTB_F32_F16
+ arm_VCVTB_ZZ_F32_F16
+ arm_VCVTB_EQ_F16_F32
+ arm_VCVTB_NE_F16_F32
+ arm_VCVTB_CS_F16_F32
+ arm_VCVTB_CC_F16_F32
+ arm_VCVTB_MI_F16_F32
+ arm_VCVTB_PL_F16_F32
+ arm_VCVTB_VS_F16_F32
+ arm_VCVTB_VC_F16_F32
+ arm_VCVTB_HI_F16_F32
+ arm_VCVTB_LS_F16_F32
+ arm_VCVTB_GE_F16_F32
+ arm_VCVTB_LT_F16_F32
+ arm_VCVTB_GT_F16_F32
+ arm_VCVTB_LE_F16_F32
+ arm_VCVTB_F16_F32
+ arm_VCVTB_ZZ_F16_F32
+ arm_VCVTT_EQ_F32_F16
+ arm_VCVTT_NE_F32_F16
+ arm_VCVTT_CS_F32_F16
+ arm_VCVTT_CC_F32_F16
+ arm_VCVTT_MI_F32_F16
+ arm_VCVTT_PL_F32_F16
+ arm_VCVTT_VS_F32_F16
+ arm_VCVTT_VC_F32_F16
+ arm_VCVTT_HI_F32_F16
+ arm_VCVTT_LS_F32_F16
+ arm_VCVTT_GE_F32_F16
+ arm_VCVTT_LT_F32_F16
+ arm_VCVTT_GT_F32_F16
+ arm_VCVTT_LE_F32_F16
+ arm_VCVTT_F32_F16
+ arm_VCVTT_ZZ_F32_F16
+ arm_VCVTT_EQ_F16_F32
+ arm_VCVTT_NE_F16_F32
+ arm_VCVTT_CS_F16_F32
+ arm_VCVTT_CC_F16_F32
+ arm_VCVTT_MI_F16_F32
+ arm_VCVTT_PL_F16_F32
+ arm_VCVTT_VS_F16_F32
+ arm_VCVTT_VC_F16_F32
+ arm_VCVTT_HI_F16_F32
+ arm_VCVTT_LS_F16_F32
+ arm_VCVTT_GE_F16_F32
+ arm_VCVTT_LT_F16_F32
+ arm_VCVTT_GT_F16_F32
+ arm_VCVTT_LE_F16_F32
+ arm_VCVTT_F16_F32
+ arm_VCVTT_ZZ_F16_F32
+ arm_VCVTR_EQ_U32_F32
+ arm_VCVTR_NE_U32_F32
+ arm_VCVTR_CS_U32_F32
+ arm_VCVTR_CC_U32_F32
+ arm_VCVTR_MI_U32_F32
+ arm_VCVTR_PL_U32_F32
+ arm_VCVTR_VS_U32_F32
+ arm_VCVTR_VC_U32_F32
+ arm_VCVTR_HI_U32_F32
+ arm_VCVTR_LS_U32_F32
+ arm_VCVTR_GE_U32_F32
+ arm_VCVTR_LT_U32_F32
+ arm_VCVTR_GT_U32_F32
+ arm_VCVTR_LE_U32_F32
+ arm_VCVTR_U32_F32
+ arm_VCVTR_ZZ_U32_F32
+ arm_VCVTR_EQ_U32_F64
+ arm_VCVTR_NE_U32_F64
+ arm_VCVTR_CS_U32_F64
+ arm_VCVTR_CC_U32_F64
+ arm_VCVTR_MI_U32_F64
+ arm_VCVTR_PL_U32_F64
+ arm_VCVTR_VS_U32_F64
+ arm_VCVTR_VC_U32_F64
+ arm_VCVTR_HI_U32_F64
+ arm_VCVTR_LS_U32_F64
+ arm_VCVTR_GE_U32_F64
+ arm_VCVTR_LT_U32_F64
+ arm_VCVTR_GT_U32_F64
+ arm_VCVTR_LE_U32_F64
+ arm_VCVTR_U32_F64
+ arm_VCVTR_ZZ_U32_F64
+ arm_VCVTR_EQ_S32_F32
+ arm_VCVTR_NE_S32_F32
+ arm_VCVTR_CS_S32_F32
+ arm_VCVTR_CC_S32_F32
+ arm_VCVTR_MI_S32_F32
+ arm_VCVTR_PL_S32_F32
+ arm_VCVTR_VS_S32_F32
+ arm_VCVTR_VC_S32_F32
+ arm_VCVTR_HI_S32_F32
+ arm_VCVTR_LS_S32_F32
+ arm_VCVTR_GE_S32_F32
+ arm_VCVTR_LT_S32_F32
+ arm_VCVTR_GT_S32_F32
+ arm_VCVTR_LE_S32_F32
+ arm_VCVTR_S32_F32
+ arm_VCVTR_ZZ_S32_F32
+ arm_VCVTR_EQ_S32_F64
+ arm_VCVTR_NE_S32_F64
+ arm_VCVTR_CS_S32_F64
+ arm_VCVTR_CC_S32_F64
+ arm_VCVTR_MI_S32_F64
+ arm_VCVTR_PL_S32_F64
+ arm_VCVTR_VS_S32_F64
+ arm_VCVTR_VC_S32_F64
+ arm_VCVTR_HI_S32_F64
+ arm_VCVTR_LS_S32_F64
+ arm_VCVTR_GE_S32_F64
+ arm_VCVTR_LT_S32_F64
+ arm_VCVTR_GT_S32_F64
+ arm_VCVTR_LE_S32_F64
+ arm_VCVTR_S32_F64
+ arm_VCVTR_ZZ_S32_F64
+ arm_VCVT_EQ_U32_F32
+ arm_VCVT_NE_U32_F32
+ arm_VCVT_CS_U32_F32
+ arm_VCVT_CC_U32_F32
+ arm_VCVT_MI_U32_F32
+ arm_VCVT_PL_U32_F32
+ arm_VCVT_VS_U32_F32
+ arm_VCVT_VC_U32_F32
+ arm_VCVT_HI_U32_F32
+ arm_VCVT_LS_U32_F32
+ arm_VCVT_GE_U32_F32
+ arm_VCVT_LT_U32_F32
+ arm_VCVT_GT_U32_F32
+ arm_VCVT_LE_U32_F32
+ arm_VCVT_U32_F32
+ arm_VCVT_ZZ_U32_F32
+ arm_VCVT_EQ_U32_F64
+ arm_VCVT_NE_U32_F64
+ arm_VCVT_CS_U32_F64
+ arm_VCVT_CC_U32_F64
+ arm_VCVT_MI_U32_F64
+ arm_VCVT_PL_U32_F64
+ arm_VCVT_VS_U32_F64
+ arm_VCVT_VC_U32_F64
+ arm_VCVT_HI_U32_F64
+ arm_VCVT_LS_U32_F64
+ arm_VCVT_GE_U32_F64
+ arm_VCVT_LT_U32_F64
+ arm_VCVT_GT_U32_F64
+ arm_VCVT_LE_U32_F64
+ arm_VCVT_U32_F64
+ arm_VCVT_ZZ_U32_F64
+ arm_VCVT_EQ_S32_F32
+ arm_VCVT_NE_S32_F32
+ arm_VCVT_CS_S32_F32
+ arm_VCVT_CC_S32_F32
+ arm_VCVT_MI_S32_F32
+ arm_VCVT_PL_S32_F32
+ arm_VCVT_VS_S32_F32
+ arm_VCVT_VC_S32_F32
+ arm_VCVT_HI_S32_F32
+ arm_VCVT_LS_S32_F32
+ arm_VCVT_GE_S32_F32
+ arm_VCVT_LT_S32_F32
+ arm_VCVT_GT_S32_F32
+ arm_VCVT_LE_S32_F32
+ arm_VCVT_S32_F32
+ arm_VCVT_ZZ_S32_F32
+ arm_VCVT_EQ_S32_F64
+ arm_VCVT_NE_S32_F64
+ arm_VCVT_CS_S32_F64
+ arm_VCVT_CC_S32_F64
+ arm_VCVT_MI_S32_F64
+ arm_VCVT_PL_S32_F64
+ arm_VCVT_VS_S32_F64
+ arm_VCVT_VC_S32_F64
+ arm_VCVT_HI_S32_F64
+ arm_VCVT_LS_S32_F64
+ arm_VCVT_GE_S32_F64
+ arm_VCVT_LT_S32_F64
+ arm_VCVT_GT_S32_F64
+ arm_VCVT_LE_S32_F64
+ arm_VCVT_S32_F64
+ arm_VCVT_ZZ_S32_F64
+ arm_VDIV_EQ_F32
+ arm_VDIV_NE_F32
+ arm_VDIV_CS_F32
+ arm_VDIV_CC_F32
+ arm_VDIV_MI_F32
+ arm_VDIV_PL_F32
+ arm_VDIV_VS_F32
+ arm_VDIV_VC_F32
+ arm_VDIV_HI_F32
+ arm_VDIV_LS_F32
+ arm_VDIV_GE_F32
+ arm_VDIV_LT_F32
+ arm_VDIV_GT_F32
+ arm_VDIV_LE_F32
+ arm_VDIV_F32
+ arm_VDIV_ZZ_F32
+ arm_VDIV_EQ_F64
+ arm_VDIV_NE_F64
+ arm_VDIV_CS_F64
+ arm_VDIV_CC_F64
+ arm_VDIV_MI_F64
+ arm_VDIV_PL_F64
+ arm_VDIV_VS_F64
+ arm_VDIV_VC_F64
+ arm_VDIV_HI_F64
+ arm_VDIV_LS_F64
+ arm_VDIV_GE_F64
+ arm_VDIV_LT_F64
+ arm_VDIV_GT_F64
+ arm_VDIV_LE_F64
+ arm_VDIV_F64
+ arm_VDIV_ZZ_F64
+ arm_VLDR_EQ
+ arm_VLDR_NE
+ arm_VLDR_CS
+ arm_VLDR_CC
+ arm_VLDR_MI
+ arm_VLDR_PL
+ arm_VLDR_VS
+ arm_VLDR_VC
+ arm_VLDR_HI
+ arm_VLDR_LS
+ arm_VLDR_GE
+ arm_VLDR_LT
+ arm_VLDR_GT
+ arm_VLDR_LE
+ arm_VLDR
+ arm_VLDR_ZZ
+ arm_VMLA_EQ_F32
+ arm_VMLA_NE_F32
+ arm_VMLA_CS_F32
+ arm_VMLA_CC_F32
+ arm_VMLA_MI_F32
+ arm_VMLA_PL_F32
+ arm_VMLA_VS_F32
+ arm_VMLA_VC_F32
+ arm_VMLA_HI_F32
+ arm_VMLA_LS_F32
+ arm_VMLA_GE_F32
+ arm_VMLA_LT_F32
+ arm_VMLA_GT_F32
+ arm_VMLA_LE_F32
+ arm_VMLA_F32
+ arm_VMLA_ZZ_F32
+ arm_VMLA_EQ_F64
+ arm_VMLA_NE_F64
+ arm_VMLA_CS_F64
+ arm_VMLA_CC_F64
+ arm_VMLA_MI_F64
+ arm_VMLA_PL_F64
+ arm_VMLA_VS_F64
+ arm_VMLA_VC_F64
+ arm_VMLA_HI_F64
+ arm_VMLA_LS_F64
+ arm_VMLA_GE_F64
+ arm_VMLA_LT_F64
+ arm_VMLA_GT_F64
+ arm_VMLA_LE_F64
+ arm_VMLA_F64
+ arm_VMLA_ZZ_F64
+ arm_VMLS_EQ_F32
+ arm_VMLS_NE_F32
+ arm_VMLS_CS_F32
+ arm_VMLS_CC_F32
+ arm_VMLS_MI_F32
+ arm_VMLS_PL_F32
+ arm_VMLS_VS_F32
+ arm_VMLS_VC_F32
+ arm_VMLS_HI_F32
+ arm_VMLS_LS_F32
+ arm_VMLS_GE_F32
+ arm_VMLS_LT_F32
+ arm_VMLS_GT_F32
+ arm_VMLS_LE_F32
+ arm_VMLS_F32
+ arm_VMLS_ZZ_F32
+ arm_VMLS_EQ_F64
+ arm_VMLS_NE_F64
+ arm_VMLS_CS_F64
+ arm_VMLS_CC_F64
+ arm_VMLS_MI_F64
+ arm_VMLS_PL_F64
+ arm_VMLS_VS_F64
+ arm_VMLS_VC_F64
+ arm_VMLS_HI_F64
+ arm_VMLS_LS_F64
+ arm_VMLS_GE_F64
+ arm_VMLS_LT_F64
+ arm_VMLS_GT_F64
+ arm_VMLS_LE_F64
+ arm_VMLS_F64
+ arm_VMLS_ZZ_F64
+ arm_VMOV_EQ
+ arm_VMOV_NE
+ arm_VMOV_CS
+ arm_VMOV_CC
+ arm_VMOV_MI
+ arm_VMOV_PL
+ arm_VMOV_VS
+ arm_VMOV_VC
+ arm_VMOV_HI
+ arm_VMOV_LS
+ arm_VMOV_GE
+ arm_VMOV_LT
+ arm_VMOV_GT
+ arm_VMOV_LE
+ arm_VMOV
+ arm_VMOV_ZZ
+ arm_VMOV_EQ_32
+ arm_VMOV_NE_32
+ arm_VMOV_CS_32
+ arm_VMOV_CC_32
+ arm_VMOV_MI_32
+ arm_VMOV_PL_32
+ arm_VMOV_VS_32
+ arm_VMOV_VC_32
+ arm_VMOV_HI_32
+ arm_VMOV_LS_32
+ arm_VMOV_GE_32
+ arm_VMOV_LT_32
+ arm_VMOV_GT_32
+ arm_VMOV_LE_32
+ arm_VMOV_32
+ arm_VMOV_ZZ_32
+ arm_VMOV_EQ_F32
+ arm_VMOV_NE_F32
+ arm_VMOV_CS_F32
+ arm_VMOV_CC_F32
+ arm_VMOV_MI_F32
+ arm_VMOV_PL_F32
+ arm_VMOV_VS_F32
+ arm_VMOV_VC_F32
+ arm_VMOV_HI_F32
+ arm_VMOV_LS_F32
+ arm_VMOV_GE_F32
+ arm_VMOV_LT_F32
+ arm_VMOV_GT_F32
+ arm_VMOV_LE_F32
+ arm_VMOV_F32
+ arm_VMOV_ZZ_F32
+ arm_VMOV_EQ_F64
+ arm_VMOV_NE_F64
+ arm_VMOV_CS_F64
+ arm_VMOV_CC_F64
+ arm_VMOV_MI_F64
+ arm_VMOV_PL_F64
+ arm_VMOV_VS_F64
+ arm_VMOV_VC_F64
+ arm_VMOV_HI_F64
+ arm_VMOV_LS_F64
+ arm_VMOV_GE_F64
+ arm_VMOV_LT_F64
+ arm_VMOV_GT_F64
+ arm_VMOV_LE_F64
+ arm_VMOV_F64
+ arm_VMOV_ZZ_F64
+ arm_VMRS_EQ
+ arm_VMRS_NE
+ arm_VMRS_CS
+ arm_VMRS_CC
+ arm_VMRS_MI
+ arm_VMRS_PL
+ arm_VMRS_VS
+ arm_VMRS_VC
+ arm_VMRS_HI
+ arm_VMRS_LS
+ arm_VMRS_GE
+ arm_VMRS_LT
+ arm_VMRS_GT
+ arm_VMRS_LE
+ arm_VMRS
+ arm_VMRS_ZZ
+ arm_VMSR_EQ
+ arm_VMSR_NE
+ arm_VMSR_CS
+ arm_VMSR_CC
+ arm_VMSR_MI
+ arm_VMSR_PL
+ arm_VMSR_VS
+ arm_VMSR_VC
+ arm_VMSR_HI
+ arm_VMSR_LS
+ arm_VMSR_GE
+ arm_VMSR_LT
+ arm_VMSR_GT
+ arm_VMSR_LE
+ arm_VMSR
+ arm_VMSR_ZZ
+ arm_VMUL_EQ_F32
+ arm_VMUL_NE_F32
+ arm_VMUL_CS_F32
+ arm_VMUL_CC_F32
+ arm_VMUL_MI_F32
+ arm_VMUL_PL_F32
+ arm_VMUL_VS_F32
+ arm_VMUL_VC_F32
+ arm_VMUL_HI_F32
+ arm_VMUL_LS_F32
+ arm_VMUL_GE_F32
+ arm_VMUL_LT_F32
+ arm_VMUL_GT_F32
+ arm_VMUL_LE_F32
+ arm_VMUL_F32
+ arm_VMUL_ZZ_F32
+ arm_VMUL_EQ_F64
+ arm_VMUL_NE_F64
+ arm_VMUL_CS_F64
+ arm_VMUL_CC_F64
+ arm_VMUL_MI_F64
+ arm_VMUL_PL_F64
+ arm_VMUL_VS_F64
+ arm_VMUL_VC_F64
+ arm_VMUL_HI_F64
+ arm_VMUL_LS_F64
+ arm_VMUL_GE_F64
+ arm_VMUL_LT_F64
+ arm_VMUL_GT_F64
+ arm_VMUL_LE_F64
+ arm_VMUL_F64
+ arm_VMUL_ZZ_F64
+ arm_VNEG_EQ_F32
+ arm_VNEG_NE_F32
+ arm_VNEG_CS_F32
+ arm_VNEG_CC_F32
+ arm_VNEG_MI_F32
+ arm_VNEG_PL_F32
+ arm_VNEG_VS_F32
+ arm_VNEG_VC_F32
+ arm_VNEG_HI_F32
+ arm_VNEG_LS_F32
+ arm_VNEG_GE_F32
+ arm_VNEG_LT_F32
+ arm_VNEG_GT_F32
+ arm_VNEG_LE_F32
+ arm_VNEG_F32
+ arm_VNEG_ZZ_F32
+ arm_VNEG_EQ_F64
+ arm_VNEG_NE_F64
+ arm_VNEG_CS_F64
+ arm_VNEG_CC_F64
+ arm_VNEG_MI_F64
+ arm_VNEG_PL_F64
+ arm_VNEG_VS_F64
+ arm_VNEG_VC_F64
+ arm_VNEG_HI_F64
+ arm_VNEG_LS_F64
+ arm_VNEG_GE_F64
+ arm_VNEG_LT_F64
+ arm_VNEG_GT_F64
+ arm_VNEG_LE_F64
+ arm_VNEG_F64
+ arm_VNEG_ZZ_F64
+ arm_VNMLS_EQ_F32
+ arm_VNMLS_NE_F32
+ arm_VNMLS_CS_F32
+ arm_VNMLS_CC_F32
+ arm_VNMLS_MI_F32
+ arm_VNMLS_PL_F32
+ arm_VNMLS_VS_F32
+ arm_VNMLS_VC_F32
+ arm_VNMLS_HI_F32
+ arm_VNMLS_LS_F32
+ arm_VNMLS_GE_F32
+ arm_VNMLS_LT_F32
+ arm_VNMLS_GT_F32
+ arm_VNMLS_LE_F32
+ arm_VNMLS_F32
+ arm_VNMLS_ZZ_F32
+ arm_VNMLS_EQ_F64
+ arm_VNMLS_NE_F64
+ arm_VNMLS_CS_F64
+ arm_VNMLS_CC_F64
+ arm_VNMLS_MI_F64
+ arm_VNMLS_PL_F64
+ arm_VNMLS_VS_F64
+ arm_VNMLS_VC_F64
+ arm_VNMLS_HI_F64
+ arm_VNMLS_LS_F64
+ arm_VNMLS_GE_F64
+ arm_VNMLS_LT_F64
+ arm_VNMLS_GT_F64
+ arm_VNMLS_LE_F64
+ arm_VNMLS_F64
+ arm_VNMLS_ZZ_F64
+ arm_VNMLA_EQ_F32
+ arm_VNMLA_NE_F32
+ arm_VNMLA_CS_F32
+ arm_VNMLA_CC_F32
+ arm_VNMLA_MI_F32
+ arm_VNMLA_PL_F32
+ arm_VNMLA_VS_F32
+ arm_VNMLA_VC_F32
+ arm_VNMLA_HI_F32
+ arm_VNMLA_LS_F32
+ arm_VNMLA_GE_F32
+ arm_VNMLA_LT_F32
+ arm_VNMLA_GT_F32
+ arm_VNMLA_LE_F32
+ arm_VNMLA_F32
+ arm_VNMLA_ZZ_F32
+ arm_VNMLA_EQ_F64
+ arm_VNMLA_NE_F64
+ arm_VNMLA_CS_F64
+ arm_VNMLA_CC_F64
+ arm_VNMLA_MI_F64
+ arm_VNMLA_PL_F64
+ arm_VNMLA_VS_F64
+ arm_VNMLA_VC_F64
+ arm_VNMLA_HI_F64
+ arm_VNMLA_LS_F64
+ arm_VNMLA_GE_F64
+ arm_VNMLA_LT_F64
+ arm_VNMLA_GT_F64
+ arm_VNMLA_LE_F64
+ arm_VNMLA_F64
+ arm_VNMLA_ZZ_F64
+ arm_VNMUL_EQ_F32
+ arm_VNMUL_NE_F32
+ arm_VNMUL_CS_F32
+ arm_VNMUL_CC_F32
+ arm_VNMUL_MI_F32
+ arm_VNMUL_PL_F32
+ arm_VNMUL_VS_F32
+ arm_VNMUL_VC_F32
+ arm_VNMUL_HI_F32
+ arm_VNMUL_LS_F32
+ arm_VNMUL_GE_F32
+ arm_VNMUL_LT_F32
+ arm_VNMUL_GT_F32
+ arm_VNMUL_LE_F32
+ arm_VNMUL_F32
+ arm_VNMUL_ZZ_F32
+ arm_VNMUL_EQ_F64
+ arm_VNMUL_NE_F64
+ arm_VNMUL_CS_F64
+ arm_VNMUL_CC_F64
+ arm_VNMUL_MI_F64
+ arm_VNMUL_PL_F64
+ arm_VNMUL_VS_F64
+ arm_VNMUL_VC_F64
+ arm_VNMUL_HI_F64
+ arm_VNMUL_LS_F64
+ arm_VNMUL_GE_F64
+ arm_VNMUL_LT_F64
+ arm_VNMUL_GT_F64
+ arm_VNMUL_LE_F64
+ arm_VNMUL_F64
+ arm_VNMUL_ZZ_F64
+ arm_VSQRT_EQ_F32
+ arm_VSQRT_NE_F32
+ arm_VSQRT_CS_F32
+ arm_VSQRT_CC_F32
+ arm_VSQRT_MI_F32
+ arm_VSQRT_PL_F32
+ arm_VSQRT_VS_F32
+ arm_VSQRT_VC_F32
+ arm_VSQRT_HI_F32
+ arm_VSQRT_LS_F32
+ arm_VSQRT_GE_F32
+ arm_VSQRT_LT_F32
+ arm_VSQRT_GT_F32
+ arm_VSQRT_LE_F32
+ arm_VSQRT_F32
+ arm_VSQRT_ZZ_F32
+ arm_VSQRT_EQ_F64
+ arm_VSQRT_NE_F64
+ arm_VSQRT_CS_F64
+ arm_VSQRT_CC_F64
+ arm_VSQRT_MI_F64
+ arm_VSQRT_PL_F64
+ arm_VSQRT_VS_F64
+ arm_VSQRT_VC_F64
+ arm_VSQRT_HI_F64
+ arm_VSQRT_LS_F64
+ arm_VSQRT_GE_F64
+ arm_VSQRT_LT_F64
+ arm_VSQRT_GT_F64
+ arm_VSQRT_LE_F64
+ arm_VSQRT_F64
+ arm_VSQRT_ZZ_F64
+ arm_VSTR_EQ
+ arm_VSTR_NE
+ arm_VSTR_CS
+ arm_VSTR_CC
+ arm_VSTR_MI
+ arm_VSTR_PL
+ arm_VSTR_VS
+ arm_VSTR_VC
+ arm_VSTR_HI
+ arm_VSTR_LS
+ arm_VSTR_GE
+ arm_VSTR_LT
+ arm_VSTR_GT
+ arm_VSTR_LE
+ arm_VSTR
+ arm_VSTR_ZZ
+ arm_VSUB_EQ_F32
+ arm_VSUB_NE_F32
+ arm_VSUB_CS_F32
+ arm_VSUB_CC_F32
+ arm_VSUB_MI_F32
+ arm_VSUB_PL_F32
+ arm_VSUB_VS_F32
+ arm_VSUB_VC_F32
+ arm_VSUB_HI_F32
+ arm_VSUB_LS_F32
+ arm_VSUB_GE_F32
+ arm_VSUB_LT_F32
+ arm_VSUB_GT_F32
+ arm_VSUB_LE_F32
+ arm_VSUB_F32
+ arm_VSUB_ZZ_F32
+ arm_VSUB_EQ_F64
+ arm_VSUB_NE_F64
+ arm_VSUB_CS_F64
+ arm_VSUB_CC_F64
+ arm_VSUB_MI_F64
+ arm_VSUB_PL_F64
+ arm_VSUB_VS_F64
+ arm_VSUB_VC_F64
+ arm_VSUB_HI_F64
+ arm_VSUB_LS_F64
+ arm_VSUB_GE_F64
+ arm_VSUB_LT_F64
+ arm_VSUB_GT_F64
+ arm_VSUB_LE_F64
+ arm_VSUB_F64
+ arm_VSUB_ZZ_F64
+ arm_WFE_EQ
+ arm_WFE_NE
+ arm_WFE_CS
+ arm_WFE_CC
+ arm_WFE_MI
+ arm_WFE_PL
+ arm_WFE_VS
+ arm_WFE_VC
+ arm_WFE_HI
+ arm_WFE_LS
+ arm_WFE_GE
+ arm_WFE_LT
+ arm_WFE_GT
+ arm_WFE_LE
+ arm_WFE
+ arm_WFE_ZZ
+ arm_WFI_EQ
+ arm_WFI_NE
+ arm_WFI_CS
+ arm_WFI_CC
+ arm_WFI_MI
+ arm_WFI_PL
+ arm_WFI_VS
+ arm_WFI_VC
+ arm_WFI_HI
+ arm_WFI_LS
+ arm_WFI_GE
+ arm_WFI_LT
+ arm_WFI_GT
+ arm_WFI_LE
+ arm_WFI
+ arm_WFI_ZZ
+ arm_YIELD_EQ
+ arm_YIELD_NE
+ arm_YIELD_CS
+ arm_YIELD_CC
+ arm_YIELD_MI
+ arm_YIELD_PL
+ arm_YIELD_VS
+ arm_YIELD_VC
+ arm_YIELD_HI
+ arm_YIELD_LS
+ arm_YIELD_GE
+ arm_YIELD_LT
+ arm_YIELD_GT
+ arm_YIELD_LE
+ arm_YIELD
+ arm_YIELD_ZZ
+)
+
+var arm_opstr = [...]string{
+ arm_ADC_EQ: "ADC.EQ",
+ arm_ADC_NE: "ADC.NE",
+ arm_ADC_CS: "ADC.CS",
+ arm_ADC_CC: "ADC.CC",
+ arm_ADC_MI: "ADC.MI",
+ arm_ADC_PL: "ADC.PL",
+ arm_ADC_VS: "ADC.VS",
+ arm_ADC_VC: "ADC.VC",
+ arm_ADC_HI: "ADC.HI",
+ arm_ADC_LS: "ADC.LS",
+ arm_ADC_GE: "ADC.GE",
+ arm_ADC_LT: "ADC.LT",
+ arm_ADC_GT: "ADC.GT",
+ arm_ADC_LE: "ADC.LE",
+ arm_ADC: "ADC",
+ arm_ADC_ZZ: "ADC.ZZ",
+ arm_ADC_S_EQ: "ADC.S.EQ",
+ arm_ADC_S_NE: "ADC.S.NE",
+ arm_ADC_S_CS: "ADC.S.CS",
+ arm_ADC_S_CC: "ADC.S.CC",
+ arm_ADC_S_MI: "ADC.S.MI",
+ arm_ADC_S_PL: "ADC.S.PL",
+ arm_ADC_S_VS: "ADC.S.VS",
+ arm_ADC_S_VC: "ADC.S.VC",
+ arm_ADC_S_HI: "ADC.S.HI",
+ arm_ADC_S_LS: "ADC.S.LS",
+ arm_ADC_S_GE: "ADC.S.GE",
+ arm_ADC_S_LT: "ADC.S.LT",
+ arm_ADC_S_GT: "ADC.S.GT",
+ arm_ADC_S_LE: "ADC.S.LE",
+ arm_ADC_S: "ADC.S",
+ arm_ADC_S_ZZ: "ADC.S.ZZ",
+ arm_ADD_EQ: "ADD.EQ",
+ arm_ADD_NE: "ADD.NE",
+ arm_ADD_CS: "ADD.CS",
+ arm_ADD_CC: "ADD.CC",
+ arm_ADD_MI: "ADD.MI",
+ arm_ADD_PL: "ADD.PL",
+ arm_ADD_VS: "ADD.VS",
+ arm_ADD_VC: "ADD.VC",
+ arm_ADD_HI: "ADD.HI",
+ arm_ADD_LS: "ADD.LS",
+ arm_ADD_GE: "ADD.GE",
+ arm_ADD_LT: "ADD.LT",
+ arm_ADD_GT: "ADD.GT",
+ arm_ADD_LE: "ADD.LE",
+ arm_ADD: "ADD",
+ arm_ADD_ZZ: "ADD.ZZ",
+ arm_ADD_S_EQ: "ADD.S.EQ",
+ arm_ADD_S_NE: "ADD.S.NE",
+ arm_ADD_S_CS: "ADD.S.CS",
+ arm_ADD_S_CC: "ADD.S.CC",
+ arm_ADD_S_MI: "ADD.S.MI",
+ arm_ADD_S_PL: "ADD.S.PL",
+ arm_ADD_S_VS: "ADD.S.VS",
+ arm_ADD_S_VC: "ADD.S.VC",
+ arm_ADD_S_HI: "ADD.S.HI",
+ arm_ADD_S_LS: "ADD.S.LS",
+ arm_ADD_S_GE: "ADD.S.GE",
+ arm_ADD_S_LT: "ADD.S.LT",
+ arm_ADD_S_GT: "ADD.S.GT",
+ arm_ADD_S_LE: "ADD.S.LE",
+ arm_ADD_S: "ADD.S",
+ arm_ADD_S_ZZ: "ADD.S.ZZ",
+ arm_AND_EQ: "AND.EQ",
+ arm_AND_NE: "AND.NE",
+ arm_AND_CS: "AND.CS",
+ arm_AND_CC: "AND.CC",
+ arm_AND_MI: "AND.MI",
+ arm_AND_PL: "AND.PL",
+ arm_AND_VS: "AND.VS",
+ arm_AND_VC: "AND.VC",
+ arm_AND_HI: "AND.HI",
+ arm_AND_LS: "AND.LS",
+ arm_AND_GE: "AND.GE",
+ arm_AND_LT: "AND.LT",
+ arm_AND_GT: "AND.GT",
+ arm_AND_LE: "AND.LE",
+ arm_AND: "AND",
+ arm_AND_ZZ: "AND.ZZ",
+ arm_AND_S_EQ: "AND.S.EQ",
+ arm_AND_S_NE: "AND.S.NE",
+ arm_AND_S_CS: "AND.S.CS",
+ arm_AND_S_CC: "AND.S.CC",
+ arm_AND_S_MI: "AND.S.MI",
+ arm_AND_S_PL: "AND.S.PL",
+ arm_AND_S_VS: "AND.S.VS",
+ arm_AND_S_VC: "AND.S.VC",
+ arm_AND_S_HI: "AND.S.HI",
+ arm_AND_S_LS: "AND.S.LS",
+ arm_AND_S_GE: "AND.S.GE",
+ arm_AND_S_LT: "AND.S.LT",
+ arm_AND_S_GT: "AND.S.GT",
+ arm_AND_S_LE: "AND.S.LE",
+ arm_AND_S: "AND.S",
+ arm_AND_S_ZZ: "AND.S.ZZ",
+ arm_ASR_EQ: "ASR.EQ",
+ arm_ASR_NE: "ASR.NE",
+ arm_ASR_CS: "ASR.CS",
+ arm_ASR_CC: "ASR.CC",
+ arm_ASR_MI: "ASR.MI",
+ arm_ASR_PL: "ASR.PL",
+ arm_ASR_VS: "ASR.VS",
+ arm_ASR_VC: "ASR.VC",
+ arm_ASR_HI: "ASR.HI",
+ arm_ASR_LS: "ASR.LS",
+ arm_ASR_GE: "ASR.GE",
+ arm_ASR_LT: "ASR.LT",
+ arm_ASR_GT: "ASR.GT",
+ arm_ASR_LE: "ASR.LE",
+ arm_ASR: "ASR",
+ arm_ASR_ZZ: "ASR.ZZ",
+ arm_ASR_S_EQ: "ASR.S.EQ",
+ arm_ASR_S_NE: "ASR.S.NE",
+ arm_ASR_S_CS: "ASR.S.CS",
+ arm_ASR_S_CC: "ASR.S.CC",
+ arm_ASR_S_MI: "ASR.S.MI",
+ arm_ASR_S_PL: "ASR.S.PL",
+ arm_ASR_S_VS: "ASR.S.VS",
+ arm_ASR_S_VC: "ASR.S.VC",
+ arm_ASR_S_HI: "ASR.S.HI",
+ arm_ASR_S_LS: "ASR.S.LS",
+ arm_ASR_S_GE: "ASR.S.GE",
+ arm_ASR_S_LT: "ASR.S.LT",
+ arm_ASR_S_GT: "ASR.S.GT",
+ arm_ASR_S_LE: "ASR.S.LE",
+ arm_ASR_S: "ASR.S",
+ arm_ASR_S_ZZ: "ASR.S.ZZ",
+ arm_B_EQ: "B.EQ",
+ arm_B_NE: "B.NE",
+ arm_B_CS: "B.CS",
+ arm_B_CC: "B.CC",
+ arm_B_MI: "B.MI",
+ arm_B_PL: "B.PL",
+ arm_B_VS: "B.VS",
+ arm_B_VC: "B.VC",
+ arm_B_HI: "B.HI",
+ arm_B_LS: "B.LS",
+ arm_B_GE: "B.GE",
+ arm_B_LT: "B.LT",
+ arm_B_GT: "B.GT",
+ arm_B_LE: "B.LE",
+ arm_B: "B",
+ arm_B_ZZ: "B.ZZ",
+ arm_BFC_EQ: "BFC.EQ",
+ arm_BFC_NE: "BFC.NE",
+ arm_BFC_CS: "BFC.CS",
+ arm_BFC_CC: "BFC.CC",
+ arm_BFC_MI: "BFC.MI",
+ arm_BFC_PL: "BFC.PL",
+ arm_BFC_VS: "BFC.VS",
+ arm_BFC_VC: "BFC.VC",
+ arm_BFC_HI: "BFC.HI",
+ arm_BFC_LS: "BFC.LS",
+ arm_BFC_GE: "BFC.GE",
+ arm_BFC_LT: "BFC.LT",
+ arm_BFC_GT: "BFC.GT",
+ arm_BFC_LE: "BFC.LE",
+ arm_BFC: "BFC",
+ arm_BFC_ZZ: "BFC.ZZ",
+ arm_BFI_EQ: "BFI.EQ",
+ arm_BFI_NE: "BFI.NE",
+ arm_BFI_CS: "BFI.CS",
+ arm_BFI_CC: "BFI.CC",
+ arm_BFI_MI: "BFI.MI",
+ arm_BFI_PL: "BFI.PL",
+ arm_BFI_VS: "BFI.VS",
+ arm_BFI_VC: "BFI.VC",
+ arm_BFI_HI: "BFI.HI",
+ arm_BFI_LS: "BFI.LS",
+ arm_BFI_GE: "BFI.GE",
+ arm_BFI_LT: "BFI.LT",
+ arm_BFI_GT: "BFI.GT",
+ arm_BFI_LE: "BFI.LE",
+ arm_BFI: "BFI",
+ arm_BFI_ZZ: "BFI.ZZ",
+ arm_BIC_EQ: "BIC.EQ",
+ arm_BIC_NE: "BIC.NE",
+ arm_BIC_CS: "BIC.CS",
+ arm_BIC_CC: "BIC.CC",
+ arm_BIC_MI: "BIC.MI",
+ arm_BIC_PL: "BIC.PL",
+ arm_BIC_VS: "BIC.VS",
+ arm_BIC_VC: "BIC.VC",
+ arm_BIC_HI: "BIC.HI",
+ arm_BIC_LS: "BIC.LS",
+ arm_BIC_GE: "BIC.GE",
+ arm_BIC_LT: "BIC.LT",
+ arm_BIC_GT: "BIC.GT",
+ arm_BIC_LE: "BIC.LE",
+ arm_BIC: "BIC",
+ arm_BIC_ZZ: "BIC.ZZ",
+ arm_BIC_S_EQ: "BIC.S.EQ",
+ arm_BIC_S_NE: "BIC.S.NE",
+ arm_BIC_S_CS: "BIC.S.CS",
+ arm_BIC_S_CC: "BIC.S.CC",
+ arm_BIC_S_MI: "BIC.S.MI",
+ arm_BIC_S_PL: "BIC.S.PL",
+ arm_BIC_S_VS: "BIC.S.VS",
+ arm_BIC_S_VC: "BIC.S.VC",
+ arm_BIC_S_HI: "BIC.S.HI",
+ arm_BIC_S_LS: "BIC.S.LS",
+ arm_BIC_S_GE: "BIC.S.GE",
+ arm_BIC_S_LT: "BIC.S.LT",
+ arm_BIC_S_GT: "BIC.S.GT",
+ arm_BIC_S_LE: "BIC.S.LE",
+ arm_BIC_S: "BIC.S",
+ arm_BIC_S_ZZ: "BIC.S.ZZ",
+ arm_BKPT_EQ: "BKPT.EQ",
+ arm_BKPT_NE: "BKPT.NE",
+ arm_BKPT_CS: "BKPT.CS",
+ arm_BKPT_CC: "BKPT.CC",
+ arm_BKPT_MI: "BKPT.MI",
+ arm_BKPT_PL: "BKPT.PL",
+ arm_BKPT_VS: "BKPT.VS",
+ arm_BKPT_VC: "BKPT.VC",
+ arm_BKPT_HI: "BKPT.HI",
+ arm_BKPT_LS: "BKPT.LS",
+ arm_BKPT_GE: "BKPT.GE",
+ arm_BKPT_LT: "BKPT.LT",
+ arm_BKPT_GT: "BKPT.GT",
+ arm_BKPT_LE: "BKPT.LE",
+ arm_BKPT: "BKPT",
+ arm_BKPT_ZZ: "BKPT.ZZ",
+ arm_BL_EQ: "BL.EQ",
+ arm_BL_NE: "BL.NE",
+ arm_BL_CS: "BL.CS",
+ arm_BL_CC: "BL.CC",
+ arm_BL_MI: "BL.MI",
+ arm_BL_PL: "BL.PL",
+ arm_BL_VS: "BL.VS",
+ arm_BL_VC: "BL.VC",
+ arm_BL_HI: "BL.HI",
+ arm_BL_LS: "BL.LS",
+ arm_BL_GE: "BL.GE",
+ arm_BL_LT: "BL.LT",
+ arm_BL_GT: "BL.GT",
+ arm_BL_LE: "BL.LE",
+ arm_BL: "BL",
+ arm_BL_ZZ: "BL.ZZ",
+ arm_BLX_EQ: "BLX.EQ",
+ arm_BLX_NE: "BLX.NE",
+ arm_BLX_CS: "BLX.CS",
+ arm_BLX_CC: "BLX.CC",
+ arm_BLX_MI: "BLX.MI",
+ arm_BLX_PL: "BLX.PL",
+ arm_BLX_VS: "BLX.VS",
+ arm_BLX_VC: "BLX.VC",
+ arm_BLX_HI: "BLX.HI",
+ arm_BLX_LS: "BLX.LS",
+ arm_BLX_GE: "BLX.GE",
+ arm_BLX_LT: "BLX.LT",
+ arm_BLX_GT: "BLX.GT",
+ arm_BLX_LE: "BLX.LE",
+ arm_BLX: "BLX",
+ arm_BLX_ZZ: "BLX.ZZ",
+ arm_BX_EQ: "BX.EQ",
+ arm_BX_NE: "BX.NE",
+ arm_BX_CS: "BX.CS",
+ arm_BX_CC: "BX.CC",
+ arm_BX_MI: "BX.MI",
+ arm_BX_PL: "BX.PL",
+ arm_BX_VS: "BX.VS",
+ arm_BX_VC: "BX.VC",
+ arm_BX_HI: "BX.HI",
+ arm_BX_LS: "BX.LS",
+ arm_BX_GE: "BX.GE",
+ arm_BX_LT: "BX.LT",
+ arm_BX_GT: "BX.GT",
+ arm_BX_LE: "BX.LE",
+ arm_BX: "BX",
+ arm_BX_ZZ: "BX.ZZ",
+ arm_BXJ_EQ: "BXJ.EQ",
+ arm_BXJ_NE: "BXJ.NE",
+ arm_BXJ_CS: "BXJ.CS",
+ arm_BXJ_CC: "BXJ.CC",
+ arm_BXJ_MI: "BXJ.MI",
+ arm_BXJ_PL: "BXJ.PL",
+ arm_BXJ_VS: "BXJ.VS",
+ arm_BXJ_VC: "BXJ.VC",
+ arm_BXJ_HI: "BXJ.HI",
+ arm_BXJ_LS: "BXJ.LS",
+ arm_BXJ_GE: "BXJ.GE",
+ arm_BXJ_LT: "BXJ.LT",
+ arm_BXJ_GT: "BXJ.GT",
+ arm_BXJ_LE: "BXJ.LE",
+ arm_BXJ: "BXJ",
+ arm_BXJ_ZZ: "BXJ.ZZ",
+ arm_CLREX: "CLREX",
+ arm_CLZ_EQ: "CLZ.EQ",
+ arm_CLZ_NE: "CLZ.NE",
+ arm_CLZ_CS: "CLZ.CS",
+ arm_CLZ_CC: "CLZ.CC",
+ arm_CLZ_MI: "CLZ.MI",
+ arm_CLZ_PL: "CLZ.PL",
+ arm_CLZ_VS: "CLZ.VS",
+ arm_CLZ_VC: "CLZ.VC",
+ arm_CLZ_HI: "CLZ.HI",
+ arm_CLZ_LS: "CLZ.LS",
+ arm_CLZ_GE: "CLZ.GE",
+ arm_CLZ_LT: "CLZ.LT",
+ arm_CLZ_GT: "CLZ.GT",
+ arm_CLZ_LE: "CLZ.LE",
+ arm_CLZ: "CLZ",
+ arm_CLZ_ZZ: "CLZ.ZZ",
+ arm_CMN_EQ: "CMN.EQ",
+ arm_CMN_NE: "CMN.NE",
+ arm_CMN_CS: "CMN.CS",
+ arm_CMN_CC: "CMN.CC",
+ arm_CMN_MI: "CMN.MI",
+ arm_CMN_PL: "CMN.PL",
+ arm_CMN_VS: "CMN.VS",
+ arm_CMN_VC: "CMN.VC",
+ arm_CMN_HI: "CMN.HI",
+ arm_CMN_LS: "CMN.LS",
+ arm_CMN_GE: "CMN.GE",
+ arm_CMN_LT: "CMN.LT",
+ arm_CMN_GT: "CMN.GT",
+ arm_CMN_LE: "CMN.LE",
+ arm_CMN: "CMN",
+ arm_CMN_ZZ: "CMN.ZZ",
+ arm_CMP_EQ: "CMP.EQ",
+ arm_CMP_NE: "CMP.NE",
+ arm_CMP_CS: "CMP.CS",
+ arm_CMP_CC: "CMP.CC",
+ arm_CMP_MI: "CMP.MI",
+ arm_CMP_PL: "CMP.PL",
+ arm_CMP_VS: "CMP.VS",
+ arm_CMP_VC: "CMP.VC",
+ arm_CMP_HI: "CMP.HI",
+ arm_CMP_LS: "CMP.LS",
+ arm_CMP_GE: "CMP.GE",
+ arm_CMP_LT: "CMP.LT",
+ arm_CMP_GT: "CMP.GT",
+ arm_CMP_LE: "CMP.LE",
+ arm_CMP: "CMP",
+ arm_CMP_ZZ: "CMP.ZZ",
+ arm_DBG_EQ: "DBG.EQ",
+ arm_DBG_NE: "DBG.NE",
+ arm_DBG_CS: "DBG.CS",
+ arm_DBG_CC: "DBG.CC",
+ arm_DBG_MI: "DBG.MI",
+ arm_DBG_PL: "DBG.PL",
+ arm_DBG_VS: "DBG.VS",
+ arm_DBG_VC: "DBG.VC",
+ arm_DBG_HI: "DBG.HI",
+ arm_DBG_LS: "DBG.LS",
+ arm_DBG_GE: "DBG.GE",
+ arm_DBG_LT: "DBG.LT",
+ arm_DBG_GT: "DBG.GT",
+ arm_DBG_LE: "DBG.LE",
+ arm_DBG: "DBG",
+ arm_DBG_ZZ: "DBG.ZZ",
+ arm_DMB: "DMB",
+ arm_DSB: "DSB",
+ arm_EOR_EQ: "EOR.EQ",
+ arm_EOR_NE: "EOR.NE",
+ arm_EOR_CS: "EOR.CS",
+ arm_EOR_CC: "EOR.CC",
+ arm_EOR_MI: "EOR.MI",
+ arm_EOR_PL: "EOR.PL",
+ arm_EOR_VS: "EOR.VS",
+ arm_EOR_VC: "EOR.VC",
+ arm_EOR_HI: "EOR.HI",
+ arm_EOR_LS: "EOR.LS",
+ arm_EOR_GE: "EOR.GE",
+ arm_EOR_LT: "EOR.LT",
+ arm_EOR_GT: "EOR.GT",
+ arm_EOR_LE: "EOR.LE",
+ arm_EOR: "EOR",
+ arm_EOR_ZZ: "EOR.ZZ",
+ arm_EOR_S_EQ: "EOR.S.EQ",
+ arm_EOR_S_NE: "EOR.S.NE",
+ arm_EOR_S_CS: "EOR.S.CS",
+ arm_EOR_S_CC: "EOR.S.CC",
+ arm_EOR_S_MI: "EOR.S.MI",
+ arm_EOR_S_PL: "EOR.S.PL",
+ arm_EOR_S_VS: "EOR.S.VS",
+ arm_EOR_S_VC: "EOR.S.VC",
+ arm_EOR_S_HI: "EOR.S.HI",
+ arm_EOR_S_LS: "EOR.S.LS",
+ arm_EOR_S_GE: "EOR.S.GE",
+ arm_EOR_S_LT: "EOR.S.LT",
+ arm_EOR_S_GT: "EOR.S.GT",
+ arm_EOR_S_LE: "EOR.S.LE",
+ arm_EOR_S: "EOR.S",
+ arm_EOR_S_ZZ: "EOR.S.ZZ",
+ arm_ISB: "ISB",
+ arm_LDM_EQ: "LDM.EQ",
+ arm_LDM_NE: "LDM.NE",
+ arm_LDM_CS: "LDM.CS",
+ arm_LDM_CC: "LDM.CC",
+ arm_LDM_MI: "LDM.MI",
+ arm_LDM_PL: "LDM.PL",
+ arm_LDM_VS: "LDM.VS",
+ arm_LDM_VC: "LDM.VC",
+ arm_LDM_HI: "LDM.HI",
+ arm_LDM_LS: "LDM.LS",
+ arm_LDM_GE: "LDM.GE",
+ arm_LDM_LT: "LDM.LT",
+ arm_LDM_GT: "LDM.GT",
+ arm_LDM_LE: "LDM.LE",
+ arm_LDM: "LDM",
+ arm_LDM_ZZ: "LDM.ZZ",
+ arm_LDMDA_EQ: "LDMDA.EQ",
+ arm_LDMDA_NE: "LDMDA.NE",
+ arm_LDMDA_CS: "LDMDA.CS",
+ arm_LDMDA_CC: "LDMDA.CC",
+ arm_LDMDA_MI: "LDMDA.MI",
+ arm_LDMDA_PL: "LDMDA.PL",
+ arm_LDMDA_VS: "LDMDA.VS",
+ arm_LDMDA_VC: "LDMDA.VC",
+ arm_LDMDA_HI: "LDMDA.HI",
+ arm_LDMDA_LS: "LDMDA.LS",
+ arm_LDMDA_GE: "LDMDA.GE",
+ arm_LDMDA_LT: "LDMDA.LT",
+ arm_LDMDA_GT: "LDMDA.GT",
+ arm_LDMDA_LE: "LDMDA.LE",
+ arm_LDMDA: "LDMDA",
+ arm_LDMDA_ZZ: "LDMDA.ZZ",
+ arm_LDMDB_EQ: "LDMDB.EQ",
+ arm_LDMDB_NE: "LDMDB.NE",
+ arm_LDMDB_CS: "LDMDB.CS",
+ arm_LDMDB_CC: "LDMDB.CC",
+ arm_LDMDB_MI: "LDMDB.MI",
+ arm_LDMDB_PL: "LDMDB.PL",
+ arm_LDMDB_VS: "LDMDB.VS",
+ arm_LDMDB_VC: "LDMDB.VC",
+ arm_LDMDB_HI: "LDMDB.HI",
+ arm_LDMDB_LS: "LDMDB.LS",
+ arm_LDMDB_GE: "LDMDB.GE",
+ arm_LDMDB_LT: "LDMDB.LT",
+ arm_LDMDB_GT: "LDMDB.GT",
+ arm_LDMDB_LE: "LDMDB.LE",
+ arm_LDMDB: "LDMDB",
+ arm_LDMDB_ZZ: "LDMDB.ZZ",
+ arm_LDMIB_EQ: "LDMIB.EQ",
+ arm_LDMIB_NE: "LDMIB.NE",
+ arm_LDMIB_CS: "LDMIB.CS",
+ arm_LDMIB_CC: "LDMIB.CC",
+ arm_LDMIB_MI: "LDMIB.MI",
+ arm_LDMIB_PL: "LDMIB.PL",
+ arm_LDMIB_VS: "LDMIB.VS",
+ arm_LDMIB_VC: "LDMIB.VC",
+ arm_LDMIB_HI: "LDMIB.HI",
+ arm_LDMIB_LS: "LDMIB.LS",
+ arm_LDMIB_GE: "LDMIB.GE",
+ arm_LDMIB_LT: "LDMIB.LT",
+ arm_LDMIB_GT: "LDMIB.GT",
+ arm_LDMIB_LE: "LDMIB.LE",
+ arm_LDMIB: "LDMIB",
+ arm_LDMIB_ZZ: "LDMIB.ZZ",
+ arm_LDR_EQ: "LDR.EQ",
+ arm_LDR_NE: "LDR.NE",
+ arm_LDR_CS: "LDR.CS",
+ arm_LDR_CC: "LDR.CC",
+ arm_LDR_MI: "LDR.MI",
+ arm_LDR_PL: "LDR.PL",
+ arm_LDR_VS: "LDR.VS",
+ arm_LDR_VC: "LDR.VC",
+ arm_LDR_HI: "LDR.HI",
+ arm_LDR_LS: "LDR.LS",
+ arm_LDR_GE: "LDR.GE",
+ arm_LDR_LT: "LDR.LT",
+ arm_LDR_GT: "LDR.GT",
+ arm_LDR_LE: "LDR.LE",
+ arm_LDR: "LDR",
+ arm_LDR_ZZ: "LDR.ZZ",
+ arm_LDRB_EQ: "LDRB.EQ",
+ arm_LDRB_NE: "LDRB.NE",
+ arm_LDRB_CS: "LDRB.CS",
+ arm_LDRB_CC: "LDRB.CC",
+ arm_LDRB_MI: "LDRB.MI",
+ arm_LDRB_PL: "LDRB.PL",
+ arm_LDRB_VS: "LDRB.VS",
+ arm_LDRB_VC: "LDRB.VC",
+ arm_LDRB_HI: "LDRB.HI",
+ arm_LDRB_LS: "LDRB.LS",
+ arm_LDRB_GE: "LDRB.GE",
+ arm_LDRB_LT: "LDRB.LT",
+ arm_LDRB_GT: "LDRB.GT",
+ arm_LDRB_LE: "LDRB.LE",
+ arm_LDRB: "LDRB",
+ arm_LDRB_ZZ: "LDRB.ZZ",
+ arm_LDRBT_EQ: "LDRBT.EQ",
+ arm_LDRBT_NE: "LDRBT.NE",
+ arm_LDRBT_CS: "LDRBT.CS",
+ arm_LDRBT_CC: "LDRBT.CC",
+ arm_LDRBT_MI: "LDRBT.MI",
+ arm_LDRBT_PL: "LDRBT.PL",
+ arm_LDRBT_VS: "LDRBT.VS",
+ arm_LDRBT_VC: "LDRBT.VC",
+ arm_LDRBT_HI: "LDRBT.HI",
+ arm_LDRBT_LS: "LDRBT.LS",
+ arm_LDRBT_GE: "LDRBT.GE",
+ arm_LDRBT_LT: "LDRBT.LT",
+ arm_LDRBT_GT: "LDRBT.GT",
+ arm_LDRBT_LE: "LDRBT.LE",
+ arm_LDRBT: "LDRBT",
+ arm_LDRBT_ZZ: "LDRBT.ZZ",
+ arm_LDRD_EQ: "LDRD.EQ",
+ arm_LDRD_NE: "LDRD.NE",
+ arm_LDRD_CS: "LDRD.CS",
+ arm_LDRD_CC: "LDRD.CC",
+ arm_LDRD_MI: "LDRD.MI",
+ arm_LDRD_PL: "LDRD.PL",
+ arm_LDRD_VS: "LDRD.VS",
+ arm_LDRD_VC: "LDRD.VC",
+ arm_LDRD_HI: "LDRD.HI",
+ arm_LDRD_LS: "LDRD.LS",
+ arm_LDRD_GE: "LDRD.GE",
+ arm_LDRD_LT: "LDRD.LT",
+ arm_LDRD_GT: "LDRD.GT",
+ arm_LDRD_LE: "LDRD.LE",
+ arm_LDRD: "LDRD",
+ arm_LDRD_ZZ: "LDRD.ZZ",
+ arm_LDREX_EQ: "LDREX.EQ",
+ arm_LDREX_NE: "LDREX.NE",
+ arm_LDREX_CS: "LDREX.CS",
+ arm_LDREX_CC: "LDREX.CC",
+ arm_LDREX_MI: "LDREX.MI",
+ arm_LDREX_PL: "LDREX.PL",
+ arm_LDREX_VS: "LDREX.VS",
+ arm_LDREX_VC: "LDREX.VC",
+ arm_LDREX_HI: "LDREX.HI",
+ arm_LDREX_LS: "LDREX.LS",
+ arm_LDREX_GE: "LDREX.GE",
+ arm_LDREX_LT: "LDREX.LT",
+ arm_LDREX_GT: "LDREX.GT",
+ arm_LDREX_LE: "LDREX.LE",
+ arm_LDREX: "LDREX",
+ arm_LDREX_ZZ: "LDREX.ZZ",
+ arm_LDREXB_EQ: "LDREXB.EQ",
+ arm_LDREXB_NE: "LDREXB.NE",
+ arm_LDREXB_CS: "LDREXB.CS",
+ arm_LDREXB_CC: "LDREXB.CC",
+ arm_LDREXB_MI: "LDREXB.MI",
+ arm_LDREXB_PL: "LDREXB.PL",
+ arm_LDREXB_VS: "LDREXB.VS",
+ arm_LDREXB_VC: "LDREXB.VC",
+ arm_LDREXB_HI: "LDREXB.HI",
+ arm_LDREXB_LS: "LDREXB.LS",
+ arm_LDREXB_GE: "LDREXB.GE",
+ arm_LDREXB_LT: "LDREXB.LT",
+ arm_LDREXB_GT: "LDREXB.GT",
+ arm_LDREXB_LE: "LDREXB.LE",
+ arm_LDREXB: "LDREXB",
+ arm_LDREXB_ZZ: "LDREXB.ZZ",
+ arm_LDREXD_EQ: "LDREXD.EQ",
+ arm_LDREXD_NE: "LDREXD.NE",
+ arm_LDREXD_CS: "LDREXD.CS",
+ arm_LDREXD_CC: "LDREXD.CC",
+ arm_LDREXD_MI: "LDREXD.MI",
+ arm_LDREXD_PL: "LDREXD.PL",
+ arm_LDREXD_VS: "LDREXD.VS",
+ arm_LDREXD_VC: "LDREXD.VC",
+ arm_LDREXD_HI: "LDREXD.HI",
+ arm_LDREXD_LS: "LDREXD.LS",
+ arm_LDREXD_GE: "LDREXD.GE",
+ arm_LDREXD_LT: "LDREXD.LT",
+ arm_LDREXD_GT: "LDREXD.GT",
+ arm_LDREXD_LE: "LDREXD.LE",
+ arm_LDREXD: "LDREXD",
+ arm_LDREXD_ZZ: "LDREXD.ZZ",
+ arm_LDREXH_EQ: "LDREXH.EQ",
+ arm_LDREXH_NE: "LDREXH.NE",
+ arm_LDREXH_CS: "LDREXH.CS",
+ arm_LDREXH_CC: "LDREXH.CC",
+ arm_LDREXH_MI: "LDREXH.MI",
+ arm_LDREXH_PL: "LDREXH.PL",
+ arm_LDREXH_VS: "LDREXH.VS",
+ arm_LDREXH_VC: "LDREXH.VC",
+ arm_LDREXH_HI: "LDREXH.HI",
+ arm_LDREXH_LS: "LDREXH.LS",
+ arm_LDREXH_GE: "LDREXH.GE",
+ arm_LDREXH_LT: "LDREXH.LT",
+ arm_LDREXH_GT: "LDREXH.GT",
+ arm_LDREXH_LE: "LDREXH.LE",
+ arm_LDREXH: "LDREXH",
+ arm_LDREXH_ZZ: "LDREXH.ZZ",
+ arm_LDRH_EQ: "LDRH.EQ",
+ arm_LDRH_NE: "LDRH.NE",
+ arm_LDRH_CS: "LDRH.CS",
+ arm_LDRH_CC: "LDRH.CC",
+ arm_LDRH_MI: "LDRH.MI",
+ arm_LDRH_PL: "LDRH.PL",
+ arm_LDRH_VS: "LDRH.VS",
+ arm_LDRH_VC: "LDRH.VC",
+ arm_LDRH_HI: "LDRH.HI",
+ arm_LDRH_LS: "LDRH.LS",
+ arm_LDRH_GE: "LDRH.GE",
+ arm_LDRH_LT: "LDRH.LT",
+ arm_LDRH_GT: "LDRH.GT",
+ arm_LDRH_LE: "LDRH.LE",
+ arm_LDRH: "LDRH",
+ arm_LDRH_ZZ: "LDRH.ZZ",
+ arm_LDRHT_EQ: "LDRHT.EQ",
+ arm_LDRHT_NE: "LDRHT.NE",
+ arm_LDRHT_CS: "LDRHT.CS",
+ arm_LDRHT_CC: "LDRHT.CC",
+ arm_LDRHT_MI: "LDRHT.MI",
+ arm_LDRHT_PL: "LDRHT.PL",
+ arm_LDRHT_VS: "LDRHT.VS",
+ arm_LDRHT_VC: "LDRHT.VC",
+ arm_LDRHT_HI: "LDRHT.HI",
+ arm_LDRHT_LS: "LDRHT.LS",
+ arm_LDRHT_GE: "LDRHT.GE",
+ arm_LDRHT_LT: "LDRHT.LT",
+ arm_LDRHT_GT: "LDRHT.GT",
+ arm_LDRHT_LE: "LDRHT.LE",
+ arm_LDRHT: "LDRHT",
+ arm_LDRHT_ZZ: "LDRHT.ZZ",
+ arm_LDRSB_EQ: "LDRSB.EQ",
+ arm_LDRSB_NE: "LDRSB.NE",
+ arm_LDRSB_CS: "LDRSB.CS",
+ arm_LDRSB_CC: "LDRSB.CC",
+ arm_LDRSB_MI: "LDRSB.MI",
+ arm_LDRSB_PL: "LDRSB.PL",
+ arm_LDRSB_VS: "LDRSB.VS",
+ arm_LDRSB_VC: "LDRSB.VC",
+ arm_LDRSB_HI: "LDRSB.HI",
+ arm_LDRSB_LS: "LDRSB.LS",
+ arm_LDRSB_GE: "LDRSB.GE",
+ arm_LDRSB_LT: "LDRSB.LT",
+ arm_LDRSB_GT: "LDRSB.GT",
+ arm_LDRSB_LE: "LDRSB.LE",
+ arm_LDRSB: "LDRSB",
+ arm_LDRSB_ZZ: "LDRSB.ZZ",
+ arm_LDRSBT_EQ: "LDRSBT.EQ",
+ arm_LDRSBT_NE: "LDRSBT.NE",
+ arm_LDRSBT_CS: "LDRSBT.CS",
+ arm_LDRSBT_CC: "LDRSBT.CC",
+ arm_LDRSBT_MI: "LDRSBT.MI",
+ arm_LDRSBT_PL: "LDRSBT.PL",
+ arm_LDRSBT_VS: "LDRSBT.VS",
+ arm_LDRSBT_VC: "LDRSBT.VC",
+ arm_LDRSBT_HI: "LDRSBT.HI",
+ arm_LDRSBT_LS: "LDRSBT.LS",
+ arm_LDRSBT_GE: "LDRSBT.GE",
+ arm_LDRSBT_LT: "LDRSBT.LT",
+ arm_LDRSBT_GT: "LDRSBT.GT",
+ arm_LDRSBT_LE: "LDRSBT.LE",
+ arm_LDRSBT: "LDRSBT",
+ arm_LDRSBT_ZZ: "LDRSBT.ZZ",
+ arm_LDRSH_EQ: "LDRSH.EQ",
+ arm_LDRSH_NE: "LDRSH.NE",
+ arm_LDRSH_CS: "LDRSH.CS",
+ arm_LDRSH_CC: "LDRSH.CC",
+ arm_LDRSH_MI: "LDRSH.MI",
+ arm_LDRSH_PL: "LDRSH.PL",
+ arm_LDRSH_VS: "LDRSH.VS",
+ arm_LDRSH_VC: "LDRSH.VC",
+ arm_LDRSH_HI: "LDRSH.HI",
+ arm_LDRSH_LS: "LDRSH.LS",
+ arm_LDRSH_GE: "LDRSH.GE",
+ arm_LDRSH_LT: "LDRSH.LT",
+ arm_LDRSH_GT: "LDRSH.GT",
+ arm_LDRSH_LE: "LDRSH.LE",
+ arm_LDRSH: "LDRSH",
+ arm_LDRSH_ZZ: "LDRSH.ZZ",
+ arm_LDRSHT_EQ: "LDRSHT.EQ",
+ arm_LDRSHT_NE: "LDRSHT.NE",
+ arm_LDRSHT_CS: "LDRSHT.CS",
+ arm_LDRSHT_CC: "LDRSHT.CC",
+ arm_LDRSHT_MI: "LDRSHT.MI",
+ arm_LDRSHT_PL: "LDRSHT.PL",
+ arm_LDRSHT_VS: "LDRSHT.VS",
+ arm_LDRSHT_VC: "LDRSHT.VC",
+ arm_LDRSHT_HI: "LDRSHT.HI",
+ arm_LDRSHT_LS: "LDRSHT.LS",
+ arm_LDRSHT_GE: "LDRSHT.GE",
+ arm_LDRSHT_LT: "LDRSHT.LT",
+ arm_LDRSHT_GT: "LDRSHT.GT",
+ arm_LDRSHT_LE: "LDRSHT.LE",
+ arm_LDRSHT: "LDRSHT",
+ arm_LDRSHT_ZZ: "LDRSHT.ZZ",
+ arm_LDRT_EQ: "LDRT.EQ",
+ arm_LDRT_NE: "LDRT.NE",
+ arm_LDRT_CS: "LDRT.CS",
+ arm_LDRT_CC: "LDRT.CC",
+ arm_LDRT_MI: "LDRT.MI",
+ arm_LDRT_PL: "LDRT.PL",
+ arm_LDRT_VS: "LDRT.VS",
+ arm_LDRT_VC: "LDRT.VC",
+ arm_LDRT_HI: "LDRT.HI",
+ arm_LDRT_LS: "LDRT.LS",
+ arm_LDRT_GE: "LDRT.GE",
+ arm_LDRT_LT: "LDRT.LT",
+ arm_LDRT_GT: "LDRT.GT",
+ arm_LDRT_LE: "LDRT.LE",
+ arm_LDRT: "LDRT",
+ arm_LDRT_ZZ: "LDRT.ZZ",
+ arm_LSL_EQ: "LSL.EQ",
+ arm_LSL_NE: "LSL.NE",
+ arm_LSL_CS: "LSL.CS",
+ arm_LSL_CC: "LSL.CC",
+ arm_LSL_MI: "LSL.MI",
+ arm_LSL_PL: "LSL.PL",
+ arm_LSL_VS: "LSL.VS",
+ arm_LSL_VC: "LSL.VC",
+ arm_LSL_HI: "LSL.HI",
+ arm_LSL_LS: "LSL.LS",
+ arm_LSL_GE: "LSL.GE",
+ arm_LSL_LT: "LSL.LT",
+ arm_LSL_GT: "LSL.GT",
+ arm_LSL_LE: "LSL.LE",
+ arm_LSL: "LSL",
+ arm_LSL_ZZ: "LSL.ZZ",
+ arm_LSL_S_EQ: "LSL.S.EQ",
+ arm_LSL_S_NE: "LSL.S.NE",
+ arm_LSL_S_CS: "LSL.S.CS",
+ arm_LSL_S_CC: "LSL.S.CC",
+ arm_LSL_S_MI: "LSL.S.MI",
+ arm_LSL_S_PL: "LSL.S.PL",
+ arm_LSL_S_VS: "LSL.S.VS",
+ arm_LSL_S_VC: "LSL.S.VC",
+ arm_LSL_S_HI: "LSL.S.HI",
+ arm_LSL_S_LS: "LSL.S.LS",
+ arm_LSL_S_GE: "LSL.S.GE",
+ arm_LSL_S_LT: "LSL.S.LT",
+ arm_LSL_S_GT: "LSL.S.GT",
+ arm_LSL_S_LE: "LSL.S.LE",
+ arm_LSL_S: "LSL.S",
+ arm_LSL_S_ZZ: "LSL.S.ZZ",
+ arm_LSR_EQ: "LSR.EQ",
+ arm_LSR_NE: "LSR.NE",
+ arm_LSR_CS: "LSR.CS",
+ arm_LSR_CC: "LSR.CC",
+ arm_LSR_MI: "LSR.MI",
+ arm_LSR_PL: "LSR.PL",
+ arm_LSR_VS: "LSR.VS",
+ arm_LSR_VC: "LSR.VC",
+ arm_LSR_HI: "LSR.HI",
+ arm_LSR_LS: "LSR.LS",
+ arm_LSR_GE: "LSR.GE",
+ arm_LSR_LT: "LSR.LT",
+ arm_LSR_GT: "LSR.GT",
+ arm_LSR_LE: "LSR.LE",
+ arm_LSR: "LSR",
+ arm_LSR_ZZ: "LSR.ZZ",
+ arm_LSR_S_EQ: "LSR.S.EQ",
+ arm_LSR_S_NE: "LSR.S.NE",
+ arm_LSR_S_CS: "LSR.S.CS",
+ arm_LSR_S_CC: "LSR.S.CC",
+ arm_LSR_S_MI: "LSR.S.MI",
+ arm_LSR_S_PL: "LSR.S.PL",
+ arm_LSR_S_VS: "LSR.S.VS",
+ arm_LSR_S_VC: "LSR.S.VC",
+ arm_LSR_S_HI: "LSR.S.HI",
+ arm_LSR_S_LS: "LSR.S.LS",
+ arm_LSR_S_GE: "LSR.S.GE",
+ arm_LSR_S_LT: "LSR.S.LT",
+ arm_LSR_S_GT: "LSR.S.GT",
+ arm_LSR_S_LE: "LSR.S.LE",
+ arm_LSR_S: "LSR.S",
+ arm_LSR_S_ZZ: "LSR.S.ZZ",
+ arm_MLA_EQ: "MLA.EQ",
+ arm_MLA_NE: "MLA.NE",
+ arm_MLA_CS: "MLA.CS",
+ arm_MLA_CC: "MLA.CC",
+ arm_MLA_MI: "MLA.MI",
+ arm_MLA_PL: "MLA.PL",
+ arm_MLA_VS: "MLA.VS",
+ arm_MLA_VC: "MLA.VC",
+ arm_MLA_HI: "MLA.HI",
+ arm_MLA_LS: "MLA.LS",
+ arm_MLA_GE: "MLA.GE",
+ arm_MLA_LT: "MLA.LT",
+ arm_MLA_GT: "MLA.GT",
+ arm_MLA_LE: "MLA.LE",
+ arm_MLA: "MLA",
+ arm_MLA_ZZ: "MLA.ZZ",
+ arm_MLA_S_EQ: "MLA.S.EQ",
+ arm_MLA_S_NE: "MLA.S.NE",
+ arm_MLA_S_CS: "MLA.S.CS",
+ arm_MLA_S_CC: "MLA.S.CC",
+ arm_MLA_S_MI: "MLA.S.MI",
+ arm_MLA_S_PL: "MLA.S.PL",
+ arm_MLA_S_VS: "MLA.S.VS",
+ arm_MLA_S_VC: "MLA.S.VC",
+ arm_MLA_S_HI: "MLA.S.HI",
+ arm_MLA_S_LS: "MLA.S.LS",
+ arm_MLA_S_GE: "MLA.S.GE",
+ arm_MLA_S_LT: "MLA.S.LT",
+ arm_MLA_S_GT: "MLA.S.GT",
+ arm_MLA_S_LE: "MLA.S.LE",
+ arm_MLA_S: "MLA.S",
+ arm_MLA_S_ZZ: "MLA.S.ZZ",
+ arm_MLS_EQ: "MLS.EQ",
+ arm_MLS_NE: "MLS.NE",
+ arm_MLS_CS: "MLS.CS",
+ arm_MLS_CC: "MLS.CC",
+ arm_MLS_MI: "MLS.MI",
+ arm_MLS_PL: "MLS.PL",
+ arm_MLS_VS: "MLS.VS",
+ arm_MLS_VC: "MLS.VC",
+ arm_MLS_HI: "MLS.HI",
+ arm_MLS_LS: "MLS.LS",
+ arm_MLS_GE: "MLS.GE",
+ arm_MLS_LT: "MLS.LT",
+ arm_MLS_GT: "MLS.GT",
+ arm_MLS_LE: "MLS.LE",
+ arm_MLS: "MLS",
+ arm_MLS_ZZ: "MLS.ZZ",
+ arm_MOV_EQ: "MOV.EQ",
+ arm_MOV_NE: "MOV.NE",
+ arm_MOV_CS: "MOV.CS",
+ arm_MOV_CC: "MOV.CC",
+ arm_MOV_MI: "MOV.MI",
+ arm_MOV_PL: "MOV.PL",
+ arm_MOV_VS: "MOV.VS",
+ arm_MOV_VC: "MOV.VC",
+ arm_MOV_HI: "MOV.HI",
+ arm_MOV_LS: "MOV.LS",
+ arm_MOV_GE: "MOV.GE",
+ arm_MOV_LT: "MOV.LT",
+ arm_MOV_GT: "MOV.GT",
+ arm_MOV_LE: "MOV.LE",
+ arm_MOV: "MOV",
+ arm_MOV_ZZ: "MOV.ZZ",
+ arm_MOV_S_EQ: "MOV.S.EQ",
+ arm_MOV_S_NE: "MOV.S.NE",
+ arm_MOV_S_CS: "MOV.S.CS",
+ arm_MOV_S_CC: "MOV.S.CC",
+ arm_MOV_S_MI: "MOV.S.MI",
+ arm_MOV_S_PL: "MOV.S.PL",
+ arm_MOV_S_VS: "MOV.S.VS",
+ arm_MOV_S_VC: "MOV.S.VC",
+ arm_MOV_S_HI: "MOV.S.HI",
+ arm_MOV_S_LS: "MOV.S.LS",
+ arm_MOV_S_GE: "MOV.S.GE",
+ arm_MOV_S_LT: "MOV.S.LT",
+ arm_MOV_S_GT: "MOV.S.GT",
+ arm_MOV_S_LE: "MOV.S.LE",
+ arm_MOV_S: "MOV.S",
+ arm_MOV_S_ZZ: "MOV.S.ZZ",
+ arm_MOVT_EQ: "MOVT.EQ",
+ arm_MOVT_NE: "MOVT.NE",
+ arm_MOVT_CS: "MOVT.CS",
+ arm_MOVT_CC: "MOVT.CC",
+ arm_MOVT_MI: "MOVT.MI",
+ arm_MOVT_PL: "MOVT.PL",
+ arm_MOVT_VS: "MOVT.VS",
+ arm_MOVT_VC: "MOVT.VC",
+ arm_MOVT_HI: "MOVT.HI",
+ arm_MOVT_LS: "MOVT.LS",
+ arm_MOVT_GE: "MOVT.GE",
+ arm_MOVT_LT: "MOVT.LT",
+ arm_MOVT_GT: "MOVT.GT",
+ arm_MOVT_LE: "MOVT.LE",
+ arm_MOVT: "MOVT",
+ arm_MOVT_ZZ: "MOVT.ZZ",
+ arm_MOVW_EQ: "MOVW.EQ",
+ arm_MOVW_NE: "MOVW.NE",
+ arm_MOVW_CS: "MOVW.CS",
+ arm_MOVW_CC: "MOVW.CC",
+ arm_MOVW_MI: "MOVW.MI",
+ arm_MOVW_PL: "MOVW.PL",
+ arm_MOVW_VS: "MOVW.VS",
+ arm_MOVW_VC: "MOVW.VC",
+ arm_MOVW_HI: "MOVW.HI",
+ arm_MOVW_LS: "MOVW.LS",
+ arm_MOVW_GE: "MOVW.GE",
+ arm_MOVW_LT: "MOVW.LT",
+ arm_MOVW_GT: "MOVW.GT",
+ arm_MOVW_LE: "MOVW.LE",
+ arm_MOVW: "MOVW",
+ arm_MOVW_ZZ: "MOVW.ZZ",
+ arm_MRS_EQ: "MRS.EQ",
+ arm_MRS_NE: "MRS.NE",
+ arm_MRS_CS: "MRS.CS",
+ arm_MRS_CC: "MRS.CC",
+ arm_MRS_MI: "MRS.MI",
+ arm_MRS_PL: "MRS.PL",
+ arm_MRS_VS: "MRS.VS",
+ arm_MRS_VC: "MRS.VC",
+ arm_MRS_HI: "MRS.HI",
+ arm_MRS_LS: "MRS.LS",
+ arm_MRS_GE: "MRS.GE",
+ arm_MRS_LT: "MRS.LT",
+ arm_MRS_GT: "MRS.GT",
+ arm_MRS_LE: "MRS.LE",
+ arm_MRS: "MRS",
+ arm_MRS_ZZ: "MRS.ZZ",
+ arm_MUL_EQ: "MUL.EQ",
+ arm_MUL_NE: "MUL.NE",
+ arm_MUL_CS: "MUL.CS",
+ arm_MUL_CC: "MUL.CC",
+ arm_MUL_MI: "MUL.MI",
+ arm_MUL_PL: "MUL.PL",
+ arm_MUL_VS: "MUL.VS",
+ arm_MUL_VC: "MUL.VC",
+ arm_MUL_HI: "MUL.HI",
+ arm_MUL_LS: "MUL.LS",
+ arm_MUL_GE: "MUL.GE",
+ arm_MUL_LT: "MUL.LT",
+ arm_MUL_GT: "MUL.GT",
+ arm_MUL_LE: "MUL.LE",
+ arm_MUL: "MUL",
+ arm_MUL_ZZ: "MUL.ZZ",
+ arm_MUL_S_EQ: "MUL.S.EQ",
+ arm_MUL_S_NE: "MUL.S.NE",
+ arm_MUL_S_CS: "MUL.S.CS",
+ arm_MUL_S_CC: "MUL.S.CC",
+ arm_MUL_S_MI: "MUL.S.MI",
+ arm_MUL_S_PL: "MUL.S.PL",
+ arm_MUL_S_VS: "MUL.S.VS",
+ arm_MUL_S_VC: "MUL.S.VC",
+ arm_MUL_S_HI: "MUL.S.HI",
+ arm_MUL_S_LS: "MUL.S.LS",
+ arm_MUL_S_GE: "MUL.S.GE",
+ arm_MUL_S_LT: "MUL.S.LT",
+ arm_MUL_S_GT: "MUL.S.GT",
+ arm_MUL_S_LE: "MUL.S.LE",
+ arm_MUL_S: "MUL.S",
+ arm_MUL_S_ZZ: "MUL.S.ZZ",
+ arm_MVN_EQ: "MVN.EQ",
+ arm_MVN_NE: "MVN.NE",
+ arm_MVN_CS: "MVN.CS",
+ arm_MVN_CC: "MVN.CC",
+ arm_MVN_MI: "MVN.MI",
+ arm_MVN_PL: "MVN.PL",
+ arm_MVN_VS: "MVN.VS",
+ arm_MVN_VC: "MVN.VC",
+ arm_MVN_HI: "MVN.HI",
+ arm_MVN_LS: "MVN.LS",
+ arm_MVN_GE: "MVN.GE",
+ arm_MVN_LT: "MVN.LT",
+ arm_MVN_GT: "MVN.GT",
+ arm_MVN_LE: "MVN.LE",
+ arm_MVN: "MVN",
+ arm_MVN_ZZ: "MVN.ZZ",
+ arm_MVN_S_EQ: "MVN.S.EQ",
+ arm_MVN_S_NE: "MVN.S.NE",
+ arm_MVN_S_CS: "MVN.S.CS",
+ arm_MVN_S_CC: "MVN.S.CC",
+ arm_MVN_S_MI: "MVN.S.MI",
+ arm_MVN_S_PL: "MVN.S.PL",
+ arm_MVN_S_VS: "MVN.S.VS",
+ arm_MVN_S_VC: "MVN.S.VC",
+ arm_MVN_S_HI: "MVN.S.HI",
+ arm_MVN_S_LS: "MVN.S.LS",
+ arm_MVN_S_GE: "MVN.S.GE",
+ arm_MVN_S_LT: "MVN.S.LT",
+ arm_MVN_S_GT: "MVN.S.GT",
+ arm_MVN_S_LE: "MVN.S.LE",
+ arm_MVN_S: "MVN.S",
+ arm_MVN_S_ZZ: "MVN.S.ZZ",
+ arm_NOP_EQ: "NOP.EQ",
+ arm_NOP_NE: "NOP.NE",
+ arm_NOP_CS: "NOP.CS",
+ arm_NOP_CC: "NOP.CC",
+ arm_NOP_MI: "NOP.MI",
+ arm_NOP_PL: "NOP.PL",
+ arm_NOP_VS: "NOP.VS",
+ arm_NOP_VC: "NOP.VC",
+ arm_NOP_HI: "NOP.HI",
+ arm_NOP_LS: "NOP.LS",
+ arm_NOP_GE: "NOP.GE",
+ arm_NOP_LT: "NOP.LT",
+ arm_NOP_GT: "NOP.GT",
+ arm_NOP_LE: "NOP.LE",
+ arm_NOP: "NOP",
+ arm_NOP_ZZ: "NOP.ZZ",
+ arm_ORR_EQ: "ORR.EQ",
+ arm_ORR_NE: "ORR.NE",
+ arm_ORR_CS: "ORR.CS",
+ arm_ORR_CC: "ORR.CC",
+ arm_ORR_MI: "ORR.MI",
+ arm_ORR_PL: "ORR.PL",
+ arm_ORR_VS: "ORR.VS",
+ arm_ORR_VC: "ORR.VC",
+ arm_ORR_HI: "ORR.HI",
+ arm_ORR_LS: "ORR.LS",
+ arm_ORR_GE: "ORR.GE",
+ arm_ORR_LT: "ORR.LT",
+ arm_ORR_GT: "ORR.GT",
+ arm_ORR_LE: "ORR.LE",
+ arm_ORR: "ORR",
+ arm_ORR_ZZ: "ORR.ZZ",
+ arm_ORR_S_EQ: "ORR.S.EQ",
+ arm_ORR_S_NE: "ORR.S.NE",
+ arm_ORR_S_CS: "ORR.S.CS",
+ arm_ORR_S_CC: "ORR.S.CC",
+ arm_ORR_S_MI: "ORR.S.MI",
+ arm_ORR_S_PL: "ORR.S.PL",
+ arm_ORR_S_VS: "ORR.S.VS",
+ arm_ORR_S_VC: "ORR.S.VC",
+ arm_ORR_S_HI: "ORR.S.HI",
+ arm_ORR_S_LS: "ORR.S.LS",
+ arm_ORR_S_GE: "ORR.S.GE",
+ arm_ORR_S_LT: "ORR.S.LT",
+ arm_ORR_S_GT: "ORR.S.GT",
+ arm_ORR_S_LE: "ORR.S.LE",
+ arm_ORR_S: "ORR.S",
+ arm_ORR_S_ZZ: "ORR.S.ZZ",
+ arm_PKHBT_EQ: "PKHBT.EQ",
+ arm_PKHBT_NE: "PKHBT.NE",
+ arm_PKHBT_CS: "PKHBT.CS",
+ arm_PKHBT_CC: "PKHBT.CC",
+ arm_PKHBT_MI: "PKHBT.MI",
+ arm_PKHBT_PL: "PKHBT.PL",
+ arm_PKHBT_VS: "PKHBT.VS",
+ arm_PKHBT_VC: "PKHBT.VC",
+ arm_PKHBT_HI: "PKHBT.HI",
+ arm_PKHBT_LS: "PKHBT.LS",
+ arm_PKHBT_GE: "PKHBT.GE",
+ arm_PKHBT_LT: "PKHBT.LT",
+ arm_PKHBT_GT: "PKHBT.GT",
+ arm_PKHBT_LE: "PKHBT.LE",
+ arm_PKHBT: "PKHBT",
+ arm_PKHBT_ZZ: "PKHBT.ZZ",
+ arm_PKHTB_EQ: "PKHTB.EQ",
+ arm_PKHTB_NE: "PKHTB.NE",
+ arm_PKHTB_CS: "PKHTB.CS",
+ arm_PKHTB_CC: "PKHTB.CC",
+ arm_PKHTB_MI: "PKHTB.MI",
+ arm_PKHTB_PL: "PKHTB.PL",
+ arm_PKHTB_VS: "PKHTB.VS",
+ arm_PKHTB_VC: "PKHTB.VC",
+ arm_PKHTB_HI: "PKHTB.HI",
+ arm_PKHTB_LS: "PKHTB.LS",
+ arm_PKHTB_GE: "PKHTB.GE",
+ arm_PKHTB_LT: "PKHTB.LT",
+ arm_PKHTB_GT: "PKHTB.GT",
+ arm_PKHTB_LE: "PKHTB.LE",
+ arm_PKHTB: "PKHTB",
+ arm_PKHTB_ZZ: "PKHTB.ZZ",
+ arm_PLD_W: "PLD.W",
+ arm_PLD: "PLD",
+ arm_PLI: "PLI",
+ arm_POP_EQ: "POP.EQ",
+ arm_POP_NE: "POP.NE",
+ arm_POP_CS: "POP.CS",
+ arm_POP_CC: "POP.CC",
+ arm_POP_MI: "POP.MI",
+ arm_POP_PL: "POP.PL",
+ arm_POP_VS: "POP.VS",
+ arm_POP_VC: "POP.VC",
+ arm_POP_HI: "POP.HI",
+ arm_POP_LS: "POP.LS",
+ arm_POP_GE: "POP.GE",
+ arm_POP_LT: "POP.LT",
+ arm_POP_GT: "POP.GT",
+ arm_POP_LE: "POP.LE",
+ arm_POP: "POP",
+ arm_POP_ZZ: "POP.ZZ",
+ arm_PUSH_EQ: "PUSH.EQ",
+ arm_PUSH_NE: "PUSH.NE",
+ arm_PUSH_CS: "PUSH.CS",
+ arm_PUSH_CC: "PUSH.CC",
+ arm_PUSH_MI: "PUSH.MI",
+ arm_PUSH_PL: "PUSH.PL",
+ arm_PUSH_VS: "PUSH.VS",
+ arm_PUSH_VC: "PUSH.VC",
+ arm_PUSH_HI: "PUSH.HI",
+ arm_PUSH_LS: "PUSH.LS",
+ arm_PUSH_GE: "PUSH.GE",
+ arm_PUSH_LT: "PUSH.LT",
+ arm_PUSH_GT: "PUSH.GT",
+ arm_PUSH_LE: "PUSH.LE",
+ arm_PUSH: "PUSH",
+ arm_PUSH_ZZ: "PUSH.ZZ",
+ arm_QADD_EQ: "QADD.EQ",
+ arm_QADD_NE: "QADD.NE",
+ arm_QADD_CS: "QADD.CS",
+ arm_QADD_CC: "QADD.CC",
+ arm_QADD_MI: "QADD.MI",
+ arm_QADD_PL: "QADD.PL",
+ arm_QADD_VS: "QADD.VS",
+ arm_QADD_VC: "QADD.VC",
+ arm_QADD_HI: "QADD.HI",
+ arm_QADD_LS: "QADD.LS",
+ arm_QADD_GE: "QADD.GE",
+ arm_QADD_LT: "QADD.LT",
+ arm_QADD_GT: "QADD.GT",
+ arm_QADD_LE: "QADD.LE",
+ arm_QADD: "QADD",
+ arm_QADD_ZZ: "QADD.ZZ",
+ arm_QADD16_EQ: "QADD16.EQ",
+ arm_QADD16_NE: "QADD16.NE",
+ arm_QADD16_CS: "QADD16.CS",
+ arm_QADD16_CC: "QADD16.CC",
+ arm_QADD16_MI: "QADD16.MI",
+ arm_QADD16_PL: "QADD16.PL",
+ arm_QADD16_VS: "QADD16.VS",
+ arm_QADD16_VC: "QADD16.VC",
+ arm_QADD16_HI: "QADD16.HI",
+ arm_QADD16_LS: "QADD16.LS",
+ arm_QADD16_GE: "QADD16.GE",
+ arm_QADD16_LT: "QADD16.LT",
+ arm_QADD16_GT: "QADD16.GT",
+ arm_QADD16_LE: "QADD16.LE",
+ arm_QADD16: "QADD16",
+ arm_QADD16_ZZ: "QADD16.ZZ",
+ arm_QADD8_EQ: "QADD8.EQ",
+ arm_QADD8_NE: "QADD8.NE",
+ arm_QADD8_CS: "QADD8.CS",
+ arm_QADD8_CC: "QADD8.CC",
+ arm_QADD8_MI: "QADD8.MI",
+ arm_QADD8_PL: "QADD8.PL",
+ arm_QADD8_VS: "QADD8.VS",
+ arm_QADD8_VC: "QADD8.VC",
+ arm_QADD8_HI: "QADD8.HI",
+ arm_QADD8_LS: "QADD8.LS",
+ arm_QADD8_GE: "QADD8.GE",
+ arm_QADD8_LT: "QADD8.LT",
+ arm_QADD8_GT: "QADD8.GT",
+ arm_QADD8_LE: "QADD8.LE",
+ arm_QADD8: "QADD8",
+ arm_QADD8_ZZ: "QADD8.ZZ",
+ arm_QASX_EQ: "QASX.EQ",
+ arm_QASX_NE: "QASX.NE",
+ arm_QASX_CS: "QASX.CS",
+ arm_QASX_CC: "QASX.CC",
+ arm_QASX_MI: "QASX.MI",
+ arm_QASX_PL: "QASX.PL",
+ arm_QASX_VS: "QASX.VS",
+ arm_QASX_VC: "QASX.VC",
+ arm_QASX_HI: "QASX.HI",
+ arm_QASX_LS: "QASX.LS",
+ arm_QASX_GE: "QASX.GE",
+ arm_QASX_LT: "QASX.LT",
+ arm_QASX_GT: "QASX.GT",
+ arm_QASX_LE: "QASX.LE",
+ arm_QASX: "QASX",
+ arm_QASX_ZZ: "QASX.ZZ",
+ arm_QDADD_EQ: "QDADD.EQ",
+ arm_QDADD_NE: "QDADD.NE",
+ arm_QDADD_CS: "QDADD.CS",
+ arm_QDADD_CC: "QDADD.CC",
+ arm_QDADD_MI: "QDADD.MI",
+ arm_QDADD_PL: "QDADD.PL",
+ arm_QDADD_VS: "QDADD.VS",
+ arm_QDADD_VC: "QDADD.VC",
+ arm_QDADD_HI: "QDADD.HI",
+ arm_QDADD_LS: "QDADD.LS",
+ arm_QDADD_GE: "QDADD.GE",
+ arm_QDADD_LT: "QDADD.LT",
+ arm_QDADD_GT: "QDADD.GT",
+ arm_QDADD_LE: "QDADD.LE",
+ arm_QDADD: "QDADD",
+ arm_QDADD_ZZ: "QDADD.ZZ",
+ arm_QDSUB_EQ: "QDSUB.EQ",
+ arm_QDSUB_NE: "QDSUB.NE",
+ arm_QDSUB_CS: "QDSUB.CS",
+ arm_QDSUB_CC: "QDSUB.CC",
+ arm_QDSUB_MI: "QDSUB.MI",
+ arm_QDSUB_PL: "QDSUB.PL",
+ arm_QDSUB_VS: "QDSUB.VS",
+ arm_QDSUB_VC: "QDSUB.VC",
+ arm_QDSUB_HI: "QDSUB.HI",
+ arm_QDSUB_LS: "QDSUB.LS",
+ arm_QDSUB_GE: "QDSUB.GE",
+ arm_QDSUB_LT: "QDSUB.LT",
+ arm_QDSUB_GT: "QDSUB.GT",
+ arm_QDSUB_LE: "QDSUB.LE",
+ arm_QDSUB: "QDSUB",
+ arm_QDSUB_ZZ: "QDSUB.ZZ",
+ arm_QSAX_EQ: "QSAX.EQ",
+ arm_QSAX_NE: "QSAX.NE",
+ arm_QSAX_CS: "QSAX.CS",
+ arm_QSAX_CC: "QSAX.CC",
+ arm_QSAX_MI: "QSAX.MI",
+ arm_QSAX_PL: "QSAX.PL",
+ arm_QSAX_VS: "QSAX.VS",
+ arm_QSAX_VC: "QSAX.VC",
+ arm_QSAX_HI: "QSAX.HI",
+ arm_QSAX_LS: "QSAX.LS",
+ arm_QSAX_GE: "QSAX.GE",
+ arm_QSAX_LT: "QSAX.LT",
+ arm_QSAX_GT: "QSAX.GT",
+ arm_QSAX_LE: "QSAX.LE",
+ arm_QSAX: "QSAX",
+ arm_QSAX_ZZ: "QSAX.ZZ",
+ arm_QSUB_EQ: "QSUB.EQ",
+ arm_QSUB_NE: "QSUB.NE",
+ arm_QSUB_CS: "QSUB.CS",
+ arm_QSUB_CC: "QSUB.CC",
+ arm_QSUB_MI: "QSUB.MI",
+ arm_QSUB_PL: "QSUB.PL",
+ arm_QSUB_VS: "QSUB.VS",
+ arm_QSUB_VC: "QSUB.VC",
+ arm_QSUB_HI: "QSUB.HI",
+ arm_QSUB_LS: "QSUB.LS",
+ arm_QSUB_GE: "QSUB.GE",
+ arm_QSUB_LT: "QSUB.LT",
+ arm_QSUB_GT: "QSUB.GT",
+ arm_QSUB_LE: "QSUB.LE",
+ arm_QSUB: "QSUB",
+ arm_QSUB_ZZ: "QSUB.ZZ",
+ arm_QSUB16_EQ: "QSUB16.EQ",
+ arm_QSUB16_NE: "QSUB16.NE",
+ arm_QSUB16_CS: "QSUB16.CS",
+ arm_QSUB16_CC: "QSUB16.CC",
+ arm_QSUB16_MI: "QSUB16.MI",
+ arm_QSUB16_PL: "QSUB16.PL",
+ arm_QSUB16_VS: "QSUB16.VS",
+ arm_QSUB16_VC: "QSUB16.VC",
+ arm_QSUB16_HI: "QSUB16.HI",
+ arm_QSUB16_LS: "QSUB16.LS",
+ arm_QSUB16_GE: "QSUB16.GE",
+ arm_QSUB16_LT: "QSUB16.LT",
+ arm_QSUB16_GT: "QSUB16.GT",
+ arm_QSUB16_LE: "QSUB16.LE",
+ arm_QSUB16: "QSUB16",
+ arm_QSUB16_ZZ: "QSUB16.ZZ",
+ arm_QSUB8_EQ: "QSUB8.EQ",
+ arm_QSUB8_NE: "QSUB8.NE",
+ arm_QSUB8_CS: "QSUB8.CS",
+ arm_QSUB8_CC: "QSUB8.CC",
+ arm_QSUB8_MI: "QSUB8.MI",
+ arm_QSUB8_PL: "QSUB8.PL",
+ arm_QSUB8_VS: "QSUB8.VS",
+ arm_QSUB8_VC: "QSUB8.VC",
+ arm_QSUB8_HI: "QSUB8.HI",
+ arm_QSUB8_LS: "QSUB8.LS",
+ arm_QSUB8_GE: "QSUB8.GE",
+ arm_QSUB8_LT: "QSUB8.LT",
+ arm_QSUB8_GT: "QSUB8.GT",
+ arm_QSUB8_LE: "QSUB8.LE",
+ arm_QSUB8: "QSUB8",
+ arm_QSUB8_ZZ: "QSUB8.ZZ",
+ arm_RBIT_EQ: "RBIT.EQ",
+ arm_RBIT_NE: "RBIT.NE",
+ arm_RBIT_CS: "RBIT.CS",
+ arm_RBIT_CC: "RBIT.CC",
+ arm_RBIT_MI: "RBIT.MI",
+ arm_RBIT_PL: "RBIT.PL",
+ arm_RBIT_VS: "RBIT.VS",
+ arm_RBIT_VC: "RBIT.VC",
+ arm_RBIT_HI: "RBIT.HI",
+ arm_RBIT_LS: "RBIT.LS",
+ arm_RBIT_GE: "RBIT.GE",
+ arm_RBIT_LT: "RBIT.LT",
+ arm_RBIT_GT: "RBIT.GT",
+ arm_RBIT_LE: "RBIT.LE",
+ arm_RBIT: "RBIT",
+ arm_RBIT_ZZ: "RBIT.ZZ",
+ arm_REV_EQ: "REV.EQ",
+ arm_REV_NE: "REV.NE",
+ arm_REV_CS: "REV.CS",
+ arm_REV_CC: "REV.CC",
+ arm_REV_MI: "REV.MI",
+ arm_REV_PL: "REV.PL",
+ arm_REV_VS: "REV.VS",
+ arm_REV_VC: "REV.VC",
+ arm_REV_HI: "REV.HI",
+ arm_REV_LS: "REV.LS",
+ arm_REV_GE: "REV.GE",
+ arm_REV_LT: "REV.LT",
+ arm_REV_GT: "REV.GT",
+ arm_REV_LE: "REV.LE",
+ arm_REV: "REV",
+ arm_REV_ZZ: "REV.ZZ",
+ arm_REV16_EQ: "REV16.EQ",
+ arm_REV16_NE: "REV16.NE",
+ arm_REV16_CS: "REV16.CS",
+ arm_REV16_CC: "REV16.CC",
+ arm_REV16_MI: "REV16.MI",
+ arm_REV16_PL: "REV16.PL",
+ arm_REV16_VS: "REV16.VS",
+ arm_REV16_VC: "REV16.VC",
+ arm_REV16_HI: "REV16.HI",
+ arm_REV16_LS: "REV16.LS",
+ arm_REV16_GE: "REV16.GE",
+ arm_REV16_LT: "REV16.LT",
+ arm_REV16_GT: "REV16.GT",
+ arm_REV16_LE: "REV16.LE",
+ arm_REV16: "REV16",
+ arm_REV16_ZZ: "REV16.ZZ",
+ arm_REVSH_EQ: "REVSH.EQ",
+ arm_REVSH_NE: "REVSH.NE",
+ arm_REVSH_CS: "REVSH.CS",
+ arm_REVSH_CC: "REVSH.CC",
+ arm_REVSH_MI: "REVSH.MI",
+ arm_REVSH_PL: "REVSH.PL",
+ arm_REVSH_VS: "REVSH.VS",
+ arm_REVSH_VC: "REVSH.VC",
+ arm_REVSH_HI: "REVSH.HI",
+ arm_REVSH_LS: "REVSH.LS",
+ arm_REVSH_GE: "REVSH.GE",
+ arm_REVSH_LT: "REVSH.LT",
+ arm_REVSH_GT: "REVSH.GT",
+ arm_REVSH_LE: "REVSH.LE",
+ arm_REVSH: "REVSH",
+ arm_REVSH_ZZ: "REVSH.ZZ",
+ arm_ROR_EQ: "ROR.EQ",
+ arm_ROR_NE: "ROR.NE",
+ arm_ROR_CS: "ROR.CS",
+ arm_ROR_CC: "ROR.CC",
+ arm_ROR_MI: "ROR.MI",
+ arm_ROR_PL: "ROR.PL",
+ arm_ROR_VS: "ROR.VS",
+ arm_ROR_VC: "ROR.VC",
+ arm_ROR_HI: "ROR.HI",
+ arm_ROR_LS: "ROR.LS",
+ arm_ROR_GE: "ROR.GE",
+ arm_ROR_LT: "ROR.LT",
+ arm_ROR_GT: "ROR.GT",
+ arm_ROR_LE: "ROR.LE",
+ arm_ROR: "ROR",
+ arm_ROR_ZZ: "ROR.ZZ",
+ arm_ROR_S_EQ: "ROR.S.EQ",
+ arm_ROR_S_NE: "ROR.S.NE",
+ arm_ROR_S_CS: "ROR.S.CS",
+ arm_ROR_S_CC: "ROR.S.CC",
+ arm_ROR_S_MI: "ROR.S.MI",
+ arm_ROR_S_PL: "ROR.S.PL",
+ arm_ROR_S_VS: "ROR.S.VS",
+ arm_ROR_S_VC: "ROR.S.VC",
+ arm_ROR_S_HI: "ROR.S.HI",
+ arm_ROR_S_LS: "ROR.S.LS",
+ arm_ROR_S_GE: "ROR.S.GE",
+ arm_ROR_S_LT: "ROR.S.LT",
+ arm_ROR_S_GT: "ROR.S.GT",
+ arm_ROR_S_LE: "ROR.S.LE",
+ arm_ROR_S: "ROR.S",
+ arm_ROR_S_ZZ: "ROR.S.ZZ",
+ arm_RRX_EQ: "RRX.EQ",
+ arm_RRX_NE: "RRX.NE",
+ arm_RRX_CS: "RRX.CS",
+ arm_RRX_CC: "RRX.CC",
+ arm_RRX_MI: "RRX.MI",
+ arm_RRX_PL: "RRX.PL",
+ arm_RRX_VS: "RRX.VS",
+ arm_RRX_VC: "RRX.VC",
+ arm_RRX_HI: "RRX.HI",
+ arm_RRX_LS: "RRX.LS",
+ arm_RRX_GE: "RRX.GE",
+ arm_RRX_LT: "RRX.LT",
+ arm_RRX_GT: "RRX.GT",
+ arm_RRX_LE: "RRX.LE",
+ arm_RRX: "RRX",
+ arm_RRX_ZZ: "RRX.ZZ",
+ arm_RRX_S_EQ: "RRX.S.EQ",
+ arm_RRX_S_NE: "RRX.S.NE",
+ arm_RRX_S_CS: "RRX.S.CS",
+ arm_RRX_S_CC: "RRX.S.CC",
+ arm_RRX_S_MI: "RRX.S.MI",
+ arm_RRX_S_PL: "RRX.S.PL",
+ arm_RRX_S_VS: "RRX.S.VS",
+ arm_RRX_S_VC: "RRX.S.VC",
+ arm_RRX_S_HI: "RRX.S.HI",
+ arm_RRX_S_LS: "RRX.S.LS",
+ arm_RRX_S_GE: "RRX.S.GE",
+ arm_RRX_S_LT: "RRX.S.LT",
+ arm_RRX_S_GT: "RRX.S.GT",
+ arm_RRX_S_LE: "RRX.S.LE",
+ arm_RRX_S: "RRX.S",
+ arm_RRX_S_ZZ: "RRX.S.ZZ",
+ arm_RSB_EQ: "RSB.EQ",
+ arm_RSB_NE: "RSB.NE",
+ arm_RSB_CS: "RSB.CS",
+ arm_RSB_CC: "RSB.CC",
+ arm_RSB_MI: "RSB.MI",
+ arm_RSB_PL: "RSB.PL",
+ arm_RSB_VS: "RSB.VS",
+ arm_RSB_VC: "RSB.VC",
+ arm_RSB_HI: "RSB.HI",
+ arm_RSB_LS: "RSB.LS",
+ arm_RSB_GE: "RSB.GE",
+ arm_RSB_LT: "RSB.LT",
+ arm_RSB_GT: "RSB.GT",
+ arm_RSB_LE: "RSB.LE",
+ arm_RSB: "RSB",
+ arm_RSB_ZZ: "RSB.ZZ",
+ arm_RSB_S_EQ: "RSB.S.EQ",
+ arm_RSB_S_NE: "RSB.S.NE",
+ arm_RSB_S_CS: "RSB.S.CS",
+ arm_RSB_S_CC: "RSB.S.CC",
+ arm_RSB_S_MI: "RSB.S.MI",
+ arm_RSB_S_PL: "RSB.S.PL",
+ arm_RSB_S_VS: "RSB.S.VS",
+ arm_RSB_S_VC: "RSB.S.VC",
+ arm_RSB_S_HI: "RSB.S.HI",
+ arm_RSB_S_LS: "RSB.S.LS",
+ arm_RSB_S_GE: "RSB.S.GE",
+ arm_RSB_S_LT: "RSB.S.LT",
+ arm_RSB_S_GT: "RSB.S.GT",
+ arm_RSB_S_LE: "RSB.S.LE",
+ arm_RSB_S: "RSB.S",
+ arm_RSB_S_ZZ: "RSB.S.ZZ",
+ arm_RSC_EQ: "RSC.EQ",
+ arm_RSC_NE: "RSC.NE",
+ arm_RSC_CS: "RSC.CS",
+ arm_RSC_CC: "RSC.CC",
+ arm_RSC_MI: "RSC.MI",
+ arm_RSC_PL: "RSC.PL",
+ arm_RSC_VS: "RSC.VS",
+ arm_RSC_VC: "RSC.VC",
+ arm_RSC_HI: "RSC.HI",
+ arm_RSC_LS: "RSC.LS",
+ arm_RSC_GE: "RSC.GE",
+ arm_RSC_LT: "RSC.LT",
+ arm_RSC_GT: "RSC.GT",
+ arm_RSC_LE: "RSC.LE",
+ arm_RSC: "RSC",
+ arm_RSC_ZZ: "RSC.ZZ",
+ arm_RSC_S_EQ: "RSC.S.EQ",
+ arm_RSC_S_NE: "RSC.S.NE",
+ arm_RSC_S_CS: "RSC.S.CS",
+ arm_RSC_S_CC: "RSC.S.CC",
+ arm_RSC_S_MI: "RSC.S.MI",
+ arm_RSC_S_PL: "RSC.S.PL",
+ arm_RSC_S_VS: "RSC.S.VS",
+ arm_RSC_S_VC: "RSC.S.VC",
+ arm_RSC_S_HI: "RSC.S.HI",
+ arm_RSC_S_LS: "RSC.S.LS",
+ arm_RSC_S_GE: "RSC.S.GE",
+ arm_RSC_S_LT: "RSC.S.LT",
+ arm_RSC_S_GT: "RSC.S.GT",
+ arm_RSC_S_LE: "RSC.S.LE",
+ arm_RSC_S: "RSC.S",
+ arm_RSC_S_ZZ: "RSC.S.ZZ",
+ arm_SADD16_EQ: "SADD16.EQ",
+ arm_SADD16_NE: "SADD16.NE",
+ arm_SADD16_CS: "SADD16.CS",
+ arm_SADD16_CC: "SADD16.CC",
+ arm_SADD16_MI: "SADD16.MI",
+ arm_SADD16_PL: "SADD16.PL",
+ arm_SADD16_VS: "SADD16.VS",
+ arm_SADD16_VC: "SADD16.VC",
+ arm_SADD16_HI: "SADD16.HI",
+ arm_SADD16_LS: "SADD16.LS",
+ arm_SADD16_GE: "SADD16.GE",
+ arm_SADD16_LT: "SADD16.LT",
+ arm_SADD16_GT: "SADD16.GT",
+ arm_SADD16_LE: "SADD16.LE",
+ arm_SADD16: "SADD16",
+ arm_SADD16_ZZ: "SADD16.ZZ",
+ arm_SADD8_EQ: "SADD8.EQ",
+ arm_SADD8_NE: "SADD8.NE",
+ arm_SADD8_CS: "SADD8.CS",
+ arm_SADD8_CC: "SADD8.CC",
+ arm_SADD8_MI: "SADD8.MI",
+ arm_SADD8_PL: "SADD8.PL",
+ arm_SADD8_VS: "SADD8.VS",
+ arm_SADD8_VC: "SADD8.VC",
+ arm_SADD8_HI: "SADD8.HI",
+ arm_SADD8_LS: "SADD8.LS",
+ arm_SADD8_GE: "SADD8.GE",
+ arm_SADD8_LT: "SADD8.LT",
+ arm_SADD8_GT: "SADD8.GT",
+ arm_SADD8_LE: "SADD8.LE",
+ arm_SADD8: "SADD8",
+ arm_SADD8_ZZ: "SADD8.ZZ",
+ arm_SASX_EQ: "SASX.EQ",
+ arm_SASX_NE: "SASX.NE",
+ arm_SASX_CS: "SASX.CS",
+ arm_SASX_CC: "SASX.CC",
+ arm_SASX_MI: "SASX.MI",
+ arm_SASX_PL: "SASX.PL",
+ arm_SASX_VS: "SASX.VS",
+ arm_SASX_VC: "SASX.VC",
+ arm_SASX_HI: "SASX.HI",
+ arm_SASX_LS: "SASX.LS",
+ arm_SASX_GE: "SASX.GE",
+ arm_SASX_LT: "SASX.LT",
+ arm_SASX_GT: "SASX.GT",
+ arm_SASX_LE: "SASX.LE",
+ arm_SASX: "SASX",
+ arm_SASX_ZZ: "SASX.ZZ",
+ arm_SBC_EQ: "SBC.EQ",
+ arm_SBC_NE: "SBC.NE",
+ arm_SBC_CS: "SBC.CS",
+ arm_SBC_CC: "SBC.CC",
+ arm_SBC_MI: "SBC.MI",
+ arm_SBC_PL: "SBC.PL",
+ arm_SBC_VS: "SBC.VS",
+ arm_SBC_VC: "SBC.VC",
+ arm_SBC_HI: "SBC.HI",
+ arm_SBC_LS: "SBC.LS",
+ arm_SBC_GE: "SBC.GE",
+ arm_SBC_LT: "SBC.LT",
+ arm_SBC_GT: "SBC.GT",
+ arm_SBC_LE: "SBC.LE",
+ arm_SBC: "SBC",
+ arm_SBC_ZZ: "SBC.ZZ",
+ arm_SBC_S_EQ: "SBC.S.EQ",
+ arm_SBC_S_NE: "SBC.S.NE",
+ arm_SBC_S_CS: "SBC.S.CS",
+ arm_SBC_S_CC: "SBC.S.CC",
+ arm_SBC_S_MI: "SBC.S.MI",
+ arm_SBC_S_PL: "SBC.S.PL",
+ arm_SBC_S_VS: "SBC.S.VS",
+ arm_SBC_S_VC: "SBC.S.VC",
+ arm_SBC_S_HI: "SBC.S.HI",
+ arm_SBC_S_LS: "SBC.S.LS",
+ arm_SBC_S_GE: "SBC.S.GE",
+ arm_SBC_S_LT: "SBC.S.LT",
+ arm_SBC_S_GT: "SBC.S.GT",
+ arm_SBC_S_LE: "SBC.S.LE",
+ arm_SBC_S: "SBC.S",
+ arm_SBC_S_ZZ: "SBC.S.ZZ",
+ arm_SBFX_EQ: "SBFX.EQ",
+ arm_SBFX_NE: "SBFX.NE",
+ arm_SBFX_CS: "SBFX.CS",
+ arm_SBFX_CC: "SBFX.CC",
+ arm_SBFX_MI: "SBFX.MI",
+ arm_SBFX_PL: "SBFX.PL",
+ arm_SBFX_VS: "SBFX.VS",
+ arm_SBFX_VC: "SBFX.VC",
+ arm_SBFX_HI: "SBFX.HI",
+ arm_SBFX_LS: "SBFX.LS",
+ arm_SBFX_GE: "SBFX.GE",
+ arm_SBFX_LT: "SBFX.LT",
+ arm_SBFX_GT: "SBFX.GT",
+ arm_SBFX_LE: "SBFX.LE",
+ arm_SBFX: "SBFX",
+ arm_SBFX_ZZ: "SBFX.ZZ",
+ arm_SEL_EQ: "SEL.EQ",
+ arm_SEL_NE: "SEL.NE",
+ arm_SEL_CS: "SEL.CS",
+ arm_SEL_CC: "SEL.CC",
+ arm_SEL_MI: "SEL.MI",
+ arm_SEL_PL: "SEL.PL",
+ arm_SEL_VS: "SEL.VS",
+ arm_SEL_VC: "SEL.VC",
+ arm_SEL_HI: "SEL.HI",
+ arm_SEL_LS: "SEL.LS",
+ arm_SEL_GE: "SEL.GE",
+ arm_SEL_LT: "SEL.LT",
+ arm_SEL_GT: "SEL.GT",
+ arm_SEL_LE: "SEL.LE",
+ arm_SEL: "SEL",
+ arm_SEL_ZZ: "SEL.ZZ",
+ arm_SETEND: "SETEND",
+ arm_SEV_EQ: "SEV.EQ",
+ arm_SEV_NE: "SEV.NE",
+ arm_SEV_CS: "SEV.CS",
+ arm_SEV_CC: "SEV.CC",
+ arm_SEV_MI: "SEV.MI",
+ arm_SEV_PL: "SEV.PL",
+ arm_SEV_VS: "SEV.VS",
+ arm_SEV_VC: "SEV.VC",
+ arm_SEV_HI: "SEV.HI",
+ arm_SEV_LS: "SEV.LS",
+ arm_SEV_GE: "SEV.GE",
+ arm_SEV_LT: "SEV.LT",
+ arm_SEV_GT: "SEV.GT",
+ arm_SEV_LE: "SEV.LE",
+ arm_SEV: "SEV",
+ arm_SEV_ZZ: "SEV.ZZ",
+ arm_SHADD16_EQ: "SHADD16.EQ",
+ arm_SHADD16_NE: "SHADD16.NE",
+ arm_SHADD16_CS: "SHADD16.CS",
+ arm_SHADD16_CC: "SHADD16.CC",
+ arm_SHADD16_MI: "SHADD16.MI",
+ arm_SHADD16_PL: "SHADD16.PL",
+ arm_SHADD16_VS: "SHADD16.VS",
+ arm_SHADD16_VC: "SHADD16.VC",
+ arm_SHADD16_HI: "SHADD16.HI",
+ arm_SHADD16_LS: "SHADD16.LS",
+ arm_SHADD16_GE: "SHADD16.GE",
+ arm_SHADD16_LT: "SHADD16.LT",
+ arm_SHADD16_GT: "SHADD16.GT",
+ arm_SHADD16_LE: "SHADD16.LE",
+ arm_SHADD16: "SHADD16",
+ arm_SHADD16_ZZ: "SHADD16.ZZ",
+ arm_SHADD8_EQ: "SHADD8.EQ",
+ arm_SHADD8_NE: "SHADD8.NE",
+ arm_SHADD8_CS: "SHADD8.CS",
+ arm_SHADD8_CC: "SHADD8.CC",
+ arm_SHADD8_MI: "SHADD8.MI",
+ arm_SHADD8_PL: "SHADD8.PL",
+ arm_SHADD8_VS: "SHADD8.VS",
+ arm_SHADD8_VC: "SHADD8.VC",
+ arm_SHADD8_HI: "SHADD8.HI",
+ arm_SHADD8_LS: "SHADD8.LS",
+ arm_SHADD8_GE: "SHADD8.GE",
+ arm_SHADD8_LT: "SHADD8.LT",
+ arm_SHADD8_GT: "SHADD8.GT",
+ arm_SHADD8_LE: "SHADD8.LE",
+ arm_SHADD8: "SHADD8",
+ arm_SHADD8_ZZ: "SHADD8.ZZ",
+ arm_SHASX_EQ: "SHASX.EQ",
+ arm_SHASX_NE: "SHASX.NE",
+ arm_SHASX_CS: "SHASX.CS",
+ arm_SHASX_CC: "SHASX.CC",
+ arm_SHASX_MI: "SHASX.MI",
+ arm_SHASX_PL: "SHASX.PL",
+ arm_SHASX_VS: "SHASX.VS",
+ arm_SHASX_VC: "SHASX.VC",
+ arm_SHASX_HI: "SHASX.HI",
+ arm_SHASX_LS: "SHASX.LS",
+ arm_SHASX_GE: "SHASX.GE",
+ arm_SHASX_LT: "SHASX.LT",
+ arm_SHASX_GT: "SHASX.GT",
+ arm_SHASX_LE: "SHASX.LE",
+ arm_SHASX: "SHASX",
+ arm_SHASX_ZZ: "SHASX.ZZ",
+ arm_SHSAX_EQ: "SHSAX.EQ",
+ arm_SHSAX_NE: "SHSAX.NE",
+ arm_SHSAX_CS: "SHSAX.CS",
+ arm_SHSAX_CC: "SHSAX.CC",
+ arm_SHSAX_MI: "SHSAX.MI",
+ arm_SHSAX_PL: "SHSAX.PL",
+ arm_SHSAX_VS: "SHSAX.VS",
+ arm_SHSAX_VC: "SHSAX.VC",
+ arm_SHSAX_HI: "SHSAX.HI",
+ arm_SHSAX_LS: "SHSAX.LS",
+ arm_SHSAX_GE: "SHSAX.GE",
+ arm_SHSAX_LT: "SHSAX.LT",
+ arm_SHSAX_GT: "SHSAX.GT",
+ arm_SHSAX_LE: "SHSAX.LE",
+ arm_SHSAX: "SHSAX",
+ arm_SHSAX_ZZ: "SHSAX.ZZ",
+ arm_SHSUB16_EQ: "SHSUB16.EQ",
+ arm_SHSUB16_NE: "SHSUB16.NE",
+ arm_SHSUB16_CS: "SHSUB16.CS",
+ arm_SHSUB16_CC: "SHSUB16.CC",
+ arm_SHSUB16_MI: "SHSUB16.MI",
+ arm_SHSUB16_PL: "SHSUB16.PL",
+ arm_SHSUB16_VS: "SHSUB16.VS",
+ arm_SHSUB16_VC: "SHSUB16.VC",
+ arm_SHSUB16_HI: "SHSUB16.HI",
+ arm_SHSUB16_LS: "SHSUB16.LS",
+ arm_SHSUB16_GE: "SHSUB16.GE",
+ arm_SHSUB16_LT: "SHSUB16.LT",
+ arm_SHSUB16_GT: "SHSUB16.GT",
+ arm_SHSUB16_LE: "SHSUB16.LE",
+ arm_SHSUB16: "SHSUB16",
+ arm_SHSUB16_ZZ: "SHSUB16.ZZ",
+ arm_SHSUB8_EQ: "SHSUB8.EQ",
+ arm_SHSUB8_NE: "SHSUB8.NE",
+ arm_SHSUB8_CS: "SHSUB8.CS",
+ arm_SHSUB8_CC: "SHSUB8.CC",
+ arm_SHSUB8_MI: "SHSUB8.MI",
+ arm_SHSUB8_PL: "SHSUB8.PL",
+ arm_SHSUB8_VS: "SHSUB8.VS",
+ arm_SHSUB8_VC: "SHSUB8.VC",
+ arm_SHSUB8_HI: "SHSUB8.HI",
+ arm_SHSUB8_LS: "SHSUB8.LS",
+ arm_SHSUB8_GE: "SHSUB8.GE",
+ arm_SHSUB8_LT: "SHSUB8.LT",
+ arm_SHSUB8_GT: "SHSUB8.GT",
+ arm_SHSUB8_LE: "SHSUB8.LE",
+ arm_SHSUB8: "SHSUB8",
+ arm_SHSUB8_ZZ: "SHSUB8.ZZ",
+ arm_SMLABB_EQ: "SMLABB.EQ",
+ arm_SMLABB_NE: "SMLABB.NE",
+ arm_SMLABB_CS: "SMLABB.CS",
+ arm_SMLABB_CC: "SMLABB.CC",
+ arm_SMLABB_MI: "SMLABB.MI",
+ arm_SMLABB_PL: "SMLABB.PL",
+ arm_SMLABB_VS: "SMLABB.VS",
+ arm_SMLABB_VC: "SMLABB.VC",
+ arm_SMLABB_HI: "SMLABB.HI",
+ arm_SMLABB_LS: "SMLABB.LS",
+ arm_SMLABB_GE: "SMLABB.GE",
+ arm_SMLABB_LT: "SMLABB.LT",
+ arm_SMLABB_GT: "SMLABB.GT",
+ arm_SMLABB_LE: "SMLABB.LE",
+ arm_SMLABB: "SMLABB",
+ arm_SMLABB_ZZ: "SMLABB.ZZ",
+ arm_SMLABT_EQ: "SMLABT.EQ",
+ arm_SMLABT_NE: "SMLABT.NE",
+ arm_SMLABT_CS: "SMLABT.CS",
+ arm_SMLABT_CC: "SMLABT.CC",
+ arm_SMLABT_MI: "SMLABT.MI",
+ arm_SMLABT_PL: "SMLABT.PL",
+ arm_SMLABT_VS: "SMLABT.VS",
+ arm_SMLABT_VC: "SMLABT.VC",
+ arm_SMLABT_HI: "SMLABT.HI",
+ arm_SMLABT_LS: "SMLABT.LS",
+ arm_SMLABT_GE: "SMLABT.GE",
+ arm_SMLABT_LT: "SMLABT.LT",
+ arm_SMLABT_GT: "SMLABT.GT",
+ arm_SMLABT_LE: "SMLABT.LE",
+ arm_SMLABT: "SMLABT",
+ arm_SMLABT_ZZ: "SMLABT.ZZ",
+ arm_SMLATB_EQ: "SMLATB.EQ",
+ arm_SMLATB_NE: "SMLATB.NE",
+ arm_SMLATB_CS: "SMLATB.CS",
+ arm_SMLATB_CC: "SMLATB.CC",
+ arm_SMLATB_MI: "SMLATB.MI",
+ arm_SMLATB_PL: "SMLATB.PL",
+ arm_SMLATB_VS: "SMLATB.VS",
+ arm_SMLATB_VC: "SMLATB.VC",
+ arm_SMLATB_HI: "SMLATB.HI",
+ arm_SMLATB_LS: "SMLATB.LS",
+ arm_SMLATB_GE: "SMLATB.GE",
+ arm_SMLATB_LT: "SMLATB.LT",
+ arm_SMLATB_GT: "SMLATB.GT",
+ arm_SMLATB_LE: "SMLATB.LE",
+ arm_SMLATB: "SMLATB",
+ arm_SMLATB_ZZ: "SMLATB.ZZ",
+ arm_SMLATT_EQ: "SMLATT.EQ",
+ arm_SMLATT_NE: "SMLATT.NE",
+ arm_SMLATT_CS: "SMLATT.CS",
+ arm_SMLATT_CC: "SMLATT.CC",
+ arm_SMLATT_MI: "SMLATT.MI",
+ arm_SMLATT_PL: "SMLATT.PL",
+ arm_SMLATT_VS: "SMLATT.VS",
+ arm_SMLATT_VC: "SMLATT.VC",
+ arm_SMLATT_HI: "SMLATT.HI",
+ arm_SMLATT_LS: "SMLATT.LS",
+ arm_SMLATT_GE: "SMLATT.GE",
+ arm_SMLATT_LT: "SMLATT.LT",
+ arm_SMLATT_GT: "SMLATT.GT",
+ arm_SMLATT_LE: "SMLATT.LE",
+ arm_SMLATT: "SMLATT",
+ arm_SMLATT_ZZ: "SMLATT.ZZ",
+ arm_SMLAD_EQ: "SMLAD.EQ",
+ arm_SMLAD_NE: "SMLAD.NE",
+ arm_SMLAD_CS: "SMLAD.CS",
+ arm_SMLAD_CC: "SMLAD.CC",
+ arm_SMLAD_MI: "SMLAD.MI",
+ arm_SMLAD_PL: "SMLAD.PL",
+ arm_SMLAD_VS: "SMLAD.VS",
+ arm_SMLAD_VC: "SMLAD.VC",
+ arm_SMLAD_HI: "SMLAD.HI",
+ arm_SMLAD_LS: "SMLAD.LS",
+ arm_SMLAD_GE: "SMLAD.GE",
+ arm_SMLAD_LT: "SMLAD.LT",
+ arm_SMLAD_GT: "SMLAD.GT",
+ arm_SMLAD_LE: "SMLAD.LE",
+ arm_SMLAD: "SMLAD",
+ arm_SMLAD_ZZ: "SMLAD.ZZ",
+ arm_SMLAD_X_EQ: "SMLAD.X.EQ",
+ arm_SMLAD_X_NE: "SMLAD.X.NE",
+ arm_SMLAD_X_CS: "SMLAD.X.CS",
+ arm_SMLAD_X_CC: "SMLAD.X.CC",
+ arm_SMLAD_X_MI: "SMLAD.X.MI",
+ arm_SMLAD_X_PL: "SMLAD.X.PL",
+ arm_SMLAD_X_VS: "SMLAD.X.VS",
+ arm_SMLAD_X_VC: "SMLAD.X.VC",
+ arm_SMLAD_X_HI: "SMLAD.X.HI",
+ arm_SMLAD_X_LS: "SMLAD.X.LS",
+ arm_SMLAD_X_GE: "SMLAD.X.GE",
+ arm_SMLAD_X_LT: "SMLAD.X.LT",
+ arm_SMLAD_X_GT: "SMLAD.X.GT",
+ arm_SMLAD_X_LE: "SMLAD.X.LE",
+ arm_SMLAD_X: "SMLAD.X",
+ arm_SMLAD_X_ZZ: "SMLAD.X.ZZ",
+ arm_SMLAL_EQ: "SMLAL.EQ",
+ arm_SMLAL_NE: "SMLAL.NE",
+ arm_SMLAL_CS: "SMLAL.CS",
+ arm_SMLAL_CC: "SMLAL.CC",
+ arm_SMLAL_MI: "SMLAL.MI",
+ arm_SMLAL_PL: "SMLAL.PL",
+ arm_SMLAL_VS: "SMLAL.VS",
+ arm_SMLAL_VC: "SMLAL.VC",
+ arm_SMLAL_HI: "SMLAL.HI",
+ arm_SMLAL_LS: "SMLAL.LS",
+ arm_SMLAL_GE: "SMLAL.GE",
+ arm_SMLAL_LT: "SMLAL.LT",
+ arm_SMLAL_GT: "SMLAL.GT",
+ arm_SMLAL_LE: "SMLAL.LE",
+ arm_SMLAL: "SMLAL",
+ arm_SMLAL_ZZ: "SMLAL.ZZ",
+ arm_SMLAL_S_EQ: "SMLAL.S.EQ",
+ arm_SMLAL_S_NE: "SMLAL.S.NE",
+ arm_SMLAL_S_CS: "SMLAL.S.CS",
+ arm_SMLAL_S_CC: "SMLAL.S.CC",
+ arm_SMLAL_S_MI: "SMLAL.S.MI",
+ arm_SMLAL_S_PL: "SMLAL.S.PL",
+ arm_SMLAL_S_VS: "SMLAL.S.VS",
+ arm_SMLAL_S_VC: "SMLAL.S.VC",
+ arm_SMLAL_S_HI: "SMLAL.S.HI",
+ arm_SMLAL_S_LS: "SMLAL.S.LS",
+ arm_SMLAL_S_GE: "SMLAL.S.GE",
+ arm_SMLAL_S_LT: "SMLAL.S.LT",
+ arm_SMLAL_S_GT: "SMLAL.S.GT",
+ arm_SMLAL_S_LE: "SMLAL.S.LE",
+ arm_SMLAL_S: "SMLAL.S",
+ arm_SMLAL_S_ZZ: "SMLAL.S.ZZ",
+ arm_SMLALBB_EQ: "SMLALBB.EQ",
+ arm_SMLALBB_NE: "SMLALBB.NE",
+ arm_SMLALBB_CS: "SMLALBB.CS",
+ arm_SMLALBB_CC: "SMLALBB.CC",
+ arm_SMLALBB_MI: "SMLALBB.MI",
+ arm_SMLALBB_PL: "SMLALBB.PL",
+ arm_SMLALBB_VS: "SMLALBB.VS",
+ arm_SMLALBB_VC: "SMLALBB.VC",
+ arm_SMLALBB_HI: "SMLALBB.HI",
+ arm_SMLALBB_LS: "SMLALBB.LS",
+ arm_SMLALBB_GE: "SMLALBB.GE",
+ arm_SMLALBB_LT: "SMLALBB.LT",
+ arm_SMLALBB_GT: "SMLALBB.GT",
+ arm_SMLALBB_LE: "SMLALBB.LE",
+ arm_SMLALBB: "SMLALBB",
+ arm_SMLALBB_ZZ: "SMLALBB.ZZ",
+ arm_SMLALBT_EQ: "SMLALBT.EQ",
+ arm_SMLALBT_NE: "SMLALBT.NE",
+ arm_SMLALBT_CS: "SMLALBT.CS",
+ arm_SMLALBT_CC: "SMLALBT.CC",
+ arm_SMLALBT_MI: "SMLALBT.MI",
+ arm_SMLALBT_PL: "SMLALBT.PL",
+ arm_SMLALBT_VS: "SMLALBT.VS",
+ arm_SMLALBT_VC: "SMLALBT.VC",
+ arm_SMLALBT_HI: "SMLALBT.HI",
+ arm_SMLALBT_LS: "SMLALBT.LS",
+ arm_SMLALBT_GE: "SMLALBT.GE",
+ arm_SMLALBT_LT: "SMLALBT.LT",
+ arm_SMLALBT_GT: "SMLALBT.GT",
+ arm_SMLALBT_LE: "SMLALBT.LE",
+ arm_SMLALBT: "SMLALBT",
+ arm_SMLALBT_ZZ: "SMLALBT.ZZ",
+ arm_SMLALTB_EQ: "SMLALTB.EQ",
+ arm_SMLALTB_NE: "SMLALTB.NE",
+ arm_SMLALTB_CS: "SMLALTB.CS",
+ arm_SMLALTB_CC: "SMLALTB.CC",
+ arm_SMLALTB_MI: "SMLALTB.MI",
+ arm_SMLALTB_PL: "SMLALTB.PL",
+ arm_SMLALTB_VS: "SMLALTB.VS",
+ arm_SMLALTB_VC: "SMLALTB.VC",
+ arm_SMLALTB_HI: "SMLALTB.HI",
+ arm_SMLALTB_LS: "SMLALTB.LS",
+ arm_SMLALTB_GE: "SMLALTB.GE",
+ arm_SMLALTB_LT: "SMLALTB.LT",
+ arm_SMLALTB_GT: "SMLALTB.GT",
+ arm_SMLALTB_LE: "SMLALTB.LE",
+ arm_SMLALTB: "SMLALTB",
+ arm_SMLALTB_ZZ: "SMLALTB.ZZ",
+ arm_SMLALTT_EQ: "SMLALTT.EQ",
+ arm_SMLALTT_NE: "SMLALTT.NE",
+ arm_SMLALTT_CS: "SMLALTT.CS",
+ arm_SMLALTT_CC: "SMLALTT.CC",
+ arm_SMLALTT_MI: "SMLALTT.MI",
+ arm_SMLALTT_PL: "SMLALTT.PL",
+ arm_SMLALTT_VS: "SMLALTT.VS",
+ arm_SMLALTT_VC: "SMLALTT.VC",
+ arm_SMLALTT_HI: "SMLALTT.HI",
+ arm_SMLALTT_LS: "SMLALTT.LS",
+ arm_SMLALTT_GE: "SMLALTT.GE",
+ arm_SMLALTT_LT: "SMLALTT.LT",
+ arm_SMLALTT_GT: "SMLALTT.GT",
+ arm_SMLALTT_LE: "SMLALTT.LE",
+ arm_SMLALTT: "SMLALTT",
+ arm_SMLALTT_ZZ: "SMLALTT.ZZ",
+ arm_SMLALD_EQ: "SMLALD.EQ",
+ arm_SMLALD_NE: "SMLALD.NE",
+ arm_SMLALD_CS: "SMLALD.CS",
+ arm_SMLALD_CC: "SMLALD.CC",
+ arm_SMLALD_MI: "SMLALD.MI",
+ arm_SMLALD_PL: "SMLALD.PL",
+ arm_SMLALD_VS: "SMLALD.VS",
+ arm_SMLALD_VC: "SMLALD.VC",
+ arm_SMLALD_HI: "SMLALD.HI",
+ arm_SMLALD_LS: "SMLALD.LS",
+ arm_SMLALD_GE: "SMLALD.GE",
+ arm_SMLALD_LT: "SMLALD.LT",
+ arm_SMLALD_GT: "SMLALD.GT",
+ arm_SMLALD_LE: "SMLALD.LE",
+ arm_SMLALD: "SMLALD",
+ arm_SMLALD_ZZ: "SMLALD.ZZ",
+ arm_SMLALD_X_EQ: "SMLALD.X.EQ",
+ arm_SMLALD_X_NE: "SMLALD.X.NE",
+ arm_SMLALD_X_CS: "SMLALD.X.CS",
+ arm_SMLALD_X_CC: "SMLALD.X.CC",
+ arm_SMLALD_X_MI: "SMLALD.X.MI",
+ arm_SMLALD_X_PL: "SMLALD.X.PL",
+ arm_SMLALD_X_VS: "SMLALD.X.VS",
+ arm_SMLALD_X_VC: "SMLALD.X.VC",
+ arm_SMLALD_X_HI: "SMLALD.X.HI",
+ arm_SMLALD_X_LS: "SMLALD.X.LS",
+ arm_SMLALD_X_GE: "SMLALD.X.GE",
+ arm_SMLALD_X_LT: "SMLALD.X.LT",
+ arm_SMLALD_X_GT: "SMLALD.X.GT",
+ arm_SMLALD_X_LE: "SMLALD.X.LE",
+ arm_SMLALD_X: "SMLALD.X",
+ arm_SMLALD_X_ZZ: "SMLALD.X.ZZ",
+ arm_SMLAWB_EQ: "SMLAWB.EQ",
+ arm_SMLAWB_NE: "SMLAWB.NE",
+ arm_SMLAWB_CS: "SMLAWB.CS",
+ arm_SMLAWB_CC: "SMLAWB.CC",
+ arm_SMLAWB_MI: "SMLAWB.MI",
+ arm_SMLAWB_PL: "SMLAWB.PL",
+ arm_SMLAWB_VS: "SMLAWB.VS",
+ arm_SMLAWB_VC: "SMLAWB.VC",
+ arm_SMLAWB_HI: "SMLAWB.HI",
+ arm_SMLAWB_LS: "SMLAWB.LS",
+ arm_SMLAWB_GE: "SMLAWB.GE",
+ arm_SMLAWB_LT: "SMLAWB.LT",
+ arm_SMLAWB_GT: "SMLAWB.GT",
+ arm_SMLAWB_LE: "SMLAWB.LE",
+ arm_SMLAWB: "SMLAWB",
+ arm_SMLAWB_ZZ: "SMLAWB.ZZ",
+ arm_SMLAWT_EQ: "SMLAWT.EQ",
+ arm_SMLAWT_NE: "SMLAWT.NE",
+ arm_SMLAWT_CS: "SMLAWT.CS",
+ arm_SMLAWT_CC: "SMLAWT.CC",
+ arm_SMLAWT_MI: "SMLAWT.MI",
+ arm_SMLAWT_PL: "SMLAWT.PL",
+ arm_SMLAWT_VS: "SMLAWT.VS",
+ arm_SMLAWT_VC: "SMLAWT.VC",
+ arm_SMLAWT_HI: "SMLAWT.HI",
+ arm_SMLAWT_LS: "SMLAWT.LS",
+ arm_SMLAWT_GE: "SMLAWT.GE",
+ arm_SMLAWT_LT: "SMLAWT.LT",
+ arm_SMLAWT_GT: "SMLAWT.GT",
+ arm_SMLAWT_LE: "SMLAWT.LE",
+ arm_SMLAWT: "SMLAWT",
+ arm_SMLAWT_ZZ: "SMLAWT.ZZ",
+ arm_SMLSD_EQ: "SMLSD.EQ",
+ arm_SMLSD_NE: "SMLSD.NE",
+ arm_SMLSD_CS: "SMLSD.CS",
+ arm_SMLSD_CC: "SMLSD.CC",
+ arm_SMLSD_MI: "SMLSD.MI",
+ arm_SMLSD_PL: "SMLSD.PL",
+ arm_SMLSD_VS: "SMLSD.VS",
+ arm_SMLSD_VC: "SMLSD.VC",
+ arm_SMLSD_HI: "SMLSD.HI",
+ arm_SMLSD_LS: "SMLSD.LS",
+ arm_SMLSD_GE: "SMLSD.GE",
+ arm_SMLSD_LT: "SMLSD.LT",
+ arm_SMLSD_GT: "SMLSD.GT",
+ arm_SMLSD_LE: "SMLSD.LE",
+ arm_SMLSD: "SMLSD",
+ arm_SMLSD_ZZ: "SMLSD.ZZ",
+ arm_SMLSD_X_EQ: "SMLSD.X.EQ",
+ arm_SMLSD_X_NE: "SMLSD.X.NE",
+ arm_SMLSD_X_CS: "SMLSD.X.CS",
+ arm_SMLSD_X_CC: "SMLSD.X.CC",
+ arm_SMLSD_X_MI: "SMLSD.X.MI",
+ arm_SMLSD_X_PL: "SMLSD.X.PL",
+ arm_SMLSD_X_VS: "SMLSD.X.VS",
+ arm_SMLSD_X_VC: "SMLSD.X.VC",
+ arm_SMLSD_X_HI: "SMLSD.X.HI",
+ arm_SMLSD_X_LS: "SMLSD.X.LS",
+ arm_SMLSD_X_GE: "SMLSD.X.GE",
+ arm_SMLSD_X_LT: "SMLSD.X.LT",
+ arm_SMLSD_X_GT: "SMLSD.X.GT",
+ arm_SMLSD_X_LE: "SMLSD.X.LE",
+ arm_SMLSD_X: "SMLSD.X",
+ arm_SMLSD_X_ZZ: "SMLSD.X.ZZ",
+ arm_SMLSLD_EQ: "SMLSLD.EQ",
+ arm_SMLSLD_NE: "SMLSLD.NE",
+ arm_SMLSLD_CS: "SMLSLD.CS",
+ arm_SMLSLD_CC: "SMLSLD.CC",
+ arm_SMLSLD_MI: "SMLSLD.MI",
+ arm_SMLSLD_PL: "SMLSLD.PL",
+ arm_SMLSLD_VS: "SMLSLD.VS",
+ arm_SMLSLD_VC: "SMLSLD.VC",
+ arm_SMLSLD_HI: "SMLSLD.HI",
+ arm_SMLSLD_LS: "SMLSLD.LS",
+ arm_SMLSLD_GE: "SMLSLD.GE",
+ arm_SMLSLD_LT: "SMLSLD.LT",
+ arm_SMLSLD_GT: "SMLSLD.GT",
+ arm_SMLSLD_LE: "SMLSLD.LE",
+ arm_SMLSLD: "SMLSLD",
+ arm_SMLSLD_ZZ: "SMLSLD.ZZ",
+ arm_SMLSLD_X_EQ: "SMLSLD.X.EQ",
+ arm_SMLSLD_X_NE: "SMLSLD.X.NE",
+ arm_SMLSLD_X_CS: "SMLSLD.X.CS",
+ arm_SMLSLD_X_CC: "SMLSLD.X.CC",
+ arm_SMLSLD_X_MI: "SMLSLD.X.MI",
+ arm_SMLSLD_X_PL: "SMLSLD.X.PL",
+ arm_SMLSLD_X_VS: "SMLSLD.X.VS",
+ arm_SMLSLD_X_VC: "SMLSLD.X.VC",
+ arm_SMLSLD_X_HI: "SMLSLD.X.HI",
+ arm_SMLSLD_X_LS: "SMLSLD.X.LS",
+ arm_SMLSLD_X_GE: "SMLSLD.X.GE",
+ arm_SMLSLD_X_LT: "SMLSLD.X.LT",
+ arm_SMLSLD_X_GT: "SMLSLD.X.GT",
+ arm_SMLSLD_X_LE: "SMLSLD.X.LE",
+ arm_SMLSLD_X: "SMLSLD.X",
+ arm_SMLSLD_X_ZZ: "SMLSLD.X.ZZ",
+ arm_SMMLA_EQ: "SMMLA.EQ",
+ arm_SMMLA_NE: "SMMLA.NE",
+ arm_SMMLA_CS: "SMMLA.CS",
+ arm_SMMLA_CC: "SMMLA.CC",
+ arm_SMMLA_MI: "SMMLA.MI",
+ arm_SMMLA_PL: "SMMLA.PL",
+ arm_SMMLA_VS: "SMMLA.VS",
+ arm_SMMLA_VC: "SMMLA.VC",
+ arm_SMMLA_HI: "SMMLA.HI",
+ arm_SMMLA_LS: "SMMLA.LS",
+ arm_SMMLA_GE: "SMMLA.GE",
+ arm_SMMLA_LT: "SMMLA.LT",
+ arm_SMMLA_GT: "SMMLA.GT",
+ arm_SMMLA_LE: "SMMLA.LE",
+ arm_SMMLA: "SMMLA",
+ arm_SMMLA_ZZ: "SMMLA.ZZ",
+ arm_SMMLA_R_EQ: "SMMLA.R.EQ",
+ arm_SMMLA_R_NE: "SMMLA.R.NE",
+ arm_SMMLA_R_CS: "SMMLA.R.CS",
+ arm_SMMLA_R_CC: "SMMLA.R.CC",
+ arm_SMMLA_R_MI: "SMMLA.R.MI",
+ arm_SMMLA_R_PL: "SMMLA.R.PL",
+ arm_SMMLA_R_VS: "SMMLA.R.VS",
+ arm_SMMLA_R_VC: "SMMLA.R.VC",
+ arm_SMMLA_R_HI: "SMMLA.R.HI",
+ arm_SMMLA_R_LS: "SMMLA.R.LS",
+ arm_SMMLA_R_GE: "SMMLA.R.GE",
+ arm_SMMLA_R_LT: "SMMLA.R.LT",
+ arm_SMMLA_R_GT: "SMMLA.R.GT",
+ arm_SMMLA_R_LE: "SMMLA.R.LE",
+ arm_SMMLA_R: "SMMLA.R",
+ arm_SMMLA_R_ZZ: "SMMLA.R.ZZ",
+ arm_SMMLS_EQ: "SMMLS.EQ",
+ arm_SMMLS_NE: "SMMLS.NE",
+ arm_SMMLS_CS: "SMMLS.CS",
+ arm_SMMLS_CC: "SMMLS.CC",
+ arm_SMMLS_MI: "SMMLS.MI",
+ arm_SMMLS_PL: "SMMLS.PL",
+ arm_SMMLS_VS: "SMMLS.VS",
+ arm_SMMLS_VC: "SMMLS.VC",
+ arm_SMMLS_HI: "SMMLS.HI",
+ arm_SMMLS_LS: "SMMLS.LS",
+ arm_SMMLS_GE: "SMMLS.GE",
+ arm_SMMLS_LT: "SMMLS.LT",
+ arm_SMMLS_GT: "SMMLS.GT",
+ arm_SMMLS_LE: "SMMLS.LE",
+ arm_SMMLS: "SMMLS",
+ arm_SMMLS_ZZ: "SMMLS.ZZ",
+ arm_SMMLS_R_EQ: "SMMLS.R.EQ",
+ arm_SMMLS_R_NE: "SMMLS.R.NE",
+ arm_SMMLS_R_CS: "SMMLS.R.CS",
+ arm_SMMLS_R_CC: "SMMLS.R.CC",
+ arm_SMMLS_R_MI: "SMMLS.R.MI",
+ arm_SMMLS_R_PL: "SMMLS.R.PL",
+ arm_SMMLS_R_VS: "SMMLS.R.VS",
+ arm_SMMLS_R_VC: "SMMLS.R.VC",
+ arm_SMMLS_R_HI: "SMMLS.R.HI",
+ arm_SMMLS_R_LS: "SMMLS.R.LS",
+ arm_SMMLS_R_GE: "SMMLS.R.GE",
+ arm_SMMLS_R_LT: "SMMLS.R.LT",
+ arm_SMMLS_R_GT: "SMMLS.R.GT",
+ arm_SMMLS_R_LE: "SMMLS.R.LE",
+ arm_SMMLS_R: "SMMLS.R",
+ arm_SMMLS_R_ZZ: "SMMLS.R.ZZ",
+ arm_SMMUL_EQ: "SMMUL.EQ",
+ arm_SMMUL_NE: "SMMUL.NE",
+ arm_SMMUL_CS: "SMMUL.CS",
+ arm_SMMUL_CC: "SMMUL.CC",
+ arm_SMMUL_MI: "SMMUL.MI",
+ arm_SMMUL_PL: "SMMUL.PL",
+ arm_SMMUL_VS: "SMMUL.VS",
+ arm_SMMUL_VC: "SMMUL.VC",
+ arm_SMMUL_HI: "SMMUL.HI",
+ arm_SMMUL_LS: "SMMUL.LS",
+ arm_SMMUL_GE: "SMMUL.GE",
+ arm_SMMUL_LT: "SMMUL.LT",
+ arm_SMMUL_GT: "SMMUL.GT",
+ arm_SMMUL_LE: "SMMUL.LE",
+ arm_SMMUL: "SMMUL",
+ arm_SMMUL_ZZ: "SMMUL.ZZ",
+ arm_SMMUL_R_EQ: "SMMUL.R.EQ",
+ arm_SMMUL_R_NE: "SMMUL.R.NE",
+ arm_SMMUL_R_CS: "SMMUL.R.CS",
+ arm_SMMUL_R_CC: "SMMUL.R.CC",
+ arm_SMMUL_R_MI: "SMMUL.R.MI",
+ arm_SMMUL_R_PL: "SMMUL.R.PL",
+ arm_SMMUL_R_VS: "SMMUL.R.VS",
+ arm_SMMUL_R_VC: "SMMUL.R.VC",
+ arm_SMMUL_R_HI: "SMMUL.R.HI",
+ arm_SMMUL_R_LS: "SMMUL.R.LS",
+ arm_SMMUL_R_GE: "SMMUL.R.GE",
+ arm_SMMUL_R_LT: "SMMUL.R.LT",
+ arm_SMMUL_R_GT: "SMMUL.R.GT",
+ arm_SMMUL_R_LE: "SMMUL.R.LE",
+ arm_SMMUL_R: "SMMUL.R",
+ arm_SMMUL_R_ZZ: "SMMUL.R.ZZ",
+ arm_SMUAD_EQ: "SMUAD.EQ",
+ arm_SMUAD_NE: "SMUAD.NE",
+ arm_SMUAD_CS: "SMUAD.CS",
+ arm_SMUAD_CC: "SMUAD.CC",
+ arm_SMUAD_MI: "SMUAD.MI",
+ arm_SMUAD_PL: "SMUAD.PL",
+ arm_SMUAD_VS: "SMUAD.VS",
+ arm_SMUAD_VC: "SMUAD.VC",
+ arm_SMUAD_HI: "SMUAD.HI",
+ arm_SMUAD_LS: "SMUAD.LS",
+ arm_SMUAD_GE: "SMUAD.GE",
+ arm_SMUAD_LT: "SMUAD.LT",
+ arm_SMUAD_GT: "SMUAD.GT",
+ arm_SMUAD_LE: "SMUAD.LE",
+ arm_SMUAD: "SMUAD",
+ arm_SMUAD_ZZ: "SMUAD.ZZ",
+ arm_SMUAD_X_EQ: "SMUAD.X.EQ",
+ arm_SMUAD_X_NE: "SMUAD.X.NE",
+ arm_SMUAD_X_CS: "SMUAD.X.CS",
+ arm_SMUAD_X_CC: "SMUAD.X.CC",
+ arm_SMUAD_X_MI: "SMUAD.X.MI",
+ arm_SMUAD_X_PL: "SMUAD.X.PL",
+ arm_SMUAD_X_VS: "SMUAD.X.VS",
+ arm_SMUAD_X_VC: "SMUAD.X.VC",
+ arm_SMUAD_X_HI: "SMUAD.X.HI",
+ arm_SMUAD_X_LS: "SMUAD.X.LS",
+ arm_SMUAD_X_GE: "SMUAD.X.GE",
+ arm_SMUAD_X_LT: "SMUAD.X.LT",
+ arm_SMUAD_X_GT: "SMUAD.X.GT",
+ arm_SMUAD_X_LE: "SMUAD.X.LE",
+ arm_SMUAD_X: "SMUAD.X",
+ arm_SMUAD_X_ZZ: "SMUAD.X.ZZ",
+ arm_SMULBB_EQ: "SMULBB.EQ",
+ arm_SMULBB_NE: "SMULBB.NE",
+ arm_SMULBB_CS: "SMULBB.CS",
+ arm_SMULBB_CC: "SMULBB.CC",
+ arm_SMULBB_MI: "SMULBB.MI",
+ arm_SMULBB_PL: "SMULBB.PL",
+ arm_SMULBB_VS: "SMULBB.VS",
+ arm_SMULBB_VC: "SMULBB.VC",
+ arm_SMULBB_HI: "SMULBB.HI",
+ arm_SMULBB_LS: "SMULBB.LS",
+ arm_SMULBB_GE: "SMULBB.GE",
+ arm_SMULBB_LT: "SMULBB.LT",
+ arm_SMULBB_GT: "SMULBB.GT",
+ arm_SMULBB_LE: "SMULBB.LE",
+ arm_SMULBB: "SMULBB",
+ arm_SMULBB_ZZ: "SMULBB.ZZ",
+ arm_SMULBT_EQ: "SMULBT.EQ",
+ arm_SMULBT_NE: "SMULBT.NE",
+ arm_SMULBT_CS: "SMULBT.CS",
+ arm_SMULBT_CC: "SMULBT.CC",
+ arm_SMULBT_MI: "SMULBT.MI",
+ arm_SMULBT_PL: "SMULBT.PL",
+ arm_SMULBT_VS: "SMULBT.VS",
+ arm_SMULBT_VC: "SMULBT.VC",
+ arm_SMULBT_HI: "SMULBT.HI",
+ arm_SMULBT_LS: "SMULBT.LS",
+ arm_SMULBT_GE: "SMULBT.GE",
+ arm_SMULBT_LT: "SMULBT.LT",
+ arm_SMULBT_GT: "SMULBT.GT",
+ arm_SMULBT_LE: "SMULBT.LE",
+ arm_SMULBT: "SMULBT",
+ arm_SMULBT_ZZ: "SMULBT.ZZ",
+ arm_SMULTB_EQ: "SMULTB.EQ",
+ arm_SMULTB_NE: "SMULTB.NE",
+ arm_SMULTB_CS: "SMULTB.CS",
+ arm_SMULTB_CC: "SMULTB.CC",
+ arm_SMULTB_MI: "SMULTB.MI",
+ arm_SMULTB_PL: "SMULTB.PL",
+ arm_SMULTB_VS: "SMULTB.VS",
+ arm_SMULTB_VC: "SMULTB.VC",
+ arm_SMULTB_HI: "SMULTB.HI",
+ arm_SMULTB_LS: "SMULTB.LS",
+ arm_SMULTB_GE: "SMULTB.GE",
+ arm_SMULTB_LT: "SMULTB.LT",
+ arm_SMULTB_GT: "SMULTB.GT",
+ arm_SMULTB_LE: "SMULTB.LE",
+ arm_SMULTB: "SMULTB",
+ arm_SMULTB_ZZ: "SMULTB.ZZ",
+ arm_SMULTT_EQ: "SMULTT.EQ",
+ arm_SMULTT_NE: "SMULTT.NE",
+ arm_SMULTT_CS: "SMULTT.CS",
+ arm_SMULTT_CC: "SMULTT.CC",
+ arm_SMULTT_MI: "SMULTT.MI",
+ arm_SMULTT_PL: "SMULTT.PL",
+ arm_SMULTT_VS: "SMULTT.VS",
+ arm_SMULTT_VC: "SMULTT.VC",
+ arm_SMULTT_HI: "SMULTT.HI",
+ arm_SMULTT_LS: "SMULTT.LS",
+ arm_SMULTT_GE: "SMULTT.GE",
+ arm_SMULTT_LT: "SMULTT.LT",
+ arm_SMULTT_GT: "SMULTT.GT",
+ arm_SMULTT_LE: "SMULTT.LE",
+ arm_SMULTT: "SMULTT",
+ arm_SMULTT_ZZ: "SMULTT.ZZ",
+ arm_SMULL_EQ: "SMULL.EQ",
+ arm_SMULL_NE: "SMULL.NE",
+ arm_SMULL_CS: "SMULL.CS",
+ arm_SMULL_CC: "SMULL.CC",
+ arm_SMULL_MI: "SMULL.MI",
+ arm_SMULL_PL: "SMULL.PL",
+ arm_SMULL_VS: "SMULL.VS",
+ arm_SMULL_VC: "SMULL.VC",
+ arm_SMULL_HI: "SMULL.HI",
+ arm_SMULL_LS: "SMULL.LS",
+ arm_SMULL_GE: "SMULL.GE",
+ arm_SMULL_LT: "SMULL.LT",
+ arm_SMULL_GT: "SMULL.GT",
+ arm_SMULL_LE: "SMULL.LE",
+ arm_SMULL: "SMULL",
+ arm_SMULL_ZZ: "SMULL.ZZ",
+ arm_SMULL_S_EQ: "SMULL.S.EQ",
+ arm_SMULL_S_NE: "SMULL.S.NE",
+ arm_SMULL_S_CS: "SMULL.S.CS",
+ arm_SMULL_S_CC: "SMULL.S.CC",
+ arm_SMULL_S_MI: "SMULL.S.MI",
+ arm_SMULL_S_PL: "SMULL.S.PL",
+ arm_SMULL_S_VS: "SMULL.S.VS",
+ arm_SMULL_S_VC: "SMULL.S.VC",
+ arm_SMULL_S_HI: "SMULL.S.HI",
+ arm_SMULL_S_LS: "SMULL.S.LS",
+ arm_SMULL_S_GE: "SMULL.S.GE",
+ arm_SMULL_S_LT: "SMULL.S.LT",
+ arm_SMULL_S_GT: "SMULL.S.GT",
+ arm_SMULL_S_LE: "SMULL.S.LE",
+ arm_SMULL_S: "SMULL.S",
+ arm_SMULL_S_ZZ: "SMULL.S.ZZ",
+ arm_SMULWB_EQ: "SMULWB.EQ",
+ arm_SMULWB_NE: "SMULWB.NE",
+ arm_SMULWB_CS: "SMULWB.CS",
+ arm_SMULWB_CC: "SMULWB.CC",
+ arm_SMULWB_MI: "SMULWB.MI",
+ arm_SMULWB_PL: "SMULWB.PL",
+ arm_SMULWB_VS: "SMULWB.VS",
+ arm_SMULWB_VC: "SMULWB.VC",
+ arm_SMULWB_HI: "SMULWB.HI",
+ arm_SMULWB_LS: "SMULWB.LS",
+ arm_SMULWB_GE: "SMULWB.GE",
+ arm_SMULWB_LT: "SMULWB.LT",
+ arm_SMULWB_GT: "SMULWB.GT",
+ arm_SMULWB_LE: "SMULWB.LE",
+ arm_SMULWB: "SMULWB",
+ arm_SMULWB_ZZ: "SMULWB.ZZ",
+ arm_SMULWT_EQ: "SMULWT.EQ",
+ arm_SMULWT_NE: "SMULWT.NE",
+ arm_SMULWT_CS: "SMULWT.CS",
+ arm_SMULWT_CC: "SMULWT.CC",
+ arm_SMULWT_MI: "SMULWT.MI",
+ arm_SMULWT_PL: "SMULWT.PL",
+ arm_SMULWT_VS: "SMULWT.VS",
+ arm_SMULWT_VC: "SMULWT.VC",
+ arm_SMULWT_HI: "SMULWT.HI",
+ arm_SMULWT_LS: "SMULWT.LS",
+ arm_SMULWT_GE: "SMULWT.GE",
+ arm_SMULWT_LT: "SMULWT.LT",
+ arm_SMULWT_GT: "SMULWT.GT",
+ arm_SMULWT_LE: "SMULWT.LE",
+ arm_SMULWT: "SMULWT",
+ arm_SMULWT_ZZ: "SMULWT.ZZ",
+ arm_SMUSD_EQ: "SMUSD.EQ",
+ arm_SMUSD_NE: "SMUSD.NE",
+ arm_SMUSD_CS: "SMUSD.CS",
+ arm_SMUSD_CC: "SMUSD.CC",
+ arm_SMUSD_MI: "SMUSD.MI",
+ arm_SMUSD_PL: "SMUSD.PL",
+ arm_SMUSD_VS: "SMUSD.VS",
+ arm_SMUSD_VC: "SMUSD.VC",
+ arm_SMUSD_HI: "SMUSD.HI",
+ arm_SMUSD_LS: "SMUSD.LS",
+ arm_SMUSD_GE: "SMUSD.GE",
+ arm_SMUSD_LT: "SMUSD.LT",
+ arm_SMUSD_GT: "SMUSD.GT",
+ arm_SMUSD_LE: "SMUSD.LE",
+ arm_SMUSD: "SMUSD",
+ arm_SMUSD_ZZ: "SMUSD.ZZ",
+ arm_SMUSD_X_EQ: "SMUSD.X.EQ",
+ arm_SMUSD_X_NE: "SMUSD.X.NE",
+ arm_SMUSD_X_CS: "SMUSD.X.CS",
+ arm_SMUSD_X_CC: "SMUSD.X.CC",
+ arm_SMUSD_X_MI: "SMUSD.X.MI",
+ arm_SMUSD_X_PL: "SMUSD.X.PL",
+ arm_SMUSD_X_VS: "SMUSD.X.VS",
+ arm_SMUSD_X_VC: "SMUSD.X.VC",
+ arm_SMUSD_X_HI: "SMUSD.X.HI",
+ arm_SMUSD_X_LS: "SMUSD.X.LS",
+ arm_SMUSD_X_GE: "SMUSD.X.GE",
+ arm_SMUSD_X_LT: "SMUSD.X.LT",
+ arm_SMUSD_X_GT: "SMUSD.X.GT",
+ arm_SMUSD_X_LE: "SMUSD.X.LE",
+ arm_SMUSD_X: "SMUSD.X",
+ arm_SMUSD_X_ZZ: "SMUSD.X.ZZ",
+ arm_SSAT_EQ: "SSAT.EQ",
+ arm_SSAT_NE: "SSAT.NE",
+ arm_SSAT_CS: "SSAT.CS",
+ arm_SSAT_CC: "SSAT.CC",
+ arm_SSAT_MI: "SSAT.MI",
+ arm_SSAT_PL: "SSAT.PL",
+ arm_SSAT_VS: "SSAT.VS",
+ arm_SSAT_VC: "SSAT.VC",
+ arm_SSAT_HI: "SSAT.HI",
+ arm_SSAT_LS: "SSAT.LS",
+ arm_SSAT_GE: "SSAT.GE",
+ arm_SSAT_LT: "SSAT.LT",
+ arm_SSAT_GT: "SSAT.GT",
+ arm_SSAT_LE: "SSAT.LE",
+ arm_SSAT: "SSAT",
+ arm_SSAT_ZZ: "SSAT.ZZ",
+ arm_SSAT16_EQ: "SSAT16.EQ",
+ arm_SSAT16_NE: "SSAT16.NE",
+ arm_SSAT16_CS: "SSAT16.CS",
+ arm_SSAT16_CC: "SSAT16.CC",
+ arm_SSAT16_MI: "SSAT16.MI",
+ arm_SSAT16_PL: "SSAT16.PL",
+ arm_SSAT16_VS: "SSAT16.VS",
+ arm_SSAT16_VC: "SSAT16.VC",
+ arm_SSAT16_HI: "SSAT16.HI",
+ arm_SSAT16_LS: "SSAT16.LS",
+ arm_SSAT16_GE: "SSAT16.GE",
+ arm_SSAT16_LT: "SSAT16.LT",
+ arm_SSAT16_GT: "SSAT16.GT",
+ arm_SSAT16_LE: "SSAT16.LE",
+ arm_SSAT16: "SSAT16",
+ arm_SSAT16_ZZ: "SSAT16.ZZ",
+ arm_SSAX_EQ: "SSAX.EQ",
+ arm_SSAX_NE: "SSAX.NE",
+ arm_SSAX_CS: "SSAX.CS",
+ arm_SSAX_CC: "SSAX.CC",
+ arm_SSAX_MI: "SSAX.MI",
+ arm_SSAX_PL: "SSAX.PL",
+ arm_SSAX_VS: "SSAX.VS",
+ arm_SSAX_VC: "SSAX.VC",
+ arm_SSAX_HI: "SSAX.HI",
+ arm_SSAX_LS: "SSAX.LS",
+ arm_SSAX_GE: "SSAX.GE",
+ arm_SSAX_LT: "SSAX.LT",
+ arm_SSAX_GT: "SSAX.GT",
+ arm_SSAX_LE: "SSAX.LE",
+ arm_SSAX: "SSAX",
+ arm_SSAX_ZZ: "SSAX.ZZ",
+ arm_SSUB16_EQ: "SSUB16.EQ",
+ arm_SSUB16_NE: "SSUB16.NE",
+ arm_SSUB16_CS: "SSUB16.CS",
+ arm_SSUB16_CC: "SSUB16.CC",
+ arm_SSUB16_MI: "SSUB16.MI",
+ arm_SSUB16_PL: "SSUB16.PL",
+ arm_SSUB16_VS: "SSUB16.VS",
+ arm_SSUB16_VC: "SSUB16.VC",
+ arm_SSUB16_HI: "SSUB16.HI",
+ arm_SSUB16_LS: "SSUB16.LS",
+ arm_SSUB16_GE: "SSUB16.GE",
+ arm_SSUB16_LT: "SSUB16.LT",
+ arm_SSUB16_GT: "SSUB16.GT",
+ arm_SSUB16_LE: "SSUB16.LE",
+ arm_SSUB16: "SSUB16",
+ arm_SSUB16_ZZ: "SSUB16.ZZ",
+ arm_SSUB8_EQ: "SSUB8.EQ",
+ arm_SSUB8_NE: "SSUB8.NE",
+ arm_SSUB8_CS: "SSUB8.CS",
+ arm_SSUB8_CC: "SSUB8.CC",
+ arm_SSUB8_MI: "SSUB8.MI",
+ arm_SSUB8_PL: "SSUB8.PL",
+ arm_SSUB8_VS: "SSUB8.VS",
+ arm_SSUB8_VC: "SSUB8.VC",
+ arm_SSUB8_HI: "SSUB8.HI",
+ arm_SSUB8_LS: "SSUB8.LS",
+ arm_SSUB8_GE: "SSUB8.GE",
+ arm_SSUB8_LT: "SSUB8.LT",
+ arm_SSUB8_GT: "SSUB8.GT",
+ arm_SSUB8_LE: "SSUB8.LE",
+ arm_SSUB8: "SSUB8",
+ arm_SSUB8_ZZ: "SSUB8.ZZ",
+ arm_STM_EQ: "STM.EQ",
+ arm_STM_NE: "STM.NE",
+ arm_STM_CS: "STM.CS",
+ arm_STM_CC: "STM.CC",
+ arm_STM_MI: "STM.MI",
+ arm_STM_PL: "STM.PL",
+ arm_STM_VS: "STM.VS",
+ arm_STM_VC: "STM.VC",
+ arm_STM_HI: "STM.HI",
+ arm_STM_LS: "STM.LS",
+ arm_STM_GE: "STM.GE",
+ arm_STM_LT: "STM.LT",
+ arm_STM_GT: "STM.GT",
+ arm_STM_LE: "STM.LE",
+ arm_STM: "STM",
+ arm_STM_ZZ: "STM.ZZ",
+ arm_STMDA_EQ: "STMDA.EQ",
+ arm_STMDA_NE: "STMDA.NE",
+ arm_STMDA_CS: "STMDA.CS",
+ arm_STMDA_CC: "STMDA.CC",
+ arm_STMDA_MI: "STMDA.MI",
+ arm_STMDA_PL: "STMDA.PL",
+ arm_STMDA_VS: "STMDA.VS",
+ arm_STMDA_VC: "STMDA.VC",
+ arm_STMDA_HI: "STMDA.HI",
+ arm_STMDA_LS: "STMDA.LS",
+ arm_STMDA_GE: "STMDA.GE",
+ arm_STMDA_LT: "STMDA.LT",
+ arm_STMDA_GT: "STMDA.GT",
+ arm_STMDA_LE: "STMDA.LE",
+ arm_STMDA: "STMDA",
+ arm_STMDA_ZZ: "STMDA.ZZ",
+ arm_STMDB_EQ: "STMDB.EQ",
+ arm_STMDB_NE: "STMDB.NE",
+ arm_STMDB_CS: "STMDB.CS",
+ arm_STMDB_CC: "STMDB.CC",
+ arm_STMDB_MI: "STMDB.MI",
+ arm_STMDB_PL: "STMDB.PL",
+ arm_STMDB_VS: "STMDB.VS",
+ arm_STMDB_VC: "STMDB.VC",
+ arm_STMDB_HI: "STMDB.HI",
+ arm_STMDB_LS: "STMDB.LS",
+ arm_STMDB_GE: "STMDB.GE",
+ arm_STMDB_LT: "STMDB.LT",
+ arm_STMDB_GT: "STMDB.GT",
+ arm_STMDB_LE: "STMDB.LE",
+ arm_STMDB: "STMDB",
+ arm_STMDB_ZZ: "STMDB.ZZ",
+ arm_STMIB_EQ: "STMIB.EQ",
+ arm_STMIB_NE: "STMIB.NE",
+ arm_STMIB_CS: "STMIB.CS",
+ arm_STMIB_CC: "STMIB.CC",
+ arm_STMIB_MI: "STMIB.MI",
+ arm_STMIB_PL: "STMIB.PL",
+ arm_STMIB_VS: "STMIB.VS",
+ arm_STMIB_VC: "STMIB.VC",
+ arm_STMIB_HI: "STMIB.HI",
+ arm_STMIB_LS: "STMIB.LS",
+ arm_STMIB_GE: "STMIB.GE",
+ arm_STMIB_LT: "STMIB.LT",
+ arm_STMIB_GT: "STMIB.GT",
+ arm_STMIB_LE: "STMIB.LE",
+ arm_STMIB: "STMIB",
+ arm_STMIB_ZZ: "STMIB.ZZ",
+ arm_STR_EQ: "STR.EQ",
+ arm_STR_NE: "STR.NE",
+ arm_STR_CS: "STR.CS",
+ arm_STR_CC: "STR.CC",
+ arm_STR_MI: "STR.MI",
+ arm_STR_PL: "STR.PL",
+ arm_STR_VS: "STR.VS",
+ arm_STR_VC: "STR.VC",
+ arm_STR_HI: "STR.HI",
+ arm_STR_LS: "STR.LS",
+ arm_STR_GE: "STR.GE",
+ arm_STR_LT: "STR.LT",
+ arm_STR_GT: "STR.GT",
+ arm_STR_LE: "STR.LE",
+ arm_STR: "STR",
+ arm_STR_ZZ: "STR.ZZ",
+ arm_STRB_EQ: "STRB.EQ",
+ arm_STRB_NE: "STRB.NE",
+ arm_STRB_CS: "STRB.CS",
+ arm_STRB_CC: "STRB.CC",
+ arm_STRB_MI: "STRB.MI",
+ arm_STRB_PL: "STRB.PL",
+ arm_STRB_VS: "STRB.VS",
+ arm_STRB_VC: "STRB.VC",
+ arm_STRB_HI: "STRB.HI",
+ arm_STRB_LS: "STRB.LS",
+ arm_STRB_GE: "STRB.GE",
+ arm_STRB_LT: "STRB.LT",
+ arm_STRB_GT: "STRB.GT",
+ arm_STRB_LE: "STRB.LE",
+ arm_STRB: "STRB",
+ arm_STRB_ZZ: "STRB.ZZ",
+ arm_STRBT_EQ: "STRBT.EQ",
+ arm_STRBT_NE: "STRBT.NE",
+ arm_STRBT_CS: "STRBT.CS",
+ arm_STRBT_CC: "STRBT.CC",
+ arm_STRBT_MI: "STRBT.MI",
+ arm_STRBT_PL: "STRBT.PL",
+ arm_STRBT_VS: "STRBT.VS",
+ arm_STRBT_VC: "STRBT.VC",
+ arm_STRBT_HI: "STRBT.HI",
+ arm_STRBT_LS: "STRBT.LS",
+ arm_STRBT_GE: "STRBT.GE",
+ arm_STRBT_LT: "STRBT.LT",
+ arm_STRBT_GT: "STRBT.GT",
+ arm_STRBT_LE: "STRBT.LE",
+ arm_STRBT: "STRBT",
+ arm_STRBT_ZZ: "STRBT.ZZ",
+ arm_STRD_EQ: "STRD.EQ",
+ arm_STRD_NE: "STRD.NE",
+ arm_STRD_CS: "STRD.CS",
+ arm_STRD_CC: "STRD.CC",
+ arm_STRD_MI: "STRD.MI",
+ arm_STRD_PL: "STRD.PL",
+ arm_STRD_VS: "STRD.VS",
+ arm_STRD_VC: "STRD.VC",
+ arm_STRD_HI: "STRD.HI",
+ arm_STRD_LS: "STRD.LS",
+ arm_STRD_GE: "STRD.GE",
+ arm_STRD_LT: "STRD.LT",
+ arm_STRD_GT: "STRD.GT",
+ arm_STRD_LE: "STRD.LE",
+ arm_STRD: "STRD",
+ arm_STRD_ZZ: "STRD.ZZ",
+ arm_STREX_EQ: "STREX.EQ",
+ arm_STREX_NE: "STREX.NE",
+ arm_STREX_CS: "STREX.CS",
+ arm_STREX_CC: "STREX.CC",
+ arm_STREX_MI: "STREX.MI",
+ arm_STREX_PL: "STREX.PL",
+ arm_STREX_VS: "STREX.VS",
+ arm_STREX_VC: "STREX.VC",
+ arm_STREX_HI: "STREX.HI",
+ arm_STREX_LS: "STREX.LS",
+ arm_STREX_GE: "STREX.GE",
+ arm_STREX_LT: "STREX.LT",
+ arm_STREX_GT: "STREX.GT",
+ arm_STREX_LE: "STREX.LE",
+ arm_STREX: "STREX",
+ arm_STREX_ZZ: "STREX.ZZ",
+ arm_STREXB_EQ: "STREXB.EQ",
+ arm_STREXB_NE: "STREXB.NE",
+ arm_STREXB_CS: "STREXB.CS",
+ arm_STREXB_CC: "STREXB.CC",
+ arm_STREXB_MI: "STREXB.MI",
+ arm_STREXB_PL: "STREXB.PL",
+ arm_STREXB_VS: "STREXB.VS",
+ arm_STREXB_VC: "STREXB.VC",
+ arm_STREXB_HI: "STREXB.HI",
+ arm_STREXB_LS: "STREXB.LS",
+ arm_STREXB_GE: "STREXB.GE",
+ arm_STREXB_LT: "STREXB.LT",
+ arm_STREXB_GT: "STREXB.GT",
+ arm_STREXB_LE: "STREXB.LE",
+ arm_STREXB: "STREXB",
+ arm_STREXB_ZZ: "STREXB.ZZ",
+ arm_STREXD_EQ: "STREXD.EQ",
+ arm_STREXD_NE: "STREXD.NE",
+ arm_STREXD_CS: "STREXD.CS",
+ arm_STREXD_CC: "STREXD.CC",
+ arm_STREXD_MI: "STREXD.MI",
+ arm_STREXD_PL: "STREXD.PL",
+ arm_STREXD_VS: "STREXD.VS",
+ arm_STREXD_VC: "STREXD.VC",
+ arm_STREXD_HI: "STREXD.HI",
+ arm_STREXD_LS: "STREXD.LS",
+ arm_STREXD_GE: "STREXD.GE",
+ arm_STREXD_LT: "STREXD.LT",
+ arm_STREXD_GT: "STREXD.GT",
+ arm_STREXD_LE: "STREXD.LE",
+ arm_STREXD: "STREXD",
+ arm_STREXD_ZZ: "STREXD.ZZ",
+ arm_STREXH_EQ: "STREXH.EQ",
+ arm_STREXH_NE: "STREXH.NE",
+ arm_STREXH_CS: "STREXH.CS",
+ arm_STREXH_CC: "STREXH.CC",
+ arm_STREXH_MI: "STREXH.MI",
+ arm_STREXH_PL: "STREXH.PL",
+ arm_STREXH_VS: "STREXH.VS",
+ arm_STREXH_VC: "STREXH.VC",
+ arm_STREXH_HI: "STREXH.HI",
+ arm_STREXH_LS: "STREXH.LS",
+ arm_STREXH_GE: "STREXH.GE",
+ arm_STREXH_LT: "STREXH.LT",
+ arm_STREXH_GT: "STREXH.GT",
+ arm_STREXH_LE: "STREXH.LE",
+ arm_STREXH: "STREXH",
+ arm_STREXH_ZZ: "STREXH.ZZ",
+ arm_STRH_EQ: "STRH.EQ",
+ arm_STRH_NE: "STRH.NE",
+ arm_STRH_CS: "STRH.CS",
+ arm_STRH_CC: "STRH.CC",
+ arm_STRH_MI: "STRH.MI",
+ arm_STRH_PL: "STRH.PL",
+ arm_STRH_VS: "STRH.VS",
+ arm_STRH_VC: "STRH.VC",
+ arm_STRH_HI: "STRH.HI",
+ arm_STRH_LS: "STRH.LS",
+ arm_STRH_GE: "STRH.GE",
+ arm_STRH_LT: "STRH.LT",
+ arm_STRH_GT: "STRH.GT",
+ arm_STRH_LE: "STRH.LE",
+ arm_STRH: "STRH",
+ arm_STRH_ZZ: "STRH.ZZ",
+ arm_STRHT_EQ: "STRHT.EQ",
+ arm_STRHT_NE: "STRHT.NE",
+ arm_STRHT_CS: "STRHT.CS",
+ arm_STRHT_CC: "STRHT.CC",
+ arm_STRHT_MI: "STRHT.MI",
+ arm_STRHT_PL: "STRHT.PL",
+ arm_STRHT_VS: "STRHT.VS",
+ arm_STRHT_VC: "STRHT.VC",
+ arm_STRHT_HI: "STRHT.HI",
+ arm_STRHT_LS: "STRHT.LS",
+ arm_STRHT_GE: "STRHT.GE",
+ arm_STRHT_LT: "STRHT.LT",
+ arm_STRHT_GT: "STRHT.GT",
+ arm_STRHT_LE: "STRHT.LE",
+ arm_STRHT: "STRHT",
+ arm_STRHT_ZZ: "STRHT.ZZ",
+ arm_STRT_EQ: "STRT.EQ",
+ arm_STRT_NE: "STRT.NE",
+ arm_STRT_CS: "STRT.CS",
+ arm_STRT_CC: "STRT.CC",
+ arm_STRT_MI: "STRT.MI",
+ arm_STRT_PL: "STRT.PL",
+ arm_STRT_VS: "STRT.VS",
+ arm_STRT_VC: "STRT.VC",
+ arm_STRT_HI: "STRT.HI",
+ arm_STRT_LS: "STRT.LS",
+ arm_STRT_GE: "STRT.GE",
+ arm_STRT_LT: "STRT.LT",
+ arm_STRT_GT: "STRT.GT",
+ arm_STRT_LE: "STRT.LE",
+ arm_STRT: "STRT",
+ arm_STRT_ZZ: "STRT.ZZ",
+ arm_SUB_EQ: "SUB.EQ",
+ arm_SUB_NE: "SUB.NE",
+ arm_SUB_CS: "SUB.CS",
+ arm_SUB_CC: "SUB.CC",
+ arm_SUB_MI: "SUB.MI",
+ arm_SUB_PL: "SUB.PL",
+ arm_SUB_VS: "SUB.VS",
+ arm_SUB_VC: "SUB.VC",
+ arm_SUB_HI: "SUB.HI",
+ arm_SUB_LS: "SUB.LS",
+ arm_SUB_GE: "SUB.GE",
+ arm_SUB_LT: "SUB.LT",
+ arm_SUB_GT: "SUB.GT",
+ arm_SUB_LE: "SUB.LE",
+ arm_SUB: "SUB",
+ arm_SUB_ZZ: "SUB.ZZ",
+ arm_SUB_S_EQ: "SUB.S.EQ",
+ arm_SUB_S_NE: "SUB.S.NE",
+ arm_SUB_S_CS: "SUB.S.CS",
+ arm_SUB_S_CC: "SUB.S.CC",
+ arm_SUB_S_MI: "SUB.S.MI",
+ arm_SUB_S_PL: "SUB.S.PL",
+ arm_SUB_S_VS: "SUB.S.VS",
+ arm_SUB_S_VC: "SUB.S.VC",
+ arm_SUB_S_HI: "SUB.S.HI",
+ arm_SUB_S_LS: "SUB.S.LS",
+ arm_SUB_S_GE: "SUB.S.GE",
+ arm_SUB_S_LT: "SUB.S.LT",
+ arm_SUB_S_GT: "SUB.S.GT",
+ arm_SUB_S_LE: "SUB.S.LE",
+ arm_SUB_S: "SUB.S",
+ arm_SUB_S_ZZ: "SUB.S.ZZ",
+ arm_SVC_EQ: "SVC.EQ",
+ arm_SVC_NE: "SVC.NE",
+ arm_SVC_CS: "SVC.CS",
+ arm_SVC_CC: "SVC.CC",
+ arm_SVC_MI: "SVC.MI",
+ arm_SVC_PL: "SVC.PL",
+ arm_SVC_VS: "SVC.VS",
+ arm_SVC_VC: "SVC.VC",
+ arm_SVC_HI: "SVC.HI",
+ arm_SVC_LS: "SVC.LS",
+ arm_SVC_GE: "SVC.GE",
+ arm_SVC_LT: "SVC.LT",
+ arm_SVC_GT: "SVC.GT",
+ arm_SVC_LE: "SVC.LE",
+ arm_SVC: "SVC",
+ arm_SVC_ZZ: "SVC.ZZ",
+ arm_SWP_EQ: "SWP.EQ",
+ arm_SWP_NE: "SWP.NE",
+ arm_SWP_CS: "SWP.CS",
+ arm_SWP_CC: "SWP.CC",
+ arm_SWP_MI: "SWP.MI",
+ arm_SWP_PL: "SWP.PL",
+ arm_SWP_VS: "SWP.VS",
+ arm_SWP_VC: "SWP.VC",
+ arm_SWP_HI: "SWP.HI",
+ arm_SWP_LS: "SWP.LS",
+ arm_SWP_GE: "SWP.GE",
+ arm_SWP_LT: "SWP.LT",
+ arm_SWP_GT: "SWP.GT",
+ arm_SWP_LE: "SWP.LE",
+ arm_SWP: "SWP",
+ arm_SWP_ZZ: "SWP.ZZ",
+ arm_SWP_B_EQ: "SWP.B.EQ",
+ arm_SWP_B_NE: "SWP.B.NE",
+ arm_SWP_B_CS: "SWP.B.CS",
+ arm_SWP_B_CC: "SWP.B.CC",
+ arm_SWP_B_MI: "SWP.B.MI",
+ arm_SWP_B_PL: "SWP.B.PL",
+ arm_SWP_B_VS: "SWP.B.VS",
+ arm_SWP_B_VC: "SWP.B.VC",
+ arm_SWP_B_HI: "SWP.B.HI",
+ arm_SWP_B_LS: "SWP.B.LS",
+ arm_SWP_B_GE: "SWP.B.GE",
+ arm_SWP_B_LT: "SWP.B.LT",
+ arm_SWP_B_GT: "SWP.B.GT",
+ arm_SWP_B_LE: "SWP.B.LE",
+ arm_SWP_B: "SWP.B",
+ arm_SWP_B_ZZ: "SWP.B.ZZ",
+ arm_SXTAB_EQ: "SXTAB.EQ",
+ arm_SXTAB_NE: "SXTAB.NE",
+ arm_SXTAB_CS: "SXTAB.CS",
+ arm_SXTAB_CC: "SXTAB.CC",
+ arm_SXTAB_MI: "SXTAB.MI",
+ arm_SXTAB_PL: "SXTAB.PL",
+ arm_SXTAB_VS: "SXTAB.VS",
+ arm_SXTAB_VC: "SXTAB.VC",
+ arm_SXTAB_HI: "SXTAB.HI",
+ arm_SXTAB_LS: "SXTAB.LS",
+ arm_SXTAB_GE: "SXTAB.GE",
+ arm_SXTAB_LT: "SXTAB.LT",
+ arm_SXTAB_GT: "SXTAB.GT",
+ arm_SXTAB_LE: "SXTAB.LE",
+ arm_SXTAB: "SXTAB",
+ arm_SXTAB_ZZ: "SXTAB.ZZ",
+ arm_SXTAB16_EQ: "SXTAB16.EQ",
+ arm_SXTAB16_NE: "SXTAB16.NE",
+ arm_SXTAB16_CS: "SXTAB16.CS",
+ arm_SXTAB16_CC: "SXTAB16.CC",
+ arm_SXTAB16_MI: "SXTAB16.MI",
+ arm_SXTAB16_PL: "SXTAB16.PL",
+ arm_SXTAB16_VS: "SXTAB16.VS",
+ arm_SXTAB16_VC: "SXTAB16.VC",
+ arm_SXTAB16_HI: "SXTAB16.HI",
+ arm_SXTAB16_LS: "SXTAB16.LS",
+ arm_SXTAB16_GE: "SXTAB16.GE",
+ arm_SXTAB16_LT: "SXTAB16.LT",
+ arm_SXTAB16_GT: "SXTAB16.GT",
+ arm_SXTAB16_LE: "SXTAB16.LE",
+ arm_SXTAB16: "SXTAB16",
+ arm_SXTAB16_ZZ: "SXTAB16.ZZ",
+ arm_SXTAH_EQ: "SXTAH.EQ",
+ arm_SXTAH_NE: "SXTAH.NE",
+ arm_SXTAH_CS: "SXTAH.CS",
+ arm_SXTAH_CC: "SXTAH.CC",
+ arm_SXTAH_MI: "SXTAH.MI",
+ arm_SXTAH_PL: "SXTAH.PL",
+ arm_SXTAH_VS: "SXTAH.VS",
+ arm_SXTAH_VC: "SXTAH.VC",
+ arm_SXTAH_HI: "SXTAH.HI",
+ arm_SXTAH_LS: "SXTAH.LS",
+ arm_SXTAH_GE: "SXTAH.GE",
+ arm_SXTAH_LT: "SXTAH.LT",
+ arm_SXTAH_GT: "SXTAH.GT",
+ arm_SXTAH_LE: "SXTAH.LE",
+ arm_SXTAH: "SXTAH",
+ arm_SXTAH_ZZ: "SXTAH.ZZ",
+ arm_SXTB_EQ: "SXTB.EQ",
+ arm_SXTB_NE: "SXTB.NE",
+ arm_SXTB_CS: "SXTB.CS",
+ arm_SXTB_CC: "SXTB.CC",
+ arm_SXTB_MI: "SXTB.MI",
+ arm_SXTB_PL: "SXTB.PL",
+ arm_SXTB_VS: "SXTB.VS",
+ arm_SXTB_VC: "SXTB.VC",
+ arm_SXTB_HI: "SXTB.HI",
+ arm_SXTB_LS: "SXTB.LS",
+ arm_SXTB_GE: "SXTB.GE",
+ arm_SXTB_LT: "SXTB.LT",
+ arm_SXTB_GT: "SXTB.GT",
+ arm_SXTB_LE: "SXTB.LE",
+ arm_SXTB: "SXTB",
+ arm_SXTB_ZZ: "SXTB.ZZ",
+ arm_SXTB16_EQ: "SXTB16.EQ",
+ arm_SXTB16_NE: "SXTB16.NE",
+ arm_SXTB16_CS: "SXTB16.CS",
+ arm_SXTB16_CC: "SXTB16.CC",
+ arm_SXTB16_MI: "SXTB16.MI",
+ arm_SXTB16_PL: "SXTB16.PL",
+ arm_SXTB16_VS: "SXTB16.VS",
+ arm_SXTB16_VC: "SXTB16.VC",
+ arm_SXTB16_HI: "SXTB16.HI",
+ arm_SXTB16_LS: "SXTB16.LS",
+ arm_SXTB16_GE: "SXTB16.GE",
+ arm_SXTB16_LT: "SXTB16.LT",
+ arm_SXTB16_GT: "SXTB16.GT",
+ arm_SXTB16_LE: "SXTB16.LE",
+ arm_SXTB16: "SXTB16",
+ arm_SXTB16_ZZ: "SXTB16.ZZ",
+ arm_SXTH_EQ: "SXTH.EQ",
+ arm_SXTH_NE: "SXTH.NE",
+ arm_SXTH_CS: "SXTH.CS",
+ arm_SXTH_CC: "SXTH.CC",
+ arm_SXTH_MI: "SXTH.MI",
+ arm_SXTH_PL: "SXTH.PL",
+ arm_SXTH_VS: "SXTH.VS",
+ arm_SXTH_VC: "SXTH.VC",
+ arm_SXTH_HI: "SXTH.HI",
+ arm_SXTH_LS: "SXTH.LS",
+ arm_SXTH_GE: "SXTH.GE",
+ arm_SXTH_LT: "SXTH.LT",
+ arm_SXTH_GT: "SXTH.GT",
+ arm_SXTH_LE: "SXTH.LE",
+ arm_SXTH: "SXTH",
+ arm_SXTH_ZZ: "SXTH.ZZ",
+ arm_TEQ_EQ: "TEQ.EQ",
+ arm_TEQ_NE: "TEQ.NE",
+ arm_TEQ_CS: "TEQ.CS",
+ arm_TEQ_CC: "TEQ.CC",
+ arm_TEQ_MI: "TEQ.MI",
+ arm_TEQ_PL: "TEQ.PL",
+ arm_TEQ_VS: "TEQ.VS",
+ arm_TEQ_VC: "TEQ.VC",
+ arm_TEQ_HI: "TEQ.HI",
+ arm_TEQ_LS: "TEQ.LS",
+ arm_TEQ_GE: "TEQ.GE",
+ arm_TEQ_LT: "TEQ.LT",
+ arm_TEQ_GT: "TEQ.GT",
+ arm_TEQ_LE: "TEQ.LE",
+ arm_TEQ: "TEQ",
+ arm_TEQ_ZZ: "TEQ.ZZ",
+ arm_TST_EQ: "TST.EQ",
+ arm_TST_NE: "TST.NE",
+ arm_TST_CS: "TST.CS",
+ arm_TST_CC: "TST.CC",
+ arm_TST_MI: "TST.MI",
+ arm_TST_PL: "TST.PL",
+ arm_TST_VS: "TST.VS",
+ arm_TST_VC: "TST.VC",
+ arm_TST_HI: "TST.HI",
+ arm_TST_LS: "TST.LS",
+ arm_TST_GE: "TST.GE",
+ arm_TST_LT: "TST.LT",
+ arm_TST_GT: "TST.GT",
+ arm_TST_LE: "TST.LE",
+ arm_TST: "TST",
+ arm_TST_ZZ: "TST.ZZ",
+ arm_UADD16_EQ: "UADD16.EQ",
+ arm_UADD16_NE: "UADD16.NE",
+ arm_UADD16_CS: "UADD16.CS",
+ arm_UADD16_CC: "UADD16.CC",
+ arm_UADD16_MI: "UADD16.MI",
+ arm_UADD16_PL: "UADD16.PL",
+ arm_UADD16_VS: "UADD16.VS",
+ arm_UADD16_VC: "UADD16.VC",
+ arm_UADD16_HI: "UADD16.HI",
+ arm_UADD16_LS: "UADD16.LS",
+ arm_UADD16_GE: "UADD16.GE",
+ arm_UADD16_LT: "UADD16.LT",
+ arm_UADD16_GT: "UADD16.GT",
+ arm_UADD16_LE: "UADD16.LE",
+ arm_UADD16: "UADD16",
+ arm_UADD16_ZZ: "UADD16.ZZ",
+ arm_UADD8_EQ: "UADD8.EQ",
+ arm_UADD8_NE: "UADD8.NE",
+ arm_UADD8_CS: "UADD8.CS",
+ arm_UADD8_CC: "UADD8.CC",
+ arm_UADD8_MI: "UADD8.MI",
+ arm_UADD8_PL: "UADD8.PL",
+ arm_UADD8_VS: "UADD8.VS",
+ arm_UADD8_VC: "UADD8.VC",
+ arm_UADD8_HI: "UADD8.HI",
+ arm_UADD8_LS: "UADD8.LS",
+ arm_UADD8_GE: "UADD8.GE",
+ arm_UADD8_LT: "UADD8.LT",
+ arm_UADD8_GT: "UADD8.GT",
+ arm_UADD8_LE: "UADD8.LE",
+ arm_UADD8: "UADD8",
+ arm_UADD8_ZZ: "UADD8.ZZ",
+ arm_UASX_EQ: "UASX.EQ",
+ arm_UASX_NE: "UASX.NE",
+ arm_UASX_CS: "UASX.CS",
+ arm_UASX_CC: "UASX.CC",
+ arm_UASX_MI: "UASX.MI",
+ arm_UASX_PL: "UASX.PL",
+ arm_UASX_VS: "UASX.VS",
+ arm_UASX_VC: "UASX.VC",
+ arm_UASX_HI: "UASX.HI",
+ arm_UASX_LS: "UASX.LS",
+ arm_UASX_GE: "UASX.GE",
+ arm_UASX_LT: "UASX.LT",
+ arm_UASX_GT: "UASX.GT",
+ arm_UASX_LE: "UASX.LE",
+ arm_UASX: "UASX",
+ arm_UASX_ZZ: "UASX.ZZ",
+ arm_UBFX_EQ: "UBFX.EQ",
+ arm_UBFX_NE: "UBFX.NE",
+ arm_UBFX_CS: "UBFX.CS",
+ arm_UBFX_CC: "UBFX.CC",
+ arm_UBFX_MI: "UBFX.MI",
+ arm_UBFX_PL: "UBFX.PL",
+ arm_UBFX_VS: "UBFX.VS",
+ arm_UBFX_VC: "UBFX.VC",
+ arm_UBFX_HI: "UBFX.HI",
+ arm_UBFX_LS: "UBFX.LS",
+ arm_UBFX_GE: "UBFX.GE",
+ arm_UBFX_LT: "UBFX.LT",
+ arm_UBFX_GT: "UBFX.GT",
+ arm_UBFX_LE: "UBFX.LE",
+ arm_UBFX: "UBFX",
+ arm_UBFX_ZZ: "UBFX.ZZ",
+ arm_UHADD16_EQ: "UHADD16.EQ",
+ arm_UHADD16_NE: "UHADD16.NE",
+ arm_UHADD16_CS: "UHADD16.CS",
+ arm_UHADD16_CC: "UHADD16.CC",
+ arm_UHADD16_MI: "UHADD16.MI",
+ arm_UHADD16_PL: "UHADD16.PL",
+ arm_UHADD16_VS: "UHADD16.VS",
+ arm_UHADD16_VC: "UHADD16.VC",
+ arm_UHADD16_HI: "UHADD16.HI",
+ arm_UHADD16_LS: "UHADD16.LS",
+ arm_UHADD16_GE: "UHADD16.GE",
+ arm_UHADD16_LT: "UHADD16.LT",
+ arm_UHADD16_GT: "UHADD16.GT",
+ arm_UHADD16_LE: "UHADD16.LE",
+ arm_UHADD16: "UHADD16",
+ arm_UHADD16_ZZ: "UHADD16.ZZ",
+ arm_UHADD8_EQ: "UHADD8.EQ",
+ arm_UHADD8_NE: "UHADD8.NE",
+ arm_UHADD8_CS: "UHADD8.CS",
+ arm_UHADD8_CC: "UHADD8.CC",
+ arm_UHADD8_MI: "UHADD8.MI",
+ arm_UHADD8_PL: "UHADD8.PL",
+ arm_UHADD8_VS: "UHADD8.VS",
+ arm_UHADD8_VC: "UHADD8.VC",
+ arm_UHADD8_HI: "UHADD8.HI",
+ arm_UHADD8_LS: "UHADD8.LS",
+ arm_UHADD8_GE: "UHADD8.GE",
+ arm_UHADD8_LT: "UHADD8.LT",
+ arm_UHADD8_GT: "UHADD8.GT",
+ arm_UHADD8_LE: "UHADD8.LE",
+ arm_UHADD8: "UHADD8",
+ arm_UHADD8_ZZ: "UHADD8.ZZ",
+ arm_UHASX_EQ: "UHASX.EQ",
+ arm_UHASX_NE: "UHASX.NE",
+ arm_UHASX_CS: "UHASX.CS",
+ arm_UHASX_CC: "UHASX.CC",
+ arm_UHASX_MI: "UHASX.MI",
+ arm_UHASX_PL: "UHASX.PL",
+ arm_UHASX_VS: "UHASX.VS",
+ arm_UHASX_VC: "UHASX.VC",
+ arm_UHASX_HI: "UHASX.HI",
+ arm_UHASX_LS: "UHASX.LS",
+ arm_UHASX_GE: "UHASX.GE",
+ arm_UHASX_LT: "UHASX.LT",
+ arm_UHASX_GT: "UHASX.GT",
+ arm_UHASX_LE: "UHASX.LE",
+ arm_UHASX: "UHASX",
+ arm_UHASX_ZZ: "UHASX.ZZ",
+ arm_UHSAX_EQ: "UHSAX.EQ",
+ arm_UHSAX_NE: "UHSAX.NE",
+ arm_UHSAX_CS: "UHSAX.CS",
+ arm_UHSAX_CC: "UHSAX.CC",
+ arm_UHSAX_MI: "UHSAX.MI",
+ arm_UHSAX_PL: "UHSAX.PL",
+ arm_UHSAX_VS: "UHSAX.VS",
+ arm_UHSAX_VC: "UHSAX.VC",
+ arm_UHSAX_HI: "UHSAX.HI",
+ arm_UHSAX_LS: "UHSAX.LS",
+ arm_UHSAX_GE: "UHSAX.GE",
+ arm_UHSAX_LT: "UHSAX.LT",
+ arm_UHSAX_GT: "UHSAX.GT",
+ arm_UHSAX_LE: "UHSAX.LE",
+ arm_UHSAX: "UHSAX",
+ arm_UHSAX_ZZ: "UHSAX.ZZ",
+ arm_UHSUB16_EQ: "UHSUB16.EQ",
+ arm_UHSUB16_NE: "UHSUB16.NE",
+ arm_UHSUB16_CS: "UHSUB16.CS",
+ arm_UHSUB16_CC: "UHSUB16.CC",
+ arm_UHSUB16_MI: "UHSUB16.MI",
+ arm_UHSUB16_PL: "UHSUB16.PL",
+ arm_UHSUB16_VS: "UHSUB16.VS",
+ arm_UHSUB16_VC: "UHSUB16.VC",
+ arm_UHSUB16_HI: "UHSUB16.HI",
+ arm_UHSUB16_LS: "UHSUB16.LS",
+ arm_UHSUB16_GE: "UHSUB16.GE",
+ arm_UHSUB16_LT: "UHSUB16.LT",
+ arm_UHSUB16_GT: "UHSUB16.GT",
+ arm_UHSUB16_LE: "UHSUB16.LE",
+ arm_UHSUB16: "UHSUB16",
+ arm_UHSUB16_ZZ: "UHSUB16.ZZ",
+ arm_UHSUB8_EQ: "UHSUB8.EQ",
+ arm_UHSUB8_NE: "UHSUB8.NE",
+ arm_UHSUB8_CS: "UHSUB8.CS",
+ arm_UHSUB8_CC: "UHSUB8.CC",
+ arm_UHSUB8_MI: "UHSUB8.MI",
+ arm_UHSUB8_PL: "UHSUB8.PL",
+ arm_UHSUB8_VS: "UHSUB8.VS",
+ arm_UHSUB8_VC: "UHSUB8.VC",
+ arm_UHSUB8_HI: "UHSUB8.HI",
+ arm_UHSUB8_LS: "UHSUB8.LS",
+ arm_UHSUB8_GE: "UHSUB8.GE",
+ arm_UHSUB8_LT: "UHSUB8.LT",
+ arm_UHSUB8_GT: "UHSUB8.GT",
+ arm_UHSUB8_LE: "UHSUB8.LE",
+ arm_UHSUB8: "UHSUB8",
+ arm_UHSUB8_ZZ: "UHSUB8.ZZ",
+ arm_UMAAL_EQ: "UMAAL.EQ",
+ arm_UMAAL_NE: "UMAAL.NE",
+ arm_UMAAL_CS: "UMAAL.CS",
+ arm_UMAAL_CC: "UMAAL.CC",
+ arm_UMAAL_MI: "UMAAL.MI",
+ arm_UMAAL_PL: "UMAAL.PL",
+ arm_UMAAL_VS: "UMAAL.VS",
+ arm_UMAAL_VC: "UMAAL.VC",
+ arm_UMAAL_HI: "UMAAL.HI",
+ arm_UMAAL_LS: "UMAAL.LS",
+ arm_UMAAL_GE: "UMAAL.GE",
+ arm_UMAAL_LT: "UMAAL.LT",
+ arm_UMAAL_GT: "UMAAL.GT",
+ arm_UMAAL_LE: "UMAAL.LE",
+ arm_UMAAL: "UMAAL",
+ arm_UMAAL_ZZ: "UMAAL.ZZ",
+ arm_UMLAL_EQ: "UMLAL.EQ",
+ arm_UMLAL_NE: "UMLAL.NE",
+ arm_UMLAL_CS: "UMLAL.CS",
+ arm_UMLAL_CC: "UMLAL.CC",
+ arm_UMLAL_MI: "UMLAL.MI",
+ arm_UMLAL_PL: "UMLAL.PL",
+ arm_UMLAL_VS: "UMLAL.VS",
+ arm_UMLAL_VC: "UMLAL.VC",
+ arm_UMLAL_HI: "UMLAL.HI",
+ arm_UMLAL_LS: "UMLAL.LS",
+ arm_UMLAL_GE: "UMLAL.GE",
+ arm_UMLAL_LT: "UMLAL.LT",
+ arm_UMLAL_GT: "UMLAL.GT",
+ arm_UMLAL_LE: "UMLAL.LE",
+ arm_UMLAL: "UMLAL",
+ arm_UMLAL_ZZ: "UMLAL.ZZ",
+ arm_UMLAL_S_EQ: "UMLAL.S.EQ",
+ arm_UMLAL_S_NE: "UMLAL.S.NE",
+ arm_UMLAL_S_CS: "UMLAL.S.CS",
+ arm_UMLAL_S_CC: "UMLAL.S.CC",
+ arm_UMLAL_S_MI: "UMLAL.S.MI",
+ arm_UMLAL_S_PL: "UMLAL.S.PL",
+ arm_UMLAL_S_VS: "UMLAL.S.VS",
+ arm_UMLAL_S_VC: "UMLAL.S.VC",
+ arm_UMLAL_S_HI: "UMLAL.S.HI",
+ arm_UMLAL_S_LS: "UMLAL.S.LS",
+ arm_UMLAL_S_GE: "UMLAL.S.GE",
+ arm_UMLAL_S_LT: "UMLAL.S.LT",
+ arm_UMLAL_S_GT: "UMLAL.S.GT",
+ arm_UMLAL_S_LE: "UMLAL.S.LE",
+ arm_UMLAL_S: "UMLAL.S",
+ arm_UMLAL_S_ZZ: "UMLAL.S.ZZ",
+ arm_UMULL_EQ: "UMULL.EQ",
+ arm_UMULL_NE: "UMULL.NE",
+ arm_UMULL_CS: "UMULL.CS",
+ arm_UMULL_CC: "UMULL.CC",
+ arm_UMULL_MI: "UMULL.MI",
+ arm_UMULL_PL: "UMULL.PL",
+ arm_UMULL_VS: "UMULL.VS",
+ arm_UMULL_VC: "UMULL.VC",
+ arm_UMULL_HI: "UMULL.HI",
+ arm_UMULL_LS: "UMULL.LS",
+ arm_UMULL_GE: "UMULL.GE",
+ arm_UMULL_LT: "UMULL.LT",
+ arm_UMULL_GT: "UMULL.GT",
+ arm_UMULL_LE: "UMULL.LE",
+ arm_UMULL: "UMULL",
+ arm_UMULL_ZZ: "UMULL.ZZ",
+ arm_UMULL_S_EQ: "UMULL.S.EQ",
+ arm_UMULL_S_NE: "UMULL.S.NE",
+ arm_UMULL_S_CS: "UMULL.S.CS",
+ arm_UMULL_S_CC: "UMULL.S.CC",
+ arm_UMULL_S_MI: "UMULL.S.MI",
+ arm_UMULL_S_PL: "UMULL.S.PL",
+ arm_UMULL_S_VS: "UMULL.S.VS",
+ arm_UMULL_S_VC: "UMULL.S.VC",
+ arm_UMULL_S_HI: "UMULL.S.HI",
+ arm_UMULL_S_LS: "UMULL.S.LS",
+ arm_UMULL_S_GE: "UMULL.S.GE",
+ arm_UMULL_S_LT: "UMULL.S.LT",
+ arm_UMULL_S_GT: "UMULL.S.GT",
+ arm_UMULL_S_LE: "UMULL.S.LE",
+ arm_UMULL_S: "UMULL.S",
+ arm_UMULL_S_ZZ: "UMULL.S.ZZ",
+ arm_UNDEF: "UNDEF",
+ arm_UQADD16_EQ: "UQADD16.EQ",
+ arm_UQADD16_NE: "UQADD16.NE",
+ arm_UQADD16_CS: "UQADD16.CS",
+ arm_UQADD16_CC: "UQADD16.CC",
+ arm_UQADD16_MI: "UQADD16.MI",
+ arm_UQADD16_PL: "UQADD16.PL",
+ arm_UQADD16_VS: "UQADD16.VS",
+ arm_UQADD16_VC: "UQADD16.VC",
+ arm_UQADD16_HI: "UQADD16.HI",
+ arm_UQADD16_LS: "UQADD16.LS",
+ arm_UQADD16_GE: "UQADD16.GE",
+ arm_UQADD16_LT: "UQADD16.LT",
+ arm_UQADD16_GT: "UQADD16.GT",
+ arm_UQADD16_LE: "UQADD16.LE",
+ arm_UQADD16: "UQADD16",
+ arm_UQADD16_ZZ: "UQADD16.ZZ",
+ arm_UQADD8_EQ: "UQADD8.EQ",
+ arm_UQADD8_NE: "UQADD8.NE",
+ arm_UQADD8_CS: "UQADD8.CS",
+ arm_UQADD8_CC: "UQADD8.CC",
+ arm_UQADD8_MI: "UQADD8.MI",
+ arm_UQADD8_PL: "UQADD8.PL",
+ arm_UQADD8_VS: "UQADD8.VS",
+ arm_UQADD8_VC: "UQADD8.VC",
+ arm_UQADD8_HI: "UQADD8.HI",
+ arm_UQADD8_LS: "UQADD8.LS",
+ arm_UQADD8_GE: "UQADD8.GE",
+ arm_UQADD8_LT: "UQADD8.LT",
+ arm_UQADD8_GT: "UQADD8.GT",
+ arm_UQADD8_LE: "UQADD8.LE",
+ arm_UQADD8: "UQADD8",
+ arm_UQADD8_ZZ: "UQADD8.ZZ",
+ arm_UQASX_EQ: "UQASX.EQ",
+ arm_UQASX_NE: "UQASX.NE",
+ arm_UQASX_CS: "UQASX.CS",
+ arm_UQASX_CC: "UQASX.CC",
+ arm_UQASX_MI: "UQASX.MI",
+ arm_UQASX_PL: "UQASX.PL",
+ arm_UQASX_VS: "UQASX.VS",
+ arm_UQASX_VC: "UQASX.VC",
+ arm_UQASX_HI: "UQASX.HI",
+ arm_UQASX_LS: "UQASX.LS",
+ arm_UQASX_GE: "UQASX.GE",
+ arm_UQASX_LT: "UQASX.LT",
+ arm_UQASX_GT: "UQASX.GT",
+ arm_UQASX_LE: "UQASX.LE",
+ arm_UQASX: "UQASX",
+ arm_UQASX_ZZ: "UQASX.ZZ",
+ arm_UQSAX_EQ: "UQSAX.EQ",
+ arm_UQSAX_NE: "UQSAX.NE",
+ arm_UQSAX_CS: "UQSAX.CS",
+ arm_UQSAX_CC: "UQSAX.CC",
+ arm_UQSAX_MI: "UQSAX.MI",
+ arm_UQSAX_PL: "UQSAX.PL",
+ arm_UQSAX_VS: "UQSAX.VS",
+ arm_UQSAX_VC: "UQSAX.VC",
+ arm_UQSAX_HI: "UQSAX.HI",
+ arm_UQSAX_LS: "UQSAX.LS",
+ arm_UQSAX_GE: "UQSAX.GE",
+ arm_UQSAX_LT: "UQSAX.LT",
+ arm_UQSAX_GT: "UQSAX.GT",
+ arm_UQSAX_LE: "UQSAX.LE",
+ arm_UQSAX: "UQSAX",
+ arm_UQSAX_ZZ: "UQSAX.ZZ",
+ arm_UQSUB16_EQ: "UQSUB16.EQ",
+ arm_UQSUB16_NE: "UQSUB16.NE",
+ arm_UQSUB16_CS: "UQSUB16.CS",
+ arm_UQSUB16_CC: "UQSUB16.CC",
+ arm_UQSUB16_MI: "UQSUB16.MI",
+ arm_UQSUB16_PL: "UQSUB16.PL",
+ arm_UQSUB16_VS: "UQSUB16.VS",
+ arm_UQSUB16_VC: "UQSUB16.VC",
+ arm_UQSUB16_HI: "UQSUB16.HI",
+ arm_UQSUB16_LS: "UQSUB16.LS",
+ arm_UQSUB16_GE: "UQSUB16.GE",
+ arm_UQSUB16_LT: "UQSUB16.LT",
+ arm_UQSUB16_GT: "UQSUB16.GT",
+ arm_UQSUB16_LE: "UQSUB16.LE",
+ arm_UQSUB16: "UQSUB16",
+ arm_UQSUB16_ZZ: "UQSUB16.ZZ",
+ arm_UQSUB8_EQ: "UQSUB8.EQ",
+ arm_UQSUB8_NE: "UQSUB8.NE",
+ arm_UQSUB8_CS: "UQSUB8.CS",
+ arm_UQSUB8_CC: "UQSUB8.CC",
+ arm_UQSUB8_MI: "UQSUB8.MI",
+ arm_UQSUB8_PL: "UQSUB8.PL",
+ arm_UQSUB8_VS: "UQSUB8.VS",
+ arm_UQSUB8_VC: "UQSUB8.VC",
+ arm_UQSUB8_HI: "UQSUB8.HI",
+ arm_UQSUB8_LS: "UQSUB8.LS",
+ arm_UQSUB8_GE: "UQSUB8.GE",
+ arm_UQSUB8_LT: "UQSUB8.LT",
+ arm_UQSUB8_GT: "UQSUB8.GT",
+ arm_UQSUB8_LE: "UQSUB8.LE",
+ arm_UQSUB8: "UQSUB8",
+ arm_UQSUB8_ZZ: "UQSUB8.ZZ",
+ arm_USAD8_EQ: "USAD8.EQ",
+ arm_USAD8_NE: "USAD8.NE",
+ arm_USAD8_CS: "USAD8.CS",
+ arm_USAD8_CC: "USAD8.CC",
+ arm_USAD8_MI: "USAD8.MI",
+ arm_USAD8_PL: "USAD8.PL",
+ arm_USAD8_VS: "USAD8.VS",
+ arm_USAD8_VC: "USAD8.VC",
+ arm_USAD8_HI: "USAD8.HI",
+ arm_USAD8_LS: "USAD8.LS",
+ arm_USAD8_GE: "USAD8.GE",
+ arm_USAD8_LT: "USAD8.LT",
+ arm_USAD8_GT: "USAD8.GT",
+ arm_USAD8_LE: "USAD8.LE",
+ arm_USAD8: "USAD8",
+ arm_USAD8_ZZ: "USAD8.ZZ",
+ arm_USADA8_EQ: "USADA8.EQ",
+ arm_USADA8_NE: "USADA8.NE",
+ arm_USADA8_CS: "USADA8.CS",
+ arm_USADA8_CC: "USADA8.CC",
+ arm_USADA8_MI: "USADA8.MI",
+ arm_USADA8_PL: "USADA8.PL",
+ arm_USADA8_VS: "USADA8.VS",
+ arm_USADA8_VC: "USADA8.VC",
+ arm_USADA8_HI: "USADA8.HI",
+ arm_USADA8_LS: "USADA8.LS",
+ arm_USADA8_GE: "USADA8.GE",
+ arm_USADA8_LT: "USADA8.LT",
+ arm_USADA8_GT: "USADA8.GT",
+ arm_USADA8_LE: "USADA8.LE",
+ arm_USADA8: "USADA8",
+ arm_USADA8_ZZ: "USADA8.ZZ",
+ arm_USAT_EQ: "USAT.EQ",
+ arm_USAT_NE: "USAT.NE",
+ arm_USAT_CS: "USAT.CS",
+ arm_USAT_CC: "USAT.CC",
+ arm_USAT_MI: "USAT.MI",
+ arm_USAT_PL: "USAT.PL",
+ arm_USAT_VS: "USAT.VS",
+ arm_USAT_VC: "USAT.VC",
+ arm_USAT_HI: "USAT.HI",
+ arm_USAT_LS: "USAT.LS",
+ arm_USAT_GE: "USAT.GE",
+ arm_USAT_LT: "USAT.LT",
+ arm_USAT_GT: "USAT.GT",
+ arm_USAT_LE: "USAT.LE",
+ arm_USAT: "USAT",
+ arm_USAT_ZZ: "USAT.ZZ",
+ arm_USAT16_EQ: "USAT16.EQ",
+ arm_USAT16_NE: "USAT16.NE",
+ arm_USAT16_CS: "USAT16.CS",
+ arm_USAT16_CC: "USAT16.CC",
+ arm_USAT16_MI: "USAT16.MI",
+ arm_USAT16_PL: "USAT16.PL",
+ arm_USAT16_VS: "USAT16.VS",
+ arm_USAT16_VC: "USAT16.VC",
+ arm_USAT16_HI: "USAT16.HI",
+ arm_USAT16_LS: "USAT16.LS",
+ arm_USAT16_GE: "USAT16.GE",
+ arm_USAT16_LT: "USAT16.LT",
+ arm_USAT16_GT: "USAT16.GT",
+ arm_USAT16_LE: "USAT16.LE",
+ arm_USAT16: "USAT16",
+ arm_USAT16_ZZ: "USAT16.ZZ",
+ arm_USAX_EQ: "USAX.EQ",
+ arm_USAX_NE: "USAX.NE",
+ arm_USAX_CS: "USAX.CS",
+ arm_USAX_CC: "USAX.CC",
+ arm_USAX_MI: "USAX.MI",
+ arm_USAX_PL: "USAX.PL",
+ arm_USAX_VS: "USAX.VS",
+ arm_USAX_VC: "USAX.VC",
+ arm_USAX_HI: "USAX.HI",
+ arm_USAX_LS: "USAX.LS",
+ arm_USAX_GE: "USAX.GE",
+ arm_USAX_LT: "USAX.LT",
+ arm_USAX_GT: "USAX.GT",
+ arm_USAX_LE: "USAX.LE",
+ arm_USAX: "USAX",
+ arm_USAX_ZZ: "USAX.ZZ",
+ arm_USUB16_EQ: "USUB16.EQ",
+ arm_USUB16_NE: "USUB16.NE",
+ arm_USUB16_CS: "USUB16.CS",
+ arm_USUB16_CC: "USUB16.CC",
+ arm_USUB16_MI: "USUB16.MI",
+ arm_USUB16_PL: "USUB16.PL",
+ arm_USUB16_VS: "USUB16.VS",
+ arm_USUB16_VC: "USUB16.VC",
+ arm_USUB16_HI: "USUB16.HI",
+ arm_USUB16_LS: "USUB16.LS",
+ arm_USUB16_GE: "USUB16.GE",
+ arm_USUB16_LT: "USUB16.LT",
+ arm_USUB16_GT: "USUB16.GT",
+ arm_USUB16_LE: "USUB16.LE",
+ arm_USUB16: "USUB16",
+ arm_USUB16_ZZ: "USUB16.ZZ",
+ arm_USUB8_EQ: "USUB8.EQ",
+ arm_USUB8_NE: "USUB8.NE",
+ arm_USUB8_CS: "USUB8.CS",
+ arm_USUB8_CC: "USUB8.CC",
+ arm_USUB8_MI: "USUB8.MI",
+ arm_USUB8_PL: "USUB8.PL",
+ arm_USUB8_VS: "USUB8.VS",
+ arm_USUB8_VC: "USUB8.VC",
+ arm_USUB8_HI: "USUB8.HI",
+ arm_USUB8_LS: "USUB8.LS",
+ arm_USUB8_GE: "USUB8.GE",
+ arm_USUB8_LT: "USUB8.LT",
+ arm_USUB8_GT: "USUB8.GT",
+ arm_USUB8_LE: "USUB8.LE",
+ arm_USUB8: "USUB8",
+ arm_USUB8_ZZ: "USUB8.ZZ",
+ arm_UXTAB_EQ: "UXTAB.EQ",
+ arm_UXTAB_NE: "UXTAB.NE",
+ arm_UXTAB_CS: "UXTAB.CS",
+ arm_UXTAB_CC: "UXTAB.CC",
+ arm_UXTAB_MI: "UXTAB.MI",
+ arm_UXTAB_PL: "UXTAB.PL",
+ arm_UXTAB_VS: "UXTAB.VS",
+ arm_UXTAB_VC: "UXTAB.VC",
+ arm_UXTAB_HI: "UXTAB.HI",
+ arm_UXTAB_LS: "UXTAB.LS",
+ arm_UXTAB_GE: "UXTAB.GE",
+ arm_UXTAB_LT: "UXTAB.LT",
+ arm_UXTAB_GT: "UXTAB.GT",
+ arm_UXTAB_LE: "UXTAB.LE",
+ arm_UXTAB: "UXTAB",
+ arm_UXTAB_ZZ: "UXTAB.ZZ",
+ arm_UXTAB16_EQ: "UXTAB16.EQ",
+ arm_UXTAB16_NE: "UXTAB16.NE",
+ arm_UXTAB16_CS: "UXTAB16.CS",
+ arm_UXTAB16_CC: "UXTAB16.CC",
+ arm_UXTAB16_MI: "UXTAB16.MI",
+ arm_UXTAB16_PL: "UXTAB16.PL",
+ arm_UXTAB16_VS: "UXTAB16.VS",
+ arm_UXTAB16_VC: "UXTAB16.VC",
+ arm_UXTAB16_HI: "UXTAB16.HI",
+ arm_UXTAB16_LS: "UXTAB16.LS",
+ arm_UXTAB16_GE: "UXTAB16.GE",
+ arm_UXTAB16_LT: "UXTAB16.LT",
+ arm_UXTAB16_GT: "UXTAB16.GT",
+ arm_UXTAB16_LE: "UXTAB16.LE",
+ arm_UXTAB16: "UXTAB16",
+ arm_UXTAB16_ZZ: "UXTAB16.ZZ",
+ arm_UXTAH_EQ: "UXTAH.EQ",
+ arm_UXTAH_NE: "UXTAH.NE",
+ arm_UXTAH_CS: "UXTAH.CS",
+ arm_UXTAH_CC: "UXTAH.CC",
+ arm_UXTAH_MI: "UXTAH.MI",
+ arm_UXTAH_PL: "UXTAH.PL",
+ arm_UXTAH_VS: "UXTAH.VS",
+ arm_UXTAH_VC: "UXTAH.VC",
+ arm_UXTAH_HI: "UXTAH.HI",
+ arm_UXTAH_LS: "UXTAH.LS",
+ arm_UXTAH_GE: "UXTAH.GE",
+ arm_UXTAH_LT: "UXTAH.LT",
+ arm_UXTAH_GT: "UXTAH.GT",
+ arm_UXTAH_LE: "UXTAH.LE",
+ arm_UXTAH: "UXTAH",
+ arm_UXTAH_ZZ: "UXTAH.ZZ",
+ arm_UXTB_EQ: "UXTB.EQ",
+ arm_UXTB_NE: "UXTB.NE",
+ arm_UXTB_CS: "UXTB.CS",
+ arm_UXTB_CC: "UXTB.CC",
+ arm_UXTB_MI: "UXTB.MI",
+ arm_UXTB_PL: "UXTB.PL",
+ arm_UXTB_VS: "UXTB.VS",
+ arm_UXTB_VC: "UXTB.VC",
+ arm_UXTB_HI: "UXTB.HI",
+ arm_UXTB_LS: "UXTB.LS",
+ arm_UXTB_GE: "UXTB.GE",
+ arm_UXTB_LT: "UXTB.LT",
+ arm_UXTB_GT: "UXTB.GT",
+ arm_UXTB_LE: "UXTB.LE",
+ arm_UXTB: "UXTB",
+ arm_UXTB_ZZ: "UXTB.ZZ",
+ arm_UXTB16_EQ: "UXTB16.EQ",
+ arm_UXTB16_NE: "UXTB16.NE",
+ arm_UXTB16_CS: "UXTB16.CS",
+ arm_UXTB16_CC: "UXTB16.CC",
+ arm_UXTB16_MI: "UXTB16.MI",
+ arm_UXTB16_PL: "UXTB16.PL",
+ arm_UXTB16_VS: "UXTB16.VS",
+ arm_UXTB16_VC: "UXTB16.VC",
+ arm_UXTB16_HI: "UXTB16.HI",
+ arm_UXTB16_LS: "UXTB16.LS",
+ arm_UXTB16_GE: "UXTB16.GE",
+ arm_UXTB16_LT: "UXTB16.LT",
+ arm_UXTB16_GT: "UXTB16.GT",
+ arm_UXTB16_LE: "UXTB16.LE",
+ arm_UXTB16: "UXTB16",
+ arm_UXTB16_ZZ: "UXTB16.ZZ",
+ arm_UXTH_EQ: "UXTH.EQ",
+ arm_UXTH_NE: "UXTH.NE",
+ arm_UXTH_CS: "UXTH.CS",
+ arm_UXTH_CC: "UXTH.CC",
+ arm_UXTH_MI: "UXTH.MI",
+ arm_UXTH_PL: "UXTH.PL",
+ arm_UXTH_VS: "UXTH.VS",
+ arm_UXTH_VC: "UXTH.VC",
+ arm_UXTH_HI: "UXTH.HI",
+ arm_UXTH_LS: "UXTH.LS",
+ arm_UXTH_GE: "UXTH.GE",
+ arm_UXTH_LT: "UXTH.LT",
+ arm_UXTH_GT: "UXTH.GT",
+ arm_UXTH_LE: "UXTH.LE",
+ arm_UXTH: "UXTH",
+ arm_UXTH_ZZ: "UXTH.ZZ",
+ arm_VABS_EQ_F32: "VABS.EQ.F32",
+ arm_VABS_NE_F32: "VABS.NE.F32",
+ arm_VABS_CS_F32: "VABS.CS.F32",
+ arm_VABS_CC_F32: "VABS.CC.F32",
+ arm_VABS_MI_F32: "VABS.MI.F32",
+ arm_VABS_PL_F32: "VABS.PL.F32",
+ arm_VABS_VS_F32: "VABS.VS.F32",
+ arm_VABS_VC_F32: "VABS.VC.F32",
+ arm_VABS_HI_F32: "VABS.HI.F32",
+ arm_VABS_LS_F32: "VABS.LS.F32",
+ arm_VABS_GE_F32: "VABS.GE.F32",
+ arm_VABS_LT_F32: "VABS.LT.F32",
+ arm_VABS_GT_F32: "VABS.GT.F32",
+ arm_VABS_LE_F32: "VABS.LE.F32",
+ arm_VABS_F32: "VABS.F32",
+ arm_VABS_ZZ_F32: "VABS.ZZ.F32",
+ arm_VABS_EQ_F64: "VABS.EQ.F64",
+ arm_VABS_NE_F64: "VABS.NE.F64",
+ arm_VABS_CS_F64: "VABS.CS.F64",
+ arm_VABS_CC_F64: "VABS.CC.F64",
+ arm_VABS_MI_F64: "VABS.MI.F64",
+ arm_VABS_PL_F64: "VABS.PL.F64",
+ arm_VABS_VS_F64: "VABS.VS.F64",
+ arm_VABS_VC_F64: "VABS.VC.F64",
+ arm_VABS_HI_F64: "VABS.HI.F64",
+ arm_VABS_LS_F64: "VABS.LS.F64",
+ arm_VABS_GE_F64: "VABS.GE.F64",
+ arm_VABS_LT_F64: "VABS.LT.F64",
+ arm_VABS_GT_F64: "VABS.GT.F64",
+ arm_VABS_LE_F64: "VABS.LE.F64",
+ arm_VABS_F64: "VABS.F64",
+ arm_VABS_ZZ_F64: "VABS.ZZ.F64",
+ arm_VADD_EQ_F32: "VADD.EQ.F32",
+ arm_VADD_NE_F32: "VADD.NE.F32",
+ arm_VADD_CS_F32: "VADD.CS.F32",
+ arm_VADD_CC_F32: "VADD.CC.F32",
+ arm_VADD_MI_F32: "VADD.MI.F32",
+ arm_VADD_PL_F32: "VADD.PL.F32",
+ arm_VADD_VS_F32: "VADD.VS.F32",
+ arm_VADD_VC_F32: "VADD.VC.F32",
+ arm_VADD_HI_F32: "VADD.HI.F32",
+ arm_VADD_LS_F32: "VADD.LS.F32",
+ arm_VADD_GE_F32: "VADD.GE.F32",
+ arm_VADD_LT_F32: "VADD.LT.F32",
+ arm_VADD_GT_F32: "VADD.GT.F32",
+ arm_VADD_LE_F32: "VADD.LE.F32",
+ arm_VADD_F32: "VADD.F32",
+ arm_VADD_ZZ_F32: "VADD.ZZ.F32",
+ arm_VADD_EQ_F64: "VADD.EQ.F64",
+ arm_VADD_NE_F64: "VADD.NE.F64",
+ arm_VADD_CS_F64: "VADD.CS.F64",
+ arm_VADD_CC_F64: "VADD.CC.F64",
+ arm_VADD_MI_F64: "VADD.MI.F64",
+ arm_VADD_PL_F64: "VADD.PL.F64",
+ arm_VADD_VS_F64: "VADD.VS.F64",
+ arm_VADD_VC_F64: "VADD.VC.F64",
+ arm_VADD_HI_F64: "VADD.HI.F64",
+ arm_VADD_LS_F64: "VADD.LS.F64",
+ arm_VADD_GE_F64: "VADD.GE.F64",
+ arm_VADD_LT_F64: "VADD.LT.F64",
+ arm_VADD_GT_F64: "VADD.GT.F64",
+ arm_VADD_LE_F64: "VADD.LE.F64",
+ arm_VADD_F64: "VADD.F64",
+ arm_VADD_ZZ_F64: "VADD.ZZ.F64",
+ arm_VCMP_EQ_F32: "VCMP.EQ.F32",
+ arm_VCMP_NE_F32: "VCMP.NE.F32",
+ arm_VCMP_CS_F32: "VCMP.CS.F32",
+ arm_VCMP_CC_F32: "VCMP.CC.F32",
+ arm_VCMP_MI_F32: "VCMP.MI.F32",
+ arm_VCMP_PL_F32: "VCMP.PL.F32",
+ arm_VCMP_VS_F32: "VCMP.VS.F32",
+ arm_VCMP_VC_F32: "VCMP.VC.F32",
+ arm_VCMP_HI_F32: "VCMP.HI.F32",
+ arm_VCMP_LS_F32: "VCMP.LS.F32",
+ arm_VCMP_GE_F32: "VCMP.GE.F32",
+ arm_VCMP_LT_F32: "VCMP.LT.F32",
+ arm_VCMP_GT_F32: "VCMP.GT.F32",
+ arm_VCMP_LE_F32: "VCMP.LE.F32",
+ arm_VCMP_F32: "VCMP.F32",
+ arm_VCMP_ZZ_F32: "VCMP.ZZ.F32",
+ arm_VCMP_EQ_F64: "VCMP.EQ.F64",
+ arm_VCMP_NE_F64: "VCMP.NE.F64",
+ arm_VCMP_CS_F64: "VCMP.CS.F64",
+ arm_VCMP_CC_F64: "VCMP.CC.F64",
+ arm_VCMP_MI_F64: "VCMP.MI.F64",
+ arm_VCMP_PL_F64: "VCMP.PL.F64",
+ arm_VCMP_VS_F64: "VCMP.VS.F64",
+ arm_VCMP_VC_F64: "VCMP.VC.F64",
+ arm_VCMP_HI_F64: "VCMP.HI.F64",
+ arm_VCMP_LS_F64: "VCMP.LS.F64",
+ arm_VCMP_GE_F64: "VCMP.GE.F64",
+ arm_VCMP_LT_F64: "VCMP.LT.F64",
+ arm_VCMP_GT_F64: "VCMP.GT.F64",
+ arm_VCMP_LE_F64: "VCMP.LE.F64",
+ arm_VCMP_F64: "VCMP.F64",
+ arm_VCMP_ZZ_F64: "VCMP.ZZ.F64",
+ arm_VCMP_E_EQ_F32: "VCMP.E.EQ.F32",
+ arm_VCMP_E_NE_F32: "VCMP.E.NE.F32",
+ arm_VCMP_E_CS_F32: "VCMP.E.CS.F32",
+ arm_VCMP_E_CC_F32: "VCMP.E.CC.F32",
+ arm_VCMP_E_MI_F32: "VCMP.E.MI.F32",
+ arm_VCMP_E_PL_F32: "VCMP.E.PL.F32",
+ arm_VCMP_E_VS_F32: "VCMP.E.VS.F32",
+ arm_VCMP_E_VC_F32: "VCMP.E.VC.F32",
+ arm_VCMP_E_HI_F32: "VCMP.E.HI.F32",
+ arm_VCMP_E_LS_F32: "VCMP.E.LS.F32",
+ arm_VCMP_E_GE_F32: "VCMP.E.GE.F32",
+ arm_VCMP_E_LT_F32: "VCMP.E.LT.F32",
+ arm_VCMP_E_GT_F32: "VCMP.E.GT.F32",
+ arm_VCMP_E_LE_F32: "VCMP.E.LE.F32",
+ arm_VCMP_E_F32: "VCMP.E.F32",
+ arm_VCMP_E_ZZ_F32: "VCMP.E.ZZ.F32",
+ arm_VCMP_E_EQ_F64: "VCMP.E.EQ.F64",
+ arm_VCMP_E_NE_F64: "VCMP.E.NE.F64",
+ arm_VCMP_E_CS_F64: "VCMP.E.CS.F64",
+ arm_VCMP_E_CC_F64: "VCMP.E.CC.F64",
+ arm_VCMP_E_MI_F64: "VCMP.E.MI.F64",
+ arm_VCMP_E_PL_F64: "VCMP.E.PL.F64",
+ arm_VCMP_E_VS_F64: "VCMP.E.VS.F64",
+ arm_VCMP_E_VC_F64: "VCMP.E.VC.F64",
+ arm_VCMP_E_HI_F64: "VCMP.E.HI.F64",
+ arm_VCMP_E_LS_F64: "VCMP.E.LS.F64",
+ arm_VCMP_E_GE_F64: "VCMP.E.GE.F64",
+ arm_VCMP_E_LT_F64: "VCMP.E.LT.F64",
+ arm_VCMP_E_GT_F64: "VCMP.E.GT.F64",
+ arm_VCMP_E_LE_F64: "VCMP.E.LE.F64",
+ arm_VCMP_E_F64: "VCMP.E.F64",
+ arm_VCMP_E_ZZ_F64: "VCMP.E.ZZ.F64",
+ arm_VCVT_EQ_F32_FXS16: "VCVT.EQ.F32.FXS16",
+ arm_VCVT_NE_F32_FXS16: "VCVT.NE.F32.FXS16",
+ arm_VCVT_CS_F32_FXS16: "VCVT.CS.F32.FXS16",
+ arm_VCVT_CC_F32_FXS16: "VCVT.CC.F32.FXS16",
+ arm_VCVT_MI_F32_FXS16: "VCVT.MI.F32.FXS16",
+ arm_VCVT_PL_F32_FXS16: "VCVT.PL.F32.FXS16",
+ arm_VCVT_VS_F32_FXS16: "VCVT.VS.F32.FXS16",
+ arm_VCVT_VC_F32_FXS16: "VCVT.VC.F32.FXS16",
+ arm_VCVT_HI_F32_FXS16: "VCVT.HI.F32.FXS16",
+ arm_VCVT_LS_F32_FXS16: "VCVT.LS.F32.FXS16",
+ arm_VCVT_GE_F32_FXS16: "VCVT.GE.F32.FXS16",
+ arm_VCVT_LT_F32_FXS16: "VCVT.LT.F32.FXS16",
+ arm_VCVT_GT_F32_FXS16: "VCVT.GT.F32.FXS16",
+ arm_VCVT_LE_F32_FXS16: "VCVT.LE.F32.FXS16",
+ arm_VCVT_F32_FXS16: "VCVT.F32.FXS16",
+ arm_VCVT_ZZ_F32_FXS16: "VCVT.ZZ.F32.FXS16",
+ arm_VCVT_EQ_F32_FXS32: "VCVT.EQ.F32.FXS32",
+ arm_VCVT_NE_F32_FXS32: "VCVT.NE.F32.FXS32",
+ arm_VCVT_CS_F32_FXS32: "VCVT.CS.F32.FXS32",
+ arm_VCVT_CC_F32_FXS32: "VCVT.CC.F32.FXS32",
+ arm_VCVT_MI_F32_FXS32: "VCVT.MI.F32.FXS32",
+ arm_VCVT_PL_F32_FXS32: "VCVT.PL.F32.FXS32",
+ arm_VCVT_VS_F32_FXS32: "VCVT.VS.F32.FXS32",
+ arm_VCVT_VC_F32_FXS32: "VCVT.VC.F32.FXS32",
+ arm_VCVT_HI_F32_FXS32: "VCVT.HI.F32.FXS32",
+ arm_VCVT_LS_F32_FXS32: "VCVT.LS.F32.FXS32",
+ arm_VCVT_GE_F32_FXS32: "VCVT.GE.F32.FXS32",
+ arm_VCVT_LT_F32_FXS32: "VCVT.LT.F32.FXS32",
+ arm_VCVT_GT_F32_FXS32: "VCVT.GT.F32.FXS32",
+ arm_VCVT_LE_F32_FXS32: "VCVT.LE.F32.FXS32",
+ arm_VCVT_F32_FXS32: "VCVT.F32.FXS32",
+ arm_VCVT_ZZ_F32_FXS32: "VCVT.ZZ.F32.FXS32",
+ arm_VCVT_EQ_F32_FXU16: "VCVT.EQ.F32.FXU16",
+ arm_VCVT_NE_F32_FXU16: "VCVT.NE.F32.FXU16",
+ arm_VCVT_CS_F32_FXU16: "VCVT.CS.F32.FXU16",
+ arm_VCVT_CC_F32_FXU16: "VCVT.CC.F32.FXU16",
+ arm_VCVT_MI_F32_FXU16: "VCVT.MI.F32.FXU16",
+ arm_VCVT_PL_F32_FXU16: "VCVT.PL.F32.FXU16",
+ arm_VCVT_VS_F32_FXU16: "VCVT.VS.F32.FXU16",
+ arm_VCVT_VC_F32_FXU16: "VCVT.VC.F32.FXU16",
+ arm_VCVT_HI_F32_FXU16: "VCVT.HI.F32.FXU16",
+ arm_VCVT_LS_F32_FXU16: "VCVT.LS.F32.FXU16",
+ arm_VCVT_GE_F32_FXU16: "VCVT.GE.F32.FXU16",
+ arm_VCVT_LT_F32_FXU16: "VCVT.LT.F32.FXU16",
+ arm_VCVT_GT_F32_FXU16: "VCVT.GT.F32.FXU16",
+ arm_VCVT_LE_F32_FXU16: "VCVT.LE.F32.FXU16",
+ arm_VCVT_F32_FXU16: "VCVT.F32.FXU16",
+ arm_VCVT_ZZ_F32_FXU16: "VCVT.ZZ.F32.FXU16",
+ arm_VCVT_EQ_F32_FXU32: "VCVT.EQ.F32.FXU32",
+ arm_VCVT_NE_F32_FXU32: "VCVT.NE.F32.FXU32",
+ arm_VCVT_CS_F32_FXU32: "VCVT.CS.F32.FXU32",
+ arm_VCVT_CC_F32_FXU32: "VCVT.CC.F32.FXU32",
+ arm_VCVT_MI_F32_FXU32: "VCVT.MI.F32.FXU32",
+ arm_VCVT_PL_F32_FXU32: "VCVT.PL.F32.FXU32",
+ arm_VCVT_VS_F32_FXU32: "VCVT.VS.F32.FXU32",
+ arm_VCVT_VC_F32_FXU32: "VCVT.VC.F32.FXU32",
+ arm_VCVT_HI_F32_FXU32: "VCVT.HI.F32.FXU32",
+ arm_VCVT_LS_F32_FXU32: "VCVT.LS.F32.FXU32",
+ arm_VCVT_GE_F32_FXU32: "VCVT.GE.F32.FXU32",
+ arm_VCVT_LT_F32_FXU32: "VCVT.LT.F32.FXU32",
+ arm_VCVT_GT_F32_FXU32: "VCVT.GT.F32.FXU32",
+ arm_VCVT_LE_F32_FXU32: "VCVT.LE.F32.FXU32",
+ arm_VCVT_F32_FXU32: "VCVT.F32.FXU32",
+ arm_VCVT_ZZ_F32_FXU32: "VCVT.ZZ.F32.FXU32",
+ arm_VCVT_EQ_F64_FXS16: "VCVT.EQ.F64.FXS16",
+ arm_VCVT_NE_F64_FXS16: "VCVT.NE.F64.FXS16",
+ arm_VCVT_CS_F64_FXS16: "VCVT.CS.F64.FXS16",
+ arm_VCVT_CC_F64_FXS16: "VCVT.CC.F64.FXS16",
+ arm_VCVT_MI_F64_FXS16: "VCVT.MI.F64.FXS16",
+ arm_VCVT_PL_F64_FXS16: "VCVT.PL.F64.FXS16",
+ arm_VCVT_VS_F64_FXS16: "VCVT.VS.F64.FXS16",
+ arm_VCVT_VC_F64_FXS16: "VCVT.VC.F64.FXS16",
+ arm_VCVT_HI_F64_FXS16: "VCVT.HI.F64.FXS16",
+ arm_VCVT_LS_F64_FXS16: "VCVT.LS.F64.FXS16",
+ arm_VCVT_GE_F64_FXS16: "VCVT.GE.F64.FXS16",
+ arm_VCVT_LT_F64_FXS16: "VCVT.LT.F64.FXS16",
+ arm_VCVT_GT_F64_FXS16: "VCVT.GT.F64.FXS16",
+ arm_VCVT_LE_F64_FXS16: "VCVT.LE.F64.FXS16",
+ arm_VCVT_F64_FXS16: "VCVT.F64.FXS16",
+ arm_VCVT_ZZ_F64_FXS16: "VCVT.ZZ.F64.FXS16",
+ arm_VCVT_EQ_F64_FXS32: "VCVT.EQ.F64.FXS32",
+ arm_VCVT_NE_F64_FXS32: "VCVT.NE.F64.FXS32",
+ arm_VCVT_CS_F64_FXS32: "VCVT.CS.F64.FXS32",
+ arm_VCVT_CC_F64_FXS32: "VCVT.CC.F64.FXS32",
+ arm_VCVT_MI_F64_FXS32: "VCVT.MI.F64.FXS32",
+ arm_VCVT_PL_F64_FXS32: "VCVT.PL.F64.FXS32",
+ arm_VCVT_VS_F64_FXS32: "VCVT.VS.F64.FXS32",
+ arm_VCVT_VC_F64_FXS32: "VCVT.VC.F64.FXS32",
+ arm_VCVT_HI_F64_FXS32: "VCVT.HI.F64.FXS32",
+ arm_VCVT_LS_F64_FXS32: "VCVT.LS.F64.FXS32",
+ arm_VCVT_GE_F64_FXS32: "VCVT.GE.F64.FXS32",
+ arm_VCVT_LT_F64_FXS32: "VCVT.LT.F64.FXS32",
+ arm_VCVT_GT_F64_FXS32: "VCVT.GT.F64.FXS32",
+ arm_VCVT_LE_F64_FXS32: "VCVT.LE.F64.FXS32",
+ arm_VCVT_F64_FXS32: "VCVT.F64.FXS32",
+ arm_VCVT_ZZ_F64_FXS32: "VCVT.ZZ.F64.FXS32",
+ arm_VCVT_EQ_F64_FXU16: "VCVT.EQ.F64.FXU16",
+ arm_VCVT_NE_F64_FXU16: "VCVT.NE.F64.FXU16",
+ arm_VCVT_CS_F64_FXU16: "VCVT.CS.F64.FXU16",
+ arm_VCVT_CC_F64_FXU16: "VCVT.CC.F64.FXU16",
+ arm_VCVT_MI_F64_FXU16: "VCVT.MI.F64.FXU16",
+ arm_VCVT_PL_F64_FXU16: "VCVT.PL.F64.FXU16",
+ arm_VCVT_VS_F64_FXU16: "VCVT.VS.F64.FXU16",
+ arm_VCVT_VC_F64_FXU16: "VCVT.VC.F64.FXU16",
+ arm_VCVT_HI_F64_FXU16: "VCVT.HI.F64.FXU16",
+ arm_VCVT_LS_F64_FXU16: "VCVT.LS.F64.FXU16",
+ arm_VCVT_GE_F64_FXU16: "VCVT.GE.F64.FXU16",
+ arm_VCVT_LT_F64_FXU16: "VCVT.LT.F64.FXU16",
+ arm_VCVT_GT_F64_FXU16: "VCVT.GT.F64.FXU16",
+ arm_VCVT_LE_F64_FXU16: "VCVT.LE.F64.FXU16",
+ arm_VCVT_F64_FXU16: "VCVT.F64.FXU16",
+ arm_VCVT_ZZ_F64_FXU16: "VCVT.ZZ.F64.FXU16",
+ arm_VCVT_EQ_F64_FXU32: "VCVT.EQ.F64.FXU32",
+ arm_VCVT_NE_F64_FXU32: "VCVT.NE.F64.FXU32",
+ arm_VCVT_CS_F64_FXU32: "VCVT.CS.F64.FXU32",
+ arm_VCVT_CC_F64_FXU32: "VCVT.CC.F64.FXU32",
+ arm_VCVT_MI_F64_FXU32: "VCVT.MI.F64.FXU32",
+ arm_VCVT_PL_F64_FXU32: "VCVT.PL.F64.FXU32",
+ arm_VCVT_VS_F64_FXU32: "VCVT.VS.F64.FXU32",
+ arm_VCVT_VC_F64_FXU32: "VCVT.VC.F64.FXU32",
+ arm_VCVT_HI_F64_FXU32: "VCVT.HI.F64.FXU32",
+ arm_VCVT_LS_F64_FXU32: "VCVT.LS.F64.FXU32",
+ arm_VCVT_GE_F64_FXU32: "VCVT.GE.F64.FXU32",
+ arm_VCVT_LT_F64_FXU32: "VCVT.LT.F64.FXU32",
+ arm_VCVT_GT_F64_FXU32: "VCVT.GT.F64.FXU32",
+ arm_VCVT_LE_F64_FXU32: "VCVT.LE.F64.FXU32",
+ arm_VCVT_F64_FXU32: "VCVT.F64.FXU32",
+ arm_VCVT_ZZ_F64_FXU32: "VCVT.ZZ.F64.FXU32",
+ arm_VCVT_EQ_F32_U32: "VCVT.EQ.F32.U32",
+ arm_VCVT_NE_F32_U32: "VCVT.NE.F32.U32",
+ arm_VCVT_CS_F32_U32: "VCVT.CS.F32.U32",
+ arm_VCVT_CC_F32_U32: "VCVT.CC.F32.U32",
+ arm_VCVT_MI_F32_U32: "VCVT.MI.F32.U32",
+ arm_VCVT_PL_F32_U32: "VCVT.PL.F32.U32",
+ arm_VCVT_VS_F32_U32: "VCVT.VS.F32.U32",
+ arm_VCVT_VC_F32_U32: "VCVT.VC.F32.U32",
+ arm_VCVT_HI_F32_U32: "VCVT.HI.F32.U32",
+ arm_VCVT_LS_F32_U32: "VCVT.LS.F32.U32",
+ arm_VCVT_GE_F32_U32: "VCVT.GE.F32.U32",
+ arm_VCVT_LT_F32_U32: "VCVT.LT.F32.U32",
+ arm_VCVT_GT_F32_U32: "VCVT.GT.F32.U32",
+ arm_VCVT_LE_F32_U32: "VCVT.LE.F32.U32",
+ arm_VCVT_F32_U32: "VCVT.F32.U32",
+ arm_VCVT_ZZ_F32_U32: "VCVT.ZZ.F32.U32",
+ arm_VCVT_EQ_F32_S32: "VCVT.EQ.F32.S32",
+ arm_VCVT_NE_F32_S32: "VCVT.NE.F32.S32",
+ arm_VCVT_CS_F32_S32: "VCVT.CS.F32.S32",
+ arm_VCVT_CC_F32_S32: "VCVT.CC.F32.S32",
+ arm_VCVT_MI_F32_S32: "VCVT.MI.F32.S32",
+ arm_VCVT_PL_F32_S32: "VCVT.PL.F32.S32",
+ arm_VCVT_VS_F32_S32: "VCVT.VS.F32.S32",
+ arm_VCVT_VC_F32_S32: "VCVT.VC.F32.S32",
+ arm_VCVT_HI_F32_S32: "VCVT.HI.F32.S32",
+ arm_VCVT_LS_F32_S32: "VCVT.LS.F32.S32",
+ arm_VCVT_GE_F32_S32: "VCVT.GE.F32.S32",
+ arm_VCVT_LT_F32_S32: "VCVT.LT.F32.S32",
+ arm_VCVT_GT_F32_S32: "VCVT.GT.F32.S32",
+ arm_VCVT_LE_F32_S32: "VCVT.LE.F32.S32",
+ arm_VCVT_F32_S32: "VCVT.F32.S32",
+ arm_VCVT_ZZ_F32_S32: "VCVT.ZZ.F32.S32",
+ arm_VCVT_EQ_F64_U32: "VCVT.EQ.F64.U32",
+ arm_VCVT_NE_F64_U32: "VCVT.NE.F64.U32",
+ arm_VCVT_CS_F64_U32: "VCVT.CS.F64.U32",
+ arm_VCVT_CC_F64_U32: "VCVT.CC.F64.U32",
+ arm_VCVT_MI_F64_U32: "VCVT.MI.F64.U32",
+ arm_VCVT_PL_F64_U32: "VCVT.PL.F64.U32",
+ arm_VCVT_VS_F64_U32: "VCVT.VS.F64.U32",
+ arm_VCVT_VC_F64_U32: "VCVT.VC.F64.U32",
+ arm_VCVT_HI_F64_U32: "VCVT.HI.F64.U32",
+ arm_VCVT_LS_F64_U32: "VCVT.LS.F64.U32",
+ arm_VCVT_GE_F64_U32: "VCVT.GE.F64.U32",
+ arm_VCVT_LT_F64_U32: "VCVT.LT.F64.U32",
+ arm_VCVT_GT_F64_U32: "VCVT.GT.F64.U32",
+ arm_VCVT_LE_F64_U32: "VCVT.LE.F64.U32",
+ arm_VCVT_F64_U32: "VCVT.F64.U32",
+ arm_VCVT_ZZ_F64_U32: "VCVT.ZZ.F64.U32",
+ arm_VCVT_EQ_F64_S32: "VCVT.EQ.F64.S32",
+ arm_VCVT_NE_F64_S32: "VCVT.NE.F64.S32",
+ arm_VCVT_CS_F64_S32: "VCVT.CS.F64.S32",
+ arm_VCVT_CC_F64_S32: "VCVT.CC.F64.S32",
+ arm_VCVT_MI_F64_S32: "VCVT.MI.F64.S32",
+ arm_VCVT_PL_F64_S32: "VCVT.PL.F64.S32",
+ arm_VCVT_VS_F64_S32: "VCVT.VS.F64.S32",
+ arm_VCVT_VC_F64_S32: "VCVT.VC.F64.S32",
+ arm_VCVT_HI_F64_S32: "VCVT.HI.F64.S32",
+ arm_VCVT_LS_F64_S32: "VCVT.LS.F64.S32",
+ arm_VCVT_GE_F64_S32: "VCVT.GE.F64.S32",
+ arm_VCVT_LT_F64_S32: "VCVT.LT.F64.S32",
+ arm_VCVT_GT_F64_S32: "VCVT.GT.F64.S32",
+ arm_VCVT_LE_F64_S32: "VCVT.LE.F64.S32",
+ arm_VCVT_F64_S32: "VCVT.F64.S32",
+ arm_VCVT_ZZ_F64_S32: "VCVT.ZZ.F64.S32",
+ arm_VCVT_EQ_F64_F32: "VCVT.EQ.F64.F32",
+ arm_VCVT_NE_F64_F32: "VCVT.NE.F64.F32",
+ arm_VCVT_CS_F64_F32: "VCVT.CS.F64.F32",
+ arm_VCVT_CC_F64_F32: "VCVT.CC.F64.F32",
+ arm_VCVT_MI_F64_F32: "VCVT.MI.F64.F32",
+ arm_VCVT_PL_F64_F32: "VCVT.PL.F64.F32",
+ arm_VCVT_VS_F64_F32: "VCVT.VS.F64.F32",
+ arm_VCVT_VC_F64_F32: "VCVT.VC.F64.F32",
+ arm_VCVT_HI_F64_F32: "VCVT.HI.F64.F32",
+ arm_VCVT_LS_F64_F32: "VCVT.LS.F64.F32",
+ arm_VCVT_GE_F64_F32: "VCVT.GE.F64.F32",
+ arm_VCVT_LT_F64_F32: "VCVT.LT.F64.F32",
+ arm_VCVT_GT_F64_F32: "VCVT.GT.F64.F32",
+ arm_VCVT_LE_F64_F32: "VCVT.LE.F64.F32",
+ arm_VCVT_F64_F32: "VCVT.F64.F32",
+ arm_VCVT_ZZ_F64_F32: "VCVT.ZZ.F64.F32",
+ arm_VCVT_EQ_F32_F64: "VCVT.EQ.F32.F64",
+ arm_VCVT_NE_F32_F64: "VCVT.NE.F32.F64",
+ arm_VCVT_CS_F32_F64: "VCVT.CS.F32.F64",
+ arm_VCVT_CC_F32_F64: "VCVT.CC.F32.F64",
+ arm_VCVT_MI_F32_F64: "VCVT.MI.F32.F64",
+ arm_VCVT_PL_F32_F64: "VCVT.PL.F32.F64",
+ arm_VCVT_VS_F32_F64: "VCVT.VS.F32.F64",
+ arm_VCVT_VC_F32_F64: "VCVT.VC.F32.F64",
+ arm_VCVT_HI_F32_F64: "VCVT.HI.F32.F64",
+ arm_VCVT_LS_F32_F64: "VCVT.LS.F32.F64",
+ arm_VCVT_GE_F32_F64: "VCVT.GE.F32.F64",
+ arm_VCVT_LT_F32_F64: "VCVT.LT.F32.F64",
+ arm_VCVT_GT_F32_F64: "VCVT.GT.F32.F64",
+ arm_VCVT_LE_F32_F64: "VCVT.LE.F32.F64",
+ arm_VCVT_F32_F64: "VCVT.F32.F64",
+ arm_VCVT_ZZ_F32_F64: "VCVT.ZZ.F32.F64",
+ arm_VCVT_EQ_FXS16_F32: "VCVT.EQ.FXS16.F32",
+ arm_VCVT_NE_FXS16_F32: "VCVT.NE.FXS16.F32",
+ arm_VCVT_CS_FXS16_F32: "VCVT.CS.FXS16.F32",
+ arm_VCVT_CC_FXS16_F32: "VCVT.CC.FXS16.F32",
+ arm_VCVT_MI_FXS16_F32: "VCVT.MI.FXS16.F32",
+ arm_VCVT_PL_FXS16_F32: "VCVT.PL.FXS16.F32",
+ arm_VCVT_VS_FXS16_F32: "VCVT.VS.FXS16.F32",
+ arm_VCVT_VC_FXS16_F32: "VCVT.VC.FXS16.F32",
+ arm_VCVT_HI_FXS16_F32: "VCVT.HI.FXS16.F32",
+ arm_VCVT_LS_FXS16_F32: "VCVT.LS.FXS16.F32",
+ arm_VCVT_GE_FXS16_F32: "VCVT.GE.FXS16.F32",
+ arm_VCVT_LT_FXS16_F32: "VCVT.LT.FXS16.F32",
+ arm_VCVT_GT_FXS16_F32: "VCVT.GT.FXS16.F32",
+ arm_VCVT_LE_FXS16_F32: "VCVT.LE.FXS16.F32",
+ arm_VCVT_FXS16_F32: "VCVT.FXS16.F32",
+ arm_VCVT_ZZ_FXS16_F32: "VCVT.ZZ.FXS16.F32",
+ arm_VCVT_EQ_FXS16_F64: "VCVT.EQ.FXS16.F64",
+ arm_VCVT_NE_FXS16_F64: "VCVT.NE.FXS16.F64",
+ arm_VCVT_CS_FXS16_F64: "VCVT.CS.FXS16.F64",
+ arm_VCVT_CC_FXS16_F64: "VCVT.CC.FXS16.F64",
+ arm_VCVT_MI_FXS16_F64: "VCVT.MI.FXS16.F64",
+ arm_VCVT_PL_FXS16_F64: "VCVT.PL.FXS16.F64",
+ arm_VCVT_VS_FXS16_F64: "VCVT.VS.FXS16.F64",
+ arm_VCVT_VC_FXS16_F64: "VCVT.VC.FXS16.F64",
+ arm_VCVT_HI_FXS16_F64: "VCVT.HI.FXS16.F64",
+ arm_VCVT_LS_FXS16_F64: "VCVT.LS.FXS16.F64",
+ arm_VCVT_GE_FXS16_F64: "VCVT.GE.FXS16.F64",
+ arm_VCVT_LT_FXS16_F64: "VCVT.LT.FXS16.F64",
+ arm_VCVT_GT_FXS16_F64: "VCVT.GT.FXS16.F64",
+ arm_VCVT_LE_FXS16_F64: "VCVT.LE.FXS16.F64",
+ arm_VCVT_FXS16_F64: "VCVT.FXS16.F64",
+ arm_VCVT_ZZ_FXS16_F64: "VCVT.ZZ.FXS16.F64",
+ arm_VCVT_EQ_FXS32_F32: "VCVT.EQ.FXS32.F32",
+ arm_VCVT_NE_FXS32_F32: "VCVT.NE.FXS32.F32",
+ arm_VCVT_CS_FXS32_F32: "VCVT.CS.FXS32.F32",
+ arm_VCVT_CC_FXS32_F32: "VCVT.CC.FXS32.F32",
+ arm_VCVT_MI_FXS32_F32: "VCVT.MI.FXS32.F32",
+ arm_VCVT_PL_FXS32_F32: "VCVT.PL.FXS32.F32",
+ arm_VCVT_VS_FXS32_F32: "VCVT.VS.FXS32.F32",
+ arm_VCVT_VC_FXS32_F32: "VCVT.VC.FXS32.F32",
+ arm_VCVT_HI_FXS32_F32: "VCVT.HI.FXS32.F32",
+ arm_VCVT_LS_FXS32_F32: "VCVT.LS.FXS32.F32",
+ arm_VCVT_GE_FXS32_F32: "VCVT.GE.FXS32.F32",
+ arm_VCVT_LT_FXS32_F32: "VCVT.LT.FXS32.F32",
+ arm_VCVT_GT_FXS32_F32: "VCVT.GT.FXS32.F32",
+ arm_VCVT_LE_FXS32_F32: "VCVT.LE.FXS32.F32",
+ arm_VCVT_FXS32_F32: "VCVT.FXS32.F32",
+ arm_VCVT_ZZ_FXS32_F32: "VCVT.ZZ.FXS32.F32",
+ arm_VCVT_EQ_FXS32_F64: "VCVT.EQ.FXS32.F64",
+ arm_VCVT_NE_FXS32_F64: "VCVT.NE.FXS32.F64",
+ arm_VCVT_CS_FXS32_F64: "VCVT.CS.FXS32.F64",
+ arm_VCVT_CC_FXS32_F64: "VCVT.CC.FXS32.F64",
+ arm_VCVT_MI_FXS32_F64: "VCVT.MI.FXS32.F64",
+ arm_VCVT_PL_FXS32_F64: "VCVT.PL.FXS32.F64",
+ arm_VCVT_VS_FXS32_F64: "VCVT.VS.FXS32.F64",
+ arm_VCVT_VC_FXS32_F64: "VCVT.VC.FXS32.F64",
+ arm_VCVT_HI_FXS32_F64: "VCVT.HI.FXS32.F64",
+ arm_VCVT_LS_FXS32_F64: "VCVT.LS.FXS32.F64",
+ arm_VCVT_GE_FXS32_F64: "VCVT.GE.FXS32.F64",
+ arm_VCVT_LT_FXS32_F64: "VCVT.LT.FXS32.F64",
+ arm_VCVT_GT_FXS32_F64: "VCVT.GT.FXS32.F64",
+ arm_VCVT_LE_FXS32_F64: "VCVT.LE.FXS32.F64",
+ arm_VCVT_FXS32_F64: "VCVT.FXS32.F64",
+ arm_VCVT_ZZ_FXS32_F64: "VCVT.ZZ.FXS32.F64",
+ arm_VCVT_EQ_FXU16_F32: "VCVT.EQ.FXU16.F32",
+ arm_VCVT_NE_FXU16_F32: "VCVT.NE.FXU16.F32",
+ arm_VCVT_CS_FXU16_F32: "VCVT.CS.FXU16.F32",
+ arm_VCVT_CC_FXU16_F32: "VCVT.CC.FXU16.F32",
+ arm_VCVT_MI_FXU16_F32: "VCVT.MI.FXU16.F32",
+ arm_VCVT_PL_FXU16_F32: "VCVT.PL.FXU16.F32",
+ arm_VCVT_VS_FXU16_F32: "VCVT.VS.FXU16.F32",
+ arm_VCVT_VC_FXU16_F32: "VCVT.VC.FXU16.F32",
+ arm_VCVT_HI_FXU16_F32: "VCVT.HI.FXU16.F32",
+ arm_VCVT_LS_FXU16_F32: "VCVT.LS.FXU16.F32",
+ arm_VCVT_GE_FXU16_F32: "VCVT.GE.FXU16.F32",
+ arm_VCVT_LT_FXU16_F32: "VCVT.LT.FXU16.F32",
+ arm_VCVT_GT_FXU16_F32: "VCVT.GT.FXU16.F32",
+ arm_VCVT_LE_FXU16_F32: "VCVT.LE.FXU16.F32",
+ arm_VCVT_FXU16_F32: "VCVT.FXU16.F32",
+ arm_VCVT_ZZ_FXU16_F32: "VCVT.ZZ.FXU16.F32",
+ arm_VCVT_EQ_FXU16_F64: "VCVT.EQ.FXU16.F64",
+ arm_VCVT_NE_FXU16_F64: "VCVT.NE.FXU16.F64",
+ arm_VCVT_CS_FXU16_F64: "VCVT.CS.FXU16.F64",
+ arm_VCVT_CC_FXU16_F64: "VCVT.CC.FXU16.F64",
+ arm_VCVT_MI_FXU16_F64: "VCVT.MI.FXU16.F64",
+ arm_VCVT_PL_FXU16_F64: "VCVT.PL.FXU16.F64",
+ arm_VCVT_VS_FXU16_F64: "VCVT.VS.FXU16.F64",
+ arm_VCVT_VC_FXU16_F64: "VCVT.VC.FXU16.F64",
+ arm_VCVT_HI_FXU16_F64: "VCVT.HI.FXU16.F64",
+ arm_VCVT_LS_FXU16_F64: "VCVT.LS.FXU16.F64",
+ arm_VCVT_GE_FXU16_F64: "VCVT.GE.FXU16.F64",
+ arm_VCVT_LT_FXU16_F64: "VCVT.LT.FXU16.F64",
+ arm_VCVT_GT_FXU16_F64: "VCVT.GT.FXU16.F64",
+ arm_VCVT_LE_FXU16_F64: "VCVT.LE.FXU16.F64",
+ arm_VCVT_FXU16_F64: "VCVT.FXU16.F64",
+ arm_VCVT_ZZ_FXU16_F64: "VCVT.ZZ.FXU16.F64",
+ arm_VCVT_EQ_FXU32_F32: "VCVT.EQ.FXU32.F32",
+ arm_VCVT_NE_FXU32_F32: "VCVT.NE.FXU32.F32",
+ arm_VCVT_CS_FXU32_F32: "VCVT.CS.FXU32.F32",
+ arm_VCVT_CC_FXU32_F32: "VCVT.CC.FXU32.F32",
+ arm_VCVT_MI_FXU32_F32: "VCVT.MI.FXU32.F32",
+ arm_VCVT_PL_FXU32_F32: "VCVT.PL.FXU32.F32",
+ arm_VCVT_VS_FXU32_F32: "VCVT.VS.FXU32.F32",
+ arm_VCVT_VC_FXU32_F32: "VCVT.VC.FXU32.F32",
+ arm_VCVT_HI_FXU32_F32: "VCVT.HI.FXU32.F32",
+ arm_VCVT_LS_FXU32_F32: "VCVT.LS.FXU32.F32",
+ arm_VCVT_GE_FXU32_F32: "VCVT.GE.FXU32.F32",
+ arm_VCVT_LT_FXU32_F32: "VCVT.LT.FXU32.F32",
+ arm_VCVT_GT_FXU32_F32: "VCVT.GT.FXU32.F32",
+ arm_VCVT_LE_FXU32_F32: "VCVT.LE.FXU32.F32",
+ arm_VCVT_FXU32_F32: "VCVT.FXU32.F32",
+ arm_VCVT_ZZ_FXU32_F32: "VCVT.ZZ.FXU32.F32",
+ arm_VCVT_EQ_FXU32_F64: "VCVT.EQ.FXU32.F64",
+ arm_VCVT_NE_FXU32_F64: "VCVT.NE.FXU32.F64",
+ arm_VCVT_CS_FXU32_F64: "VCVT.CS.FXU32.F64",
+ arm_VCVT_CC_FXU32_F64: "VCVT.CC.FXU32.F64",
+ arm_VCVT_MI_FXU32_F64: "VCVT.MI.FXU32.F64",
+ arm_VCVT_PL_FXU32_F64: "VCVT.PL.FXU32.F64",
+ arm_VCVT_VS_FXU32_F64: "VCVT.VS.FXU32.F64",
+ arm_VCVT_VC_FXU32_F64: "VCVT.VC.FXU32.F64",
+ arm_VCVT_HI_FXU32_F64: "VCVT.HI.FXU32.F64",
+ arm_VCVT_LS_FXU32_F64: "VCVT.LS.FXU32.F64",
+ arm_VCVT_GE_FXU32_F64: "VCVT.GE.FXU32.F64",
+ arm_VCVT_LT_FXU32_F64: "VCVT.LT.FXU32.F64",
+ arm_VCVT_GT_FXU32_F64: "VCVT.GT.FXU32.F64",
+ arm_VCVT_LE_FXU32_F64: "VCVT.LE.FXU32.F64",
+ arm_VCVT_FXU32_F64: "VCVT.FXU32.F64",
+ arm_VCVT_ZZ_FXU32_F64: "VCVT.ZZ.FXU32.F64",
+ arm_VCVTB_EQ_F32_F16: "VCVTB.EQ.F32.F16",
+ arm_VCVTB_NE_F32_F16: "VCVTB.NE.F32.F16",
+ arm_VCVTB_CS_F32_F16: "VCVTB.CS.F32.F16",
+ arm_VCVTB_CC_F32_F16: "VCVTB.CC.F32.F16",
+ arm_VCVTB_MI_F32_F16: "VCVTB.MI.F32.F16",
+ arm_VCVTB_PL_F32_F16: "VCVTB.PL.F32.F16",
+ arm_VCVTB_VS_F32_F16: "VCVTB.VS.F32.F16",
+ arm_VCVTB_VC_F32_F16: "VCVTB.VC.F32.F16",
+ arm_VCVTB_HI_F32_F16: "VCVTB.HI.F32.F16",
+ arm_VCVTB_LS_F32_F16: "VCVTB.LS.F32.F16",
+ arm_VCVTB_GE_F32_F16: "VCVTB.GE.F32.F16",
+ arm_VCVTB_LT_F32_F16: "VCVTB.LT.F32.F16",
+ arm_VCVTB_GT_F32_F16: "VCVTB.GT.F32.F16",
+ arm_VCVTB_LE_F32_F16: "VCVTB.LE.F32.F16",
+ arm_VCVTB_F32_F16: "VCVTB.F32.F16",
+ arm_VCVTB_ZZ_F32_F16: "VCVTB.ZZ.F32.F16",
+ arm_VCVTB_EQ_F16_F32: "VCVTB.EQ.F16.F32",
+ arm_VCVTB_NE_F16_F32: "VCVTB.NE.F16.F32",
+ arm_VCVTB_CS_F16_F32: "VCVTB.CS.F16.F32",
+ arm_VCVTB_CC_F16_F32: "VCVTB.CC.F16.F32",
+ arm_VCVTB_MI_F16_F32: "VCVTB.MI.F16.F32",
+ arm_VCVTB_PL_F16_F32: "VCVTB.PL.F16.F32",
+ arm_VCVTB_VS_F16_F32: "VCVTB.VS.F16.F32",
+ arm_VCVTB_VC_F16_F32: "VCVTB.VC.F16.F32",
+ arm_VCVTB_HI_F16_F32: "VCVTB.HI.F16.F32",
+ arm_VCVTB_LS_F16_F32: "VCVTB.LS.F16.F32",
+ arm_VCVTB_GE_F16_F32: "VCVTB.GE.F16.F32",
+ arm_VCVTB_LT_F16_F32: "VCVTB.LT.F16.F32",
+ arm_VCVTB_GT_F16_F32: "VCVTB.GT.F16.F32",
+ arm_VCVTB_LE_F16_F32: "VCVTB.LE.F16.F32",
+ arm_VCVTB_F16_F32: "VCVTB.F16.F32",
+ arm_VCVTB_ZZ_F16_F32: "VCVTB.ZZ.F16.F32",
+ arm_VCVTT_EQ_F32_F16: "VCVTT.EQ.F32.F16",
+ arm_VCVTT_NE_F32_F16: "VCVTT.NE.F32.F16",
+ arm_VCVTT_CS_F32_F16: "VCVTT.CS.F32.F16",
+ arm_VCVTT_CC_F32_F16: "VCVTT.CC.F32.F16",
+ arm_VCVTT_MI_F32_F16: "VCVTT.MI.F32.F16",
+ arm_VCVTT_PL_F32_F16: "VCVTT.PL.F32.F16",
+ arm_VCVTT_VS_F32_F16: "VCVTT.VS.F32.F16",
+ arm_VCVTT_VC_F32_F16: "VCVTT.VC.F32.F16",
+ arm_VCVTT_HI_F32_F16: "VCVTT.HI.F32.F16",
+ arm_VCVTT_LS_F32_F16: "VCVTT.LS.F32.F16",
+ arm_VCVTT_GE_F32_F16: "VCVTT.GE.F32.F16",
+ arm_VCVTT_LT_F32_F16: "VCVTT.LT.F32.F16",
+ arm_VCVTT_GT_F32_F16: "VCVTT.GT.F32.F16",
+ arm_VCVTT_LE_F32_F16: "VCVTT.LE.F32.F16",
+ arm_VCVTT_F32_F16: "VCVTT.F32.F16",
+ arm_VCVTT_ZZ_F32_F16: "VCVTT.ZZ.F32.F16",
+ arm_VCVTT_EQ_F16_F32: "VCVTT.EQ.F16.F32",
+ arm_VCVTT_NE_F16_F32: "VCVTT.NE.F16.F32",
+ arm_VCVTT_CS_F16_F32: "VCVTT.CS.F16.F32",
+ arm_VCVTT_CC_F16_F32: "VCVTT.CC.F16.F32",
+ arm_VCVTT_MI_F16_F32: "VCVTT.MI.F16.F32",
+ arm_VCVTT_PL_F16_F32: "VCVTT.PL.F16.F32",
+ arm_VCVTT_VS_F16_F32: "VCVTT.VS.F16.F32",
+ arm_VCVTT_VC_F16_F32: "VCVTT.VC.F16.F32",
+ arm_VCVTT_HI_F16_F32: "VCVTT.HI.F16.F32",
+ arm_VCVTT_LS_F16_F32: "VCVTT.LS.F16.F32",
+ arm_VCVTT_GE_F16_F32: "VCVTT.GE.F16.F32",
+ arm_VCVTT_LT_F16_F32: "VCVTT.LT.F16.F32",
+ arm_VCVTT_GT_F16_F32: "VCVTT.GT.F16.F32",
+ arm_VCVTT_LE_F16_F32: "VCVTT.LE.F16.F32",
+ arm_VCVTT_F16_F32: "VCVTT.F16.F32",
+ arm_VCVTT_ZZ_F16_F32: "VCVTT.ZZ.F16.F32",
+ arm_VCVTR_EQ_U32_F32: "VCVTR.EQ.U32.F32",
+ arm_VCVTR_NE_U32_F32: "VCVTR.NE.U32.F32",
+ arm_VCVTR_CS_U32_F32: "VCVTR.CS.U32.F32",
+ arm_VCVTR_CC_U32_F32: "VCVTR.CC.U32.F32",
+ arm_VCVTR_MI_U32_F32: "VCVTR.MI.U32.F32",
+ arm_VCVTR_PL_U32_F32: "VCVTR.PL.U32.F32",
+ arm_VCVTR_VS_U32_F32: "VCVTR.VS.U32.F32",
+ arm_VCVTR_VC_U32_F32: "VCVTR.VC.U32.F32",
+ arm_VCVTR_HI_U32_F32: "VCVTR.HI.U32.F32",
+ arm_VCVTR_LS_U32_F32: "VCVTR.LS.U32.F32",
+ arm_VCVTR_GE_U32_F32: "VCVTR.GE.U32.F32",
+ arm_VCVTR_LT_U32_F32: "VCVTR.LT.U32.F32",
+ arm_VCVTR_GT_U32_F32: "VCVTR.GT.U32.F32",
+ arm_VCVTR_LE_U32_F32: "VCVTR.LE.U32.F32",
+ arm_VCVTR_U32_F32: "VCVTR.U32.F32",
+ arm_VCVTR_ZZ_U32_F32: "VCVTR.ZZ.U32.F32",
+ arm_VCVTR_EQ_U32_F64: "VCVTR.EQ.U32.F64",
+ arm_VCVTR_NE_U32_F64: "VCVTR.NE.U32.F64",
+ arm_VCVTR_CS_U32_F64: "VCVTR.CS.U32.F64",
+ arm_VCVTR_CC_U32_F64: "VCVTR.CC.U32.F64",
+ arm_VCVTR_MI_U32_F64: "VCVTR.MI.U32.F64",
+ arm_VCVTR_PL_U32_F64: "VCVTR.PL.U32.F64",
+ arm_VCVTR_VS_U32_F64: "VCVTR.VS.U32.F64",
+ arm_VCVTR_VC_U32_F64: "VCVTR.VC.U32.F64",
+ arm_VCVTR_HI_U32_F64: "VCVTR.HI.U32.F64",
+ arm_VCVTR_LS_U32_F64: "VCVTR.LS.U32.F64",
+ arm_VCVTR_GE_U32_F64: "VCVTR.GE.U32.F64",
+ arm_VCVTR_LT_U32_F64: "VCVTR.LT.U32.F64",
+ arm_VCVTR_GT_U32_F64: "VCVTR.GT.U32.F64",
+ arm_VCVTR_LE_U32_F64: "VCVTR.LE.U32.F64",
+ arm_VCVTR_U32_F64: "VCVTR.U32.F64",
+ arm_VCVTR_ZZ_U32_F64: "VCVTR.ZZ.U32.F64",
+ arm_VCVTR_EQ_S32_F32: "VCVTR.EQ.S32.F32",
+ arm_VCVTR_NE_S32_F32: "VCVTR.NE.S32.F32",
+ arm_VCVTR_CS_S32_F32: "VCVTR.CS.S32.F32",
+ arm_VCVTR_CC_S32_F32: "VCVTR.CC.S32.F32",
+ arm_VCVTR_MI_S32_F32: "VCVTR.MI.S32.F32",
+ arm_VCVTR_PL_S32_F32: "VCVTR.PL.S32.F32",
+ arm_VCVTR_VS_S32_F32: "VCVTR.VS.S32.F32",
+ arm_VCVTR_VC_S32_F32: "VCVTR.VC.S32.F32",
+ arm_VCVTR_HI_S32_F32: "VCVTR.HI.S32.F32",
+ arm_VCVTR_LS_S32_F32: "VCVTR.LS.S32.F32",
+ arm_VCVTR_GE_S32_F32: "VCVTR.GE.S32.F32",
+ arm_VCVTR_LT_S32_F32: "VCVTR.LT.S32.F32",
+ arm_VCVTR_GT_S32_F32: "VCVTR.GT.S32.F32",
+ arm_VCVTR_LE_S32_F32: "VCVTR.LE.S32.F32",
+ arm_VCVTR_S32_F32: "VCVTR.S32.F32",
+ arm_VCVTR_ZZ_S32_F32: "VCVTR.ZZ.S32.F32",
+ arm_VCVTR_EQ_S32_F64: "VCVTR.EQ.S32.F64",
+ arm_VCVTR_NE_S32_F64: "VCVTR.NE.S32.F64",
+ arm_VCVTR_CS_S32_F64: "VCVTR.CS.S32.F64",
+ arm_VCVTR_CC_S32_F64: "VCVTR.CC.S32.F64",
+ arm_VCVTR_MI_S32_F64: "VCVTR.MI.S32.F64",
+ arm_VCVTR_PL_S32_F64: "VCVTR.PL.S32.F64",
+ arm_VCVTR_VS_S32_F64: "VCVTR.VS.S32.F64",
+ arm_VCVTR_VC_S32_F64: "VCVTR.VC.S32.F64",
+ arm_VCVTR_HI_S32_F64: "VCVTR.HI.S32.F64",
+ arm_VCVTR_LS_S32_F64: "VCVTR.LS.S32.F64",
+ arm_VCVTR_GE_S32_F64: "VCVTR.GE.S32.F64",
+ arm_VCVTR_LT_S32_F64: "VCVTR.LT.S32.F64",
+ arm_VCVTR_GT_S32_F64: "VCVTR.GT.S32.F64",
+ arm_VCVTR_LE_S32_F64: "VCVTR.LE.S32.F64",
+ arm_VCVTR_S32_F64: "VCVTR.S32.F64",
+ arm_VCVTR_ZZ_S32_F64: "VCVTR.ZZ.S32.F64",
+ arm_VCVT_EQ_U32_F32: "VCVT.EQ.U32.F32",
+ arm_VCVT_NE_U32_F32: "VCVT.NE.U32.F32",
+ arm_VCVT_CS_U32_F32: "VCVT.CS.U32.F32",
+ arm_VCVT_CC_U32_F32: "VCVT.CC.U32.F32",
+ arm_VCVT_MI_U32_F32: "VCVT.MI.U32.F32",
+ arm_VCVT_PL_U32_F32: "VCVT.PL.U32.F32",
+ arm_VCVT_VS_U32_F32: "VCVT.VS.U32.F32",
+ arm_VCVT_VC_U32_F32: "VCVT.VC.U32.F32",
+ arm_VCVT_HI_U32_F32: "VCVT.HI.U32.F32",
+ arm_VCVT_LS_U32_F32: "VCVT.LS.U32.F32",
+ arm_VCVT_GE_U32_F32: "VCVT.GE.U32.F32",
+ arm_VCVT_LT_U32_F32: "VCVT.LT.U32.F32",
+ arm_VCVT_GT_U32_F32: "VCVT.GT.U32.F32",
+ arm_VCVT_LE_U32_F32: "VCVT.LE.U32.F32",
+ arm_VCVT_U32_F32: "VCVT.U32.F32",
+ arm_VCVT_ZZ_U32_F32: "VCVT.ZZ.U32.F32",
+ arm_VCVT_EQ_U32_F64: "VCVT.EQ.U32.F64",
+ arm_VCVT_NE_U32_F64: "VCVT.NE.U32.F64",
+ arm_VCVT_CS_U32_F64: "VCVT.CS.U32.F64",
+ arm_VCVT_CC_U32_F64: "VCVT.CC.U32.F64",
+ arm_VCVT_MI_U32_F64: "VCVT.MI.U32.F64",
+ arm_VCVT_PL_U32_F64: "VCVT.PL.U32.F64",
+ arm_VCVT_VS_U32_F64: "VCVT.VS.U32.F64",
+ arm_VCVT_VC_U32_F64: "VCVT.VC.U32.F64",
+ arm_VCVT_HI_U32_F64: "VCVT.HI.U32.F64",
+ arm_VCVT_LS_U32_F64: "VCVT.LS.U32.F64",
+ arm_VCVT_GE_U32_F64: "VCVT.GE.U32.F64",
+ arm_VCVT_LT_U32_F64: "VCVT.LT.U32.F64",
+ arm_VCVT_GT_U32_F64: "VCVT.GT.U32.F64",
+ arm_VCVT_LE_U32_F64: "VCVT.LE.U32.F64",
+ arm_VCVT_U32_F64: "VCVT.U32.F64",
+ arm_VCVT_ZZ_U32_F64: "VCVT.ZZ.U32.F64",
+ arm_VCVT_EQ_S32_F32: "VCVT.EQ.S32.F32",
+ arm_VCVT_NE_S32_F32: "VCVT.NE.S32.F32",
+ arm_VCVT_CS_S32_F32: "VCVT.CS.S32.F32",
+ arm_VCVT_CC_S32_F32: "VCVT.CC.S32.F32",
+ arm_VCVT_MI_S32_F32: "VCVT.MI.S32.F32",
+ arm_VCVT_PL_S32_F32: "VCVT.PL.S32.F32",
+ arm_VCVT_VS_S32_F32: "VCVT.VS.S32.F32",
+ arm_VCVT_VC_S32_F32: "VCVT.VC.S32.F32",
+ arm_VCVT_HI_S32_F32: "VCVT.HI.S32.F32",
+ arm_VCVT_LS_S32_F32: "VCVT.LS.S32.F32",
+ arm_VCVT_GE_S32_F32: "VCVT.GE.S32.F32",
+ arm_VCVT_LT_S32_F32: "VCVT.LT.S32.F32",
+ arm_VCVT_GT_S32_F32: "VCVT.GT.S32.F32",
+ arm_VCVT_LE_S32_F32: "VCVT.LE.S32.F32",
+ arm_VCVT_S32_F32: "VCVT.S32.F32",
+ arm_VCVT_ZZ_S32_F32: "VCVT.ZZ.S32.F32",
+ arm_VCVT_EQ_S32_F64: "VCVT.EQ.S32.F64",
+ arm_VCVT_NE_S32_F64: "VCVT.NE.S32.F64",
+ arm_VCVT_CS_S32_F64: "VCVT.CS.S32.F64",
+ arm_VCVT_CC_S32_F64: "VCVT.CC.S32.F64",
+ arm_VCVT_MI_S32_F64: "VCVT.MI.S32.F64",
+ arm_VCVT_PL_S32_F64: "VCVT.PL.S32.F64",
+ arm_VCVT_VS_S32_F64: "VCVT.VS.S32.F64",
+ arm_VCVT_VC_S32_F64: "VCVT.VC.S32.F64",
+ arm_VCVT_HI_S32_F64: "VCVT.HI.S32.F64",
+ arm_VCVT_LS_S32_F64: "VCVT.LS.S32.F64",
+ arm_VCVT_GE_S32_F64: "VCVT.GE.S32.F64",
+ arm_VCVT_LT_S32_F64: "VCVT.LT.S32.F64",
+ arm_VCVT_GT_S32_F64: "VCVT.GT.S32.F64",
+ arm_VCVT_LE_S32_F64: "VCVT.LE.S32.F64",
+ arm_VCVT_S32_F64: "VCVT.S32.F64",
+ arm_VCVT_ZZ_S32_F64: "VCVT.ZZ.S32.F64",
+ arm_VDIV_EQ_F32: "VDIV.EQ.F32",
+ arm_VDIV_NE_F32: "VDIV.NE.F32",
+ arm_VDIV_CS_F32: "VDIV.CS.F32",
+ arm_VDIV_CC_F32: "VDIV.CC.F32",
+ arm_VDIV_MI_F32: "VDIV.MI.F32",
+ arm_VDIV_PL_F32: "VDIV.PL.F32",
+ arm_VDIV_VS_F32: "VDIV.VS.F32",
+ arm_VDIV_VC_F32: "VDIV.VC.F32",
+ arm_VDIV_HI_F32: "VDIV.HI.F32",
+ arm_VDIV_LS_F32: "VDIV.LS.F32",
+ arm_VDIV_GE_F32: "VDIV.GE.F32",
+ arm_VDIV_LT_F32: "VDIV.LT.F32",
+ arm_VDIV_GT_F32: "VDIV.GT.F32",
+ arm_VDIV_LE_F32: "VDIV.LE.F32",
+ arm_VDIV_F32: "VDIV.F32",
+ arm_VDIV_ZZ_F32: "VDIV.ZZ.F32",
+ arm_VDIV_EQ_F64: "VDIV.EQ.F64",
+ arm_VDIV_NE_F64: "VDIV.NE.F64",
+ arm_VDIV_CS_F64: "VDIV.CS.F64",
+ arm_VDIV_CC_F64: "VDIV.CC.F64",
+ arm_VDIV_MI_F64: "VDIV.MI.F64",
+ arm_VDIV_PL_F64: "VDIV.PL.F64",
+ arm_VDIV_VS_F64: "VDIV.VS.F64",
+ arm_VDIV_VC_F64: "VDIV.VC.F64",
+ arm_VDIV_HI_F64: "VDIV.HI.F64",
+ arm_VDIV_LS_F64: "VDIV.LS.F64",
+ arm_VDIV_GE_F64: "VDIV.GE.F64",
+ arm_VDIV_LT_F64: "VDIV.LT.F64",
+ arm_VDIV_GT_F64: "VDIV.GT.F64",
+ arm_VDIV_LE_F64: "VDIV.LE.F64",
+ arm_VDIV_F64: "VDIV.F64",
+ arm_VDIV_ZZ_F64: "VDIV.ZZ.F64",
+ arm_VLDR_EQ: "VLDR.EQ",
+ arm_VLDR_NE: "VLDR.NE",
+ arm_VLDR_CS: "VLDR.CS",
+ arm_VLDR_CC: "VLDR.CC",
+ arm_VLDR_MI: "VLDR.MI",
+ arm_VLDR_PL: "VLDR.PL",
+ arm_VLDR_VS: "VLDR.VS",
+ arm_VLDR_VC: "VLDR.VC",
+ arm_VLDR_HI: "VLDR.HI",
+ arm_VLDR_LS: "VLDR.LS",
+ arm_VLDR_GE: "VLDR.GE",
+ arm_VLDR_LT: "VLDR.LT",
+ arm_VLDR_GT: "VLDR.GT",
+ arm_VLDR_LE: "VLDR.LE",
+ arm_VLDR: "VLDR",
+ arm_VLDR_ZZ: "VLDR.ZZ",
+ arm_VMLA_EQ_F32: "VMLA.EQ.F32",
+ arm_VMLA_NE_F32: "VMLA.NE.F32",
+ arm_VMLA_CS_F32: "VMLA.CS.F32",
+ arm_VMLA_CC_F32: "VMLA.CC.F32",
+ arm_VMLA_MI_F32: "VMLA.MI.F32",
+ arm_VMLA_PL_F32: "VMLA.PL.F32",
+ arm_VMLA_VS_F32: "VMLA.VS.F32",
+ arm_VMLA_VC_F32: "VMLA.VC.F32",
+ arm_VMLA_HI_F32: "VMLA.HI.F32",
+ arm_VMLA_LS_F32: "VMLA.LS.F32",
+ arm_VMLA_GE_F32: "VMLA.GE.F32",
+ arm_VMLA_LT_F32: "VMLA.LT.F32",
+ arm_VMLA_GT_F32: "VMLA.GT.F32",
+ arm_VMLA_LE_F32: "VMLA.LE.F32",
+ arm_VMLA_F32: "VMLA.F32",
+ arm_VMLA_ZZ_F32: "VMLA.ZZ.F32",
+ arm_VMLA_EQ_F64: "VMLA.EQ.F64",
+ arm_VMLA_NE_F64: "VMLA.NE.F64",
+ arm_VMLA_CS_F64: "VMLA.CS.F64",
+ arm_VMLA_CC_F64: "VMLA.CC.F64",
+ arm_VMLA_MI_F64: "VMLA.MI.F64",
+ arm_VMLA_PL_F64: "VMLA.PL.F64",
+ arm_VMLA_VS_F64: "VMLA.VS.F64",
+ arm_VMLA_VC_F64: "VMLA.VC.F64",
+ arm_VMLA_HI_F64: "VMLA.HI.F64",
+ arm_VMLA_LS_F64: "VMLA.LS.F64",
+ arm_VMLA_GE_F64: "VMLA.GE.F64",
+ arm_VMLA_LT_F64: "VMLA.LT.F64",
+ arm_VMLA_GT_F64: "VMLA.GT.F64",
+ arm_VMLA_LE_F64: "VMLA.LE.F64",
+ arm_VMLA_F64: "VMLA.F64",
+ arm_VMLA_ZZ_F64: "VMLA.ZZ.F64",
+ arm_VMLS_EQ_F32: "VMLS.EQ.F32",
+ arm_VMLS_NE_F32: "VMLS.NE.F32",
+ arm_VMLS_CS_F32: "VMLS.CS.F32",
+ arm_VMLS_CC_F32: "VMLS.CC.F32",
+ arm_VMLS_MI_F32: "VMLS.MI.F32",
+ arm_VMLS_PL_F32: "VMLS.PL.F32",
+ arm_VMLS_VS_F32: "VMLS.VS.F32",
+ arm_VMLS_VC_F32: "VMLS.VC.F32",
+ arm_VMLS_HI_F32: "VMLS.HI.F32",
+ arm_VMLS_LS_F32: "VMLS.LS.F32",
+ arm_VMLS_GE_F32: "VMLS.GE.F32",
+ arm_VMLS_LT_F32: "VMLS.LT.F32",
+ arm_VMLS_GT_F32: "VMLS.GT.F32",
+ arm_VMLS_LE_F32: "VMLS.LE.F32",
+ arm_VMLS_F32: "VMLS.F32",
+ arm_VMLS_ZZ_F32: "VMLS.ZZ.F32",
+ arm_VMLS_EQ_F64: "VMLS.EQ.F64",
+ arm_VMLS_NE_F64: "VMLS.NE.F64",
+ arm_VMLS_CS_F64: "VMLS.CS.F64",
+ arm_VMLS_CC_F64: "VMLS.CC.F64",
+ arm_VMLS_MI_F64: "VMLS.MI.F64",
+ arm_VMLS_PL_F64: "VMLS.PL.F64",
+ arm_VMLS_VS_F64: "VMLS.VS.F64",
+ arm_VMLS_VC_F64: "VMLS.VC.F64",
+ arm_VMLS_HI_F64: "VMLS.HI.F64",
+ arm_VMLS_LS_F64: "VMLS.LS.F64",
+ arm_VMLS_GE_F64: "VMLS.GE.F64",
+ arm_VMLS_LT_F64: "VMLS.LT.F64",
+ arm_VMLS_GT_F64: "VMLS.GT.F64",
+ arm_VMLS_LE_F64: "VMLS.LE.F64",
+ arm_VMLS_F64: "VMLS.F64",
+ arm_VMLS_ZZ_F64: "VMLS.ZZ.F64",
+ arm_VMOV_EQ: "VMOV.EQ",
+ arm_VMOV_NE: "VMOV.NE",
+ arm_VMOV_CS: "VMOV.CS",
+ arm_VMOV_CC: "VMOV.CC",
+ arm_VMOV_MI: "VMOV.MI",
+ arm_VMOV_PL: "VMOV.PL",
+ arm_VMOV_VS: "VMOV.VS",
+ arm_VMOV_VC: "VMOV.VC",
+ arm_VMOV_HI: "VMOV.HI",
+ arm_VMOV_LS: "VMOV.LS",
+ arm_VMOV_GE: "VMOV.GE",
+ arm_VMOV_LT: "VMOV.LT",
+ arm_VMOV_GT: "VMOV.GT",
+ arm_VMOV_LE: "VMOV.LE",
+ arm_VMOV: "VMOV",
+ arm_VMOV_ZZ: "VMOV.ZZ",
+ arm_VMOV_EQ_32: "VMOV.EQ.32",
+ arm_VMOV_NE_32: "VMOV.NE.32",
+ arm_VMOV_CS_32: "VMOV.CS.32",
+ arm_VMOV_CC_32: "VMOV.CC.32",
+ arm_VMOV_MI_32: "VMOV.MI.32",
+ arm_VMOV_PL_32: "VMOV.PL.32",
+ arm_VMOV_VS_32: "VMOV.VS.32",
+ arm_VMOV_VC_32: "VMOV.VC.32",
+ arm_VMOV_HI_32: "VMOV.HI.32",
+ arm_VMOV_LS_32: "VMOV.LS.32",
+ arm_VMOV_GE_32: "VMOV.GE.32",
+ arm_VMOV_LT_32: "VMOV.LT.32",
+ arm_VMOV_GT_32: "VMOV.GT.32",
+ arm_VMOV_LE_32: "VMOV.LE.32",
+ arm_VMOV_32: "VMOV.32",
+ arm_VMOV_ZZ_32: "VMOV.ZZ.32",
+ arm_VMOV_EQ_F32: "VMOV.EQ.F32",
+ arm_VMOV_NE_F32: "VMOV.NE.F32",
+ arm_VMOV_CS_F32: "VMOV.CS.F32",
+ arm_VMOV_CC_F32: "VMOV.CC.F32",
+ arm_VMOV_MI_F32: "VMOV.MI.F32",
+ arm_VMOV_PL_F32: "VMOV.PL.F32",
+ arm_VMOV_VS_F32: "VMOV.VS.F32",
+ arm_VMOV_VC_F32: "VMOV.VC.F32",
+ arm_VMOV_HI_F32: "VMOV.HI.F32",
+ arm_VMOV_LS_F32: "VMOV.LS.F32",
+ arm_VMOV_GE_F32: "VMOV.GE.F32",
+ arm_VMOV_LT_F32: "VMOV.LT.F32",
+ arm_VMOV_GT_F32: "VMOV.GT.F32",
+ arm_VMOV_LE_F32: "VMOV.LE.F32",
+ arm_VMOV_F32: "VMOV.F32",
+ arm_VMOV_ZZ_F32: "VMOV.ZZ.F32",
+ arm_VMOV_EQ_F64: "VMOV.EQ.F64",
+ arm_VMOV_NE_F64: "VMOV.NE.F64",
+ arm_VMOV_CS_F64: "VMOV.CS.F64",
+ arm_VMOV_CC_F64: "VMOV.CC.F64",
+ arm_VMOV_MI_F64: "VMOV.MI.F64",
+ arm_VMOV_PL_F64: "VMOV.PL.F64",
+ arm_VMOV_VS_F64: "VMOV.VS.F64",
+ arm_VMOV_VC_F64: "VMOV.VC.F64",
+ arm_VMOV_HI_F64: "VMOV.HI.F64",
+ arm_VMOV_LS_F64: "VMOV.LS.F64",
+ arm_VMOV_GE_F64: "VMOV.GE.F64",
+ arm_VMOV_LT_F64: "VMOV.LT.F64",
+ arm_VMOV_GT_F64: "VMOV.GT.F64",
+ arm_VMOV_LE_F64: "VMOV.LE.F64",
+ arm_VMOV_F64: "VMOV.F64",
+ arm_VMOV_ZZ_F64: "VMOV.ZZ.F64",
+ arm_VMRS_EQ: "VMRS.EQ",
+ arm_VMRS_NE: "VMRS.NE",
+ arm_VMRS_CS: "VMRS.CS",
+ arm_VMRS_CC: "VMRS.CC",
+ arm_VMRS_MI: "VMRS.MI",
+ arm_VMRS_PL: "VMRS.PL",
+ arm_VMRS_VS: "VMRS.VS",
+ arm_VMRS_VC: "VMRS.VC",
+ arm_VMRS_HI: "VMRS.HI",
+ arm_VMRS_LS: "VMRS.LS",
+ arm_VMRS_GE: "VMRS.GE",
+ arm_VMRS_LT: "VMRS.LT",
+ arm_VMRS_GT: "VMRS.GT",
+ arm_VMRS_LE: "VMRS.LE",
+ arm_VMRS: "VMRS",
+ arm_VMRS_ZZ: "VMRS.ZZ",
+ arm_VMSR_EQ: "VMSR.EQ",
+ arm_VMSR_NE: "VMSR.NE",
+ arm_VMSR_CS: "VMSR.CS",
+ arm_VMSR_CC: "VMSR.CC",
+ arm_VMSR_MI: "VMSR.MI",
+ arm_VMSR_PL: "VMSR.PL",
+ arm_VMSR_VS: "VMSR.VS",
+ arm_VMSR_VC: "VMSR.VC",
+ arm_VMSR_HI: "VMSR.HI",
+ arm_VMSR_LS: "VMSR.LS",
+ arm_VMSR_GE: "VMSR.GE",
+ arm_VMSR_LT: "VMSR.LT",
+ arm_VMSR_GT: "VMSR.GT",
+ arm_VMSR_LE: "VMSR.LE",
+ arm_VMSR: "VMSR",
+ arm_VMSR_ZZ: "VMSR.ZZ",
+ arm_VMUL_EQ_F32: "VMUL.EQ.F32",
+ arm_VMUL_NE_F32: "VMUL.NE.F32",
+ arm_VMUL_CS_F32: "VMUL.CS.F32",
+ arm_VMUL_CC_F32: "VMUL.CC.F32",
+ arm_VMUL_MI_F32: "VMUL.MI.F32",
+ arm_VMUL_PL_F32: "VMUL.PL.F32",
+ arm_VMUL_VS_F32: "VMUL.VS.F32",
+ arm_VMUL_VC_F32: "VMUL.VC.F32",
+ arm_VMUL_HI_F32: "VMUL.HI.F32",
+ arm_VMUL_LS_F32: "VMUL.LS.F32",
+ arm_VMUL_GE_F32: "VMUL.GE.F32",
+ arm_VMUL_LT_F32: "VMUL.LT.F32",
+ arm_VMUL_GT_F32: "VMUL.GT.F32",
+ arm_VMUL_LE_F32: "VMUL.LE.F32",
+ arm_VMUL_F32: "VMUL.F32",
+ arm_VMUL_ZZ_F32: "VMUL.ZZ.F32",
+ arm_VMUL_EQ_F64: "VMUL.EQ.F64",
+ arm_VMUL_NE_F64: "VMUL.NE.F64",
+ arm_VMUL_CS_F64: "VMUL.CS.F64",
+ arm_VMUL_CC_F64: "VMUL.CC.F64",
+ arm_VMUL_MI_F64: "VMUL.MI.F64",
+ arm_VMUL_PL_F64: "VMUL.PL.F64",
+ arm_VMUL_VS_F64: "VMUL.VS.F64",
+ arm_VMUL_VC_F64: "VMUL.VC.F64",
+ arm_VMUL_HI_F64: "VMUL.HI.F64",
+ arm_VMUL_LS_F64: "VMUL.LS.F64",
+ arm_VMUL_GE_F64: "VMUL.GE.F64",
+ arm_VMUL_LT_F64: "VMUL.LT.F64",
+ arm_VMUL_GT_F64: "VMUL.GT.F64",
+ arm_VMUL_LE_F64: "VMUL.LE.F64",
+ arm_VMUL_F64: "VMUL.F64",
+ arm_VMUL_ZZ_F64: "VMUL.ZZ.F64",
+ arm_VNEG_EQ_F32: "VNEG.EQ.F32",
+ arm_VNEG_NE_F32: "VNEG.NE.F32",
+ arm_VNEG_CS_F32: "VNEG.CS.F32",
+ arm_VNEG_CC_F32: "VNEG.CC.F32",
+ arm_VNEG_MI_F32: "VNEG.MI.F32",
+ arm_VNEG_PL_F32: "VNEG.PL.F32",
+ arm_VNEG_VS_F32: "VNEG.VS.F32",
+ arm_VNEG_VC_F32: "VNEG.VC.F32",
+ arm_VNEG_HI_F32: "VNEG.HI.F32",
+ arm_VNEG_LS_F32: "VNEG.LS.F32",
+ arm_VNEG_GE_F32: "VNEG.GE.F32",
+ arm_VNEG_LT_F32: "VNEG.LT.F32",
+ arm_VNEG_GT_F32: "VNEG.GT.F32",
+ arm_VNEG_LE_F32: "VNEG.LE.F32",
+ arm_VNEG_F32: "VNEG.F32",
+ arm_VNEG_ZZ_F32: "VNEG.ZZ.F32",
+ arm_VNEG_EQ_F64: "VNEG.EQ.F64",
+ arm_VNEG_NE_F64: "VNEG.NE.F64",
+ arm_VNEG_CS_F64: "VNEG.CS.F64",
+ arm_VNEG_CC_F64: "VNEG.CC.F64",
+ arm_VNEG_MI_F64: "VNEG.MI.F64",
+ arm_VNEG_PL_F64: "VNEG.PL.F64",
+ arm_VNEG_VS_F64: "VNEG.VS.F64",
+ arm_VNEG_VC_F64: "VNEG.VC.F64",
+ arm_VNEG_HI_F64: "VNEG.HI.F64",
+ arm_VNEG_LS_F64: "VNEG.LS.F64",
+ arm_VNEG_GE_F64: "VNEG.GE.F64",
+ arm_VNEG_LT_F64: "VNEG.LT.F64",
+ arm_VNEG_GT_F64: "VNEG.GT.F64",
+ arm_VNEG_LE_F64: "VNEG.LE.F64",
+ arm_VNEG_F64: "VNEG.F64",
+ arm_VNEG_ZZ_F64: "VNEG.ZZ.F64",
+ arm_VNMLS_EQ_F32: "VNMLS.EQ.F32",
+ arm_VNMLS_NE_F32: "VNMLS.NE.F32",
+ arm_VNMLS_CS_F32: "VNMLS.CS.F32",
+ arm_VNMLS_CC_F32: "VNMLS.CC.F32",
+ arm_VNMLS_MI_F32: "VNMLS.MI.F32",
+ arm_VNMLS_PL_F32: "VNMLS.PL.F32",
+ arm_VNMLS_VS_F32: "VNMLS.VS.F32",
+ arm_VNMLS_VC_F32: "VNMLS.VC.F32",
+ arm_VNMLS_HI_F32: "VNMLS.HI.F32",
+ arm_VNMLS_LS_F32: "VNMLS.LS.F32",
+ arm_VNMLS_GE_F32: "VNMLS.GE.F32",
+ arm_VNMLS_LT_F32: "VNMLS.LT.F32",
+ arm_VNMLS_GT_F32: "VNMLS.GT.F32",
+ arm_VNMLS_LE_F32: "VNMLS.LE.F32",
+ arm_VNMLS_F32: "VNMLS.F32",
+ arm_VNMLS_ZZ_F32: "VNMLS.ZZ.F32",
+ arm_VNMLS_EQ_F64: "VNMLS.EQ.F64",
+ arm_VNMLS_NE_F64: "VNMLS.NE.F64",
+ arm_VNMLS_CS_F64: "VNMLS.CS.F64",
+ arm_VNMLS_CC_F64: "VNMLS.CC.F64",
+ arm_VNMLS_MI_F64: "VNMLS.MI.F64",
+ arm_VNMLS_PL_F64: "VNMLS.PL.F64",
+ arm_VNMLS_VS_F64: "VNMLS.VS.F64",
+ arm_VNMLS_VC_F64: "VNMLS.VC.F64",
+ arm_VNMLS_HI_F64: "VNMLS.HI.F64",
+ arm_VNMLS_LS_F64: "VNMLS.LS.F64",
+ arm_VNMLS_GE_F64: "VNMLS.GE.F64",
+ arm_VNMLS_LT_F64: "VNMLS.LT.F64",
+ arm_VNMLS_GT_F64: "VNMLS.GT.F64",
+ arm_VNMLS_LE_F64: "VNMLS.LE.F64",
+ arm_VNMLS_F64: "VNMLS.F64",
+ arm_VNMLS_ZZ_F64: "VNMLS.ZZ.F64",
+ arm_VNMLA_EQ_F32: "VNMLA.EQ.F32",
+ arm_VNMLA_NE_F32: "VNMLA.NE.F32",
+ arm_VNMLA_CS_F32: "VNMLA.CS.F32",
+ arm_VNMLA_CC_F32: "VNMLA.CC.F32",
+ arm_VNMLA_MI_F32: "VNMLA.MI.F32",
+ arm_VNMLA_PL_F32: "VNMLA.PL.F32",
+ arm_VNMLA_VS_F32: "VNMLA.VS.F32",
+ arm_VNMLA_VC_F32: "VNMLA.VC.F32",
+ arm_VNMLA_HI_F32: "VNMLA.HI.F32",
+ arm_VNMLA_LS_F32: "VNMLA.LS.F32",
+ arm_VNMLA_GE_F32: "VNMLA.GE.F32",
+ arm_VNMLA_LT_F32: "VNMLA.LT.F32",
+ arm_VNMLA_GT_F32: "VNMLA.GT.F32",
+ arm_VNMLA_LE_F32: "VNMLA.LE.F32",
+ arm_VNMLA_F32: "VNMLA.F32",
+ arm_VNMLA_ZZ_F32: "VNMLA.ZZ.F32",
+ arm_VNMLA_EQ_F64: "VNMLA.EQ.F64",
+ arm_VNMLA_NE_F64: "VNMLA.NE.F64",
+ arm_VNMLA_CS_F64: "VNMLA.CS.F64",
+ arm_VNMLA_CC_F64: "VNMLA.CC.F64",
+ arm_VNMLA_MI_F64: "VNMLA.MI.F64",
+ arm_VNMLA_PL_F64: "VNMLA.PL.F64",
+ arm_VNMLA_VS_F64: "VNMLA.VS.F64",
+ arm_VNMLA_VC_F64: "VNMLA.VC.F64",
+ arm_VNMLA_HI_F64: "VNMLA.HI.F64",
+ arm_VNMLA_LS_F64: "VNMLA.LS.F64",
+ arm_VNMLA_GE_F64: "VNMLA.GE.F64",
+ arm_VNMLA_LT_F64: "VNMLA.LT.F64",
+ arm_VNMLA_GT_F64: "VNMLA.GT.F64",
+ arm_VNMLA_LE_F64: "VNMLA.LE.F64",
+ arm_VNMLA_F64: "VNMLA.F64",
+ arm_VNMLA_ZZ_F64: "VNMLA.ZZ.F64",
+ arm_VNMUL_EQ_F32: "VNMUL.EQ.F32",
+ arm_VNMUL_NE_F32: "VNMUL.NE.F32",
+ arm_VNMUL_CS_F32: "VNMUL.CS.F32",
+ arm_VNMUL_CC_F32: "VNMUL.CC.F32",
+ arm_VNMUL_MI_F32: "VNMUL.MI.F32",
+ arm_VNMUL_PL_F32: "VNMUL.PL.F32",
+ arm_VNMUL_VS_F32: "VNMUL.VS.F32",
+ arm_VNMUL_VC_F32: "VNMUL.VC.F32",
+ arm_VNMUL_HI_F32: "VNMUL.HI.F32",
+ arm_VNMUL_LS_F32: "VNMUL.LS.F32",
+ arm_VNMUL_GE_F32: "VNMUL.GE.F32",
+ arm_VNMUL_LT_F32: "VNMUL.LT.F32",
+ arm_VNMUL_GT_F32: "VNMUL.GT.F32",
+ arm_VNMUL_LE_F32: "VNMUL.LE.F32",
+ arm_VNMUL_F32: "VNMUL.F32",
+ arm_VNMUL_ZZ_F32: "VNMUL.ZZ.F32",
+ arm_VNMUL_EQ_F64: "VNMUL.EQ.F64",
+ arm_VNMUL_NE_F64: "VNMUL.NE.F64",
+ arm_VNMUL_CS_F64: "VNMUL.CS.F64",
+ arm_VNMUL_CC_F64: "VNMUL.CC.F64",
+ arm_VNMUL_MI_F64: "VNMUL.MI.F64",
+ arm_VNMUL_PL_F64: "VNMUL.PL.F64",
+ arm_VNMUL_VS_F64: "VNMUL.VS.F64",
+ arm_VNMUL_VC_F64: "VNMUL.VC.F64",
+ arm_VNMUL_HI_F64: "VNMUL.HI.F64",
+ arm_VNMUL_LS_F64: "VNMUL.LS.F64",
+ arm_VNMUL_GE_F64: "VNMUL.GE.F64",
+ arm_VNMUL_LT_F64: "VNMUL.LT.F64",
+ arm_VNMUL_GT_F64: "VNMUL.GT.F64",
+ arm_VNMUL_LE_F64: "VNMUL.LE.F64",
+ arm_VNMUL_F64: "VNMUL.F64",
+ arm_VNMUL_ZZ_F64: "VNMUL.ZZ.F64",
+ arm_VSQRT_EQ_F32: "VSQRT.EQ.F32",
+ arm_VSQRT_NE_F32: "VSQRT.NE.F32",
+ arm_VSQRT_CS_F32: "VSQRT.CS.F32",
+ arm_VSQRT_CC_F32: "VSQRT.CC.F32",
+ arm_VSQRT_MI_F32: "VSQRT.MI.F32",
+ arm_VSQRT_PL_F32: "VSQRT.PL.F32",
+ arm_VSQRT_VS_F32: "VSQRT.VS.F32",
+ arm_VSQRT_VC_F32: "VSQRT.VC.F32",
+ arm_VSQRT_HI_F32: "VSQRT.HI.F32",
+ arm_VSQRT_LS_F32: "VSQRT.LS.F32",
+ arm_VSQRT_GE_F32: "VSQRT.GE.F32",
+ arm_VSQRT_LT_F32: "VSQRT.LT.F32",
+ arm_VSQRT_GT_F32: "VSQRT.GT.F32",
+ arm_VSQRT_LE_F32: "VSQRT.LE.F32",
+ arm_VSQRT_F32: "VSQRT.F32",
+ arm_VSQRT_ZZ_F32: "VSQRT.ZZ.F32",
+ arm_VSQRT_EQ_F64: "VSQRT.EQ.F64",
+ arm_VSQRT_NE_F64: "VSQRT.NE.F64",
+ arm_VSQRT_CS_F64: "VSQRT.CS.F64",
+ arm_VSQRT_CC_F64: "VSQRT.CC.F64",
+ arm_VSQRT_MI_F64: "VSQRT.MI.F64",
+ arm_VSQRT_PL_F64: "VSQRT.PL.F64",
+ arm_VSQRT_VS_F64: "VSQRT.VS.F64",
+ arm_VSQRT_VC_F64: "VSQRT.VC.F64",
+ arm_VSQRT_HI_F64: "VSQRT.HI.F64",
+ arm_VSQRT_LS_F64: "VSQRT.LS.F64",
+ arm_VSQRT_GE_F64: "VSQRT.GE.F64",
+ arm_VSQRT_LT_F64: "VSQRT.LT.F64",
+ arm_VSQRT_GT_F64: "VSQRT.GT.F64",
+ arm_VSQRT_LE_F64: "VSQRT.LE.F64",
+ arm_VSQRT_F64: "VSQRT.F64",
+ arm_VSQRT_ZZ_F64: "VSQRT.ZZ.F64",
+ arm_VSTR_EQ: "VSTR.EQ",
+ arm_VSTR_NE: "VSTR.NE",
+ arm_VSTR_CS: "VSTR.CS",
+ arm_VSTR_CC: "VSTR.CC",
+ arm_VSTR_MI: "VSTR.MI",
+ arm_VSTR_PL: "VSTR.PL",
+ arm_VSTR_VS: "VSTR.VS",
+ arm_VSTR_VC: "VSTR.VC",
+ arm_VSTR_HI: "VSTR.HI",
+ arm_VSTR_LS: "VSTR.LS",
+ arm_VSTR_GE: "VSTR.GE",
+ arm_VSTR_LT: "VSTR.LT",
+ arm_VSTR_GT: "VSTR.GT",
+ arm_VSTR_LE: "VSTR.LE",
+ arm_VSTR: "VSTR",
+ arm_VSTR_ZZ: "VSTR.ZZ",
+ arm_VSUB_EQ_F32: "VSUB.EQ.F32",
+ arm_VSUB_NE_F32: "VSUB.NE.F32",
+ arm_VSUB_CS_F32: "VSUB.CS.F32",
+ arm_VSUB_CC_F32: "VSUB.CC.F32",
+ arm_VSUB_MI_F32: "VSUB.MI.F32",
+ arm_VSUB_PL_F32: "VSUB.PL.F32",
+ arm_VSUB_VS_F32: "VSUB.VS.F32",
+ arm_VSUB_VC_F32: "VSUB.VC.F32",
+ arm_VSUB_HI_F32: "VSUB.HI.F32",
+ arm_VSUB_LS_F32: "VSUB.LS.F32",
+ arm_VSUB_GE_F32: "VSUB.GE.F32",
+ arm_VSUB_LT_F32: "VSUB.LT.F32",
+ arm_VSUB_GT_F32: "VSUB.GT.F32",
+ arm_VSUB_LE_F32: "VSUB.LE.F32",
+ arm_VSUB_F32: "VSUB.F32",
+ arm_VSUB_ZZ_F32: "VSUB.ZZ.F32",
+ arm_VSUB_EQ_F64: "VSUB.EQ.F64",
+ arm_VSUB_NE_F64: "VSUB.NE.F64",
+ arm_VSUB_CS_F64: "VSUB.CS.F64",
+ arm_VSUB_CC_F64: "VSUB.CC.F64",
+ arm_VSUB_MI_F64: "VSUB.MI.F64",
+ arm_VSUB_PL_F64: "VSUB.PL.F64",
+ arm_VSUB_VS_F64: "VSUB.VS.F64",
+ arm_VSUB_VC_F64: "VSUB.VC.F64",
+ arm_VSUB_HI_F64: "VSUB.HI.F64",
+ arm_VSUB_LS_F64: "VSUB.LS.F64",
+ arm_VSUB_GE_F64: "VSUB.GE.F64",
+ arm_VSUB_LT_F64: "VSUB.LT.F64",
+ arm_VSUB_GT_F64: "VSUB.GT.F64",
+ arm_VSUB_LE_F64: "VSUB.LE.F64",
+ arm_VSUB_F64: "VSUB.F64",
+ arm_VSUB_ZZ_F64: "VSUB.ZZ.F64",
+ arm_WFE_EQ: "WFE.EQ",
+ arm_WFE_NE: "WFE.NE",
+ arm_WFE_CS: "WFE.CS",
+ arm_WFE_CC: "WFE.CC",
+ arm_WFE_MI: "WFE.MI",
+ arm_WFE_PL: "WFE.PL",
+ arm_WFE_VS: "WFE.VS",
+ arm_WFE_VC: "WFE.VC",
+ arm_WFE_HI: "WFE.HI",
+ arm_WFE_LS: "WFE.LS",
+ arm_WFE_GE: "WFE.GE",
+ arm_WFE_LT: "WFE.LT",
+ arm_WFE_GT: "WFE.GT",
+ arm_WFE_LE: "WFE.LE",
+ arm_WFE: "WFE",
+ arm_WFE_ZZ: "WFE.ZZ",
+ arm_WFI_EQ: "WFI.EQ",
+ arm_WFI_NE: "WFI.NE",
+ arm_WFI_CS: "WFI.CS",
+ arm_WFI_CC: "WFI.CC",
+ arm_WFI_MI: "WFI.MI",
+ arm_WFI_PL: "WFI.PL",
+ arm_WFI_VS: "WFI.VS",
+ arm_WFI_VC: "WFI.VC",
+ arm_WFI_HI: "WFI.HI",
+ arm_WFI_LS: "WFI.LS",
+ arm_WFI_GE: "WFI.GE",
+ arm_WFI_LT: "WFI.LT",
+ arm_WFI_GT: "WFI.GT",
+ arm_WFI_LE: "WFI.LE",
+ arm_WFI: "WFI",
+ arm_WFI_ZZ: "WFI.ZZ",
+ arm_YIELD_EQ: "YIELD.EQ",
+ arm_YIELD_NE: "YIELD.NE",
+ arm_YIELD_CS: "YIELD.CS",
+ arm_YIELD_CC: "YIELD.CC",
+ arm_YIELD_MI: "YIELD.MI",
+ arm_YIELD_PL: "YIELD.PL",
+ arm_YIELD_VS: "YIELD.VS",
+ arm_YIELD_VC: "YIELD.VC",
+ arm_YIELD_HI: "YIELD.HI",
+ arm_YIELD_LS: "YIELD.LS",
+ arm_YIELD_GE: "YIELD.GE",
+ arm_YIELD_LT: "YIELD.LT",
+ arm_YIELD_GT: "YIELD.GT",
+ arm_YIELD_LE: "YIELD.LE",
+ arm_YIELD: "YIELD",
+ arm_YIELD_ZZ: "YIELD.ZZ",
+}
+
+var arm_instFormats = [...]arm_instFormat{
+ {0x0fe00000, 0x02a00000, 2, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // ADC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|0|1|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00a00010, 4, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // ADC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00a00000, 2, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // ADC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00000, 0x02800000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // ADD{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|0|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00800010, 4, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // ADD{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00800000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // ADD{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fef0000, 0x028d0000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_const}}, // ADD{S}<c> <Rd>,SP,#<const> cond:4|0|0|1|0|1|0|0|S|1|1|0|1|Rd:4|imm12:12
+ {0x0fef0010, 0x008d0000, 2, arm_ADD_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_R_shift_imm}}, // ADD{S}<c> <Rd>,SP,<Rm>{,<shift>} cond:4|0|0|0|0|1|0|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00000, 0x02000000, 2, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // AND{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|0|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00000010, 4, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // AND{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00000000, 2, arm_AND_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // AND{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fef0070, 0x01a00040, 4, arm_ASR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_32}}, // ASR{S}<c> <Rd>,<Rm>,#<imm5_32> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|0|0|Rm:4
+ {0x0fef00f0, 0x01a00050, 4, arm_ASR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}}, // ASR{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|0|1|Rn:4
+ {0x0f000000, 0x0a000000, 4, arm_B_EQ, 0x1c04, arm_instArgs{arm_arg_label24}}, // B<c> <label24> cond:4|1|0|1|0|imm24:24
+ {0x0fe0007f, 0x07c0001f, 4, arm_BFC_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm5, arm_arg_lsb_width}}, // BFC<c> <Rd>,#<lsb>,#<width> cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|1|1|1|1
+ {0x0fe00070, 0x07c00010, 2, arm_BFI_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_lsb_width}}, // BFI<c> <Rd>,<Rn>,#<lsb>,#<width> cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|Rn:4
+ {0x0fe00000, 0x03c00000, 2, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // BIC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|1|1|1|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x01c00010, 4, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // BIC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x01c00000, 2, arm_BIC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // BIC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0ff000f0, 0x01200070, 4, arm_BKPT_EQ, 0x1c04, arm_instArgs{arm_arg_imm_12at8_4at0}}, // BKPT<c> #<imm12+4> cond:4|0|0|0|1|0|0|1|0|imm12:12|0|1|1|1|imm4:4
+ {0x0f000000, 0x0b000000, 4, arm_BL_EQ, 0x1c04, arm_instArgs{arm_arg_label24}}, // BL<c> <label24> cond:4|1|0|1|1|imm24:24
+ {0xfe000000, 0xfa000000, 4, arm_BLX, 0x0, arm_instArgs{arm_arg_label24H}}, // BLX <label24H> 1|1|1|1|1|0|1|H|imm24:24
+ {0x0ffffff0, 0x012fff30, 4, arm_BLX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BLX<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x012fff30, 3, arm_BLX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BLX<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ffffff0, 0x012fff10, 4, arm_BX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BX<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x012fff10, 3, arm_BX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BX<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ffffff0, 0x012fff20, 4, arm_BXJ_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BXJ<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4
+ {0x0ff000f0, 0x012fff20, 3, arm_BXJ_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}}, // BXJ<c> <Rm> cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4
+ {0xffffffff, 0xf57ff01f, 4, arm_CLREX, 0x0, arm_instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1)
+ {0xfff000f0, 0xf57ff01f, 3, arm_CLREX, 0x0, arm_instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1)
+ {0x0fff0ff0, 0x016f0f10, 4, arm_CLZ_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // CLZ<c> <Rd>,<Rm> cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x016f0f10, 3, arm_CLZ_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // CLZ<c> <Rd>,<Rm> cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff0f000, 0x03700000, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMN<c> <Rn>,#<const> cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff00000, 0x03700000, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMN<c> <Rn>,#<const> cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff0f090, 0x01700010, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMN<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff00090, 0x01700010, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMN<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff0f010, 0x01700000, 4, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMN<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff00010, 0x01700000, 3, arm_CMN_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMN<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff0f000, 0x03500000, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMP<c> <Rn>,#<const> cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff00000, 0x03500000, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // CMP<c> <Rn>,#<const> cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff0f090, 0x01500010, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMP<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff00090, 0x01500010, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // CMP<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff0f010, 0x01500000, 4, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMP<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff00010, 0x01500000, 3, arm_CMP_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // CMP<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ffffff0, 0x0320f0f0, 4, arm_DBG_EQ, 0x1c04, arm_instArgs{arm_arg_option}}, // DBG<c> #<option> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|1|1|1|1|option:4
+ {0x0fff00f0, 0x0320f0f0, 3, arm_DBG_EQ, 0x1c04, arm_instArgs{arm_arg_option}}, // DBG<c> #<option> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|1|1|1|1|option:4
+ {0xfffffff0, 0xf57ff050, 4, arm_DMB, 0x0, arm_instArgs{arm_arg_option}}, // DMB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|0|1|option:4
+ {0xfff000f0, 0xf57ff050, 3, arm_DMB, 0x0, arm_instArgs{arm_arg_option}}, // DMB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|0|1|option:4
+ {0xfffffff0, 0xf57ff040, 4, arm_DSB, 0x0, arm_instArgs{arm_arg_option}}, // DSB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|0|0|option:4
+ {0xfff000f0, 0xf57ff040, 3, arm_DSB, 0x0, arm_instArgs{arm_arg_option}}, // DSB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|0|0|option:4
+ {0x0fe00000, 0x02200000, 2, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // EOR{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|0|1|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00200010, 4, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // EOR{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00200000, 2, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // EOR{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0xfffffff0, 0xf57ff060, 4, arm_ISB, 0x0, arm_instArgs{arm_arg_option}}, // ISB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|1|0|option:4
+ {0xfff000f0, 0xf57ff060, 3, arm_ISB, 0x0, arm_instArgs{arm_arg_option}}, // ISB #<option> 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|1|1|0|option:4
+ {0x0fd00000, 0x08900000, 2, arm_LDM_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // LDM<c> <Rn>{!},<registers> cond:4|1|0|0|0|1|0|W|1|Rn:4|register_list:16
+ {0x0fd00000, 0x08100000, 4, arm_LDMDA_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // LDMDA<c> <Rn>{!},<registers> cond:4|1|0|0|0|0|0|W|1|Rn:4|register_list:16
+ {0x0fd00000, 0x09100000, 4, arm_LDMDB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // LDMDB<c> <Rn>{!},<registers> cond:4|1|0|0|1|0|0|W|1|Rn:4|register_list:16
+ {0x0fd00000, 0x09900000, 4, arm_LDMIB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // LDMIB<c> <Rn>{!},<registers> cond:4|1|0|0|1|1|0|W|1|Rn:4|register_list:16
+ {0x0f7f0000, 0x051f0000, 4, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}}, // LDR<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|0|(0)|1|1|1|1|1|Rt:4|imm12:12
+ {0x0e5f0000, 0x051f0000, 3, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}}, // LDR<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|0|(0)|1|1|1|1|1|Rt:4|imm12:12
+ {0x0e500010, 0x06100000, 2, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}}, // LDR<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|0|W|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500000, 0x04100000, 2, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}}, // LDR<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|0|W|1|Rn:4|Rt:4|imm12:12
+ {0x0f7f0000, 0x055f0000, 4, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}}, // LDRB<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|1|(0)|1|1|1|1|1|Rt:4|imm12:12
+ {0x0e5f0000, 0x055f0000, 3, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}}, // LDRB<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|1|(0)|1|1|1|1|1|Rt:4|imm12:12
+ {0x0e500010, 0x06500000, 2, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}}, // LDRB<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|1|W|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500000, 0x04500000, 2, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}}, // LDRB<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|1|W|1|Rn:4|Rt:4|imm12:12
+ {0x0f700000, 0x04700000, 4, arm_LDRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}}, // LDRBT<c> <Rt>,[<Rn>],#+/-<imm12> cond:4|0|1|0|0|U|1|1|1|Rn:4|Rt:4|imm12:12
+ {0x0f700010, 0x06700000, 4, arm_LDRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}}, // LDRBT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|1|1|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500ff0, 0x000000d0, 4, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}}, // LDRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|0|1|Rm:4
+ {0x0e5000f0, 0x000000d0, 3, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}}, // LDRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|0|1|Rm:4
+ {0x0e5000f0, 0x004000d0, 2, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_imm8_W}}, // LDRD<c> <Rt1>,<Rt2>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+ {0x0ff00fff, 0x01900f9f, 4, arm_LDREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREX<c> <Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff000f0, 0x01900f9f, 3, arm_LDREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREX<c> <Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff00fff, 0x01d00f9f, 4, arm_LDREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREXB<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff000f0, 0x01d00f9f, 3, arm_LDREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREXB<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff00fff, 0x01b00f9f, 4, arm_LDREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R}}, // LDREXD<c> <Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff000f0, 0x01b00f9f, 3, arm_LDREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R}}, // LDREXD<c> <Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff00fff, 0x01f00f9f, 4, arm_LDREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREXH<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0ff000f0, 0x01f00f9f, 3, arm_LDREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}}, // LDREXH<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+ {0x0e500ff0, 0x001000b0, 2, arm_LDRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}}, // LDRH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+ {0x0e5000f0, 0x005000b0, 2, arm_LDRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}}, // LDRH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+ {0x0f7000f0, 0x007000b0, 4, arm_LDRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}}, // LDRHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+ {0x0f700ff0, 0x003000b0, 4, arm_LDRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}}, // LDRHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+ {0x0e500ff0, 0x001000d0, 2, arm_LDRSB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}}, // LDRSB<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|1|0|1|Rm:4
+ {0x0e5000f0, 0x005000d0, 2, arm_LDRSB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}}, // LDRSB<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+ {0x0f7000f0, 0x007000d0, 4, arm_LDRSBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}}, // LDRSBT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+ {0x0f700ff0, 0x003000d0, 4, arm_LDRSBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}}, // LDRSBT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|1|0|1|Rm:4
+ {0x0e500ff0, 0x001000f0, 2, arm_LDRSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}}, // LDRSH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|1|1|1|Rm:4
+ {0x0e5000f0, 0x005000f0, 2, arm_LDRSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}}, // LDRSH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+ {0x0f7000f0, 0x007000f0, 4, arm_LDRSHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}}, // LDRSHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+ {0x0f700ff0, 0x003000f0, 4, arm_LDRSHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}}, // LDRSHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|1|1|1|Rm:4
+ {0x0f700000, 0x04300000, 4, arm_LDRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}}, // LDRT<c> <Rt>, [<Rn>] {,#+/-<imm12>} cond:4|0|1|0|0|U|0|1|1|Rn:4|Rt:4|imm12:12
+ {0x0f700010, 0x06300000, 4, arm_LDRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}}, // LDRT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|0|1|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0fef0070, 0x01a00000, 2, arm_LSL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_nz}}, // LSL{S}<c> <Rd>,<Rm>,#<imm5_nz> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|0|0|0|Rm:4
+ {0x0fef00f0, 0x01a00010, 4, arm_LSL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}}, // LSL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|0|0|1|Rn:4
+ {0x0fef0070, 0x01a00020, 4, arm_LSR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_32}}, // LSR{S}<c> <Rd>,<Rm>,#<imm5_32> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|0|1|0|Rm:4
+ {0x0fef00f0, 0x01a00030, 4, arm_LSR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}}, // LSR{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|0|1|1|Rn:4
+ {0x0fe000f0, 0x00200090, 4, arm_MLA_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // MLA{S}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|0|0|0|1|S|Rd:4|Ra:4|Rm:4|1|0|0|1|Rn:4
+ {0x0ff000f0, 0x00600090, 4, arm_MLS_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // MLS<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|0|0|1|1|0|Rd:4|Ra:4|Rm:4|1|0|0|1|Rn:4
+ {0x0ff00000, 0x03400000, 4, arm_MOVT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm_4at16_12at0}}, // MOVT<c> <Rd>,#<imm12+4> cond:4|0|0|1|1|0|1|0|0|imm4:4|Rd:4|imm12:12
+ {0x0ff00000, 0x03000000, 4, arm_MOVW_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm_4at16_12at0}}, // MOVW<c> <Rd>,#<imm12+4> cond:4|0|0|1|1|0|0|0|0|imm4:4|Rd:4|imm12:12
+ {0x0fef0000, 0x03a00000, 2, arm_MOV_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}}, // MOV{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|0|1|S|0|0|0|0|Rd:4|imm12:12
+ {0x0fef0ff0, 0x01a00000, 2, arm_MOV_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // MOV{S}<c> <Rd>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|0|0|0|0|0|0|0|0|Rm:4
+ {0x0fff0fff, 0x010f0000, 4, arm_MRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_APSR}}, // MRS<c> <Rd>,APSR cond:4|0|0|0|1|0|0|0|0|(1)|(1)|(1)|(1)|Rd:4|(0)|(0)|(0)|(0)|0|0|0|0|(0)|(0)|(0)|(0)
+ {0x0ff000f0, 0x010f0000, 3, arm_MRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_APSR}}, // MRS<c> <Rd>,APSR cond:4|0|0|0|1|0|0|0|0|(1)|(1)|(1)|(1)|Rd:4|(0)|(0)|(0)|(0)|0|0|0|0|(0)|(0)|(0)|(0)
+ {0x0fe0f0f0, 0x00000090, 4, arm_MUL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // MUL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|0|0|0|0|S|Rd:4|(0)|(0)|(0)|(0)|Rm:4|1|0|0|1|Rn:4
+ {0x0fe000f0, 0x00000090, 3, arm_MUL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // MUL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|0|0|0|0|S|Rd:4|(0)|(0)|(0)|(0)|Rm:4|1|0|0|1|Rn:4
+ {0x0fef0000, 0x03e00000, 2, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}}, // MVN{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm12:12
+ {0x0fe00000, 0x03e00000, 1, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}}, // MVN{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm12:12
+ {0x0fef0090, 0x01e00010, 4, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_R}}, // MVN{S}<c> <Rd>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00090, 0x01e00010, 3, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_R}}, // MVN{S}<c> <Rd>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fef0010, 0x01e00000, 2, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_imm}}, // MVN{S}<c> <Rd>,<Rm>{,<shift>} cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00010, 0x01e00000, 1, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_imm}}, // MVN{S}<c> <Rd>,<Rm>{,<shift>} cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fffffff, 0x0320f000, 4, arm_NOP_EQ, 0x1c04, arm_instArgs{}}, // NOP<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|0
+ {0x0fff00ff, 0x0320f000, 3, arm_NOP_EQ, 0x1c04, arm_instArgs{}}, // NOP<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|0
+ {0x0fe00000, 0x03800000, 2, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // ORR{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|1|1|0|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x01800010, 4, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // ORR{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x01800000, 2, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // ORR{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0ff00030, 0x06800010, 4, arm_PKHBT_EQ, 0x6011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // PKH<BT,TB><c> <Rd>,<Rn>,<Rm>{,LSL #<imm5>} cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|imm5:5|tb|0|1|Rm:4
+ {0xff7ff000, 0xf55ff000, 4, arm_PLD, 0x0, arm_instArgs{arm_arg_label_pm_12}}, // PLD <label+/-12> 1|1|1|1|0|1|0|1|U|(1)|0|1|1|1|1|1|(1)|(1)|(1)|(1)|imm12:12
+ {0xff3f0000, 0xf55ff000, 3, arm_PLD, 0x0, arm_instArgs{arm_arg_label_pm_12}}, // PLD <label+/-12> 1|1|1|1|0|1|0|1|U|(1)|0|1|1|1|1|1|(1)|(1)|(1)|(1)|imm12:12
+ {0xff30f000, 0xf510f000, 2, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}}, // PLD{W} [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+ {0xff300000, 0xf510f000, 1, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}}, // PLD{W} [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+ {0xff30f010, 0xf710f000, 4, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}}, // PLD{W} [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+ {0xff300010, 0xf710f000, 3, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}}, // PLD{W} [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+ {0xff70f000, 0xf450f000, 4, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}}, // PLI [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+ {0xff700000, 0xf450f000, 3, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}}, // PLI [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+ {0xff70f010, 0xf650f000, 4, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}}, // PLI [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+ {0xff700010, 0xf650f000, 3, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}}, // PLI [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+ {0x0fff0000, 0x08bd0000, 4, arm_POP_EQ, 0x1c04, arm_instArgs{arm_arg_registers2}}, // POP<c> <registers2> cond:4|1|0|0|0|1|0|1|1|1|1|0|1|register_list:16
+ {0x0fff0fff, 0x049d0004, 4, arm_POP_EQ, 0x1c04, arm_instArgs{arm_arg_registers1}}, // POP<c> <registers1> cond:4|0|1|0|0|1|0|0|1|1|1|0|1|Rt:4|0|0|0|0|0|0|0|0|0|1|0|0
+ {0x0fff0000, 0x092d0000, 4, arm_PUSH_EQ, 0x1c04, arm_instArgs{arm_arg_registers2}}, // PUSH<c> <registers2> cond:4|1|0|0|1|0|0|1|0|1|1|0|1|register_list:16
+ {0x0fff0fff, 0x052d0004, 4, arm_PUSH_EQ, 0x1c04, arm_instArgs{arm_arg_registers1}}, // PUSH<c> <registers1> cond:4|0|1|0|1|0|0|1|0|1|1|0|1|Rt:4|0|0|0|0|0|0|0|0|0|1|0|0
+ {0x0ff00ff0, 0x06200f10, 4, arm_QADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06200f10, 3, arm_QADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06200f90, 4, arm_QADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06200f90, 3, arm_QADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x01000050, 4, arm_QADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x01000050, 3, arm_QADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06200f30, 4, arm_QASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06200f30, 3, arm_QASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff00ff0, 0x01400050, 4, arm_QDADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QDADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x01400050, 3, arm_QDADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QDADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x01600050, 4, arm_QDSUB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QDSUB<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|1|0|Rn:4|Rd:4|0|0|0|0|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06200f50, 4, arm_QSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06200f50, 3, arm_QSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06200f70, 4, arm_QSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06200f70, 3, arm_QSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06200ff0, 4, arm_QSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06200ff0, 3, arm_QSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // QSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff00ff0, 0x01200050, 4, arm_QSUB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}}, // QSUB<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|1|0|Rn:4|Rd:4|0|0|0|0|0|1|0|1|Rm:4
+ {0x0fff0ff0, 0x06ff0f30, 4, arm_RBIT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // RBIT<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06ff0f30, 3, arm_RBIT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // RBIT<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0fff0ff0, 0x06bf0fb0, 4, arm_REV16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REV16<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0x0ff000f0, 0x06bf0fb0, 3, arm_REV16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REV16<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0x0fff0ff0, 0x06bf0f30, 4, arm_REV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REV<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06bf0f30, 3, arm_REV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REV<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0fff0ff0, 0x06ff0fb0, 4, arm_REVSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REVSH<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0x0ff000f0, 0x06ff0fb0, 3, arm_REVSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // REVSH<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0x0fef0070, 0x01a00060, 2, arm_ROR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5}}, // ROR{S}<c> <Rd>,<Rm>,#<imm5> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|1|0|Rm:4
+ {0x0fef00f0, 0x01a00070, 4, arm_ROR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}}, // ROR{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|1|1|Rn:4
+ {0x0fef0ff0, 0x01a00060, 4, arm_RRX_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}}, // RRX{S}<c> <Rd>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|0|0|0|0|0|1|1|0|Rm:4
+ {0x0fe00000, 0x02600000, 2, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // RSB{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|1|1|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00600010, 4, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // RSB{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|1|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00600000, 2, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // RSB{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00000, 0x02e00000, 2, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // RSC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|1|1|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00e00010, 4, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // RSC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|1|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00e00000, 2, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // RSC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|1|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0ff00ff0, 0x06100f10, 4, arm_SADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06100f10, 3, arm_SADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06100f90, 4, arm_SADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06100f90, 3, arm_SADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06100f30, 4, arm_SASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06100f30, 3, arm_SASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0fe00000, 0x02c00000, 2, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // SBC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|1|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00c00010, 4, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // SBC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00c00000, 2, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // SBC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00070, 0x07a00050, 4, arm_SBFX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_widthm1}}, // SBFX<c> <Rd>,<Rn>,#<lsb>,#<widthm1> cond:4|0|1|1|1|1|0|1|widthm1:5|Rd:4|lsb:5|1|0|1|Rn:4
+ {0x0ff00ff0, 0x06800fb0, 4, arm_SEL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SEL<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0x0ff000f0, 0x06800fb0, 3, arm_SEL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SEL<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+ {0xfffffdff, 0xf1010000, 4, arm_SETEND, 0x0, arm_instArgs{arm_arg_endian}}, // SETEND <endian_specifier> 1|1|1|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|E|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)
+ {0xfffffc00, 0xf1010000, 3, arm_SETEND, 0x0, arm_instArgs{arm_arg_endian}}, // SETEND <endian_specifier> 1|1|1|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|E|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)
+ {0x0fffffff, 0x0320f004, 4, arm_SEV_EQ, 0x1c04, arm_instArgs{}}, // SEV<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|1|0|0
+ {0x0fff00ff, 0x0320f004, 3, arm_SEV_EQ, 0x1c04, arm_instArgs{}}, // SEV<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|1|0|0
+ {0x0ff00ff0, 0x06300f10, 4, arm_SHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06300f10, 3, arm_SHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06300f90, 4, arm_SHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06300f90, 3, arm_SHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06300f30, 4, arm_SHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06300f30, 3, arm_SHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff00ff0, 0x06300f50, 4, arm_SHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06300f50, 3, arm_SHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06300f70, 4, arm_SHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06300f70, 3, arm_SHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06300ff0, 4, arm_SHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06300ff0, 3, arm_SHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff00090, 0x01000080, 4, arm_SMLABB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMLA<x><y><c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|1|0|0|0|0|Rd:4|Ra:4|Rm:4|1|M|N|0|Rn:4
+ {0x0ff000d0, 0x07000010, 2, arm_SMLAD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMLAD{X}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|0|0|0|Rd:4|Ra:4|Rm:4|0|0|M|1|Rn:4
+ {0x0ff00090, 0x01400080, 4, arm_SMLALBB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMLAL<x><y><c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|1|M|N|0|Rn:4
+ {0x0ff000d0, 0x07400010, 4, arm_SMLALD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMLALD{X}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|0|0|M|1|Rn:4
+ {0x0fe000f0, 0x00e00090, 4, arm_SMLAL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMLAL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|1|1|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+ {0x0ff000b0, 0x01200080, 4, arm_SMLAWB_EQ, 0x6011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMLAW<y><c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|1|0|0|1|0|Rd:4|Ra:4|Rm:4|1|M|0|0|Rn:4
+ {0x0ff000d0, 0x07000050, 2, arm_SMLSD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMLSD{X}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|0|0|0|Rd:4|Ra:4|Rm:4|0|1|M|1|Rn:4
+ {0x0ff000d0, 0x07400050, 4, arm_SMLSLD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMLSLD{X}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|0|1|M|1|Rn:4
+ {0x0ff000d0, 0x07500010, 2, arm_SMMLA_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMMLA{R}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|1|0|1|Rd:4|Ra:4|Rm:4|0|0|R|1|Rn:4
+ {0x0ff000d0, 0x075000d0, 4, arm_SMMLS_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // SMMLS{R}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|1|0|1|Rd:4|Ra:4|Rm:4|1|1|R|1|Rn:4
+ {0x0ff0f0d0, 0x0750f010, 4, arm_SMMUL_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMMUL{R}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|1|Rd:4|1|1|1|1|Rm:4|0|0|R|1|Rn:4
+ {0x0ff0f0d0, 0x0700f010, 4, arm_SMUAD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMUAD{X}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|0|0|0|Rd:4|1|1|1|1|Rm:4|0|0|M|1|Rn:4
+ {0x0ff0f090, 0x01600080, 4, arm_SMULBB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMUL<x><y><c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|0|1|1|0|Rd:4|0|0|0|0|Rm:4|1|M|N|0|Rn:4
+ {0x0fe000f0, 0x00c00090, 4, arm_SMULL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMULL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|1|0|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+ {0x0ff0f0b0, 0x012000a0, 4, arm_SMULWB_EQ, 0x6011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMULW<y><c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|0|0|1|0|Rd:4|0|0|0|0|Rm:4|1|M|1|0|Rn:4
+ {0x0ff0f0d0, 0x0700f050, 4, arm_SMUSD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // SMUSD{X}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|0|0|0|Rd:4|1|1|1|1|Rm:4|0|1|M|1|Rn:4
+ {0x0ff00ff0, 0x06a00f30, 4, arm_SSAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4m1, arm_arg_R_0}}, // SSAT16<c> <Rd>,#<sat_imm4m1>,<Rn> cond:4|0|1|1|0|1|0|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+ {0x0ff000f0, 0x06a00f30, 3, arm_SSAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4m1, arm_arg_R_0}}, // SSAT16<c> <Rd>,#<sat_imm4m1>,<Rn> cond:4|0|1|1|0|1|0|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+ {0x0fe00030, 0x06a00010, 4, arm_SSAT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm5m1, arm_arg_R_shift_imm}}, // SSAT<c> <Rd>,#<sat_imm5m1>,<Rn>{,<shift>} cond:4|0|1|1|0|1|0|1|sat_imm:5|Rd:4|imm5:5|sh|0|1|Rn:4
+ {0x0ff00ff0, 0x06100f50, 4, arm_SSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06100f50, 3, arm_SSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06100f70, 4, arm_SSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06100f70, 3, arm_SSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06100ff0, 4, arm_SSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06100ff0, 3, arm_SSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // SSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0fd00000, 0x08800000, 4, arm_STM_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // STM<c> <Rn>{!},<registers> cond:4|1|0|0|0|1|0|W|0|Rn:4|register_list:16
+ {0x0fd00000, 0x08000000, 4, arm_STMDA_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // STMDA<c> <Rn>{!},<registers> cond:4|1|0|0|0|0|0|W|0|Rn:4|register_list:16
+ {0x0fd00000, 0x09000000, 2, arm_STMDB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // STMDB<c> <Rn>{!},<registers> cond:4|1|0|0|1|0|0|W|0|Rn:4|register_list:16
+ {0x0fd00000, 0x09800000, 4, arm_STMIB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}}, // STMIB<c> <Rn>{!},<registers> cond:4|1|0|0|1|1|0|W|0|Rn:4|register_list:16
+ {0x0e500018, 0x06000000, 2, arm_STR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}}, // STR<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|0|W|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500000, 0x04000000, 2, arm_STR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}}, // STR<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|0|W|0|Rn:4|Rt:4|imm12:12
+ {0x0e500010, 0x06400000, 2, arm_STRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}}, // STRB<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|1|W|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500000, 0x04400000, 2, arm_STRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}}, // STRB<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|1|W|0|Rn:4|Rt:4|imm12:12
+ {0x0f700000, 0x04600000, 4, arm_STRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}}, // STRBT<c> <Rt>,[<Rn>],#+/-<imm12> cond:4|0|1|0|0|U|1|1|0|Rn:4|Rt:4|imm12:12
+ {0x0f700010, 0x06600000, 4, arm_STRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}}, // STRBT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|1|1|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0e500ff0, 0x000000f0, 4, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}}, // STRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|1|1|Rm:4
+ {0x0e5000f0, 0x000000f0, 3, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}}, // STRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|1|1|Rm:4
+ {0x0e5000f0, 0x004000f0, 4, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_imm8_W}}, // STRD<c> <Rt1>,<Rt2>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+ {0x0ff00ff0, 0x01800f90, 4, arm_STREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}}, // STREX<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+ {0x0ff00ff0, 0x01c00f90, 4, arm_STREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}}, // STREXB<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|1|0|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+ {0x0ff00ff0, 0x01a00f90, 4, arm_STREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R1_0, arm_arg_R2_0, arm_arg_mem_R}}, // STREXD<c> <Rd>,<Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+ {0x0ff00ff0, 0x01e00f90, 4, arm_STREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}}, // STREXH<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|1|1|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+ {0x0e500ff0, 0x000000b0, 2, arm_STRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}}, // STRH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+ {0x0e5000f0, 0x004000b0, 2, arm_STRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}}, // STRH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+ {0x0f7000f0, 0x006000b0, 4, arm_STRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}}, // STRHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|0|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+ {0x0f700ff0, 0x002000b0, 4, arm_STRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}}, // STRHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|0|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+ {0x0f700000, 0x04200000, 4, arm_STRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}}, // STRT<c> <Rt>, [<Rn>] {,#+/-<imm12>} cond:4|0|1|0|0|U|0|1|0|Rn:4|Rt:4|imm12:12
+ {0x0f700010, 0x06200000, 4, arm_STRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}}, // STRT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|0|1|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+ {0x0fe00000, 0x02400000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}}, // SUB{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|1|0|S|Rn:4|Rd:4|imm12:12
+ {0x0fe00090, 0x00400010, 4, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}}, // SUB{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+ {0x0fe00010, 0x00400000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}}, // SUB{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0fef0000, 0x024d0000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_const}}, // SUB{S}<c> <Rd>,SP,#<const> cond:4|0|0|1|0|0|1|0|S|1|1|0|1|Rd:4|imm12:12
+ {0x0fef0010, 0x004d0000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_R_shift_imm}}, // SUB{S}<c> <Rd>,SP,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4
+ {0x0f000000, 0x0f000000, 4, arm_SVC_EQ, 0x1c04, arm_instArgs{arm_arg_imm24}}, // SVC<c> #<imm24> cond:4|1|1|1|1|imm24:24
+ {0x0fb00ff0, 0x01000090, 4, arm_SWP_EQ, 0x16011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}}, // SWP{B}<c> <Rt>,<Rm>,[<Rn>] cond:4|0|0|0|1|0|B|0|0|Rn:4|Rt:4|0|0|0|0|1|0|0|1|Rm:4
+ {0x0ff003f0, 0x06800070, 2, arm_SXTAB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // SXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0ff003f0, 0x06a00070, 2, arm_SXTAB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // SXTAB<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0ff003f0, 0x06b00070, 2, arm_SXTAH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // SXTAH<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|1|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x068f0070, 4, arm_SXTB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // SXTB16<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|0|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x06af0070, 4, arm_SXTB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // SXTB<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x06bf0070, 4, arm_SXTH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // SXTH<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|1|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0ff0f000, 0x03300000, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // TEQ<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff00000, 0x03300000, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // TEQ<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff0f090, 0x01300010, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // TEQ<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff00090, 0x01300010, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // TEQ<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff0f010, 0x01300000, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // TEQ<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff00010, 0x01300000, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // TEQ<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff0f000, 0x03100000, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // TST<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff00000, 0x03100000, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}}, // TST<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+ {0x0ff0f090, 0x01100010, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // TST<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff00090, 0x01100010, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}}, // TST<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+ {0x0ff0f010, 0x01100000, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // TST<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff00010, 0x01100000, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}}, // TST<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+ {0x0ff00ff0, 0x06500f10, 4, arm_UADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06500f10, 3, arm_UADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06500f90, 4, arm_UADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06500f90, 3, arm_UADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06500f30, 4, arm_UASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06500f30, 3, arm_UASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0fe00070, 0x07e00050, 4, arm_UBFX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_widthm1}}, // UBFX<c> <Rd>,<Rn>,#<lsb>,#<widthm1> cond:4|0|1|1|1|1|1|1|widthm1:5|Rd:4|lsb:5|1|0|1|Rn:4
+ {0x0ff00ff0, 0x06700f10, 4, arm_UHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06700f10, 3, arm_UHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06700f90, 4, arm_UHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06700f90, 3, arm_UHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06700f30, 4, arm_UHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06700f30, 3, arm_UHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff00ff0, 0x06700f50, 4, arm_UHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06700f50, 3, arm_UHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06700f70, 4, arm_UHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06700f70, 3, arm_UHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06700ff0, 4, arm_UHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06700ff0, 3, arm_UHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x00400090, 4, arm_UMAAL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // UMAAL<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|0|1|0|0|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+ {0x0fe000f0, 0x00a00090, 4, arm_UMLAL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // UMLAL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|0|1|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+ {0x0fe000f0, 0x00800090, 4, arm_UMULL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // UMULL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|0|0|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+ {0x0ff00ff0, 0x06600f10, 4, arm_UQADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff000f0, 0x06600f10, 3, arm_UQADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06600f90, 4, arm_UQADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff000f0, 0x06600f90, 3, arm_UQADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+ {0x0ff00ff0, 0x06600f30, 4, arm_UQASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff000f0, 0x06600f30, 3, arm_UQASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+ {0x0ff00ff0, 0x06600f50, 4, arm_UQSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06600f50, 3, arm_UQSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06600f70, 4, arm_UQSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06600f70, 3, arm_UQSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06600ff0, 4, arm_UQSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06600ff0, 3, arm_UQSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // UQSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff0f0f0, 0x0780f010, 4, arm_USAD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}}, // USAD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|1|0|0|0|Rd:4|1|1|1|1|Rm:4|0|0|0|1|Rn:4
+ {0x0ff000f0, 0x07800010, 2, arm_USADA8_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}}, // USADA8<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|1|0|0|0|Rd:4|Ra:4|Rm:4|0|0|0|1|Rn:4
+ {0x0ff00ff0, 0x06e00f30, 4, arm_USAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4, arm_arg_R_0}}, // USAT16<c> <Rd>,#<sat_imm4>,<Rn> cond:4|0|1|1|0|1|1|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+ {0x0ff000f0, 0x06e00f30, 3, arm_USAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4, arm_arg_R_0}}, // USAT16<c> <Rd>,#<sat_imm4>,<Rn> cond:4|0|1|1|0|1|1|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+ {0x0fe00030, 0x06e00010, 4, arm_USAT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm5, arm_arg_R_shift_imm}}, // USAT<c> <Rd>,#<sat_imm5>,<Rn>{,<shift>} cond:4|0|1|1|0|1|1|1|sat_imm:5|Rd:4|imm5:5|sh|0|1|Rn:4
+ {0x0ff00ff0, 0x06500f50, 4, arm_USAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff000f0, 0x06500f50, 3, arm_USAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+ {0x0ff00ff0, 0x06500f70, 4, arm_USUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff000f0, 0x06500f70, 3, arm_USUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+ {0x0ff00ff0, 0x06500ff0, 4, arm_USUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff000f0, 0x06500ff0, 3, arm_USUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}}, // USUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+ {0x0ff003f0, 0x06c00070, 2, arm_UXTAB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // UXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|0|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0ff003f0, 0x06e00070, 2, arm_UXTAB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // UXTAB<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0ff003f0, 0x06f00070, 2, arm_UXTAH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}}, // UXTAH<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|1|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x06cf0070, 4, arm_UXTB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // UXTB16<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|0|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x06ef0070, 4, arm_UXTB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // UXTB<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fff03f0, 0x06ff0070, 4, arm_UXTH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}}, // UXTH<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|1|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+ {0x0fb00e10, 0x0e000a00, 4, arm_VMLA_EQ_F32, 0x60108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // V<MLA,MLS><c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|0|0|Vn:4|Vd:4|1|0|1|sz|N|op|M|0|Vm:4
+ {0x0fbf0ed0, 0x0eb00ac0, 4, arm_VABS_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}}, // VABS<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|0|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+ {0x0fb00e50, 0x0e300a00, 4, arm_VADD_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VADD<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|1|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+ {0x0fbf0e7f, 0x0eb50a40, 4, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_fp_0}}, // VCMP{E}<c>.F<32,64> <Sd,Dd>, #0.0 cond:4|1|1|1|0|1|D|1|1|0|1|0|1|Vd:4|1|0|1|sz|E|1|0|0|(0)|(0)|(0)|(0)
+ {0x0fbf0e70, 0x0eb50a40, 3, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_fp_0}}, // VCMP{E}<c>.F<32,64> <Sd,Dd>, #0.0 cond:4|1|1|1|0|1|D|1|1|0|1|0|1|Vd:4|1|0|1|sz|E|1|0|0|(0)|(0)|(0)|(0)
+ {0x0fbf0e50, 0x0eb40a40, 4, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}}, // VCMP{E}<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|1|0|0|Vd:4|1|0|1|sz|E|1|M|0|Vm:4
+ {0x0fbe0e50, 0x0eba0a40, 4, arm_VCVT_EQ_F32_FXS16, 0x801100107011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sd_Dd, arm_arg_fbits}}, // VCVT<c>.F<32,64>.FX<S,U><16,32> <Sd,Dd>, <Sd,Dd>, #<fbits> cond:4|1|1|1|0|1|D|1|1|1|0|1|U|Vd:4|1|0|1|sz|sx|1|i|0|imm4:4
+ {0x0fbe0e50, 0x0ebe0a40, 4, arm_VCVT_EQ_FXS16_F32, 0x1001070108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sd_Dd, arm_arg_fbits}}, // VCVT<c>.FX<S,U><16,32>.F<32,64> <Sd,Dd>, <Sd,Dd>, #<fbits> cond:4|1|1|1|0|1|D|1|1|1|1|1|U|Vd:4|1|0|1|sz|sx|1|i|0|imm4:4
+ {0x0fbf0ed0, 0x0eb70ac0, 4, arm_VCVT_EQ_F64_F32, 0x8011c04, arm_instArgs{arm_arg_Dd_Sd, arm_arg_Sm_Dm}}, // VCVT<c>.<F64.F32,F32.F64> <Dd,Sd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|1|1|1|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+ {0x0fbe0f50, 0x0eb20a40, 4, arm_VCVTB_EQ_F32_F16, 0x70110011c04, arm_instArgs{arm_arg_Sd, arm_arg_Sm}}, // VCVT<B,T><c>.<F32.F16,F16.F32> <Sd>, <Sm> cond:4|1|1|1|0|1|D|1|1|0|0|1|op|Vd:4|1|0|1|0|T|1|M|0|Vm:4
+ {0x0fbf0e50, 0x0eb80a40, 4, arm_VCVT_EQ_F32_U32, 0x80107011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm}}, // VCVT<c>.F<32,64>.<U,S>32 <Sd,Dd>, <Sm> cond:4|1|1|1|0|1|D|1|1|1|0|0|0|Vd:4|1|0|1|sz|op|1|M|0|Vm:4
+ {0x0fbe0e50, 0x0ebc0a40, 4, arm_VCVTR_EQ_U32_F32, 0x701100108011c04, arm_instArgs{arm_arg_Sd, arm_arg_Sm_Dm}}, // VCVT<R,><c>.<U,S>32.F<32,64> <Sd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|1|1|0|signed|Vd:4|1|0|1|sz|op|1|M|0|Vm:4
+ {0x0fb00e50, 0x0e800a00, 4, arm_VDIV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VDIV<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|1|D|0|0|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+ {0x0f300e00, 0x0d100a00, 4, arm_VLDR_EQ, 0x1c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_mem_R_pm_imm8at0_offset}}, // VLDR<c> <Sd,Dd>, [<Rn>{,#+/-<imm8>}] cond:4|1|1|0|1|U|D|0|1|Rn:4|Vd:4|1|0|1|sz|imm8:8
+ {0x0ff00f7f, 0x0e000a10, 4, arm_VMOV_EQ, 0x1c04, arm_instArgs{arm_arg_Sn, arm_arg_R_12}}, // VMOV<c> <Sn>, <Rt> cond:4|1|1|1|0|0|0|0|0|Vn:4|Rt:4|1|0|1|0|N|0|0|1|0|0|0|0
+ {0x0ff00f7f, 0x0e100a10, 4, arm_VMOV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_Sn}}, // VMOV<c> <Rt>, <Sn> cond:4|1|1|1|0|0|0|0|1|Vn:4|Rt:4|1|0|1|0|N|0|0|1|0|0|0|0
+ {0x0fd00f7f, 0x0e100b10, 4, arm_VMOV_EQ_32, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_Dn_half}}, // VMOV<c>.32 <Rt>, <Dn[x]> cond:4|1|1|1|0|0|0|opc1|1|Vn:4|Rt:4|1|0|1|1|N|0|0|1|0|0|0|0
+ {0x0fd00f7f, 0x0e000b10, 4, arm_VMOV_EQ_32, 0x1c04, arm_instArgs{arm_arg_Dn_half, arm_arg_R_12}}, // VMOV<c>.32 <Dd[x]>, <Rt> cond:4|1|1|1|0|0|0|opc1|0|Vd:4|Rt:4|1|0|1|1|D|0|0|1|0|0|0|0
+ {0x0fb00ef0, 0x0eb00a00, 4, arm_VMOV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_imm_vfp}}, // VMOV<c>.F<32,64> <Sd,Dd>, #<imm_vfp> cond:4|1|1|1|0|1|D|1|1|imm4H:4|Vd:4|1|0|1|sz|0|0|0|0|imm4L:4
+ {0x0fbf0ed0, 0x0eb00a40, 4, arm_VMOV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}}, // VMOV<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|0|Vd:4|1|0|1|sz|0|1|M|0|Vm:4
+ {0x0fff0fff, 0x0ef10a10, 4, arm_VMRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12_nzcv, arm_arg_FPSCR}}, // VMRS<c> <Rt_nzcv>, FPSCR cond:4|1|1|1|0|1|1|1|1|0|0|0|1|Rt:4|1|0|1|0|0|0|0|1|0|0|0|0
+ {0x0fff0fff, 0x0ee10a10, 4, arm_VMSR_EQ, 0x1c04, arm_instArgs{arm_arg_FPSCR, arm_arg_R_12}}, // VMSR<c> FPSCR, <Rt> cond:4|1|1|1|0|1|1|1|0|0|0|0|1|Rt:4|1|0|1|0|0|0|0|1|0|0|0|0
+ {0x0fb00e50, 0x0e200a00, 4, arm_VMUL_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VMUL<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|0|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+ {0x0fbf0ed0, 0x0eb10a40, 4, arm_VNEG_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}}, // VNEG<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|1|Vd:4|1|0|1|sz|0|1|M|0|Vm:4
+ {0x0fb00e10, 0x0e100a00, 4, arm_VNMLS_EQ_F32, 0x60108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VN<MLS,MLA><c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|0|1|Vn:4|Vd:4|1|0|1|sz|N|op|M|0|Vm:4
+ {0x0fb00e50, 0x0e200a40, 4, arm_VNMUL_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VNMUL<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|0|Vn:4|Vd:4|1|0|1|sz|N|1|M|0|Vm:4
+ {0x0fbf0ed0, 0x0eb10ac0, 4, arm_VSQRT_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}}, // VSQRT<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|1|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+ {0x0f300e00, 0x0d000a00, 4, arm_VSTR_EQ, 0x1c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_mem_R_pm_imm8at0_offset}}, // VSTR<c> <Sd,Dd>, [<Rn>{,#+/-<imm8>}] cond:4|1|1|0|1|U|D|0|0|Rn:4|Vd:4|1|0|1|sz|imm8:8
+ {0x0fb00e50, 0x0e300a40, 4, arm_VSUB_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}}, // VSUB<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|1|Vn:4|Vd:4|1|0|1|sz|N|1|M|0|Vm:4
+ {0x0fffffff, 0x0320f002, 4, arm_WFE_EQ, 0x1c04, arm_instArgs{}}, // WFE<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|0
+ {0x0fff00ff, 0x0320f002, 3, arm_WFE_EQ, 0x1c04, arm_instArgs{}}, // WFE<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|0
+ {0x0fffffff, 0x0320f003, 4, arm_WFI_EQ, 0x1c04, arm_instArgs{}}, // WFI<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|1
+ {0x0fff00ff, 0x0320f003, 3, arm_WFI_EQ, 0x1c04, arm_instArgs{}}, // WFI<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|1
+ {0x0fffffff, 0x0320f001, 4, arm_YIELD_EQ, 0x1c04, arm_instArgs{}}, // YIELD<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|1
+ {0x0fff00ff, 0x0320f001, 3, arm_YIELD_EQ, 0x1c04, arm_instArgs{}}, // YIELD<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|1
+ {0xffffffff, 0xf7fabcfd, 4, arm_UNDEF, 0x0, arm_instArgs{}}, // UNDEF 1|1|1|1|0|1|1|1|1|1|1|1|1|0|1|0|1|0|1|1|1|1|0|0|1|1|1|1|1|1|0|1
+}
diff --git a/src/cmd/objdump/elf.go b/src/cmd/objdump/elf.go
new file mode 100644
index 000000000..906e90353
--- /dev/null
+++ b/src/cmd/objdump/elf.go
@@ -0,0 +1,65 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of ELF executables (Linux, FreeBSD, and so on).
+
+package main
+
+import (
+ "debug/elf"
+ "os"
+)
+
+func elfSymbols(f *os.File) (syms []Sym, goarch string) {
+ p, err := elf.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ elfSyms, err := p.Symbols()
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ switch p.Machine {
+ case elf.EM_X86_64:
+ goarch = "amd64"
+ case elf.EM_386:
+ goarch = "386"
+ case elf.EM_ARM:
+ goarch = "arm"
+ }
+
+ for _, s := range elfSyms {
+ sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
+ switch s.Section {
+ case elf.SHN_UNDEF:
+ sym.Code = 'U'
+ case elf.SHN_COMMON:
+ sym.Code = 'B'
+ default:
+ i := int(s.Section)
+ if i < 0 || i >= len(p.Sections) {
+ break
+ }
+ sect := p.Sections[i]
+ switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
+ case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
+ sym.Code = 'T'
+ case elf.SHF_ALLOC:
+ sym.Code = 'R'
+ case elf.SHF_ALLOC | elf.SHF_WRITE:
+ sym.Code = 'D'
+ }
+ }
+ if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
+ sym.Code += 'a' - 'A'
+ }
+ syms = append(syms, sym)
+ }
+
+ return
+}
diff --git a/src/cmd/objdump/macho.go b/src/cmd/objdump/macho.go
new file mode 100644
index 000000000..6e0ad223d
--- /dev/null
+++ b/src/cmd/objdump/macho.go
@@ -0,0 +1,77 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Mach-O executables (OS X).
+
+package main
+
+import (
+ "debug/macho"
+ "os"
+ "sort"
+)
+
+func machoSymbols(f *os.File) (syms []Sym, goarch string) {
+ p, err := macho.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ if p.Symtab == nil {
+ errorf("%s: no symbol table", f.Name())
+ return
+ }
+
+ switch p.Cpu {
+ case macho.Cpu386:
+ goarch = "386"
+ case macho.CpuAmd64:
+ goarch = "amd64"
+ case macho.CpuArm:
+ goarch = "arm"
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+ for _, s := range p.Symtab.Syms {
+ addrs = append(addrs, s.Value)
+ }
+ sort.Sort(uint64s(addrs))
+
+ for _, s := range p.Symtab.Syms {
+ sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
+ i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
+ if i < len(addrs) {
+ sym.Size = int64(addrs[i] - s.Value)
+ }
+ if s.Sect == 0 {
+ sym.Code = 'U'
+ } else if int(s.Sect) <= len(p.Sections) {
+ sect := p.Sections[s.Sect-1]
+ switch sect.Seg {
+ case "__TEXT":
+ sym.Code = 'R'
+ case "__DATA":
+ sym.Code = 'D'
+ }
+ switch sect.Seg + " " + sect.Name {
+ case "__TEXT __text":
+ sym.Code = 'T'
+ case "__DATA __bss", "__DATA __noptrbss":
+ sym.Code = 'B'
+ }
+ }
+ syms = append(syms, sym)
+ }
+
+ return
+}
+
+type uint64s []uint64
+
+func (x uint64s) Len() int { return len(x) }
+func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
diff --git a/src/cmd/objdump/main.c b/src/cmd/objdump/main.c
deleted file mode 100644
index b684be7fb..000000000
--- a/src/cmd/objdump/main.c
+++ /dev/null
@@ -1,68 +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.
-
-/*
- * objdump simulation - only enough to make pprof work on Macs
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-void
-usage(void)
-{
- fprint(2, "usage: objdump binary start stop\n");
- fprint(2, "Disassembles binary from PC start up to stop.\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd, n;
- uvlong pc, start, stop;
- Fhdr fhdr;
- Biobuf bout;
- char buf[1024];
- Map *text;
-
- ARGBEGIN{
- default:
- usage();
- }ARGEND
-
- if(argc != 3)
- usage();
- start = strtoull(argv[1], 0, 16);
- stop = strtoull(argv[2], 0, 16);
-
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
- text = loadmap(nil, fd, &fhdr);
- if(text == nil)
- sysfatal("loadmap: %r");
-
- Binit(&bout, 1, OWRITE);
- for(pc=start; pc<stop; ) {
- if(fileline(buf, sizeof buf, pc))
- Bprint(&bout, "%s\n", buf);
- buf[0] = '\0';
- machdata->das(text, pc, 0, buf, sizeof buf);
- Bprint(&bout, " %llx: %s\n", pc, buf);
- n = machdata->instsize(text, pc);
- if(n <= 0)
- break;
- pc += n;
- }
- Bflush(&bout);
- exits(0);
-}
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
new file mode 100644
index 000000000..ade54366e
--- /dev/null
+++ b/src/cmd/objdump/main.go
@@ -0,0 +1,519 @@
+// 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.
+
+// Objdump disassembles executable files.
+//
+// Usage:
+//
+// go tool objdump [-s symregexp] binary
+//
+// Objdump prints a disassembly of all text symbols (code) in the binary.
+// If the -s option is present, objdump only disassembles
+// symbols with names matching the regular expression.
+//
+// Alternate usage:
+//
+// go tool objdump binary start end
+//
+// In this mode, objdump disassembles the binary starting at the start address and
+// stopping at the end address. The start and end addresses are program
+// counters written in hexadecimal with optional leading 0x prefix.
+// In this mode, objdump prints a sequence of stanzas of the form:
+//
+// file:line
+// address: assembly
+// address: assembly
+// ...
+//
+// Each stanza gives the disassembly for a contiguous range of addresses
+// all mapped to the same original source file and line number.
+// This mode is intended for use by pprof.
+//
+// The ARM disassembler is missing (golang.org/issue/7452) but will be added
+// before the Go 1.3 release.
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "debug/elf"
+ "debug/gosym"
+ "debug/macho"
+ "debug/pe"
+ "debug/plan9obj"
+ "encoding/binary"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "text/tabwriter"
+)
+
+var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
+var symRE *regexp.Regexp
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go tool objdump [-s symregexp] binary [start end]\n\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+type lookupFunc func(addr uint64) (sym string, base uint64)
+type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int)
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("objdump: ")
+
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 1 && flag.NArg() != 3 {
+ usage()
+ }
+
+ if *symregexp != "" {
+ re, err := regexp.Compile(*symregexp)
+ if err != nil {
+ log.Fatalf("invalid -s regexp: %v", err)
+ }
+ symRE = re
+ }
+
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ textStart, textData, symtab, pclntab, err := loadTables(f)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ syms, goarch, err := loadSymbols(f)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ // Filter out section symbols, overwriting syms in place.
+ keep := syms[:0]
+ for _, sym := range syms {
+ switch sym.Name {
+ case "text", "_text", "etext", "_etext":
+ // drop
+ default:
+ keep = append(keep, sym)
+ }
+ }
+ syms = keep
+
+ disasm := disasms[goarch]
+ if disasm == nil {
+ log.Fatalf("reading %s: unknown architecture", flag.Arg(0))
+ }
+
+ lookup := func(addr uint64) (string, uint64) {
+ i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr })
+ if i > 0 {
+ s := syms[i-1]
+ if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "etext" && s.Name != "_etext" {
+ return s.Name, s.Addr
+ }
+ }
+ return "", 0
+ }
+
+ pcln := gosym.NewLineTable(pclntab, textStart)
+ tab, err := gosym.NewTable(symtab, pcln)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ if flag.NArg() == 1 {
+ // disassembly of entire object - our format
+ dump(tab, lookup, disasm, goarch, syms, textData, textStart)
+ os.Exit(exitCode)
+ }
+
+ // disassembly of specific piece of object - gnu objdump format for pprof
+ gnuDump(tab, lookup, disasm, textData, textStart)
+ os.Exit(exitCode)
+}
+
+// base returns the final element in the path.
+// It works on both Windows and Unix paths.
+func base(path string) string {
+ path = path[strings.LastIndex(path, "/")+1:]
+ path = path[strings.LastIndex(path, `\`)+1:]
+ return path
+}
+
+func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, syms []Sym, textData []byte, textStart uint64) {
+ stdout := bufio.NewWriter(os.Stdout)
+ defer stdout.Flush()
+
+ printed := false
+ for _, sym := range syms {
+ if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) {
+ continue
+ }
+ if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) {
+ break
+ }
+ if printed {
+ fmt.Fprintf(stdout, "\n")
+ } else {
+ printed = true
+ }
+ file, _, _ := tab.PCToLine(sym.Addr)
+ fmt.Fprintf(stdout, "TEXT %s(SB) %s\n", sym.Name, file)
+ tw := tabwriter.NewWriter(stdout, 1, 8, 1, '\t', 0)
+ start := sym.Addr
+ end := sym.Addr + uint64(sym.Size)
+ for pc := start; pc < end; {
+ i := pc - textStart
+ text, size := disasm(textData[i:end-textStart], pc, lookup)
+ file, line, _ := tab.PCToLine(pc)
+
+ // ARM is word-based, so show actual word hex, not byte hex.
+ // Since ARM is little endian, they're different.
+ if goarch == "arm" && size == 4 {
+ fmt.Fprintf(tw, "\t%s:%d\t%#x\t%08x\t%s\n", base(file), line, pc, binary.LittleEndian.Uint32(textData[i:i+uint64(size)]), text)
+ } else {
+ fmt.Fprintf(tw, "\t%s:%d\t%#x\t%x\t%s\n", base(file), line, pc, textData[i:i+uint64(size)], text)
+ }
+ pc += uint64(size)
+ }
+ tw.Flush()
+ }
+}
+
+func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+ return disasm_x86(code, pc, lookup, 32)
+}
+
+func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+ return disasm_x86(code, pc, lookup, 64)
+}
+
+func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
+ inst, err := x86_Decode(code, 64)
+ var text string
+ size := inst.Len
+ if err != nil || size == 0 || inst.Op == 0 {
+ size = 1
+ text = "?"
+ } else {
+ text = x86_plan9Syntax(inst, pc, lookup)
+ }
+ return text, size
+}
+
+type textReader struct {
+ code []byte
+ pc uint64
+}
+
+func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
+ if off < 0 || uint64(off) < r.pc {
+ return 0, io.EOF
+ }
+ d := uint64(off) - r.pc
+ if d >= uint64(len(r.code)) {
+ return 0, io.EOF
+ }
+ n = copy(data, r.code[d:])
+ if n < len(data) {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+ inst, err := arm_Decode(code, arm_ModeARM)
+ var text string
+ size := inst.Len
+ if err != nil || size == 0 || inst.Op == 0 {
+ size = 4
+ text = "?"
+ } else {
+ text = arm_plan9Syntax(inst, pc, lookup, textReader{code, pc})
+ }
+ return text, size
+}
+
+var disasms = map[string]disasmFunc{
+ "386": disasm_386,
+ "amd64": disasm_amd64,
+ "arm": disasm_arm,
+}
+
+func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []byte, textStart uint64) {
+ start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 16, 64)
+ if err != nil {
+ log.Fatalf("invalid start PC: %v", err)
+ }
+ end, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(2), "0x"), 16, 64)
+ if err != nil {
+ log.Fatalf("invalid end PC: %v", err)
+ }
+ if start < textStart {
+ start = textStart
+ }
+ if end < start {
+ end = start
+ }
+ if end > textStart+uint64(len(textData)) {
+ end = textStart + uint64(len(textData))
+ }
+
+ stdout := bufio.NewWriter(os.Stdout)
+ defer stdout.Flush()
+
+ // For now, find spans of same PC/line/fn and
+ // emit them as having dummy instructions.
+ var (
+ spanPC uint64
+ spanFile string
+ spanLine int
+ spanFn *gosym.Func
+ )
+
+ flush := func(endPC uint64) {
+ if spanPC == 0 {
+ return
+ }
+ fmt.Fprintf(stdout, "%s:%d\n", spanFile, spanLine)
+ for pc := spanPC; pc < endPC; {
+ text, size := disasm(textData[pc-textStart:], pc, lookup)
+ fmt.Fprintf(stdout, " %x: %s\n", pc, text)
+ pc += uint64(size)
+ }
+ spanPC = 0
+ }
+
+ for pc := start; pc < end; pc++ {
+ file, line, fn := tab.PCToLine(pc)
+ if file != spanFile || line != spanLine || fn != spanFn {
+ flush(pc)
+ spanPC, spanFile, spanLine, spanFn = pc, file, line, fn
+ }
+ }
+ flush(end)
+}
+
+func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) {
+ if obj, err := elf.NewFile(f); err == nil {
+ if sect := obj.Section(".text"); sect != nil {
+ textStart = sect.Addr
+ textData, _ = sect.Data()
+ }
+ if sect := obj.Section(".gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ if sect := obj.Section(".gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ return textStart, textData, symtab, pclntab, nil
+ }
+
+ if obj, err := macho.NewFile(f); err == nil {
+ if sect := obj.Section("__text"); sect != nil {
+ textStart = sect.Addr
+ textData, _ = sect.Data()
+ }
+ if sect := obj.Section("__gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ if sect := obj.Section("__gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ return textStart, textData, symtab, pclntab, nil
+ }
+
+ if obj, err := pe.NewFile(f); err == nil {
+ var imageBase uint64
+ switch oh := obj.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ default:
+ return 0, nil, nil, nil, fmt.Errorf("pe file format not recognized")
+ }
+ if sect := obj.Section(".text"); sect != nil {
+ textStart = imageBase + uint64(sect.VirtualAddress)
+ textData, _ = sect.Data()
+ }
+ if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ return textStart, textData, symtab, pclntab, nil
+ }
+
+ if obj, err := plan9obj.NewFile(f); err == nil {
+ sym, err := findPlan9Symbol(obj, "text")
+ if err != nil {
+ return 0, nil, nil, nil, err
+ }
+ textStart = sym.Value
+ if sect := obj.Section("text"); sect != nil {
+ textData, _ = sect.Data()
+ }
+ if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ return textStart, textData, symtab, pclntab, nil
+ }
+
+ return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format")
+}
+
+func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
+ for _, s := range f.Symbols {
+ if s.Name != name {
+ continue
+ }
+ if s.SectionNumber <= 0 {
+ return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
+ }
+ if len(f.Sections) < int(s.SectionNumber) {
+ return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
+ }
+ return s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPESymbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPESymbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ if ssym.SectionNumber != esym.SectionNumber {
+ return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
+ }
+ sect := f.Sections[ssym.SectionNumber-1]
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ return data[ssym.Value:esym.Value], nil
+}
+
+func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
+ syms, err := f.Symbols()
+ if err != nil {
+ return nil, err
+ }
+ for _, s := range syms {
+ if s.Name != name {
+ continue
+ }
+ return &s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPlan9Symbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPlan9Symbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ text, err := findPlan9Symbol(f, "text")
+ if err != nil {
+ return nil, err
+ }
+ sect := f.Section("text")
+ if sect == nil {
+ return nil, err
+ }
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ return data[ssym.Value-text.Value : esym.Value-text.Value], nil
+}
+
+// TODO(rsc): This code is taken from cmd/nm. Arrange some way to share the code.
+
+var exitCode = 0
+
+func errorf(format string, args ...interface{}) {
+ log.Printf(format, args...)
+ exitCode = 1
+}
+
+func loadSymbols(f *os.File) (syms []Sym, goarch string, err error) {
+ f.Seek(0, 0)
+ buf := make([]byte, 16)
+ io.ReadFull(f, buf)
+ f.Seek(0, 0)
+
+ for _, p := range parsers {
+ if bytes.HasPrefix(buf, p.prefix) {
+ syms, goarch = p.parse(f)
+ sort.Sort(byAddr(syms))
+ return
+ }
+ }
+ err = fmt.Errorf("unknown file format")
+ return
+}
+
+type Sym struct {
+ Addr uint64
+ Size int64
+ Code rune
+ Name string
+ Type string
+}
+
+var parsers = []struct {
+ prefix []byte
+ parse func(*os.File) ([]Sym, string)
+}{
+ {[]byte("\x7FELF"), elfSymbols},
+ {[]byte("\xFE\xED\xFA\xCE"), machoSymbols},
+ {[]byte("\xFE\xED\xFA\xCF"), machoSymbols},
+ {[]byte("\xCE\xFA\xED\xFE"), machoSymbols},
+ {[]byte("\xCF\xFA\xED\xFE"), machoSymbols},
+ {[]byte("MZ"), peSymbols},
+ {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386
+ {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips
+ {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm
+ {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64
+}
+
+type byAddr []Sym
+
+func (x byAddr) Len() int { return len(x) }
+func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
new file mode 100644
index 000000000..82311bb1f
--- /dev/null
+++ b/src/cmd/objdump/objdump_test.go
@@ -0,0 +1,193 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func loadSyms(t *testing.T) map[string]string {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ cmd := exec.Command("go", "tool", "nm", os.Args[0])
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
+ }
+ syms := make(map[string]string)
+ scanner := bufio.NewScanner(bytes.NewReader(out))
+ for scanner.Scan() {
+ f := strings.Fields(scanner.Text())
+ if len(f) < 3 {
+ continue
+ }
+ syms[f[2]] = f[0]
+ }
+ if err := scanner.Err(); err != nil {
+ t.Fatalf("error reading symbols: %v", err)
+ }
+ return syms
+}
+
+func runObjDump(t *testing.T, exe, startaddr, endaddr string) (path, lineno string) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ cmd := exec.Command(exe, os.Args[0], startaddr, endaddr)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("go tool objdump %v: %v\n%s", os.Args[0], err, string(out))
+ }
+ f := strings.Split(string(out), "\n")
+ if len(f) < 1 {
+ t.Fatal("objdump output must have at least one line")
+ }
+ pathAndLineNo := f[0]
+ f = strings.Split(pathAndLineNo, ":")
+ if runtime.GOOS == "windows" {
+ switch len(f) {
+ case 2:
+ return f[0], f[1]
+ case 3:
+ return f[0] + ":" + f[1], f[2]
+ default:
+ t.Fatalf("no line number found in %q", pathAndLineNo)
+ }
+ }
+ if len(f) != 2 {
+ t.Fatalf("no line number found in %q", pathAndLineNo)
+ }
+ return f[0], f[1]
+}
+
+func testObjDump(t *testing.T, exe, startaddr, endaddr string, line int) {
+ srcPath, srcLineNo := runObjDump(t, exe, startaddr, endaddr)
+ fi1, err := os.Stat("objdump_test.go")
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ fi2, err := os.Stat(srcPath)
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ if !os.SameFile(fi1, fi2) {
+ t.Fatalf("objdump_test.go and %s are not same file", srcPath)
+ }
+ if srcLineNo != fmt.Sprint(line) {
+ t.Fatalf("line number = %v; want %d", srcLineNo, line)
+ }
+}
+
+func TestObjDump(t *testing.T) {
+ _, _, line, _ := runtime.Caller(0)
+ syms := loadSyms(t)
+
+ tmp, exe := buildObjdump(t)
+ defer os.RemoveAll(tmp)
+
+ startaddr := syms["cmd/objdump.TestObjDump"]
+ addr, err := strconv.ParseUint(startaddr, 16, 64)
+ if err != nil {
+ t.Fatalf("invalid start address %v: %v", startaddr, err)
+ }
+ endaddr := fmt.Sprintf("%x", addr+10)
+ testObjDump(t, exe, startaddr, endaddr, line-1)
+ testObjDump(t, exe, "0x"+startaddr, "0x"+endaddr, line-1)
+}
+
+func buildObjdump(t *testing.T) (tmp, exe string) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ tmp, err := ioutil.TempDir("", "TestObjDump")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+
+ exe = filepath.Join(tmp, "testobjdump.exe")
+ out, err := exec.Command("go", "build", "-o", exe, "cmd/objdump").CombinedOutput()
+ if err != nil {
+ os.RemoveAll(tmp)
+ t.Fatalf("go build -o %v cmd/objdump: %v\n%s", exe, err, string(out))
+ }
+ return
+}
+
+var x86Need = []string{
+ "fmthello.go:6",
+ "TEXT main.main(SB)",
+ "JMP main.main(SB)",
+ "CALL fmt.Println(SB)",
+ "RET",
+}
+
+var armNeed = []string{
+ "fmthello.go:6",
+ "TEXT main.main(SB)",
+ "B.LS main.main(SB)",
+ "BL fmt.Println(SB)",
+ "RET",
+}
+
+// objdump is fully cross platform: it can handle binaries
+// from any known operating system and architecture.
+// We could in principle add binaries to testdata and check
+// all the supported systems during this test. However, the
+// binaries would be about 1 MB each, and we don't want to
+// add that much junk to the hg repository. Instead, build a
+// binary for the current system (only) and test that objdump
+// can handle that one.
+
+func TestDisasm(t *testing.T) {
+ tmp, exe := buildObjdump(t)
+ defer os.RemoveAll(tmp)
+
+ hello := filepath.Join(tmp, "hello.exe")
+ out, err := exec.Command("go", "build", "-o", hello, "testdata/fmthello.go").CombinedOutput()
+ if err != nil {
+ t.Fatalf("go build fmthello.go: %v\n%s", err, out)
+ }
+ need := []string{
+ "fmthello.go:6",
+ "TEXT main.main(SB)",
+ }
+ switch runtime.GOARCH {
+ case "amd64", "386":
+ need = append(need, x86Need...)
+ case "arm":
+ need = append(need, armNeed...)
+ }
+
+ out, err = exec.Command(exe, "-s", "main.main", hello).CombinedOutput()
+ if err != nil {
+ t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
+ }
+
+ text := string(out)
+ ok := true
+ for _, s := range need {
+ if !strings.Contains(text, s) {
+ t.Errorf("disassembly missing '%s'", s)
+ ok = false
+ }
+ }
+ if !ok {
+ t.Logf("full disassembly:\n%s", text)
+ }
+}
diff --git a/src/cmd/objdump/pe.go b/src/cmd/objdump/pe.go
new file mode 100644
index 000000000..38190095a
--- /dev/null
+++ b/src/cmd/objdump/pe.go
@@ -0,0 +1,99 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of PE executables (Microsoft Windows).
+
+package main
+
+import (
+ "debug/pe"
+ "os"
+ "sort"
+)
+
+func peSymbols(f *os.File) (syms []Sym, goarch string) {
+ p, err := pe.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+
+ var imageBase uint64
+ switch oh := p.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ goarch = "386"
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ goarch = "amd64"
+ default:
+ errorf("parsing %s: file format not recognized", f.Name())
+ return
+ }
+
+ for _, s := range p.Symbols {
+ const (
+ N_UNDEF = 0 // An undefined (extern) symbol
+ N_ABS = -1 // An absolute symbol (e_value is a constant, not an address)
+ N_DEBUG = -2 // A debugging symbol
+ )
+ sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
+ switch s.SectionNumber {
+ case N_UNDEF:
+ sym.Code = 'U'
+ case N_ABS:
+ sym.Code = 'C'
+ case N_DEBUG:
+ sym.Code = '?'
+ default:
+ if s.SectionNumber < 0 {
+ errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber)
+ return
+ }
+ if len(p.Sections) < int(s.SectionNumber) {
+ errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections))
+ return
+ }
+ sect := p.Sections[s.SectionNumber-1]
+ const (
+ text = 0x20
+ data = 0x40
+ bss = 0x80
+ permX = 0x20000000
+ permR = 0x40000000
+ permW = 0x80000000
+ )
+ ch := sect.Characteristics
+ switch {
+ case ch&text != 0:
+ sym.Code = 'T'
+ case ch&data != 0:
+ if ch&permW == 0 {
+ sym.Code = 'R'
+ } else {
+ sym.Code = 'D'
+ }
+ case ch&bss != 0:
+ sym.Code = 'B'
+ }
+ sym.Addr += imageBase + uint64(sect.VirtualAddress)
+ }
+ syms = append(syms, sym)
+ addrs = append(addrs, sym.Addr)
+ }
+
+ sort.Sort(uint64s(addrs))
+ for i := range syms {
+ j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
+ if j < len(addrs) {
+ syms[i].Size = int64(addrs[j] - syms[i].Addr)
+ }
+ }
+
+ return
+}
diff --git a/src/cmd/objdump/plan9obj.go b/src/cmd/objdump/plan9obj.go
new file mode 100644
index 000000000..34462f31c
--- /dev/null
+++ b/src/cmd/objdump/plan9obj.go
@@ -0,0 +1,63 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Plan 9 a.out executables.
+
+package main
+
+import (
+ "debug/plan9obj"
+ "os"
+ "sort"
+)
+
+var validSymType = map[rune]bool{
+ 'T': true,
+ 't': true,
+ 'D': true,
+ 'd': true,
+ 'B': true,
+ 'b': true,
+}
+
+func plan9Symbols(f *os.File) (syms []Sym, goarch string) {
+ p, err := plan9obj.NewFile(f)
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ plan9Syms, err := p.Symbols()
+ if err != nil {
+ errorf("parsing %s: %v", f.Name(), err)
+ return
+ }
+
+ goarch = "386"
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+ for _, s := range plan9Syms {
+ if !validSymType[s.Type] {
+ continue
+ }
+ addrs = append(addrs, s.Value)
+ }
+ sort.Sort(uint64s(addrs))
+
+ for _, s := range plan9Syms {
+ if !validSymType[s.Type] {
+ continue
+ }
+ sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
+ i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
+ if i < len(addrs) {
+ sym.Size = int64(addrs[i] - s.Value)
+ }
+ syms = append(syms, sym)
+ }
+
+ return
+}
diff --git a/src/cmd/objdump/testdata/fmthello.go b/src/cmd/objdump/testdata/fmthello.go
new file mode 100644
index 000000000..635db7ae6
--- /dev/null
+++ b/src/cmd/objdump/testdata/fmthello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello, world")
+}
diff --git a/src/cmd/objdump/x86.go b/src/cmd/objdump/x86.go
new file mode 100644
index 000000000..8e741331f
--- /dev/null
+++ b/src/cmd/objdump/x86.go
@@ -0,0 +1,13800 @@
+// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle
+// bundle -p main -x x86_ rsc.io/x86/x86asm
+
+/* decode.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Table-driven decoding of x86 instructions.
+
+package main
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+// Set trace to true to cause the decoder to print the PC sequence
+// of the executed instruction codes. This is typically only useful
+// when you are running a test of a single input case.
+const x86_trace = false
+
+// A decodeOp is a single instruction in the decoder bytecode program.
+//
+// The decodeOps correspond to consuming and conditionally branching
+// on input bytes, consuming additional fields, and then interpreting
+// consumed data as instruction arguments. The names of the xRead and xArg
+// operations are taken from the Intel manual conventions, for example
+// Volume 2, Section 3.1.1, page 487 of
+// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
+//
+// The actual decoding program is generated by ../x86map.
+//
+// TODO(rsc): We may be able to merge various of the memory operands
+// since we don't care about, say, the distinction between m80dec and m80bcd.
+// Similarly, mm and mm1 have identical meaning, as do xmm and xmm1.
+
+type x86_decodeOp uint16
+
+const (
+ x86_xFail x86_decodeOp = iota // invalid instruction (return)
+ x86_xMatch // completed match
+ x86_xJump // jump to pc
+
+ x86_xCondByte // switch on instruction byte value
+ x86_xCondSlashR // read and switch on instruction /r value
+ x86_xCondPrefix // switch on presence of instruction prefix
+ x86_xCondIs64 // switch on 64-bit processor mode
+ x86_xCondDataSize // switch on operand size
+ x86_xCondAddrSize // switch on address size
+ x86_xCondIsMem // switch on memory vs register argument
+
+ x86_xSetOp // set instruction opcode
+
+ x86_xReadSlashR // read /r
+ x86_xReadIb // read ib
+ x86_xReadIw // read iw
+ x86_xReadId // read id
+ x86_xReadIo // read io
+ x86_xReadCb // read cb
+ x86_xReadCw // read cw
+ x86_xReadCd // read cd
+ x86_xReadCp // read cp
+ x86_xReadCm // read cm
+
+ x86_xArg1 // arg 1
+ x86_xArg3 // arg 3
+ x86_xArgAL // arg AL
+ x86_xArgAX // arg AX
+ x86_xArgCL // arg CL
+ x86_xArgCR0dashCR7 // arg CR0-CR7
+ x86_xArgCS // arg CS
+ x86_xArgDR0dashDR7 // arg DR0-DR7
+ x86_xArgDS // arg DS
+ x86_xArgDX // arg DX
+ x86_xArgEAX // arg EAX
+ x86_xArgEDX // arg EDX
+ x86_xArgES // arg ES
+ x86_xArgFS // arg FS
+ x86_xArgGS // arg GS
+ x86_xArgImm16 // arg imm16
+ x86_xArgImm32 // arg imm32
+ x86_xArgImm64 // arg imm64
+ x86_xArgImm8 // arg imm8
+ x86_xArgImm8u // arg imm8 but record as unsigned
+ x86_xArgImm16u // arg imm8 but record as unsigned
+ x86_xArgM // arg m
+ x86_xArgM128 // arg m128
+ x86_xArgM1428byte // arg m14/28byte
+ x86_xArgM16 // arg m16
+ x86_xArgM16and16 // arg m16&16
+ x86_xArgM16and32 // arg m16&32
+ x86_xArgM16and64 // arg m16&64
+ x86_xArgM16colon16 // arg m16:16
+ x86_xArgM16colon32 // arg m16:32
+ x86_xArgM16colon64 // arg m16:64
+ x86_xArgM16int // arg m16int
+ x86_xArgM2byte // arg m2byte
+ x86_xArgM32 // arg m32
+ x86_xArgM32and32 // arg m32&32
+ x86_xArgM32fp // arg m32fp
+ x86_xArgM32int // arg m32int
+ x86_xArgM512byte // arg m512byte
+ x86_xArgM64 // arg m64
+ x86_xArgM64fp // arg m64fp
+ x86_xArgM64int // arg m64int
+ x86_xArgM8 // arg m8
+ x86_xArgM80bcd // arg m80bcd
+ x86_xArgM80dec // arg m80dec
+ x86_xArgM80fp // arg m80fp
+ x86_xArgM94108byte // arg m94/108byte
+ x86_xArgMm // arg mm
+ x86_xArgMm1 // arg mm1
+ x86_xArgMm2 // arg mm2
+ x86_xArgMm2M64 // arg mm2/m64
+ x86_xArgMmM32 // arg mm/m32
+ x86_xArgMmM64 // arg mm/m64
+ x86_xArgMem // arg mem
+ x86_xArgMoffs16 // arg moffs16
+ x86_xArgMoffs32 // arg moffs32
+ x86_xArgMoffs64 // arg moffs64
+ x86_xArgMoffs8 // arg moffs8
+ x86_xArgPtr16colon16 // arg ptr16:16
+ x86_xArgPtr16colon32 // arg ptr16:32
+ x86_xArgR16 // arg r16
+ x86_xArgR16op // arg r16 with +rw in opcode
+ x86_xArgR32 // arg r32
+ x86_xArgR32M16 // arg r32/m16
+ x86_xArgR32M8 // arg r32/m8
+ x86_xArgR32op // arg r32 with +rd in opcode
+ x86_xArgR64 // arg r64
+ x86_xArgR64M16 // arg r64/m16
+ x86_xArgR64op // arg r64 with +rd in opcode
+ x86_xArgR8 // arg r8
+ x86_xArgR8op // arg r8 with +rb in opcode
+ x86_xArgRAX // arg RAX
+ x86_xArgRDX // arg RDX
+ x86_xArgRM // arg r/m
+ x86_xArgRM16 // arg r/m16
+ x86_xArgRM32 // arg r/m32
+ x86_xArgRM64 // arg r/m64
+ x86_xArgRM8 // arg r/m8
+ x86_xArgReg // arg reg
+ x86_xArgRegM16 // arg reg/m16
+ x86_xArgRegM32 // arg reg/m32
+ x86_xArgRegM8 // arg reg/m8
+ x86_xArgRel16 // arg rel16
+ x86_xArgRel32 // arg rel32
+ x86_xArgRel8 // arg rel8
+ x86_xArgSS // arg SS
+ x86_xArgST // arg ST, aka ST(0)
+ x86_xArgSTi // arg ST(i) with +i in opcode
+ x86_xArgSreg // arg Sreg
+ x86_xArgTR0dashTR7 // arg TR0-TR7
+ x86_xArgXmm // arg xmm
+ x86_xArgXMM0 // arg <XMM0>
+ x86_xArgXmm1 // arg xmm1
+ x86_xArgXmm2 // arg xmm2
+ x86_xArgXmm2M128 // arg xmm2/m128
+ x86_xArgXmm2M16 // arg xmm2/m16
+ x86_xArgXmm2M32 // arg xmm2/m32
+ x86_xArgXmm2M64 // arg xmm2/m64
+ x86_xArgXmmM128 // arg xmm/m128
+ x86_xArgXmmM32 // arg xmm/m32
+ x86_xArgXmmM64 // arg xmm/m64
+ x86_xArgRmf16 // arg r/m16 but force mod=3
+ x86_xArgRmf32 // arg r/m32 but force mod=3
+ x86_xArgRmf64 // arg r/m64 but force mod=3
+)
+
+// instPrefix returns an Inst describing just one prefix byte.
+// It is only used if there is a prefix followed by an unintelligible
+// or invalid instruction byte sequence.
+func x86_instPrefix(b byte, mode int) (x86_Inst, error) {
+ // When tracing it is useful to see what called instPrefix to report an error.
+ if x86_trace {
+ _, file, line, _ := runtime.Caller(1)
+ fmt.Printf("%s:%d\n", file, line)
+ }
+ p := x86_Prefix(b)
+ switch p {
+ case x86_PrefixDataSize:
+ if mode == 16 {
+ p = x86_PrefixData32
+ } else {
+ p = x86_PrefixData16
+ }
+ case x86_PrefixAddrSize:
+ if mode == 32 {
+ p = x86_PrefixAddr16
+ } else {
+ p = x86_PrefixAddr32
+ }
+ }
+ // Note: using composite literal with Prefix key confuses 'bundle' tool.
+ inst := x86_Inst{Len: 1}
+ inst.Prefix = x86_Prefixes{p}
+ return inst, nil
+}
+
+// truncated reports a truncated instruction.
+// For now we use instPrefix but perhaps later we will return
+// a specific error here.
+func x86_truncated(src []byte, mode int) (x86_Inst, error) {
+ // return Inst{}, len(src), ErrTruncated
+ return x86_instPrefix(src[0], mode) // too long
+}
+
+// These are the errors returned by Decode.
+var (
+ x86_ErrInvalidMode = errors.New("invalid x86 mode in Decode")
+ x86_ErrTruncated = errors.New("truncated instruction")
+ x86_ErrUnrecognized = errors.New("unrecognized instruction")
+)
+
+// decoderCover records coverage information for which parts
+// of the byte code have been executed.
+// TODO(rsc): This is for testing. Only use this if a flag is given.
+var x86_decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction.
+// The mode arguments specifies the assumed processor mode:
+// 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
+func x86_Decode(src []byte, mode int) (inst x86_Inst, err error) {
+ return x86_decode1(src, mode, false)
+}
+
+// decode1 is the implementation of Decode but takes an extra
+// gnuCompat flag to cause it to change its behavior to mimic
+// bugs (or at least unique features) of GNU libopcodes as used
+// by objdump. We don't believe that logic is the right thing to do
+// in general, but when testing against libopcodes it simplifies the
+// comparison if we adjust a few small pieces of logic.
+// The affected logic is in the conditional branch for "mandatory" prefixes,
+// case xCondPrefix.
+func x86_decode1(src []byte, mode int, gnuCompat bool) (x86_Inst, error) {
+ switch mode {
+ case 16, 32, 64:
+ // ok
+ // TODO(rsc): 64-bit mode not tested, probably not working.
+ default:
+ return x86_Inst{}, x86_ErrInvalidMode
+ }
+
+ // Maximum instruction size is 15 bytes.
+ // If we need to read more, return 'truncated instruction.
+ if len(src) > 15 {
+ src = src[:15]
+ }
+
+ var (
+ // prefix decoding information
+ pos = 0 // position reading src
+ nprefix = 0 // number of prefixes
+ lockIndex = -1 // index of LOCK prefix in src and inst.Prefix
+ repIndex = -1 // index of REP/REPN prefix in src and inst.Prefix
+ segIndex = -1 // index of Group 2 prefix in src and inst.Prefix
+ dataSizeIndex = -1 // index of Group 3 prefix in src and inst.Prefix
+ addrSizeIndex = -1 // index of Group 4 prefix in src and inst.Prefix
+ rex x86_Prefix // rex byte if present (or 0)
+ rexUsed x86_Prefix // bits used in rex byte
+ rexIndex = -1 // index of rex byte
+
+ addrMode = mode // address mode (width in bits)
+ dataMode = mode // operand mode (width in bits)
+
+ // decoded ModR/M fields
+ haveModrm bool
+ modrm int
+ mod int
+ regop int
+ rm int
+
+ // if ModR/M is memory reference, Mem form
+ mem x86_Mem
+ haveMem bool
+
+ // decoded SIB fields
+ haveSIB bool
+ sib int
+ scale int
+ index int
+ base int
+
+ // decoded immediate values
+ imm int64
+ imm8 int8
+ immc int64
+
+ // output
+ opshift int
+ inst x86_Inst
+ narg int // number of arguments written to inst
+ )
+
+ if mode == 64 {
+ dataMode = 32
+ }
+
+ // Prefixes are certainly the most complex and underspecified part of
+ // decoding x86 instructions. Although the manuals say things like
+ // up to four prefixes, one from each group, nearly everyone seems to
+ // agree that in practice as many prefixes as possible, including multiple
+ // from a particular group or repetitions of a given prefix, can be used on
+ // an instruction, provided the total instruction length including prefixes
+ // does not exceed the agreed-upon maximum of 15 bytes.
+ // Everyone also agrees that if one of these prefixes is the LOCK prefix
+ // and the instruction is not one of the instructions that can be used with
+ // the LOCK prefix or if the destination is not a memory operand,
+ // then the instruction is invalid and produces the #UD exception.
+ // However, that is the end of any semblance of agreement.
+ //
+ // What happens if prefixes are given that conflict with other prefixes?
+ // For example, the memory segment overrides CS, DS, ES, FS, GS, SS
+ // conflict with each other: only one segment can be in effect.
+ // Disassemblers seem to agree that later prefixes take priority over
+ // earlier ones. I have not taken the time to write assembly programs
+ // to check to see if the hardware agrees.
+ //
+ // What happens if prefixes are given that have no meaning for the
+ // specific instruction to which they are attached? It depends.
+ // If they really have no meaning, they are ignored. However, a future
+ // processor may assign a different meaning. As a disassembler, we
+ // don't really know whether we're seeing a meaningless prefix or one
+ // whose meaning we simply haven't been told yet.
+ //
+ // Combining the two questions, what happens when conflicting
+ // extension prefixes are given? No one seems to know for sure.
+ // For example, MOVQ is 66 0F D6 /r, MOVDQ2Q is F2 0F D6 /r,
+ // and MOVQ2DQ is F3 0F D6 /r. What is '66 F2 F3 0F D6 /r'?
+ // Which prefix wins? See the xCondPrefix prefix for more.
+ //
+ // Writing assembly test cases to divine which interpretation the
+ // CPU uses might clarify the situation, but more likely it would
+ // make the situation even less clear.
+
+ // Read non-REX prefixes.
+ReadPrefixes:
+ for ; pos < len(src); pos++ {
+ p := x86_Prefix(src[pos])
+ switch p {
+ default:
+ nprefix = pos
+ break ReadPrefixes
+
+ // Group 1 - lock and repeat prefixes
+ // According to Intel, there should only be one from this set,
+ // but according to AMD both can be present.
+ case 0xF0:
+ if lockIndex >= 0 {
+ inst.Prefix[lockIndex] |= x86_PrefixIgnored
+ }
+ lockIndex = pos
+ case 0xF2, 0xF3:
+ if repIndex >= 0 {
+ inst.Prefix[repIndex] |= x86_PrefixIgnored
+ }
+ repIndex = pos
+
+ // Group 2 - segment override / branch hints
+ case 0x26, 0x2E, 0x36, 0x3E:
+ if mode == 64 {
+ p |= x86_PrefixIgnored
+ break
+ }
+ fallthrough
+ case 0x64, 0x65:
+ if segIndex >= 0 {
+ inst.Prefix[segIndex] |= x86_PrefixIgnored
+ }
+ segIndex = pos
+
+ // Group 3 - operand size override
+ case 0x66:
+ if mode == 16 {
+ dataMode = 32
+ p = x86_PrefixData32
+ } else {
+ dataMode = 16
+ p = x86_PrefixData16
+ }
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] |= x86_PrefixIgnored
+ }
+ dataSizeIndex = pos
+
+ // Group 4 - address size override
+ case 0x67:
+ if mode == 32 {
+ addrMode = 16
+ p = x86_PrefixAddr16
+ } else {
+ addrMode = 32
+ p = x86_PrefixAddr32
+ }
+ if addrSizeIndex >= 0 {
+ inst.Prefix[addrSizeIndex] |= x86_PrefixIgnored
+ }
+ addrSizeIndex = pos
+ }
+
+ if pos >= len(inst.Prefix) {
+ return x86_instPrefix(src[0], mode) // too long
+ }
+
+ inst.Prefix[pos] = p
+ }
+
+ // Read REX prefix.
+ if pos < len(src) && mode == 64 && x86_Prefix(src[pos]).IsREX() {
+ rex = x86_Prefix(src[pos])
+ rexIndex = pos
+ if pos >= len(inst.Prefix) {
+ return x86_instPrefix(src[0], mode) // too long
+ }
+ inst.Prefix[pos] = rex
+ pos++
+ if rex&x86_PrefixREXW != 0 {
+ dataMode = 64
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] |= x86_PrefixIgnored
+ }
+ }
+ }
+
+ // Decode instruction stream, interpreting decoding instructions.
+ // opshift gives the shift to use when saving the next
+ // opcode byte into inst.Opcode.
+ opshift = 24
+ if x86_decoderCover == nil {
+ x86_decoderCover = make([]bool, len(x86_decoder))
+ }
+
+ // Decode loop, executing decoder program.
+ var oldPC, prevPC int
+Decode:
+ for pc := 1; ; { // TODO uint
+ oldPC = prevPC
+ prevPC = pc
+ if x86_trace {
+ println("run", pc)
+ }
+ x := x86_decoder[pc]
+ x86_decoderCover[pc] = true
+ pc++
+
+ // Read and decode ModR/M if needed by opcode.
+ switch x86_decodeOp(x) {
+ case x86_xCondSlashR, x86_xReadSlashR:
+ if haveModrm {
+ return x86_Inst{Len: pos}, x86_errInternal
+ }
+ haveModrm = true
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ modrm = int(src[pos])
+ pos++
+ if opshift >= 0 {
+ inst.Opcode |= uint32(modrm) << uint(opshift)
+ opshift -= 8
+ }
+ mod = modrm >> 6
+ regop = (modrm >> 3) & 07
+ rm = modrm & 07
+ if rex&x86_PrefixREXR != 0 {
+ rexUsed |= x86_PrefixREXR
+ regop |= 8
+ }
+ if addrMode == 16 {
+ // 16-bit modrm form
+ if mod != 3 {
+ haveMem = true
+ mem = x86_addr16[rm]
+ if rm == 6 && mod == 0 {
+ mem.Base = 0
+ }
+
+ // Consume disp16 if present.
+ if mod == 0 && rm == 6 || mod == 2 {
+ if pos+2 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ mem.Disp = int64(binary.LittleEndian.Uint16(src[pos:]))
+ pos += 2
+ }
+
+ // Consume disp8 if present.
+ if mod == 1 {
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ mem.Disp = int64(int8(src[pos]))
+ pos++
+ }
+ }
+ } else {
+ haveMem = mod != 3
+
+ // 32-bit or 64-bit form
+ // Consume SIB encoding if present.
+ if rm == 4 && mod != 3 {
+ haveSIB = true
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ sib = int(src[pos])
+ pos++
+ if opshift >= 0 {
+ inst.Opcode |= uint32(sib) << uint(opshift)
+ opshift -= 8
+ }
+ scale = sib >> 6
+ index = (sib >> 3) & 07
+ base = sib & 07
+ if rex&x86_PrefixREXB != 0 {
+ rexUsed |= x86_PrefixREXB
+ base |= 8
+ }
+ if rex&x86_PrefixREXX != 0 {
+ rexUsed |= x86_PrefixREXX
+ index |= 8
+ }
+
+ mem.Scale = 1 << uint(scale)
+ if index == 4 {
+ // no mem.Index
+ } else {
+ mem.Index = x86_baseRegForBits(addrMode) + x86_Reg(index)
+ }
+ if base&7 == 5 && mod == 0 {
+ // no mem.Base
+ } else {
+ mem.Base = x86_baseRegForBits(addrMode) + x86_Reg(base)
+ }
+ } else {
+ if rex&x86_PrefixREXB != 0 {
+ rexUsed |= x86_PrefixREXB
+ rm |= 8
+ }
+ if mod == 0 && rm&7 == 5 || rm&7 == 4 {
+ // base omitted
+ } else if mod != 3 {
+ mem.Base = x86_baseRegForBits(addrMode) + x86_Reg(rm)
+ }
+ }
+
+ // Consume disp32 if present.
+ if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 {
+ if pos+4 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:]))
+ pos += 4
+ }
+
+ // Consume disp8 if present.
+ if mod == 1 {
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ mem.Disp = int64(int8(src[pos]))
+ pos++
+ }
+
+ // In 64-bit, mod=0 rm=5 is PC-relative instead of just disp.
+ // See Vol 2A. Table 2-7.
+ if mode == 64 && mod == 0 && rm&7 == 5 {
+ if addrMode == 32 {
+ mem.Base = x86_EIP
+ } else {
+ mem.Base = x86_RIP
+ }
+ }
+ }
+
+ if segIndex >= 0 {
+ mem.Segment = x86_prefixToSegment(inst.Prefix[segIndex])
+ }
+ }
+
+ // Execute single opcode.
+ switch x86_decodeOp(x) {
+ default:
+ println("bad op", x, "at", pc-1, "from", oldPC)
+ return x86_Inst{Len: pos}, x86_errInternal
+
+ case x86_xFail:
+ inst.Op = 0
+ break Decode
+
+ case x86_xMatch:
+ break Decode
+
+ case x86_xJump:
+ pc = int(x86_decoder[pc])
+
+ // Conditional branches.
+
+ case x86_xCondByte:
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ b := src[pos]
+ n := int(x86_decoder[pc])
+ pc++
+ for i := 0; i < n; i++ {
+ xb, xpc := x86_decoder[pc], int(x86_decoder[pc+1])
+ pc += 2
+ if b == byte(xb) {
+ pc = xpc
+ pos++
+ if opshift >= 0 {
+ inst.Opcode |= uint32(b) << uint(opshift)
+ opshift -= 8
+ }
+ continue Decode
+ }
+ }
+ // xCondByte is the only conditional with a fall through,
+ // so that it can be used to pick off special cases before
+ // an xCondSlash. If the fallthrough instruction is xFail,
+ // advance the position so that the decoded instruction
+ // size includes the byte we just compared against.
+ if x86_decodeOp(x86_decoder[pc]) == x86_xJump {
+ pc = int(x86_decoder[pc+1])
+ }
+ if x86_decodeOp(x86_decoder[pc]) == x86_xFail {
+ pos++
+ }
+
+ case x86_xCondIs64:
+ if mode == 64 {
+ pc = int(x86_decoder[pc+1])
+ } else {
+ pc = int(x86_decoder[pc])
+ }
+
+ case x86_xCondIsMem:
+ mem := haveMem
+ if !haveModrm {
+ if pos >= len(src) {
+ return x86_instPrefix(src[0], mode) // too long
+ }
+ mem = src[pos]>>6 != 3
+ }
+ if mem {
+ pc = int(x86_decoder[pc+1])
+ } else {
+ pc = int(x86_decoder[pc])
+ }
+
+ case x86_xCondDataSize:
+ switch dataMode {
+ case 16:
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+ }
+ pc = int(x86_decoder[pc])
+ case 32:
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+ }
+ pc = int(x86_decoder[pc+1])
+ case 64:
+ rexUsed |= x86_PrefixREXW
+ pc = int(x86_decoder[pc+2])
+ }
+
+ case x86_xCondAddrSize:
+ switch addrMode {
+ case 16:
+ if addrSizeIndex >= 0 {
+ inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+ }
+ pc = int(x86_decoder[pc])
+ case 32:
+ if addrSizeIndex >= 0 {
+ inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+ }
+ pc = int(x86_decoder[pc+1])
+ case 64:
+ pc = int(x86_decoder[pc+2])
+ }
+
+ case x86_xCondPrefix:
+ // Conditional branch based on presence or absence of prefixes.
+ // The conflict cases here are completely undocumented and
+ // differ significantly between GNU libopcodes and Intel xed.
+ // I have not written assembly code to divine what various CPUs
+ // do, but it wouldn't surprise me if they are not consistent either.
+ //
+ // The basic idea is to switch on the presence of a prefix, so that
+ // for example:
+ //
+ // xCondPrefix, 4
+ // 0xF3, 123,
+ // 0xF2, 234,
+ // 0x66, 345,
+ // 0, 456
+ //
+ // branch to 123 if the F3 prefix is present, 234 if the F2 prefix
+ // is present, 66 if the 345 prefix is present, and 456 otherwise.
+ // The prefixes are given in descending order so that the 0 will be last.
+ //
+ // It is unclear what should happen if multiple conditions are
+ // satisfied: what if F2 and F3 are both present, or if 66 and F2
+ // are present, or if all three are present? The one chosen becomes
+ // part of the opcode and the others do not. Perhaps the answer
+ // depends on the specific opcodes in question.
+ //
+ // The only clear example is that CRC32 is F2 0F 38 F1 /r, and
+ // it comes in 16-bit and 32-bit forms based on the 66 prefix,
+ // so 66 F2 0F 38 F1 /r should be treated as F2 taking priority,
+ // with the 66 being only an operand size override, and probably
+ // F2 66 0F 38 F1 /r should be treated the same.
+ // Perhaps that rule is specific to the case of CRC32, since no
+ // 66 0F 38 F1 instruction is defined (today) (that we know of).
+ // However, both libopcodes and xed seem to generalize this
+ // example and choose F2/F3 in preference to 66, and we
+ // do the same.
+ //
+ // Next, what if both F2 and F3 are present? Which wins?
+ // The Intel xed rule, and ours, is that the one that occurs last wins.
+ // The GNU libopcodes rule, which we implement only in gnuCompat mode,
+ // is that F3 beats F2 unless F3 has no special meaning, in which
+ // case F3 can be a modified on an F2 special meaning.
+ //
+ // Concretely,
+ // 66 0F D6 /r is MOVQ
+ // F2 0F D6 /r is MOVDQ2Q
+ // F3 0F D6 /r is MOVQ2DQ.
+ //
+ // F2 66 0F D6 /r is 66 + MOVDQ2Q always.
+ // 66 F2 0F D6 /r is 66 + MOVDQ2Q always.
+ // F3 66 0F D6 /r is 66 + MOVQ2DQ always.
+ // 66 F3 0F D6 /r is 66 + MOVQ2DQ always.
+ // F2 F3 0F D6 /r is F2 + MOVQ2DQ always.
+ // F3 F2 0F D6 /r is F3 + MOVQ2DQ in Intel xed, but F2 + MOVQ2DQ in GNU libopcodes.
+ // Adding 66 anywhere in the prefix section of the
+ // last two cases does not change the outcome.
+ //
+ // Finally, what if there is a variant in which 66 is a mandatory
+ // prefix rather than an operand size override, but we know of
+ // no corresponding F2/F3 form, and we see both F2/F3 and 66.
+ // Does F2/F3 still take priority, so that the result is an unknown
+ // instruction, or does the 66 take priority, so that the extended
+ // 66 instruction should be interpreted as having a REP/REPN prefix?
+ // Intel xed does the former and GNU libopcodes does the latter.
+ // We side with Intel xed, unless we are trying to match libopcodes
+ // more closely during the comparison-based test suite.
+ //
+ // In 64-bit mode REX.W is another valid prefix to test for, but
+ // there is less ambiguity about that. When present, REX.W is
+ // always the first entry in the table.
+ n := int(x86_decoder[pc])
+ pc++
+ sawF3 := false
+ for j := 0; j < n; j++ {
+ prefix := x86_Prefix(x86_decoder[pc+2*j])
+ if prefix.IsREX() {
+ rexUsed |= prefix
+ if rex&prefix == prefix {
+ pc = int(x86_decoder[pc+2*j+1])
+ continue Decode
+ }
+ continue
+ }
+ ok := false
+ if prefix == 0 {
+ ok = true
+ } else if prefix.IsREX() {
+ rexUsed |= prefix
+ if rex&prefix == prefix {
+ ok = true
+ }
+ } else {
+ if prefix == 0xF3 {
+ sawF3 = true
+ }
+ switch prefix {
+ case x86_PrefixLOCK:
+ if lockIndex >= 0 {
+ inst.Prefix[lockIndex] |= x86_PrefixImplicit
+ ok = true
+ }
+ case x86_PrefixREP, x86_PrefixREPN:
+ if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix {
+ inst.Prefix[repIndex] |= x86_PrefixImplicit
+ ok = true
+ }
+ if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || x86_decoder[pc+2*(j+1)] != 0xF2) {
+ // Check to see if earlier prefix F3 is present.
+ for i := repIndex - 1; i >= 0; i-- {
+ if inst.Prefix[i]&0xFF == prefix {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ ok = true
+ }
+ }
+ }
+ if gnuCompat && !ok && prefix == 0xF2 && repIndex >= 0 && !sawF3 && inst.Prefix[repIndex]&0xFF == 0xF3 {
+ // Check to see if earlier prefix F2 is present.
+ for i := repIndex - 1; i >= 0; i-- {
+ if inst.Prefix[i]&0xFF == prefix {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ ok = true
+ }
+ }
+ }
+ case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+ if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix {
+ inst.Prefix[segIndex] |= x86_PrefixImplicit
+ ok = true
+ }
+ case x86_PrefixDataSize:
+ // Looking for 66 mandatory prefix.
+ // The F2/F3 mandatory prefixes take priority when both are present.
+ // If we got this far in the xCondPrefix table and an F2/F3 is present,
+ // it means the table didn't have any entry for that prefix. But if 66 has
+ // special meaning, perhaps F2/F3 have special meaning that we don't know.
+ // Intel xed works this way, treating the F2/F3 as inhibiting the 66.
+ // GNU libopcodes allows the 66 to match. We do what Intel xed does
+ // except in gnuCompat mode.
+ if repIndex >= 0 && !gnuCompat {
+ inst.Op = 0
+ break Decode
+ }
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+ ok = true
+ }
+ case x86_PrefixAddrSize:
+ if addrSizeIndex >= 0 {
+ inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+ ok = true
+ }
+ }
+ }
+ if ok {
+ pc = int(x86_decoder[pc+2*j+1])
+ continue Decode
+ }
+ }
+ inst.Op = 0
+ break Decode
+
+ case x86_xCondSlashR:
+ pc = int(x86_decoder[pc+regop&7])
+
+ // Input.
+
+ case x86_xReadSlashR:
+ // done above
+
+ case x86_xReadIb:
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ imm8 = int8(src[pos])
+ pos++
+
+ case x86_xReadIw:
+ if pos+2 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ imm = int64(binary.LittleEndian.Uint16(src[pos:]))
+ pos += 2
+
+ case x86_xReadId:
+ if pos+4 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ imm = int64(binary.LittleEndian.Uint32(src[pos:]))
+ pos += 4
+
+ case x86_xReadIo:
+ if pos+8 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ imm = int64(binary.LittleEndian.Uint64(src[pos:]))
+ pos += 8
+
+ case x86_xReadCb:
+ if pos >= len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(src[pos])
+ pos++
+
+ case x86_xReadCw:
+ if pos+2 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+ pos += 2
+
+ case x86_xReadCm:
+ if addrMode == 16 {
+ if pos+2 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+ pos += 2
+ } else if addrMode == 32 {
+ if pos+4 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+ pos += 4
+ } else {
+ if pos+8 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(binary.LittleEndian.Uint64(src[pos:]))
+ pos += 8
+ }
+ case x86_xReadCd:
+ if pos+4 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+ pos += 4
+
+ case x86_xReadCp:
+ if pos+6 > len(src) {
+ return x86_truncated(src, mode)
+ }
+ w := binary.LittleEndian.Uint32(src[pos:])
+ w2 := binary.LittleEndian.Uint16(src[pos+4:])
+ immc = int64(w2)<<32 | int64(w)
+ pos += 6
+
+ // Output.
+
+ case x86_xSetOp:
+ inst.Op = x86_Op(x86_decoder[pc])
+ pc++
+
+ case x86_xArg1,
+ x86_xArg3,
+ x86_xArgAL,
+ x86_xArgAX,
+ x86_xArgCL,
+ x86_xArgCS,
+ x86_xArgDS,
+ x86_xArgDX,
+ x86_xArgEAX,
+ x86_xArgEDX,
+ x86_xArgES,
+ x86_xArgFS,
+ x86_xArgGS,
+ x86_xArgRAX,
+ x86_xArgRDX,
+ x86_xArgSS,
+ x86_xArgST,
+ x86_xArgXMM0:
+ inst.Args[narg] = x86_fixedArg[x]
+ narg++
+
+ case x86_xArgImm8:
+ inst.Args[narg] = x86_Imm(imm8)
+ narg++
+
+ case x86_xArgImm8u:
+ inst.Args[narg] = x86_Imm(uint8(imm8))
+ narg++
+
+ case x86_xArgImm16:
+ inst.Args[narg] = x86_Imm(int16(imm))
+ narg++
+
+ case x86_xArgImm16u:
+ inst.Args[narg] = x86_Imm(uint16(imm))
+ narg++
+
+ case x86_xArgImm32:
+ inst.Args[narg] = x86_Imm(int32(imm))
+ narg++
+
+ case x86_xArgImm64:
+ inst.Args[narg] = x86_Imm(imm)
+ narg++
+
+ case x86_xArgM,
+ x86_xArgM128,
+ x86_xArgM1428byte,
+ x86_xArgM16,
+ x86_xArgM16and16,
+ x86_xArgM16and32,
+ x86_xArgM16and64,
+ x86_xArgM16colon16,
+ x86_xArgM16colon32,
+ x86_xArgM16colon64,
+ x86_xArgM16int,
+ x86_xArgM2byte,
+ x86_xArgM32,
+ x86_xArgM32and32,
+ x86_xArgM32fp,
+ x86_xArgM32int,
+ x86_xArgM512byte,
+ x86_xArgM64,
+ x86_xArgM64fp,
+ x86_xArgM64int,
+ x86_xArgM8,
+ x86_xArgM80bcd,
+ x86_xArgM80dec,
+ x86_xArgM80fp,
+ x86_xArgM94108byte,
+ x86_xArgMem:
+ if !haveMem {
+ inst.Op = 0
+ break Decode
+ }
+ inst.Args[narg] = mem
+ inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+ narg++
+
+ case x86_xArgPtr16colon16:
+ inst.Args[narg] = x86_Imm(immc >> 16)
+ inst.Args[narg+1] = x86_Imm(immc & (1<<16 - 1))
+ narg += 2
+
+ case x86_xArgPtr16colon32:
+ inst.Args[narg] = x86_Imm(immc >> 32)
+ inst.Args[narg+1] = x86_Imm(immc & (1<<32 - 1))
+ narg += 2
+
+ case x86_xArgMoffs8, x86_xArgMoffs16, x86_xArgMoffs32, x86_xArgMoffs64:
+ // TODO(rsc): Can address be 64 bits?
+ mem = x86_Mem{Disp: int64(immc)}
+ if segIndex >= 0 {
+ mem.Segment = x86_prefixToSegment(inst.Prefix[segIndex])
+ inst.Prefix[segIndex] |= x86_PrefixImplicit
+ }
+ inst.Args[narg] = mem
+ inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+ narg++
+
+ case x86_xArgR8, x86_xArgR16, x86_xArgR32, x86_xArgR64, x86_xArgXmm, x86_xArgXmm1, x86_xArgDR0dashDR7:
+ base := x86_baseReg[x]
+ index := x86_Reg(regop)
+ if rex != 0 && base == x86_AL && index >= 4 {
+ rexUsed |= x86_PrefixREX
+ index -= 4
+ base = x86_SPB
+ }
+ inst.Args[narg] = base + index
+ narg++
+
+ case x86_xArgMm, x86_xArgMm1, x86_xArgTR0dashTR7:
+ inst.Args[narg] = x86_baseReg[x] + x86_Reg(regop&7)
+ narg++
+
+ case x86_xArgCR0dashCR7:
+ // AMD documents an extension that the LOCK prefix
+ // can be used in place of a REX prefix in order to access
+ // CR8 from 32-bit mode. The LOCK prefix is allowed in
+ // all modes, provided the corresponding CPUID bit is set.
+ if lockIndex >= 0 {
+ inst.Prefix[lockIndex] |= x86_PrefixImplicit
+ regop += 8
+ }
+ inst.Args[narg] = x86_CR0 + x86_Reg(regop)
+ narg++
+
+ case x86_xArgSreg:
+ regop &= 7
+ if regop >= 6 {
+ inst.Op = 0
+ break Decode
+ }
+ inst.Args[narg] = x86_ES + x86_Reg(regop)
+ narg++
+
+ case x86_xArgRmf16, x86_xArgRmf32, x86_xArgRmf64:
+ base := x86_baseReg[x]
+ index := x86_Reg(modrm & 07)
+ if rex&x86_PrefixREXB != 0 {
+ rexUsed |= x86_PrefixREXB
+ index += 8
+ }
+ inst.Args[narg] = base + index
+ narg++
+
+ case x86_xArgR8op, x86_xArgR16op, x86_xArgR32op, x86_xArgR64op, x86_xArgSTi:
+ n := inst.Opcode >> uint(opshift+8) & 07
+ base := x86_baseReg[x]
+ index := x86_Reg(n)
+ if rex&x86_PrefixREXB != 0 && x86_decodeOp(x) != x86_xArgSTi {
+ rexUsed |= x86_PrefixREXB
+ index += 8
+ }
+ if rex != 0 && base == x86_AL && index >= 4 {
+ rexUsed |= x86_PrefixREX
+ index -= 4
+ base = x86_SPB
+ }
+ inst.Args[narg] = base + index
+ narg++
+
+ case x86_xArgRM8, x86_xArgRM16, x86_xArgRM32, x86_xArgRM64, x86_xArgR32M16, x86_xArgR32M8, x86_xArgR64M16,
+ x86_xArgMmM32, x86_xArgMmM64, x86_xArgMm2M64,
+ x86_xArgXmm2M16, x86_xArgXmm2M32, x86_xArgXmm2M64, x86_xArgXmmM64, x86_xArgXmmM128, x86_xArgXmmM32, x86_xArgXmm2M128:
+ if haveMem {
+ inst.Args[narg] = mem
+ inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+ } else {
+ base := x86_baseReg[x]
+ index := x86_Reg(rm)
+ switch x86_decodeOp(x) {
+ case x86_xArgMmM32, x86_xArgMmM64, x86_xArgMm2M64:
+ // There are only 8 MMX registers, so these ignore the REX.X bit.
+ index &= 7
+ case x86_xArgRM8:
+ if rex != 0 && index >= 4 {
+ rexUsed |= x86_PrefixREX
+ index -= 4
+ base = x86_SPB
+ }
+ }
+ inst.Args[narg] = base + index
+ }
+ narg++
+
+ case x86_xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+ if haveMem {
+ inst.Op = 0
+ break Decode
+ }
+ inst.Args[narg] = x86_baseReg[x] + x86_Reg(rm&7)
+ narg++
+
+ case x86_xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+ if haveMem {
+ inst.Op = 0
+ break Decode
+ }
+ inst.Args[narg] = x86_baseReg[x] + x86_Reg(rm)
+ narg++
+
+ case x86_xArgRel8:
+ inst.Args[narg] = x86_Rel(int8(immc))
+ narg++
+
+ case x86_xArgRel16:
+ inst.Args[narg] = x86_Rel(int16(immc))
+ narg++
+
+ case x86_xArgRel32:
+ inst.Args[narg] = x86_Rel(int32(immc))
+ narg++
+ }
+ }
+
+ if inst.Op == 0 {
+ // Invalid instruction.
+ if nprefix > 0 {
+ return x86_instPrefix(src[0], mode) // invalid instruction
+ }
+ return x86_Inst{Len: pos}, x86_ErrUnrecognized
+ }
+
+ // Matched! Hooray!
+
+ // 90 decodes as XCHG EAX, EAX but is NOP.
+ // 66 90 decodes as XCHG AX, AX and is NOP too.
+ // 48 90 decodes as XCHG RAX, RAX and is NOP too.
+ // 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
+ // F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
+ // It's all too special to handle in the decoding tables, at least for now.
+ if inst.Op == x86_XCHG && inst.Opcode>>24 == 0x90 {
+ if inst.Args[0] == x86_RAX || inst.Args[0] == x86_EAX || inst.Args[0] == x86_AX {
+ inst.Op = x86_NOP
+ if dataSizeIndex >= 0 {
+ inst.Prefix[dataSizeIndex] &^= x86_PrefixImplicit
+ }
+ inst.Args[0] = nil
+ inst.Args[1] = nil
+ }
+ if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 {
+ inst.Prefix[repIndex] |= x86_PrefixImplicit
+ inst.Op = x86_PAUSE
+ inst.Args[0] = nil
+ inst.Args[1] = nil
+ } else if gnuCompat {
+ for i := nprefix - 1; i >= 0; i-- {
+ if inst.Prefix[i]&0xFF == 0xF3 {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ inst.Op = x86_PAUSE
+ inst.Args[0] = nil
+ inst.Args[1] = nil
+ break
+ }
+ }
+ }
+ }
+
+ // defaultSeg returns the default segment for an implicit
+ // memory reference: the final override if present, or else DS.
+ defaultSeg := func() x86_Reg {
+ if segIndex >= 0 {
+ inst.Prefix[segIndex] |= x86_PrefixImplicit
+ return x86_prefixToSegment(inst.Prefix[segIndex])
+ }
+ return x86_DS
+ }
+
+ // Add implicit arguments not present in the tables.
+ // Normally we shy away from making implicit arguments explicit,
+ // following the Intel manuals, but adding the arguments seems
+ // the best way to express the effect of the segment override prefixes.
+ // TODO(rsc): Perhaps add these to the tables and
+ // create bytecode instructions for them.
+ usedAddrSize := false
+ switch inst.Op {
+ case x86_INSB, x86_INSW, x86_INSD:
+ inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+ inst.Args[1] = x86_DX
+ usedAddrSize = true
+
+ case x86_OUTSB, x86_OUTSW, x86_OUTSD:
+ inst.Args[0] = x86_DX
+ inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+ usedAddrSize = true
+
+ case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ:
+ inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+ inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+ usedAddrSize = true
+
+ case x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ:
+ inst.Args[0] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+ inst.Args[1] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+ usedAddrSize = true
+
+ case x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ:
+ switch inst.Op {
+ case x86_LODSB:
+ inst.Args[0] = x86_AL
+ case x86_LODSW:
+ inst.Args[0] = x86_AX
+ case x86_LODSD:
+ inst.Args[0] = x86_EAX
+ case x86_LODSQ:
+ inst.Args[0] = x86_RAX
+ }
+ inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+ usedAddrSize = true
+
+ case x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+ inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+ switch inst.Op {
+ case x86_STOSB:
+ inst.Args[1] = x86_AL
+ case x86_STOSW:
+ inst.Args[1] = x86_AX
+ case x86_STOSD:
+ inst.Args[1] = x86_EAX
+ case x86_STOSQ:
+ inst.Args[1] = x86_RAX
+ }
+ usedAddrSize = true
+
+ case x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+ inst.Args[1] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+ switch inst.Op {
+ case x86_SCASB:
+ inst.Args[0] = x86_AL
+ case x86_SCASW:
+ inst.Args[0] = x86_AX
+ case x86_SCASD:
+ inst.Args[0] = x86_EAX
+ case x86_SCASQ:
+ inst.Args[0] = x86_RAX
+ }
+ usedAddrSize = true
+
+ case x86_XLATB:
+ inst.Args[0] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_BX - x86_AX}
+ usedAddrSize = true
+ }
+
+ // If we used the address size annotation to construct the
+ // argument list, mark that prefix as implicit: it doesn't need
+ // to be shown when printing the instruction.
+ if haveMem || usedAddrSize {
+ if addrSizeIndex >= 0 {
+ inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+ }
+ }
+
+ // Similarly, if there's some memory operand, the segment
+ // will be shown there and doesn't need to be shown as an
+ // explicit prefix.
+ if haveMem {
+ if segIndex >= 0 {
+ inst.Prefix[segIndex] |= x86_PrefixImplicit
+ }
+ }
+
+ // Branch predict prefixes are overloaded segment prefixes,
+ // since segment prefixes don't make sense on conditional jumps.
+ // Rewrite final instance to prediction prefix.
+ // The set of instructions to which the prefixes apply (other then the
+ // Jcc conditional jumps) is not 100% clear from the manuals, but
+ // the disassemblers seem to agree about the LOOP and JCXZ instructions,
+ // so we'll follow along.
+ // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+ if x86_isCondJmp[inst.Op] || x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+ PredictLoop:
+ for i := nprefix - 1; i >= 0; i-- {
+ p := inst.Prefix[i]
+ switch p & 0xFF {
+ case x86_PrefixCS:
+ inst.Prefix[i] = x86_PrefixPN
+ break PredictLoop
+ case x86_PrefixDS:
+ inst.Prefix[i] = x86_PrefixPT
+ break PredictLoop
+ }
+ }
+ }
+
+ // The BND prefix is part of the Intel Memory Protection Extensions (MPX).
+ // A REPN applied to certain control transfers is a BND prefix to bound
+ // the range of possible destinations. There's surprisingly little documentation
+ // about this, so we just do what libopcodes and xed agree on.
+ // In particular, it's unclear why a REPN applied to LOOP or JCXZ instructions
+ // does not turn into a BND.
+ // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+ if x86_isCondJmp[inst.Op] || inst.Op == x86_JMP || inst.Op == x86_CALL || inst.Op == x86_RET {
+ for i := nprefix - 1; i >= 0; i-- {
+ p := inst.Prefix[i]
+ if p&^x86_PrefixIgnored == x86_PrefixREPN {
+ inst.Prefix[i] = x86_PrefixBND
+ break
+ }
+ }
+ }
+
+ // The LOCK prefix only applies to certain instructions, and then only
+ // to instances of the instruction with a memory destination.
+ // Other uses of LOCK are invalid and cause a processor exception,
+ // in contrast to the "just ignore it" spirit applied to all other prefixes.
+ // Mark invalid lock prefixes.
+ hasLock := false
+ if lockIndex >= 0 && inst.Prefix[lockIndex]&x86_PrefixImplicit == 0 {
+ switch inst.Op {
+ // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+ case x86_ADD, x86_ADC, x86_AND, x86_BTC, x86_BTR, x86_BTS, x86_CMPXCHG, x86_CMPXCHG8B, x86_CMPXCHG16B, x86_DEC, x86_INC, x86_NEG, x86_NOT, x86_OR, x86_SBB, x86_SUB, x86_XOR, x86_XADD, x86_XCHG:
+ if x86_isMem(inst.Args[0]) {
+ hasLock = true
+ break
+ }
+ fallthrough
+ default:
+ inst.Prefix[lockIndex] |= x86_PrefixInvalid
+ }
+ }
+
+ // In certain cases, all of which require a memory destination,
+ // the REPN and REP prefixes are interpreted as XACQUIRE and XRELEASE
+ // from the Intel Transactional Synchroniation Extensions (TSX).
+ //
+ // The specific rules are:
+ // (1) Any instruction with a valid LOCK prefix can have XACQUIRE or XRELEASE.
+ // (2) Any XCHG, which always has an implicit LOCK, can have XACQUIRE or XRELEASE.
+ // (3) Any 0x88-, 0x89-, 0xC6-, or 0xC7-opcode MOV can have XRELEASE.
+ if x86_isMem(inst.Args[0]) {
+ if inst.Op == x86_XCHG {
+ hasLock = true
+ }
+
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ p := inst.Prefix[i] &^ x86_PrefixIgnored
+ switch p {
+ case x86_PrefixREPN:
+ if hasLock {
+ inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXACQUIRE
+ }
+
+ case x86_PrefixREP:
+ if hasLock {
+ inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXRELEASE
+ }
+
+ if inst.Op == x86_MOV {
+ op := (inst.Opcode >> 24) &^ 1
+ if op == 0x88 || op == 0xC6 {
+ inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXRELEASE
+ }
+ }
+ }
+ }
+ }
+
+ // If REP is used on a non-REP-able instruction, mark the prefix as ignored.
+ if repIndex >= 0 {
+ switch inst.Prefix[repIndex] {
+ case x86_PrefixREP, x86_PrefixREPN:
+ switch inst.Op {
+ // According to the manuals, the REP/REPE prefix applies to all of these,
+ // while the REPN applies only to some of them. However, both libopcodes
+ // and xed show both prefixes explicitly for all instructions, so we do the same.
+ // TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+ case x86_INSB, x86_INSW, x86_INSD,
+ x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ,
+ x86_OUTSB, x86_OUTSW, x86_OUTSD,
+ x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ,
+ x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ,
+ x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ,
+ x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+ // ok
+ default:
+ inst.Prefix[repIndex] |= x86_PrefixIgnored
+ }
+ }
+ }
+
+ // If REX was present, mark implicit if all the 1 bits were consumed.
+ if rexIndex >= 0 {
+ if rexUsed != 0 {
+ rexUsed |= x86_PrefixREX
+ }
+ if rex&^rexUsed == 0 {
+ inst.Prefix[rexIndex] |= x86_PrefixImplicit
+ }
+ }
+
+ inst.DataSize = dataMode
+ inst.AddrSize = addrMode
+ inst.Mode = mode
+ inst.Len = pos
+ return inst, nil
+}
+
+var x86_errInternal = errors.New("internal error")
+
+// addr16 records the eight 16-bit addressing modes.
+var x86_addr16 = [8]x86_Mem{
+ {Base: x86_BX, Scale: 1, Index: x86_SI},
+ {Base: x86_BX, Scale: 1, Index: x86_DI},
+ {Base: x86_BP, Scale: 1, Index: x86_SI},
+ {Base: x86_BP, Scale: 1, Index: x86_DI},
+ {Base: x86_SI},
+ {Base: x86_DI},
+ {Base: x86_BP},
+ {Base: x86_BX},
+}
+
+// baseReg returns the base register for a given register size in bits.
+func x86_baseRegForBits(bits int) x86_Reg {
+ switch bits {
+ case 8:
+ return x86_AL
+ case 16:
+ return x86_AX
+ case 32:
+ return x86_EAX
+ case 64:
+ return x86_RAX
+ }
+ return 0
+}
+
+// baseReg records the base register for argument types that specify
+// a range of registers indexed by op, regop, or rm.
+var x86_baseReg = [...]x86_Reg{
+ x86_xArgDR0dashDR7: x86_DR0,
+ x86_xArgMm1: x86_M0,
+ x86_xArgMm2: x86_M0,
+ x86_xArgMm2M64: x86_M0,
+ x86_xArgMm: x86_M0,
+ x86_xArgMmM32: x86_M0,
+ x86_xArgMmM64: x86_M0,
+ x86_xArgR16: x86_AX,
+ x86_xArgR16op: x86_AX,
+ x86_xArgR32: x86_EAX,
+ x86_xArgR32M16: x86_EAX,
+ x86_xArgR32M8: x86_EAX,
+ x86_xArgR32op: x86_EAX,
+ x86_xArgR64: x86_RAX,
+ x86_xArgR64M16: x86_RAX,
+ x86_xArgR64op: x86_RAX,
+ x86_xArgR8: x86_AL,
+ x86_xArgR8op: x86_AL,
+ x86_xArgRM16: x86_AX,
+ x86_xArgRM32: x86_EAX,
+ x86_xArgRM64: x86_RAX,
+ x86_xArgRM8: x86_AL,
+ x86_xArgRmf16: x86_AX,
+ x86_xArgRmf32: x86_EAX,
+ x86_xArgRmf64: x86_RAX,
+ x86_xArgSTi: x86_F0,
+ x86_xArgTR0dashTR7: x86_TR0,
+ x86_xArgXmm1: x86_X0,
+ x86_xArgXmm2: x86_X0,
+ x86_xArgXmm2M128: x86_X0,
+ x86_xArgXmm2M16: x86_X0,
+ x86_xArgXmm2M32: x86_X0,
+ x86_xArgXmm2M64: x86_X0,
+ x86_xArgXmm: x86_X0,
+ x86_xArgXmmM128: x86_X0,
+ x86_xArgXmmM32: x86_X0,
+ x86_xArgXmmM64: x86_X0,
+}
+
+// prefixToSegment returns the segment register
+// corresponding to a particular segment prefix.
+func x86_prefixToSegment(p x86_Prefix) x86_Reg {
+ switch p &^ x86_PrefixImplicit {
+ case x86_PrefixCS:
+ return x86_CS
+ case x86_PrefixDS:
+ return x86_DS
+ case x86_PrefixES:
+ return x86_ES
+ case x86_PrefixFS:
+ return x86_FS
+ case x86_PrefixGS:
+ return x86_GS
+ case x86_PrefixSS:
+ return x86_SS
+ }
+ return 0
+}
+
+// fixedArg records the fixed arguments corresponding to the given bytecodes.
+var x86_fixedArg = [...]x86_Arg{
+ x86_xArg1: x86_Imm(1),
+ x86_xArg3: x86_Imm(3),
+ x86_xArgAL: x86_AL,
+ x86_xArgAX: x86_AX,
+ x86_xArgDX: x86_DX,
+ x86_xArgEAX: x86_EAX,
+ x86_xArgEDX: x86_EDX,
+ x86_xArgRAX: x86_RAX,
+ x86_xArgRDX: x86_RDX,
+ x86_xArgCL: x86_CL,
+ x86_xArgCS: x86_CS,
+ x86_xArgDS: x86_DS,
+ x86_xArgES: x86_ES,
+ x86_xArgFS: x86_FS,
+ x86_xArgGS: x86_GS,
+ x86_xArgSS: x86_SS,
+ x86_xArgST: x86_F0,
+ x86_xArgXMM0: x86_X0,
+}
+
+// memBytes records the size of the memory pointed at
+// by a memory argument of the given form.
+var x86_memBytes = [...]int8{
+ x86_xArgM128: 128 / 8,
+ x86_xArgM16: 16 / 8,
+ x86_xArgM16and16: (16 + 16) / 8,
+ x86_xArgM16colon16: (16 + 16) / 8,
+ x86_xArgM16colon32: (16 + 32) / 8,
+ x86_xArgM16int: 16 / 8,
+ x86_xArgM2byte: 2,
+ x86_xArgM32: 32 / 8,
+ x86_xArgM32and32: (32 + 32) / 8,
+ x86_xArgM32fp: 32 / 8,
+ x86_xArgM32int: 32 / 8,
+ x86_xArgM64: 64 / 8,
+ x86_xArgM64fp: 64 / 8,
+ x86_xArgM64int: 64 / 8,
+ x86_xArgMm2M64: 64 / 8,
+ x86_xArgMmM32: 32 / 8,
+ x86_xArgMmM64: 64 / 8,
+ x86_xArgMoffs16: 16 / 8,
+ x86_xArgMoffs32: 32 / 8,
+ x86_xArgMoffs64: 64 / 8,
+ x86_xArgMoffs8: 8 / 8,
+ x86_xArgR32M16: 16 / 8,
+ x86_xArgR32M8: 8 / 8,
+ x86_xArgR64M16: 16 / 8,
+ x86_xArgRM16: 16 / 8,
+ x86_xArgRM32: 32 / 8,
+ x86_xArgRM64: 64 / 8,
+ x86_xArgRM8: 8 / 8,
+ x86_xArgXmm2M128: 128 / 8,
+ x86_xArgXmm2M16: 16 / 8,
+ x86_xArgXmm2M32: 32 / 8,
+ x86_xArgXmm2M64: 64 / 8,
+ x86_xArgXmm: 128 / 8,
+ x86_xArgXmmM128: 128 / 8,
+ x86_xArgXmmM32: 32 / 8,
+ x86_xArgXmmM64: 64 / 8,
+}
+
+// isCondJmp records the conditional jumps.
+var x86_isCondJmp = [x86_maxOp + 1]bool{
+ x86_JA: true,
+ x86_JAE: true,
+ x86_JB: true,
+ x86_JBE: true,
+ x86_JE: true,
+ x86_JG: true,
+ x86_JGE: true,
+ x86_JL: true,
+ x86_JLE: true,
+ x86_JNE: true,
+ x86_JNO: true,
+ x86_JNP: true,
+ x86_JNS: true,
+ x86_JO: true,
+ x86_JP: true,
+ x86_JS: true,
+}
+
+// isLoop records the loop operators.
+var x86_isLoop = [x86_maxOp + 1]bool{
+ x86_LOOP: true,
+ x86_LOOPE: true,
+ x86_LOOPNE: true,
+ x86_JECXZ: true,
+ x86_JRCXZ: true,
+}
+
+/* gnu.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
+// This general form is often called ``AT&T syntax'' as a reference to AT&T System V Unix.
+func x86_GNUSyntax(inst x86_Inst) string {
+ // Rewrite instruction to mimic GNU peculiarities.
+ // Note that inst has been passed by value and contains
+ // no pointers, so any changes we make here are local
+ // and will not propagate back out to the caller.
+
+ // Adjust opcode [sic].
+ switch inst.Op {
+ case x86_FDIV, x86_FDIVR, x86_FSUB, x86_FSUBR, x86_FDIVP, x86_FDIVRP, x86_FSUBP, x86_FSUBRP:
+ // DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
+ // if you believe the Intel manual is correct (the encoding is irregular as given;
+ // libopcodes uses the more regular expected encoding).
+ // TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
+ // NOTE: iant thinks this is deliberate, but we can't find the history.
+ _, reg1 := inst.Args[0].(x86_Reg)
+ _, reg2 := inst.Args[1].(x86_Reg)
+ if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
+ switch inst.Op {
+ case x86_FDIV:
+ inst.Op = x86_FDIVR
+ case x86_FDIVR:
+ inst.Op = x86_FDIV
+ case x86_FSUB:
+ inst.Op = x86_FSUBR
+ case x86_FSUBR:
+ inst.Op = x86_FSUB
+ case x86_FDIVP:
+ inst.Op = x86_FDIVRP
+ case x86_FDIVRP:
+ inst.Op = x86_FDIVP
+ case x86_FSUBP:
+ inst.Op = x86_FSUBRP
+ case x86_FSUBRP:
+ inst.Op = x86_FSUBP
+ }
+ }
+
+ case x86_MOVNTSD:
+ // MOVNTSD is F2 0F 2B /r.
+ // MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
+ // Usually inner prefixes win for display,
+ // so that F3 F2 0F 2B 11 is REP MOVNTSD
+ // and F2 F3 0F 2B 11 is REPN MOVNTSS.
+ // Libopcodes always prefers MOVNTSS regardless of prefix order.
+ if x86_countPrefix(&inst, 0xF3) > 0 {
+ found := false
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ switch inst.Prefix[i] & 0xFF {
+ case 0xF3:
+ if !found {
+ found = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case 0xF2:
+ inst.Prefix[i] &^= x86_PrefixImplicit
+ }
+ }
+ inst.Op = x86_MOVNTSS
+ }
+ }
+
+ // Add implicit arguments.
+ switch inst.Op {
+ case x86_MONITOR:
+ inst.Args[0] = x86_EDX
+ inst.Args[1] = x86_ECX
+ inst.Args[2] = x86_EAX
+ if inst.AddrSize == 16 {
+ inst.Args[2] = x86_AX
+ }
+
+ case x86_MWAIT:
+ if inst.Mode == 64 {
+ inst.Args[0] = x86_RCX
+ inst.Args[1] = x86_RAX
+ } else {
+ inst.Args[0] = x86_ECX
+ inst.Args[1] = x86_EAX
+ }
+ }
+
+ // Adjust which prefixes will be displayed.
+ // The rule is to display all the prefixes not implied by
+ // the usual instruction display, that is, all the prefixes
+ // except the ones with PrefixImplicit set.
+ // However, of course, there are exceptions to the rule.
+ switch inst.Op {
+ case x86_CRC32:
+ // CRC32 has a mandatory F2 prefix.
+ // If there are multiple F2s and no F3s, the extra F2s do not print.
+ // (And Decode has already marked them implicit.)
+ // However, if there is an F3 anywhere, then the extra F2s do print.
+ // If there are multiple F2 prefixes *and* an (ignored) F3,
+ // then libopcodes prints the extra F2s as REPNs.
+ if x86_countPrefix(&inst, 0xF2) > 1 {
+ x86_unmarkImplicit(&inst, 0xF2)
+ x86_markLastImplicit(&inst, 0xF2)
+ }
+
+ // An unused data size override should probably be shown,
+ // to distinguish DATA16 CRC32B from plain CRC32B,
+ // but libopcodes always treats the final override as implicit
+ // and the others as explicit.
+ x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+ x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+ case x86_CVTSI2SD, x86_CVTSI2SS:
+ if !x86_isMem(inst.Args[1]) {
+ x86_markLastImplicit(&inst, x86_PrefixDataSize)
+ }
+
+ case x86_CVTSD2SI, x86_CVTSS2SI, x86_CVTTSD2SI, x86_CVTTSS2SI,
+ x86_ENTER, x86_FLDENV, x86_FNSAVE, x86_FNSTENV, x86_FRSTOR, x86_LGDT, x86_LIDT, x86_LRET,
+ x86_POP, x86_PUSH, x86_RET, x86_SGDT, x86_SIDT, x86_SYSRET, x86_XBEGIN:
+ x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+ case x86_LOOP, x86_LOOPE, x86_LOOPNE, x86_MONITOR:
+ x86_markLastImplicit(&inst, x86_PrefixAddrSize)
+
+ case x86_MOV:
+ // The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
+ // cannot be distinguished when src or dst refers to memory, because
+ // Sreg is always a 16-bit value, even when we're doing a 32-bit
+ // instruction. Because the instruction tables distinguished these two,
+ // any operand size prefix has been marked as used (to decide which
+ // branch to take). Unmark it, so that it will show up in disassembly,
+ // so that the reader can tell the size of memory operand.
+ // up with the same arguments
+ dst, _ := inst.Args[0].(x86_Reg)
+ src, _ := inst.Args[1].(x86_Reg)
+ if x86_ES <= src && src <= x86_GS && x86_isMem(inst.Args[0]) || x86_ES <= dst && dst <= x86_GS && x86_isMem(inst.Args[1]) {
+ x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+ }
+
+ case x86_MOVDQU:
+ if x86_countPrefix(&inst, 0xF3) > 1 {
+ x86_unmarkImplicit(&inst, 0xF3)
+ x86_markLastImplicit(&inst, 0xF3)
+ }
+
+ case x86_MOVQ2DQ:
+ x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+ case x86_SLDT, x86_SMSW, x86_STR, x86_FXRSTOR, x86_XRSTOR, x86_XSAVE, x86_XSAVEOPT, x86_CMPXCHG8B:
+ if x86_isMem(inst.Args[0]) {
+ x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+ }
+
+ case x86_SYSEXIT:
+ x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+ }
+
+ if x86_isCondJmp[inst.Op] || x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+ if x86_countPrefix(&inst, x86_PrefixCS) > 0 && x86_countPrefix(&inst, x86_PrefixDS) > 0 {
+ for i, p := range inst.Prefix {
+ switch p & 0xFFF {
+ case x86_PrefixPN, x86_PrefixPT:
+ inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
+ }
+ }
+ }
+ }
+
+ // XACQUIRE/XRELEASE adjustment.
+ if inst.Op == x86_MOV {
+ // MOV into memory is a candidate for turning REP into XRELEASE.
+ // However, if the REP is followed by a REPN, that REPN blocks the
+ // conversion.
+ haveREPN := false
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ switch inst.Prefix[i] &^ x86_PrefixIgnored {
+ case x86_PrefixREPN:
+ haveREPN = true
+ case x86_PrefixXRELEASE:
+ if haveREPN {
+ inst.Prefix[i] = x86_PrefixREP
+ }
+ }
+ }
+ }
+
+ // We only format the final F2/F3 as XRELEASE/XACQUIRE.
+ haveXA := false
+ haveXR := false
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ switch inst.Prefix[i] &^ x86_PrefixIgnored {
+ case x86_PrefixXRELEASE:
+ if !haveXR {
+ haveXR = true
+ } else {
+ inst.Prefix[i] = x86_PrefixREP
+ }
+
+ case x86_PrefixXACQUIRE:
+ if !haveXA {
+ haveXA = true
+ } else {
+ inst.Prefix[i] = x86_PrefixREPN
+ }
+ }
+ }
+
+ // Determine opcode.
+ op := strings.ToLower(inst.Op.String())
+ if alt := x86_gnuOp[inst.Op]; alt != "" {
+ op = alt
+ }
+
+ // Determine opcode suffix.
+ // Libopcodes omits the suffix if the width of the operation
+ // can be inferred from a register arguments. For example,
+ // add $1, %ebx has no suffix because you can tell from the
+ // 32-bit register destination that it is a 32-bit add,
+ // but in addl $1, (%ebx), the destination is memory, so the
+ // size is not evident without the l suffix.
+ needSuffix := true
+SuffixLoop:
+ for i, a := range inst.Args {
+ if a == nil {
+ break
+ }
+ switch a := a.(type) {
+ case x86_Reg:
+ switch inst.Op {
+ case x86_MOVSX, x86_MOVZX:
+ continue
+
+ case x86_SHL, x86_SHR, x86_RCL, x86_RCR, x86_ROL, x86_ROR, x86_SAR:
+ if i == 1 {
+ // shift count does not tell us operand size
+ continue
+ }
+
+ case x86_CRC32:
+ // The source argument does tell us operand size,
+ // but libopcodes still always puts a suffix on crc32.
+ continue
+
+ case x86_PUSH, x86_POP:
+ // Even though segment registers are 16-bit, push and pop
+ // can save/restore them from 32-bit slots, so they
+ // do not imply operand size.
+ if x86_ES <= a && a <= x86_GS {
+ continue
+ }
+
+ case x86_CVTSI2SD, x86_CVTSI2SS:
+ // The integer register argument takes priority.
+ if x86_X0 <= a && a <= x86_X15 {
+ continue
+ }
+ }
+
+ if x86_AL <= a && a <= x86_R15 || x86_ES <= a && a <= x86_GS || x86_X0 <= a && a <= x86_X15 || x86_M0 <= a && a <= x86_M7 {
+ needSuffix = false
+ break SuffixLoop
+ }
+ }
+ }
+
+ if needSuffix {
+ switch inst.Op {
+ case x86_CMPXCHG8B, x86_FLDCW, x86_FNSTCW, x86_FNSTSW, x86_LDMXCSR, x86_LLDT, x86_LMSW, x86_LTR, x86_PCLMULQDQ,
+ x86_SETA, x86_SETAE, x86_SETB, x86_SETBE, x86_SETE, x86_SETG, x86_SETGE, x86_SETL, x86_SETLE, x86_SETNE, x86_SETNO, x86_SETNP, x86_SETNS, x86_SETO, x86_SETP, x86_SETS,
+ x86_SLDT, x86_SMSW, x86_STMXCSR, x86_STR, x86_VERR, x86_VERW:
+ // For various reasons, libopcodes emits no suffix for these instructions.
+
+ case x86_CRC32:
+ op += x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[1]))
+
+ case x86_LGDT, x86_LIDT, x86_SGDT, x86_SIDT:
+ op += x86_byteSizeSuffix(inst.DataSize / 8)
+
+ case x86_MOVZX, x86_MOVSX:
+ // Integer size conversions get two suffixes.
+ op = op[:4] + x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[1])) + x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[0]))
+
+ case x86_LOOP, x86_LOOPE, x86_LOOPNE:
+ // Add w suffix to indicate use of CX register instead of ECX.
+ if inst.AddrSize == 16 {
+ op += "w"
+ }
+
+ case x86_CALL, x86_ENTER, x86_JMP, x86_LCALL, x86_LEAVE, x86_LJMP, x86_LRET, x86_RET, x86_SYSRET, x86_XBEGIN:
+ // Add w suffix to indicate use of 16-bit target.
+ // Exclude JMP rel8.
+ if inst.Opcode>>24 == 0xEB {
+ break
+ }
+ if inst.DataSize == 16 && inst.Mode != 16 {
+ x86_markLastImplicit(&inst, x86_PrefixDataSize)
+ op += "w"
+ } else if inst.Mode == 64 {
+ op += "q"
+ }
+
+ case x86_FRSTOR, x86_FNSAVE, x86_FNSTENV, x86_FLDENV:
+ // Add s suffix to indicate shortened FPU state (I guess).
+ if inst.DataSize == 16 {
+ op += "s"
+ }
+
+ case x86_PUSH, x86_POP:
+ if x86_markLastImplicit(&inst, x86_PrefixDataSize) {
+ op += x86_byteSizeSuffix(inst.DataSize / 8)
+ } else if inst.Mode == 64 {
+ op += "q"
+ } else {
+ op += x86_byteSizeSuffix(inst.MemBytes)
+ }
+
+ default:
+ if x86_isFloat(inst.Op) {
+ // I can't explain any of this, but it's what libopcodes does.
+ switch inst.MemBytes {
+ default:
+ if (inst.Op == x86_FLD || inst.Op == x86_FSTP) && x86_isMem(inst.Args[0]) {
+ op += "t"
+ }
+ case 4:
+ if x86_isFloatInt(inst.Op) {
+ op += "l"
+ } else {
+ op += "s"
+ }
+ case 8:
+ if x86_isFloatInt(inst.Op) {
+ op += "ll"
+ } else {
+ op += "l"
+ }
+ }
+ break
+ }
+
+ op += x86_byteSizeSuffix(inst.MemBytes)
+ }
+ }
+
+ // Adjust special case opcodes.
+ switch inst.Op {
+ case 0:
+ if inst.Prefix[0] != 0 {
+ return strings.ToLower(inst.Prefix[0].String())
+ }
+
+ case x86_INT:
+ if inst.Opcode>>24 == 0xCC {
+ inst.Args[0] = nil
+ op = "int3"
+ }
+
+ case x86_CMPPS, x86_CMPPD, x86_CMPSD_XMM, x86_CMPSS:
+ imm, ok := inst.Args[2].(x86_Imm)
+ if ok && 0 <= imm && imm < 8 {
+ inst.Args[2] = nil
+ op = x86_cmppsOps[imm] + op[3:]
+ }
+
+ case x86_PCLMULQDQ:
+ imm, ok := inst.Args[2].(x86_Imm)
+ if ok && imm&^0x11 == 0 {
+ inst.Args[2] = nil
+ op = x86_pclmulqOps[(imm&0x10)>>3|(imm&1)]
+ }
+
+ case x86_XLATB:
+ if x86_markLastImplicit(&inst, x86_PrefixAddrSize) {
+ op = "xlat" // not xlatb
+ }
+ }
+
+ // Build list of argument strings.
+ var (
+ usedPrefixes bool // segment prefixes consumed by Mem formatting
+ args []string // formatted arguments
+ )
+ for i, a := range inst.Args {
+ if a == nil {
+ break
+ }
+ switch inst.Op {
+ case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+ if i == 0 {
+ usedPrefixes = true // disable use of prefixes for first argument
+ } else {
+ usedPrefixes = false
+ }
+ }
+ if a == x86_Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
+ continue
+ }
+ args = append(args, x86_gnuArg(&inst, a, &usedPrefixes))
+ }
+
+ // The default is to print the arguments in reverse Intel order.
+ // A few instructions inhibit this behavior.
+ switch inst.Op {
+ case x86_BOUND, x86_LCALL, x86_ENTER, x86_LJMP:
+ // no reverse
+ default:
+ // reverse args
+ for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+ args[i], args[j] = args[j], args[i]
+ }
+ }
+
+ // Build prefix string.
+ // Must be after argument formatting, which can turn off segment prefixes.
+ var (
+ prefix = "" // output string
+ numAddr = 0
+ numData = 0
+ implicitData = false
+ )
+ for _, p := range inst.Prefix {
+ if p&0xFF == x86_PrefixDataSize && p&x86_PrefixImplicit != 0 {
+ implicitData = true
+ }
+ }
+ for _, p := range inst.Prefix {
+ if p == 0 {
+ break
+ }
+ if p&x86_PrefixImplicit != 0 {
+ continue
+ }
+ switch p &^ (x86_PrefixIgnored | x86_PrefixInvalid) {
+ default:
+ if p.IsREX() {
+ if p&0xFF == x86_PrefixREX {
+ prefix += "rex "
+ } else {
+ prefix += "rex." + p.String()[4:] + " "
+ }
+ break
+ }
+ prefix += strings.ToLower(p.String()) + " "
+
+ case x86_PrefixPN:
+ op += ",pn"
+ continue
+
+ case x86_PrefixPT:
+ op += ",pt"
+ continue
+
+ case x86_PrefixAddrSize, x86_PrefixAddr16, x86_PrefixAddr32:
+ // For unknown reasons, if the addr16 prefix is repeated,
+ // libopcodes displays all but the last as addr32, even though
+ // the addressing form used in a memory reference is clearly
+ // still 16-bit.
+ n := 32
+ if inst.Mode == 32 {
+ n = 16
+ }
+ numAddr++
+ if x86_countPrefix(&inst, x86_PrefixAddrSize) > numAddr {
+ n = inst.Mode
+ }
+ prefix += fmt.Sprintf("addr%d ", n)
+ continue
+
+ case x86_PrefixData16, x86_PrefixData32:
+ if implicitData && x86_countPrefix(&inst, x86_PrefixDataSize) > 1 {
+ // Similar to the addr32 logic above, but it only kicks in
+ // when something used the data size prefix (one is implicit).
+ n := 16
+ if inst.Mode == 16 {
+ n = 32
+ }
+ numData++
+ if x86_countPrefix(&inst, x86_PrefixDataSize) > numData {
+ if inst.Mode == 16 {
+ n = 16
+ } else {
+ n = 32
+ }
+ }
+ prefix += fmt.Sprintf("data%d ", n)
+ continue
+ }
+ prefix += strings.ToLower(p.String()) + " "
+ }
+ }
+
+ // Finally! Put it all together.
+ text := prefix + op
+ if args != nil {
+ text += " "
+ // Indirect call/jmp gets a star to distinguish from direct jump address.
+ if (inst.Op == x86_CALL || inst.Op == x86_JMP || inst.Op == x86_LJMP || inst.Op == x86_LCALL) && (x86_isMem(inst.Args[0]) || x86_isReg(inst.Args[0])) {
+ text += "*"
+ }
+ text += strings.Join(args, ",")
+ }
+ return text
+}
+
+// gnuArg returns the GNU syntax for the argument x from the instruction inst.
+// If *usedPrefixes is false and x is a Mem, then the formatting
+// includes any segment prefixes and sets *usedPrefixes to true.
+func x86_gnuArg(inst *x86_Inst, x x86_Arg, usedPrefixes *bool) string {
+ if x == nil {
+ return "<nil>"
+ }
+ switch x := x.(type) {
+ case x86_Reg:
+ switch inst.Op {
+ case x86_CVTSI2SS, x86_CVTSI2SD, x86_CVTSS2SI, x86_CVTSD2SI, x86_CVTTSD2SI, x86_CVTTSS2SI:
+ if inst.DataSize == 16 && x86_EAX <= x && x <= x86_R15L {
+ x -= x86_EAX - x86_AX
+ }
+
+ case x86_IN, x86_INSB, x86_INSW, x86_INSD, x86_OUT, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+ // DX is the port, but libopcodes prints it as if it were a memory reference.
+ if x == x86_DX {
+ return "(%dx)"
+ }
+ }
+ return x86_gccRegName[x]
+ case x86_Mem:
+ seg := ""
+ var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
+ switch x.Segment {
+ case x86_CS:
+ haveCS = true
+ case x86_DS:
+ haveDS = true
+ case x86_ES:
+ haveES = true
+ case x86_FS:
+ haveFS = true
+ case x86_GS:
+ haveGS = true
+ case x86_SS:
+ haveSS = true
+ }
+ switch inst.Op {
+ case x86_INSB, x86_INSW, x86_INSD, x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+ // These do not accept segment prefixes, at least in the GNU rendering.
+ default:
+ if *usedPrefixes {
+ break
+ }
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ p := inst.Prefix[i] &^ x86_PrefixIgnored
+ if p == 0 {
+ continue
+ }
+ switch p {
+ case x86_PrefixCS:
+ if !haveCS {
+ haveCS = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case x86_PrefixDS:
+ if !haveDS {
+ haveDS = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case x86_PrefixES:
+ if !haveES {
+ haveES = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case x86_PrefixFS:
+ if !haveFS {
+ haveFS = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case x86_PrefixGS:
+ if !haveGS {
+ haveGS = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ case x86_PrefixSS:
+ if !haveSS {
+ haveSS = true
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ }
+ }
+ *usedPrefixes = true
+ }
+ if haveCS {
+ seg += "%cs:"
+ }
+ if haveDS {
+ seg += "%ds:"
+ }
+ if haveSS {
+ seg += "%ss:"
+ }
+ if haveES {
+ seg += "%es:"
+ }
+ if haveFS {
+ seg += "%fs:"
+ }
+ if haveGS {
+ seg += "%gs:"
+ }
+ disp := ""
+ if x.Disp != 0 {
+ disp = fmt.Sprintf("%#x", x.Disp)
+ }
+ if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == x86_ESP || x.Base == x86_RSP || x.Base == 0 && inst.Mode == 64) {
+ if x.Base == 0 {
+ return seg + disp
+ }
+ return fmt.Sprintf("%s%s(%s)", seg, disp, x86_gccRegName[x.Base])
+ }
+ base := x86_gccRegName[x.Base]
+ if x.Base == 0 {
+ base = ""
+ }
+ index := x86_gccRegName[x.Index]
+ if x.Index == 0 {
+ if inst.AddrSize == 64 {
+ index = "%riz"
+ } else {
+ index = "%eiz"
+ }
+ }
+ if x86_AX <= x.Base && x.Base <= x86_DI {
+ // 16-bit addressing - no scale
+ return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
+ }
+ return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
+ case x86_Rel:
+ return fmt.Sprintf(".%+#x", int32(x))
+ case x86_Imm:
+ if inst.Mode == 32 {
+ return fmt.Sprintf("$%#x", uint32(x))
+ }
+ return fmt.Sprintf("$%#x", int64(x))
+ }
+ return x.String()
+}
+
+var x86_gccRegName = [...]string{
+ 0: "REG0",
+ x86_AL: "%al",
+ x86_CL: "%cl",
+ x86_BL: "%bl",
+ x86_DL: "%dl",
+ x86_AH: "%ah",
+ x86_CH: "%ch",
+ x86_BH: "%bh",
+ x86_DH: "%dh",
+ x86_SPB: "%spl",
+ x86_BPB: "%bpl",
+ x86_SIB: "%sil",
+ x86_DIB: "%dil",
+ x86_R8B: "%r8b",
+ x86_R9B: "%r9b",
+ x86_R10B: "%r10b",
+ x86_R11B: "%r11b",
+ x86_R12B: "%r12b",
+ x86_R13B: "%r13b",
+ x86_R14B: "%r14b",
+ x86_R15B: "%r15b",
+ x86_AX: "%ax",
+ x86_CX: "%cx",
+ x86_BX: "%bx",
+ x86_DX: "%dx",
+ x86_SP: "%sp",
+ x86_BP: "%bp",
+ x86_SI: "%si",
+ x86_DI: "%di",
+ x86_R8W: "%r8w",
+ x86_R9W: "%r9w",
+ x86_R10W: "%r10w",
+ x86_R11W: "%r11w",
+ x86_R12W: "%r12w",
+ x86_R13W: "%r13w",
+ x86_R14W: "%r14w",
+ x86_R15W: "%r15w",
+ x86_EAX: "%eax",
+ x86_ECX: "%ecx",
+ x86_EDX: "%edx",
+ x86_EBX: "%ebx",
+ x86_ESP: "%esp",
+ x86_EBP: "%ebp",
+ x86_ESI: "%esi",
+ x86_EDI: "%edi",
+ x86_R8L: "%r8d",
+ x86_R9L: "%r9d",
+ x86_R10L: "%r10d",
+ x86_R11L: "%r11d",
+ x86_R12L: "%r12d",
+ x86_R13L: "%r13d",
+ x86_R14L: "%r14d",
+ x86_R15L: "%r15d",
+ x86_RAX: "%rax",
+ x86_RCX: "%rcx",
+ x86_RDX: "%rdx",
+ x86_RBX: "%rbx",
+ x86_RSP: "%rsp",
+ x86_RBP: "%rbp",
+ x86_RSI: "%rsi",
+ x86_RDI: "%rdi",
+ x86_R8: "%r8",
+ x86_R9: "%r9",
+ x86_R10: "%r10",
+ x86_R11: "%r11",
+ x86_R12: "%r12",
+ x86_R13: "%r13",
+ x86_R14: "%r14",
+ x86_R15: "%r15",
+ x86_IP: "%ip",
+ x86_EIP: "%eip",
+ x86_RIP: "%rip",
+ x86_F0: "%st",
+ x86_F1: "%st(1)",
+ x86_F2: "%st(2)",
+ x86_F3: "%st(3)",
+ x86_F4: "%st(4)",
+ x86_F5: "%st(5)",
+ x86_F6: "%st(6)",
+ x86_F7: "%st(7)",
+ x86_M0: "%mm0",
+ x86_M1: "%mm1",
+ x86_M2: "%mm2",
+ x86_M3: "%mm3",
+ x86_M4: "%mm4",
+ x86_M5: "%mm5",
+ x86_M6: "%mm6",
+ x86_M7: "%mm7",
+ x86_X0: "%xmm0",
+ x86_X1: "%xmm1",
+ x86_X2: "%xmm2",
+ x86_X3: "%xmm3",
+ x86_X4: "%xmm4",
+ x86_X5: "%xmm5",
+ x86_X6: "%xmm6",
+ x86_X7: "%xmm7",
+ x86_X8: "%xmm8",
+ x86_X9: "%xmm9",
+ x86_X10: "%xmm10",
+ x86_X11: "%xmm11",
+ x86_X12: "%xmm12",
+ x86_X13: "%xmm13",
+ x86_X14: "%xmm14",
+ x86_X15: "%xmm15",
+ x86_CS: "%cs",
+ x86_SS: "%ss",
+ x86_DS: "%ds",
+ x86_ES: "%es",
+ x86_FS: "%fs",
+ x86_GS: "%gs",
+ x86_GDTR: "%gdtr",
+ x86_IDTR: "%idtr",
+ x86_LDTR: "%ldtr",
+ x86_MSW: "%msw",
+ x86_TASK: "%task",
+ x86_CR0: "%cr0",
+ x86_CR1: "%cr1",
+ x86_CR2: "%cr2",
+ x86_CR3: "%cr3",
+ x86_CR4: "%cr4",
+ x86_CR5: "%cr5",
+ x86_CR6: "%cr6",
+ x86_CR7: "%cr7",
+ x86_CR8: "%cr8",
+ x86_CR9: "%cr9",
+ x86_CR10: "%cr10",
+ x86_CR11: "%cr11",
+ x86_CR12: "%cr12",
+ x86_CR13: "%cr13",
+ x86_CR14: "%cr14",
+ x86_CR15: "%cr15",
+ x86_DR0: "%db0",
+ x86_DR1: "%db1",
+ x86_DR2: "%db2",
+ x86_DR3: "%db3",
+ x86_DR4: "%db4",
+ x86_DR5: "%db5",
+ x86_DR6: "%db6",
+ x86_DR7: "%db7",
+ x86_TR0: "%tr0",
+ x86_TR1: "%tr1",
+ x86_TR2: "%tr2",
+ x86_TR3: "%tr3",
+ x86_TR4: "%tr4",
+ x86_TR5: "%tr5",
+ x86_TR6: "%tr6",
+ x86_TR7: "%tr7",
+}
+
+var x86_gnuOp = map[x86_Op]string{
+ x86_CBW: "cbtw",
+ x86_CDQ: "cltd",
+ x86_CMPSD: "cmpsl",
+ x86_CMPSD_XMM: "cmpsd",
+ x86_CWD: "cwtd",
+ x86_CWDE: "cwtl",
+ x86_CQO: "cqto",
+ x86_INSD: "insl",
+ x86_IRET: "iretw",
+ x86_IRETD: "iret",
+ x86_IRETQ: "iretq",
+ x86_LODSB: "lods",
+ x86_LODSD: "lods",
+ x86_LODSQ: "lods",
+ x86_LODSW: "lods",
+ x86_MOVSD: "movsl",
+ x86_MOVSD_XMM: "movsd",
+ x86_OUTSD: "outsl",
+ x86_POPA: "popaw",
+ x86_POPAD: "popa",
+ x86_POPF: "popfw",
+ x86_POPFD: "popf",
+ x86_PUSHA: "pushaw",
+ x86_PUSHAD: "pusha",
+ x86_PUSHF: "pushfw",
+ x86_PUSHFD: "pushf",
+ x86_SCASB: "scas",
+ x86_SCASD: "scas",
+ x86_SCASQ: "scas",
+ x86_SCASW: "scas",
+ x86_STOSB: "stos",
+ x86_STOSD: "stos",
+ x86_STOSQ: "stos",
+ x86_STOSW: "stos",
+ x86_XLATB: "xlat",
+}
+
+var x86_cmppsOps = []string{
+ "cmpeq",
+ "cmplt",
+ "cmple",
+ "cmpunord",
+ "cmpneq",
+ "cmpnlt",
+ "cmpnle",
+ "cmpord",
+}
+
+var x86_pclmulqOps = []string{
+ "pclmullqlqdq",
+ "pclmulhqlqdq",
+ "pclmullqhqdq",
+ "pclmulhqhqdq",
+}
+
+func x86_countPrefix(inst *x86_Inst, target x86_Prefix) int {
+ n := 0
+ for _, p := range inst.Prefix {
+ if p&0xFF == target&0xFF {
+ n++
+ }
+ }
+ return n
+}
+
+func x86_markLastImplicit(inst *x86_Inst, prefix x86_Prefix) bool {
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ p := inst.Prefix[i]
+ if p&0xFF == prefix {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ return true
+ }
+ }
+ return false
+}
+
+func x86_unmarkImplicit(inst *x86_Inst, prefix x86_Prefix) {
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ p := inst.Prefix[i]
+ if p&0xFF == prefix {
+ inst.Prefix[i] &^= x86_PrefixImplicit
+ }
+ }
+}
+
+func x86_byteSizeSuffix(b int) string {
+ switch b {
+ case 1:
+ return "b"
+ case 2:
+ return "w"
+ case 4:
+ return "l"
+ case 8:
+ return "q"
+ }
+ return ""
+}
+
+func x86_argBytes(inst *x86_Inst, arg x86_Arg) int {
+ if x86_isMem(arg) {
+ return inst.MemBytes
+ }
+ return x86_regBytes(arg)
+}
+
+func x86_isFloat(op x86_Op) bool {
+ switch op {
+ case x86_FADD, x86_FCOM, x86_FCOMP, x86_FDIV, x86_FDIVR, x86_FIADD, x86_FICOM, x86_FICOMP, x86_FIDIV, x86_FIDIVR, x86_FILD, x86_FIMUL, x86_FIST, x86_FISTP, x86_FISTTP, x86_FISUB, x86_FISUBR, x86_FLD, x86_FMUL, x86_FST, x86_FSTP, x86_FSUB, x86_FSUBR:
+ return true
+ }
+ return false
+}
+
+func x86_isFloatInt(op x86_Op) bool {
+ switch op {
+ case x86_FIADD, x86_FICOM, x86_FICOMP, x86_FIDIV, x86_FIDIVR, x86_FILD, x86_FIMUL, x86_FIST, x86_FISTP, x86_FISTTP, x86_FISUB, x86_FISUBR:
+ return true
+ }
+ return false
+}
+
+/* inst.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package x86asm implements decoding of x86 machine code.
+
+// An Inst is a single instruction.
+type x86_Inst struct {
+ Prefix x86_Prefixes // Prefixes applied to the instruction.
+ Op x86_Op // Opcode mnemonic
+ Opcode uint32 // Encoded opcode bits, left aligned (first byte is Opcode>>24, etc)
+ Args x86_Args // Instruction arguments, in Intel order
+ Mode int // processor mode in bits: 16, 32, or 64
+ AddrSize int // address size in bits: 16, 32, or 64
+ DataSize int // operand size in bits: 16, 32, or 64
+ MemBytes int // size of memory argument in bytes: 1, 2, 4, 8, 16, and so on.
+ Len int // length of encoded instruction in bytes
+}
+
+// Prefixes is an array of prefixes associated with a single instruction.
+// The prefixes are listed in the same order as found in the instruction:
+// each prefix byte corresponds to one slot in the array. The first zero
+// in the array marks the end of the prefixes.
+type x86_Prefixes [14]x86_Prefix
+
+// A Prefix represents an Intel instruction prefix.
+// The low 8 bits are the actual prefix byte encoding,
+// and the top 8 bits contain distinguishing bits and metadata.
+type x86_Prefix uint16
+
+const (
+ // Metadata about the role of a prefix in an instruction.
+ x86_PrefixImplicit x86_Prefix = 0x8000 // prefix is implied by instruction text
+ x86_PrefixIgnored x86_Prefix = 0x4000 // prefix is ignored: either irrelevant or overridden by a later prefix
+ x86_PrefixInvalid x86_Prefix = 0x2000 // prefix makes entire instruction invalid (bad LOCK)
+
+ // Memory segment overrides.
+ x86_PrefixES x86_Prefix = 0x26 // ES segment override
+ x86_PrefixCS x86_Prefix = 0x2E // CS segment override
+ x86_PrefixSS x86_Prefix = 0x36 // SS segment override
+ x86_PrefixDS x86_Prefix = 0x3E // DS segment override
+ x86_PrefixFS x86_Prefix = 0x64 // FS segment override
+ x86_PrefixGS x86_Prefix = 0x65 // GS segment override
+
+ // Branch prediction.
+ x86_PrefixPN x86_Prefix = 0x12E // predict not taken (conditional branch only)
+ x86_PrefixPT x86_Prefix = 0x13E // predict taken (conditional branch only)
+
+ // Size attributes.
+ x86_PrefixDataSize x86_Prefix = 0x66 // operand size override
+ x86_PrefixData16 x86_Prefix = 0x166
+ x86_PrefixData32 x86_Prefix = 0x266
+ x86_PrefixAddrSize x86_Prefix = 0x67 // address size override
+ x86_PrefixAddr16 x86_Prefix = 0x167
+ x86_PrefixAddr32 x86_Prefix = 0x267
+
+ // One of a kind.
+ x86_PrefixLOCK x86_Prefix = 0xF0 // lock
+ x86_PrefixREPN x86_Prefix = 0xF2 // repeat not zero
+ x86_PrefixXACQUIRE x86_Prefix = 0x1F2
+ x86_PrefixBND x86_Prefix = 0x2F2
+ x86_PrefixREP x86_Prefix = 0xF3 // repeat
+ x86_PrefixXRELEASE x86_Prefix = 0x1F3
+
+ // The REX prefixes must be in the range [PrefixREX, PrefixREX+0x10).
+ // the other bits are set or not according to the intended use.
+ x86_PrefixREX x86_Prefix = 0x40 // REX 64-bit extension prefix
+ x86_PrefixREXW x86_Prefix = 0x08 // extension bit W (64-bit instruction width)
+ x86_PrefixREXR x86_Prefix = 0x04 // extension bit R (r field in modrm)
+ x86_PrefixREXX x86_Prefix = 0x02 // extension bit X (index field in sib)
+ x86_PrefixREXB x86_Prefix = 0x01 // extension bit B (r/m field in modrm or base field in sib)
+)
+
+// IsREX reports whether p is a REX prefix byte.
+func (p x86_Prefix) IsREX() bool {
+ return p&0xF0 == x86_PrefixREX
+}
+
+func (p x86_Prefix) String() string {
+ p &^= x86_PrefixImplicit | x86_PrefixIgnored | x86_PrefixInvalid
+ if s := x86_prefixNames[p]; s != "" {
+ return s
+ }
+
+ if p.IsREX() {
+ s := "REX."
+ if p&x86_PrefixREXW != 0 {
+ s += "W"
+ }
+ if p&x86_PrefixREXR != 0 {
+ s += "R"
+ }
+ if p&x86_PrefixREXX != 0 {
+ s += "X"
+ }
+ if p&x86_PrefixREXB != 0 {
+ s += "B"
+ }
+ return s
+ }
+
+ return fmt.Sprintf("Prefix(%#x)", int(p))
+}
+
+// An Op is an x86 opcode.
+type x86_Op uint32
+
+func (op x86_Op) String() string {
+ i := int(op)
+ if i < 0 || i >= len(x86_opNames) || x86_opNames[i] == "" {
+ return fmt.Sprintf("Op(%d)", i)
+ }
+ return x86_opNames[i]
+}
+
+// An Args holds the instruction arguments.
+// If an instruction has fewer than 4 arguments,
+// the final elements in the array are nil.
+type x86_Args [4]x86_Arg
+
+// An Arg is a single instruction argument,
+// one of these types: Reg, Mem, Imm, Rel.
+type x86_Arg interface {
+ String() string
+ isArg()
+}
+
+// Note that the implements of Arg that follow are all sized
+// so that on a 64-bit machine the data can be inlined in
+// the interface value instead of requiring an allocation.
+
+// A Reg is a single register.
+// The zero Reg value has no name but indicates ``no register.''
+type x86_Reg uint8
+
+const (
+ _ x86_Reg = iota
+
+ // 8-bit
+ x86_AL
+ x86_CL
+ x86_DL
+ x86_BL
+ x86_AH
+ x86_CH
+ x86_DH
+ x86_BH
+ x86_SPB
+ x86_BPB
+ x86_SIB
+ x86_DIB
+ x86_R8B
+ x86_R9B
+ x86_R10B
+ x86_R11B
+ x86_R12B
+ x86_R13B
+ x86_R14B
+ x86_R15B
+
+ // 16-bit
+ x86_AX
+ x86_CX
+ x86_DX
+ x86_BX
+ x86_SP
+ x86_BP
+ x86_SI
+ x86_DI
+ x86_R8W
+ x86_R9W
+ x86_R10W
+ x86_R11W
+ x86_R12W
+ x86_R13W
+ x86_R14W
+ x86_R15W
+
+ // 32-bit
+ x86_EAX
+ x86_ECX
+ x86_EDX
+ x86_EBX
+ x86_ESP
+ x86_EBP
+ x86_ESI
+ x86_EDI
+ x86_R8L
+ x86_R9L
+ x86_R10L
+ x86_R11L
+ x86_R12L
+ x86_R13L
+ x86_R14L
+ x86_R15L
+
+ // 64-bit
+ x86_RAX
+ x86_RCX
+ x86_RDX
+ x86_RBX
+ x86_RSP
+ x86_RBP
+ x86_RSI
+ x86_RDI
+ x86_R8
+ x86_R9
+ x86_R10
+ x86_R11
+ x86_R12
+ x86_R13
+ x86_R14
+ x86_R15
+
+ // Instruction pointer.
+ x86_IP // 16-bit
+ x86_EIP // 32-bit
+ x86_RIP // 64-bit
+
+ // 387 floating point registers.
+ x86_F0
+ x86_F1
+ x86_F2
+ x86_F3
+ x86_F4
+ x86_F5
+ x86_F6
+ x86_F7
+
+ // MMX registers.
+ x86_M0
+ x86_M1
+ x86_M2
+ x86_M3
+ x86_M4
+ x86_M5
+ x86_M6
+ x86_M7
+
+ // XMM registers.
+ x86_X0
+ x86_X1
+ x86_X2
+ x86_X3
+ x86_X4
+ x86_X5
+ x86_X6
+ x86_X7
+ x86_X8
+ x86_X9
+ x86_X10
+ x86_X11
+ x86_X12
+ x86_X13
+ x86_X14
+ x86_X15
+
+ // Segment registers.
+ x86_ES
+ x86_CS
+ x86_SS
+ x86_DS
+ x86_FS
+ x86_GS
+
+ // System registers.
+ x86_GDTR
+ x86_IDTR
+ x86_LDTR
+ x86_MSW
+ x86_TASK
+
+ // Control registers.
+ x86_CR0
+ x86_CR1
+ x86_CR2
+ x86_CR3
+ x86_CR4
+ x86_CR5
+ x86_CR6
+ x86_CR7
+ x86_CR8
+ x86_CR9
+ x86_CR10
+ x86_CR11
+ x86_CR12
+ x86_CR13
+ x86_CR14
+ x86_CR15
+
+ // Debug registers.
+ x86_DR0
+ x86_DR1
+ x86_DR2
+ x86_DR3
+ x86_DR4
+ x86_DR5
+ x86_DR6
+ x86_DR7
+ x86_DR8
+ x86_DR9
+ x86_DR10
+ x86_DR11
+ x86_DR12
+ x86_DR13
+ x86_DR14
+ x86_DR15
+
+ // Task registers.
+ x86_TR0
+ x86_TR1
+ x86_TR2
+ x86_TR3
+ x86_TR4
+ x86_TR5
+ x86_TR6
+ x86_TR7
+)
+
+const x86_regMax = x86_TR7
+
+func (x86_Reg) isArg() {}
+
+func (r x86_Reg) String() string {
+ i := int(r)
+ if i < 0 || i >= len(x86_regNames) || x86_regNames[i] == "" {
+ return fmt.Sprintf("Reg(%d)", i)
+ }
+ return x86_regNames[i]
+}
+
+// A Mem is a memory reference.
+// The general form is Segment:[Base+Scale*Index+Disp].
+type x86_Mem struct {
+ Segment x86_Reg
+ Base x86_Reg
+ Scale uint8
+ Index x86_Reg
+ Disp int64
+}
+
+func (x86_Mem) isArg() {}
+
+func (m x86_Mem) String() string {
+ var base, plus, scale, index, disp string
+
+ if m.Base != 0 {
+ base = m.Base.String()
+ }
+ if m.Scale != 0 {
+ if m.Base != 0 {
+ plus = "+"
+ }
+ if m.Scale > 1 {
+ scale = fmt.Sprintf("%d*", m.Scale)
+ }
+ index = m.Index.String()
+ }
+ if m.Disp != 0 || m.Base == 0 && m.Scale == 0 {
+ disp = fmt.Sprintf("%+#x", m.Disp)
+ }
+ return "[" + base + plus + scale + index + disp + "]"
+}
+
+// A Rel is an offset relative to the current instruction pointer.
+type x86_Rel int32
+
+func (x86_Rel) isArg() {}
+
+func (r x86_Rel) String() string {
+ return fmt.Sprintf(".%+d", r)
+}
+
+// An Imm is an integer constant.
+type x86_Imm int64
+
+func (x86_Imm) isArg() {}
+
+func (i x86_Imm) String() string {
+ return fmt.Sprintf("%#x", int64(i))
+}
+
+func (i x86_Inst) String() string {
+ var buf bytes.Buffer
+ for _, p := range i.Prefix {
+ if p == 0 {
+ break
+ }
+ if p&x86_PrefixImplicit != 0 {
+ continue
+ }
+ fmt.Fprintf(&buf, "%v ", p)
+ }
+ fmt.Fprintf(&buf, "%v", i.Op)
+ sep := " "
+ for _, v := range i.Args {
+ if v == nil {
+ break
+ }
+ fmt.Fprintf(&buf, "%s%v", sep, v)
+ sep = ", "
+ }
+ return buf.String()
+}
+
+func x86_isReg(a x86_Arg) bool {
+ _, ok := a.(x86_Reg)
+ return ok
+}
+
+func x86_isSegReg(a x86_Arg) bool {
+ r, ok := a.(x86_Reg)
+ return ok && x86_ES <= r && r <= x86_GS
+}
+
+func x86_isMem(a x86_Arg) bool {
+ _, ok := a.(x86_Mem)
+ return ok
+}
+
+func x86_isImm(a x86_Arg) bool {
+ _, ok := a.(x86_Imm)
+ return ok
+}
+
+func x86_regBytes(a x86_Arg) int {
+ r, ok := a.(x86_Reg)
+ if !ok {
+ return 0
+ }
+ if x86_AL <= r && r <= x86_R15B {
+ return 1
+ }
+ if x86_AX <= r && r <= x86_R15W {
+ return 2
+ }
+ if x86_EAX <= r && r <= x86_R15L {
+ return 4
+ }
+ if x86_RAX <= r && r <= x86_R15 {
+ return 8
+ }
+ return 0
+}
+
+func x86_isSegment(p x86_Prefix) bool {
+ switch p {
+ case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+ return true
+ }
+ return false
+}
+
+// The Op definitions and string list are in tables.go.
+
+var x86_prefixNames = map[x86_Prefix]string{
+ x86_PrefixCS: "CS",
+ x86_PrefixDS: "DS",
+ x86_PrefixES: "ES",
+ x86_PrefixFS: "FS",
+ x86_PrefixGS: "GS",
+ x86_PrefixSS: "SS",
+ x86_PrefixLOCK: "LOCK",
+ x86_PrefixREP: "REP",
+ x86_PrefixREPN: "REPN",
+ x86_PrefixAddrSize: "ADDRSIZE",
+ x86_PrefixDataSize: "DATASIZE",
+ x86_PrefixAddr16: "ADDR16",
+ x86_PrefixData16: "DATA16",
+ x86_PrefixAddr32: "ADDR32",
+ x86_PrefixData32: "DATA32",
+ x86_PrefixBND: "BND",
+ x86_PrefixXACQUIRE: "XACQUIRE",
+ x86_PrefixXRELEASE: "XRELEASE",
+ x86_PrefixREX: "REX",
+ x86_PrefixPT: "PT",
+ x86_PrefixPN: "PN",
+}
+
+var x86_regNames = [...]string{
+ x86_AL: "AL",
+ x86_CL: "CL",
+ x86_BL: "BL",
+ x86_DL: "DL",
+ x86_AH: "AH",
+ x86_CH: "CH",
+ x86_BH: "BH",
+ x86_DH: "DH",
+ x86_SPB: "SPB",
+ x86_BPB: "BPB",
+ x86_SIB: "SIB",
+ x86_DIB: "DIB",
+ x86_R8B: "R8B",
+ x86_R9B: "R9B",
+ x86_R10B: "R10B",
+ x86_R11B: "R11B",
+ x86_R12B: "R12B",
+ x86_R13B: "R13B",
+ x86_R14B: "R14B",
+ x86_R15B: "R15B",
+ x86_AX: "AX",
+ x86_CX: "CX",
+ x86_BX: "BX",
+ x86_DX: "DX",
+ x86_SP: "SP",
+ x86_BP: "BP",
+ x86_SI: "SI",
+ x86_DI: "DI",
+ x86_R8W: "R8W",
+ x86_R9W: "R9W",
+ x86_R10W: "R10W",
+ x86_R11W: "R11W",
+ x86_R12W: "R12W",
+ x86_R13W: "R13W",
+ x86_R14W: "R14W",
+ x86_R15W: "R15W",
+ x86_EAX: "EAX",
+ x86_ECX: "ECX",
+ x86_EDX: "EDX",
+ x86_EBX: "EBX",
+ x86_ESP: "ESP",
+ x86_EBP: "EBP",
+ x86_ESI: "ESI",
+ x86_EDI: "EDI",
+ x86_R8L: "R8L",
+ x86_R9L: "R9L",
+ x86_R10L: "R10L",
+ x86_R11L: "R11L",
+ x86_R12L: "R12L",
+ x86_R13L: "R13L",
+ x86_R14L: "R14L",
+ x86_R15L: "R15L",
+ x86_RAX: "RAX",
+ x86_RCX: "RCX",
+ x86_RDX: "RDX",
+ x86_RBX: "RBX",
+ x86_RSP: "RSP",
+ x86_RBP: "RBP",
+ x86_RSI: "RSI",
+ x86_RDI: "RDI",
+ x86_R8: "R8",
+ x86_R9: "R9",
+ x86_R10: "R10",
+ x86_R11: "R11",
+ x86_R12: "R12",
+ x86_R13: "R13",
+ x86_R14: "R14",
+ x86_R15: "R15",
+ x86_IP: "IP",
+ x86_EIP: "EIP",
+ x86_RIP: "RIP",
+ x86_F0: "F0",
+ x86_F1: "F1",
+ x86_F2: "F2",
+ x86_F3: "F3",
+ x86_F4: "F4",
+ x86_F5: "F5",
+ x86_F6: "F6",
+ x86_F7: "F7",
+ x86_M0: "M0",
+ x86_M1: "M1",
+ x86_M2: "M2",
+ x86_M3: "M3",
+ x86_M4: "M4",
+ x86_M5: "M5",
+ x86_M6: "M6",
+ x86_M7: "M7",
+ x86_X0: "X0",
+ x86_X1: "X1",
+ x86_X2: "X2",
+ x86_X3: "X3",
+ x86_X4: "X4",
+ x86_X5: "X5",
+ x86_X6: "X6",
+ x86_X7: "X7",
+ x86_X8: "X8",
+ x86_X9: "X9",
+ x86_X10: "X10",
+ x86_X11: "X11",
+ x86_X12: "X12",
+ x86_X13: "X13",
+ x86_X14: "X14",
+ x86_X15: "X15",
+ x86_CS: "CS",
+ x86_SS: "SS",
+ x86_DS: "DS",
+ x86_ES: "ES",
+ x86_FS: "FS",
+ x86_GS: "GS",
+ x86_GDTR: "GDTR",
+ x86_IDTR: "IDTR",
+ x86_LDTR: "LDTR",
+ x86_MSW: "MSW",
+ x86_TASK: "TASK",
+ x86_CR0: "CR0",
+ x86_CR1: "CR1",
+ x86_CR2: "CR2",
+ x86_CR3: "CR3",
+ x86_CR4: "CR4",
+ x86_CR5: "CR5",
+ x86_CR6: "CR6",
+ x86_CR7: "CR7",
+ x86_CR8: "CR8",
+ x86_CR9: "CR9",
+ x86_CR10: "CR10",
+ x86_CR11: "CR11",
+ x86_CR12: "CR12",
+ x86_CR13: "CR13",
+ x86_CR14: "CR14",
+ x86_CR15: "CR15",
+ x86_DR0: "DR0",
+ x86_DR1: "DR1",
+ x86_DR2: "DR2",
+ x86_DR3: "DR3",
+ x86_DR4: "DR4",
+ x86_DR5: "DR5",
+ x86_DR6: "DR6",
+ x86_DR7: "DR7",
+ x86_DR8: "DR8",
+ x86_DR9: "DR9",
+ x86_DR10: "DR10",
+ x86_DR11: "DR11",
+ x86_DR12: "DR12",
+ x86_DR13: "DR13",
+ x86_DR14: "DR14",
+ x86_DR15: "DR15",
+ x86_TR0: "TR0",
+ x86_TR1: "TR1",
+ x86_TR2: "TR2",
+ x86_TR3: "TR3",
+ x86_TR4: "TR4",
+ x86_TR5: "TR5",
+ x86_TR6: "TR6",
+ x86_TR7: "TR7",
+}
+
+/* intel.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
+func x86_IntelSyntax(inst x86_Inst) string {
+ var iargs []x86_Arg
+ for _, a := range inst.Args {
+ if a == nil {
+ break
+ }
+ iargs = append(iargs, a)
+ }
+
+ switch inst.Op {
+ case x86_INSB, x86_INSD, x86_INSW, x86_OUTSB, x86_OUTSD, x86_OUTSW, x86_LOOPNE, x86_JCXZ, x86_JECXZ, x86_JRCXZ, x86_LOOP, x86_LOOPE, x86_MOV, x86_XLATB:
+ if inst.Op == x86_MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
+ break
+ }
+ for i, p := range inst.Prefix {
+ if p&0xFF == x86_PrefixAddrSize {
+ inst.Prefix[i] &^= x86_PrefixImplicit
+ }
+ }
+ }
+
+ switch inst.Op {
+ case x86_MOV:
+ dst, _ := inst.Args[0].(x86_Reg)
+ src, _ := inst.Args[1].(x86_Reg)
+ if x86_ES <= dst && dst <= x86_GS && x86_EAX <= src && src <= x86_R15L {
+ src -= x86_EAX - x86_AX
+ iargs[1] = src
+ }
+ if x86_ES <= dst && dst <= x86_GS && x86_RAX <= src && src <= x86_R15 {
+ src -= x86_RAX - x86_AX
+ iargs[1] = src
+ }
+
+ if inst.Opcode>>24&^3 == 0xA0 {
+ for i, p := range inst.Prefix {
+ if p&0xFF == x86_PrefixAddrSize {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ }
+ }
+ }
+
+ switch inst.Op {
+ case x86_AAM, x86_AAD:
+ if imm, ok := iargs[0].(x86_Imm); ok {
+ if inst.DataSize == 32 {
+ iargs[0] = x86_Imm(uint32(int8(imm)))
+ } else if inst.DataSize == 16 {
+ iargs[0] = x86_Imm(uint16(int8(imm)))
+ }
+ }
+
+ case x86_PUSH:
+ if imm, ok := iargs[0].(x86_Imm); ok {
+ iargs[0] = x86_Imm(uint32(imm))
+ }
+ }
+
+ for _, p := range inst.Prefix {
+ if p&x86_PrefixImplicit != 0 {
+ for j, pj := range inst.Prefix {
+ if pj&0xFF == p&0xFF {
+ inst.Prefix[j] |= x86_PrefixImplicit
+ }
+ }
+ }
+ }
+
+ if inst.Op != 0 {
+ for i, p := range inst.Prefix {
+ switch p &^ x86_PrefixIgnored {
+ case x86_PrefixData16, x86_PrefixData32, x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixSS:
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ if p.IsREX() {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ }
+ }
+
+ if x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+ for i, p := range inst.Prefix {
+ if p == x86_PrefixPT || p == x86_PrefixPN {
+ inst.Prefix[i] |= x86_PrefixImplicit
+ }
+ }
+ }
+
+ switch inst.Op {
+ case x86_AAA, x86_AAS, x86_CBW, x86_CDQE, x86_CLC, x86_CLD, x86_CLI, x86_CLTS, x86_CMC, x86_CPUID, x86_CQO, x86_CWD, x86_DAA, x86_DAS,
+ x86_FDECSTP, x86_FINCSTP, x86_FNCLEX, x86_FNINIT, x86_FNOP, x86_FWAIT, x86_HLT,
+ x86_ICEBP, x86_INSB, x86_INSD, x86_INSW, x86_INT, x86_INTO, x86_INVD, x86_IRET, x86_IRETQ,
+ x86_LAHF, x86_LEAVE, x86_LRET, x86_MONITOR, x86_MWAIT, x86_NOP, x86_OUTSB, x86_OUTSD, x86_OUTSW,
+ x86_PAUSE, x86_POPA, x86_POPF, x86_POPFQ, x86_PUSHA, x86_PUSHF, x86_PUSHFQ,
+ x86_RDMSR, x86_RDPMC, x86_RDTSC, x86_RDTSCP, x86_RET, x86_RSM,
+ x86_SAHF, x86_STC, x86_STD, x86_STI, x86_SYSENTER, x86_SYSEXIT, x86_SYSRET,
+ x86_UD2, x86_WBINVD, x86_WRMSR, x86_XEND, x86_XLATB, x86_XTEST:
+
+ if inst.Op == x86_NOP && inst.Opcode>>24 != 0x90 {
+ break
+ }
+ if inst.Op == x86_RET && inst.Opcode>>24 != 0xC3 {
+ break
+ }
+ if inst.Op == x86_INT && inst.Opcode>>24 != 0xCC {
+ break
+ }
+ if inst.Op == x86_LRET && inst.Opcode>>24 != 0xcb {
+ break
+ }
+ for i, p := range inst.Prefix {
+ if p&0xFF == x86_PrefixDataSize {
+ inst.Prefix[i] &^= x86_PrefixImplicit | x86_PrefixIgnored
+ }
+ }
+
+ case 0:
+ // ok
+ }
+
+ switch inst.Op {
+ case x86_INSB, x86_INSD, x86_INSW, x86_OUTSB, x86_OUTSD, x86_OUTSW, x86_MONITOR, x86_MWAIT, x86_XLATB:
+ iargs = nil
+
+ case x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+ iargs = iargs[:1]
+
+ case x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+ iargs = iargs[1:]
+ }
+
+ const (
+ haveData16 = 1 << iota
+ haveData32
+ haveAddr16
+ haveAddr32
+ haveXacquire
+ haveXrelease
+ haveLock
+ haveHintTaken
+ haveHintNotTaken
+ haveBnd
+ )
+ var prefixBits uint32
+ prefix := ""
+ for _, p := range inst.Prefix {
+ if p == 0 {
+ break
+ }
+ if p&0xFF == 0xF3 {
+ prefixBits &^= haveBnd
+ }
+ if p&(x86_PrefixImplicit|x86_PrefixIgnored) != 0 {
+ continue
+ }
+ switch p {
+ default:
+ prefix += strings.ToLower(p.String()) + " "
+ case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+ if inst.Op == 0 {
+ prefix += strings.ToLower(p.String()) + " "
+ }
+ case x86_PrefixREPN:
+ prefix += "repne "
+ case x86_PrefixLOCK:
+ prefixBits |= haveLock
+ case x86_PrefixData16, x86_PrefixDataSize:
+ prefixBits |= haveData16
+ case x86_PrefixData32:
+ prefixBits |= haveData32
+ case x86_PrefixAddrSize, x86_PrefixAddr16:
+ prefixBits |= haveAddr16
+ case x86_PrefixAddr32:
+ prefixBits |= haveAddr32
+ case x86_PrefixXACQUIRE:
+ prefixBits |= haveXacquire
+ case x86_PrefixXRELEASE:
+ prefixBits |= haveXrelease
+ case x86_PrefixPT:
+ prefixBits |= haveHintTaken
+ case x86_PrefixPN:
+ prefixBits |= haveHintNotTaken
+ case x86_PrefixBND:
+ prefixBits |= haveBnd
+ }
+ }
+ switch inst.Op {
+ case x86_JMP:
+ if inst.Opcode>>24 == 0xEB {
+ prefixBits &^= haveBnd
+ }
+ case x86_RET, x86_LRET:
+ prefixBits &^= haveData16 | haveData32
+ }
+
+ if prefixBits&haveXacquire != 0 {
+ prefix += "xacquire "
+ }
+ if prefixBits&haveXrelease != 0 {
+ prefix += "xrelease "
+ }
+ if prefixBits&haveLock != 0 {
+ prefix += "lock "
+ }
+ if prefixBits&haveBnd != 0 {
+ prefix += "bnd "
+ }
+ if prefixBits&haveHintTaken != 0 {
+ prefix += "hint-taken "
+ }
+ if prefixBits&haveHintNotTaken != 0 {
+ prefix += "hint-not-taken "
+ }
+ if prefixBits&haveAddr16 != 0 {
+ prefix += "addr16 "
+ }
+ if prefixBits&haveAddr32 != 0 {
+ prefix += "addr32 "
+ }
+ if prefixBits&haveData16 != 0 {
+ prefix += "data16 "
+ }
+ if prefixBits&haveData32 != 0 {
+ prefix += "data32 "
+ }
+
+ if inst.Op == 0 {
+ if prefix == "" {
+ return "<no instruction>"
+ }
+ return prefix[:len(prefix)-1]
+ }
+
+ var args []string
+ for _, a := range iargs {
+ if a == nil {
+ break
+ }
+ args = append(args, x86_intelArg(&inst, a))
+ }
+
+ var op string
+ switch inst.Op {
+ case x86_NOP:
+ if inst.Opcode>>24 == 0x0F {
+ if inst.DataSize == 16 {
+ args = append(args, "ax")
+ } else {
+ args = append(args, "eax")
+ }
+ }
+
+ case x86_BLENDVPD, x86_BLENDVPS, x86_PBLENDVB:
+ args = args[:2]
+
+ case x86_INT:
+ if inst.Opcode>>24 == 0xCC {
+ args = nil
+ op = "int3"
+ }
+
+ case x86_LCALL, x86_LJMP:
+ if len(args) == 2 {
+ args[0], args[1] = args[1], args[0]
+ }
+
+ case x86_FCHS, x86_FABS, x86_FTST, x86_FLDPI, x86_FLDL2E, x86_FLDLG2, x86_F2XM1, x86_FXAM, x86_FLD1, x86_FLDL2T, x86_FSQRT, x86_FRNDINT, x86_FCOS, x86_FSIN:
+ if len(args) == 0 {
+ args = append(args, "st0")
+ }
+
+ case x86_FPTAN, x86_FSINCOS, x86_FUCOMPP, x86_FCOMPP, x86_FYL2X, x86_FPATAN, x86_FXTRACT, x86_FPREM1, x86_FPREM, x86_FYL2XP1, x86_FSCALE:
+ if len(args) == 0 {
+ args = []string{"st0", "st1"}
+ }
+
+ case x86_FST, x86_FSTP, x86_FISTTP, x86_FIST, x86_FISTP, x86_FBSTP:
+ if len(args) == 1 {
+ args = append(args, "st0")
+ }
+
+ case x86_FLD, x86_FXCH, x86_FCOM, x86_FCOMP, x86_FIADD, x86_FIMUL, x86_FICOM, x86_FICOMP, x86_FISUBR, x86_FIDIV, x86_FUCOM, x86_FUCOMP, x86_FILD, x86_FBLD, x86_FADD, x86_FMUL, x86_FSUB, x86_FSUBR, x86_FISUB, x86_FDIV, x86_FDIVR, x86_FIDIVR:
+ if len(args) == 1 {
+ args = []string{"st0", args[0]}
+ }
+
+ case x86_MASKMOVDQU, x86_MASKMOVQ, x86_XLATB, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+ FixSegment:
+ for i := len(inst.Prefix) - 1; i >= 0; i-- {
+ p := inst.Prefix[i] & 0xFF
+ switch p {
+ case x86_PrefixCS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+ if inst.Mode != 64 || p == x86_PrefixFS || p == x86_PrefixGS {
+ args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
+ break FixSegment
+ }
+ case x86_PrefixDS:
+ if inst.Mode != 64 {
+ break FixSegment
+ }
+ }
+ }
+ }
+
+ if op == "" {
+ op = x86_intelOp[inst.Op]
+ }
+ if op == "" {
+ op = strings.ToLower(inst.Op.String())
+ }
+ if args != nil {
+ op += " " + strings.Join(args, ", ")
+ }
+ return prefix + op
+}
+
+func x86_intelArg(inst *x86_Inst, arg x86_Arg) string {
+ switch a := arg.(type) {
+ case x86_Imm:
+ if inst.Mode == 32 {
+ return fmt.Sprintf("%#x", uint32(a))
+ }
+ if x86_Imm(int32(a)) == a {
+ return fmt.Sprintf("%#x", int64(a))
+ }
+ return fmt.Sprintf("%#x", uint64(a))
+ case x86_Mem:
+ if a.Base == x86_EIP {
+ a.Base = x86_RIP
+ }
+ prefix := ""
+ switch inst.MemBytes {
+ case 1:
+ prefix = "byte "
+ case 2:
+ prefix = "word "
+ case 4:
+ prefix = "dword "
+ case 8:
+ prefix = "qword "
+ case 16:
+ prefix = "xmmword "
+ }
+ switch inst.Op {
+ case x86_INVLPG:
+ prefix = "byte "
+ case x86_STOSB, x86_MOVSB, x86_CMPSB, x86_LODSB, x86_SCASB:
+ prefix = "byte "
+ case x86_STOSW, x86_MOVSW, x86_CMPSW, x86_LODSW, x86_SCASW:
+ prefix = "word "
+ case x86_STOSD, x86_MOVSD, x86_CMPSD, x86_LODSD, x86_SCASD:
+ prefix = "dword "
+ case x86_STOSQ, x86_MOVSQ, x86_CMPSQ, x86_LODSQ, x86_SCASQ:
+ prefix = "qword "
+ case x86_LAR:
+ prefix = "word "
+ case x86_BOUND:
+ if inst.Mode == 32 {
+ prefix = "qword "
+ } else {
+ prefix = "dword "
+ }
+ case x86_PREFETCHW, x86_PREFETCHNTA, x86_PREFETCHT0, x86_PREFETCHT1, x86_PREFETCHT2, x86_CLFLUSH:
+ prefix = "zmmword "
+ }
+ switch inst.Op {
+ case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ, x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ, x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ, x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ:
+ switch a.Base {
+ case x86_DI, x86_EDI, x86_RDI:
+ if a.Segment == x86_ES {
+ a.Segment = 0
+ }
+ case x86_SI, x86_ESI, x86_RSI:
+ if a.Segment == x86_DS {
+ a.Segment = 0
+ }
+ }
+ case x86_LEA:
+ a.Segment = 0
+ default:
+ switch a.Base {
+ case x86_SP, x86_ESP, x86_RSP, x86_BP, x86_EBP, x86_RBP:
+ if a.Segment == x86_SS {
+ a.Segment = 0
+ }
+ default:
+ if a.Segment == x86_DS {
+ a.Segment = 0
+ }
+ }
+ }
+
+ if inst.Mode == 64 && a.Segment != x86_FS && a.Segment != x86_GS {
+ a.Segment = 0
+ }
+
+ prefix += "ptr "
+ if a.Segment != 0 {
+ prefix += strings.ToLower(a.Segment.String()) + ":"
+ }
+ prefix += "["
+ if a.Base != 0 {
+ prefix += x86_intelArg(inst, a.Base)
+ }
+ if a.Scale != 0 && a.Index != 0 {
+ if a.Base != 0 {
+ prefix += "+"
+ }
+ prefix += fmt.Sprintf("%s*%d", x86_intelArg(inst, a.Index), a.Scale)
+ }
+ if a.Disp != 0 {
+ if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
+ prefix += fmt.Sprintf("%#x", uint64(a.Disp))
+ } else {
+ prefix += fmt.Sprintf("%+#x", a.Disp)
+ }
+ }
+ prefix += "]"
+ return prefix
+ case x86_Rel:
+ return fmt.Sprintf(".%+#x", int64(a))
+ case x86_Reg:
+ if int(a) < len(x86_intelReg) && x86_intelReg[a] != "" {
+ return x86_intelReg[a]
+ }
+ }
+ return strings.ToLower(arg.String())
+}
+
+var x86_intelOp = map[x86_Op]string{
+ x86_JAE: "jnb",
+ x86_JA: "jnbe",
+ x86_JGE: "jnl",
+ x86_JNE: "jnz",
+ x86_JG: "jnle",
+ x86_JE: "jz",
+ x86_SETAE: "setnb",
+ x86_SETA: "setnbe",
+ x86_SETGE: "setnl",
+ x86_SETNE: "setnz",
+ x86_SETG: "setnle",
+ x86_SETE: "setz",
+ x86_CMOVAE: "cmovnb",
+ x86_CMOVA: "cmovnbe",
+ x86_CMOVGE: "cmovnl",
+ x86_CMOVNE: "cmovnz",
+ x86_CMOVG: "cmovnle",
+ x86_CMOVE: "cmovz",
+ x86_LCALL: "call far",
+ x86_LJMP: "jmp far",
+ x86_LRET: "ret far",
+ x86_ICEBP: "int1",
+ x86_MOVSD_XMM: "movsd",
+ x86_XLATB: "xlat",
+}
+
+var x86_intelReg = [...]string{
+ x86_F0: "st0",
+ x86_F1: "st1",
+ x86_F2: "st2",
+ x86_F3: "st3",
+ x86_F4: "st4",
+ x86_F5: "st5",
+ x86_F6: "st6",
+ x86_F7: "st7",
+ x86_M0: "mmx0",
+ x86_M1: "mmx1",
+ x86_M2: "mmx2",
+ x86_M3: "mmx3",
+ x86_M4: "mmx4",
+ x86_M5: "mmx5",
+ x86_M6: "mmx6",
+ x86_M7: "mmx7",
+ x86_X0: "xmm0",
+ x86_X1: "xmm1",
+ x86_X2: "xmm2",
+ x86_X3: "xmm3",
+ x86_X4: "xmm4",
+ x86_X5: "xmm5",
+ x86_X6: "xmm6",
+ x86_X7: "xmm7",
+ x86_X8: "xmm8",
+ x86_X9: "xmm9",
+ x86_X10: "xmm10",
+ x86_X11: "xmm11",
+ x86_X12: "xmm12",
+ x86_X13: "xmm13",
+ x86_X14: "xmm14",
+ x86_X15: "xmm15",
+
+ // TODO: Maybe the constants are named wrong.
+ x86_SPB: "spl",
+ x86_BPB: "bpl",
+ x86_SIB: "sil",
+ x86_DIB: "dil",
+
+ x86_R8L: "r8d",
+ x86_R9L: "r9d",
+ x86_R10L: "r10d",
+ x86_R11L: "r11d",
+ x86_R12L: "r12d",
+ x86_R13L: "r13d",
+ x86_R14L: "r14d",
+ x86_R15L: "r15d",
+}
+
+/* plan9x.go */
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// plan9Syntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name and base
+// address of the symbol containing the target, if any; otherwise it returns "", 0.
+func x86_plan9Syntax(inst x86_Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+ if symname == nil {
+ symname = func(uint64) (string, uint64) { return "", 0 }
+ }
+ var args []string
+ for i := len(inst.Args) - 1; i >= 0; i-- {
+ a := inst.Args[i]
+ if a == nil {
+ continue
+ }
+ args = append(args, x86_plan9Arg(&inst, pc, symname, a))
+ }
+
+ var last x86_Prefix
+ for _, p := range inst.Prefix {
+ if p == 0 || p.IsREX() {
+ break
+ }
+ last = p
+ }
+
+ prefix := ""
+ switch last & 0xFF {
+ case 0, 0x66, 0x67:
+ // ignore
+ case x86_PrefixREPN:
+ prefix += "REPNE "
+ default:
+ prefix += last.String() + " "
+ }
+
+ op := inst.Op.String()
+ if x86_plan9Suffix[inst.Op] {
+ switch inst.DataSize {
+ case 8:
+ op += "B"
+ case 16:
+ op += "W"
+ case 32:
+ op += "L"
+ case 64:
+ op += "Q"
+ }
+ }
+
+ if args != nil {
+ op += " " + strings.Join(args, ", ")
+ }
+
+ return prefix + op
+}
+
+func x86_plan9Arg(inst *x86_Inst, pc uint64, symname func(uint64) (string, uint64), arg x86_Arg) string {
+ switch a := arg.(type) {
+ case x86_Reg:
+ return x86_plan9Reg[a]
+ case x86_Rel:
+ if pc == 0 {
+ break
+ }
+ // If the absolute address is the start of a symbol, use the name.
+ // Otherwise use the raw address, so that things like relative
+ // jumps show up as JMP 0x123 instead of JMP f+10(SB).
+ // It is usually easier to search for 0x123 than to do the mental
+ // arithmetic to find f+10.
+ addr := pc + uint64(inst.Len) + uint64(a)
+ if s, base := symname(addr); s != "" && addr == base {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ return fmt.Sprintf("%#x", addr)
+
+ case x86_Imm:
+ if s, base := symname(uint64(a)); s != "" {
+ suffix := ""
+ if uint64(a) != base {
+ suffix = fmt.Sprintf("%+d", uint64(a)-base)
+ }
+ return fmt.Sprintf("$%s%s(SB)", s, suffix)
+ }
+ if inst.Mode == 32 {
+ return fmt.Sprintf("$%#x", uint32(a))
+ }
+ if x86_Imm(int32(a)) == a {
+ return fmt.Sprintf("$%#x", int64(a))
+ }
+ return fmt.Sprintf("$%#x", uint64(a))
+ case x86_Mem:
+ if a.Segment == 0 && a.Disp != 0 && a.Base == 0 && (a.Index == 0 || a.Scale == 0) {
+ if s, base := symname(uint64(a.Disp)); s != "" {
+ suffix := ""
+ if uint64(a.Disp) != base {
+ suffix = fmt.Sprintf("%+d", uint64(a.Disp)-base)
+ }
+ return fmt.Sprintf("%s%s(SB)", s, suffix)
+ }
+ }
+ s := ""
+ if a.Segment != 0 {
+ s += fmt.Sprintf("%s:", x86_plan9Reg[a.Segment])
+ }
+ if a.Disp != 0 {
+ s += fmt.Sprintf("%#x", a.Disp)
+ } else {
+ s += "0"
+ }
+ if a.Base != 0 {
+ s += fmt.Sprintf("(%s)", x86_plan9Reg[a.Base])
+ }
+ if a.Index != 0 && a.Scale != 0 {
+ s += fmt.Sprintf("(%s*%d)", x86_plan9Reg[a.Index], a.Scale)
+ }
+ return s
+ }
+ return arg.String()
+}
+
+var x86_plan9Suffix = [x86_maxOp + 1]bool{
+ x86_ADC: true,
+ x86_ADD: true,
+ x86_AND: true,
+ x86_BSF: true,
+ x86_BSR: true,
+ x86_BT: true,
+ x86_BTC: true,
+ x86_BTR: true,
+ x86_BTS: true,
+ x86_CMP: true,
+ x86_CMPXCHG: true,
+ x86_CVTSI2SD: true,
+ x86_CVTSI2SS: true,
+ x86_CVTSD2SI: true,
+ x86_CVTSS2SI: true,
+ x86_CVTTSD2SI: true,
+ x86_CVTTSS2SI: true,
+ x86_DEC: true,
+ x86_DIV: true,
+ x86_FLDENV: true,
+ x86_FRSTOR: true,
+ x86_IDIV: true,
+ x86_IMUL: true,
+ x86_IN: true,
+ x86_INC: true,
+ x86_LEA: true,
+ x86_MOV: true,
+ x86_MOVNTI: true,
+ x86_MUL: true,
+ x86_NEG: true,
+ x86_NOP: true,
+ x86_NOT: true,
+ x86_OR: true,
+ x86_OUT: true,
+ x86_POP: true,
+ x86_POPA: true,
+ x86_PUSH: true,
+ x86_PUSHA: true,
+ x86_RCL: true,
+ x86_RCR: true,
+ x86_ROL: true,
+ x86_ROR: true,
+ x86_SAR: true,
+ x86_SBB: true,
+ x86_SHL: true,
+ x86_SHLD: true,
+ x86_SHR: true,
+ x86_SHRD: true,
+ x86_SUB: true,
+ x86_TEST: true,
+ x86_XADD: true,
+ x86_XCHG: true,
+ x86_XOR: true,
+}
+
+var x86_plan9Reg = [...]string{
+ x86_AL: "AL",
+ x86_CL: "CL",
+ x86_BL: "BL",
+ x86_DL: "DL",
+ x86_AH: "AH",
+ x86_CH: "CH",
+ x86_BH: "BH",
+ x86_DH: "DH",
+ x86_SPB: "SP",
+ x86_BPB: "BP",
+ x86_SIB: "SI",
+ x86_DIB: "DI",
+ x86_R8B: "R8",
+ x86_R9B: "R9",
+ x86_R10B: "R10",
+ x86_R11B: "R11",
+ x86_R12B: "R12",
+ x86_R13B: "R13",
+ x86_R14B: "R14",
+ x86_R15B: "R15",
+ x86_AX: "AX",
+ x86_CX: "CX",
+ x86_BX: "BX",
+ x86_DX: "DX",
+ x86_SP: "SP",
+ x86_BP: "BP",
+ x86_SI: "SI",
+ x86_DI: "DI",
+ x86_R8W: "R8",
+ x86_R9W: "R9",
+ x86_R10W: "R10",
+ x86_R11W: "R11",
+ x86_R12W: "R12",
+ x86_R13W: "R13",
+ x86_R14W: "R14",
+ x86_R15W: "R15",
+ x86_EAX: "AX",
+ x86_ECX: "CX",
+ x86_EDX: "DX",
+ x86_EBX: "BX",
+ x86_ESP: "SP",
+ x86_EBP: "BP",
+ x86_ESI: "SI",
+ x86_EDI: "DI",
+ x86_R8L: "R8",
+ x86_R9L: "R9",
+ x86_R10L: "R10",
+ x86_R11L: "R11",
+ x86_R12L: "R12",
+ x86_R13L: "R13",
+ x86_R14L: "R14",
+ x86_R15L: "R15",
+ x86_RAX: "AX",
+ x86_RCX: "CX",
+ x86_RDX: "DX",
+ x86_RBX: "BX",
+ x86_RSP: "SP",
+ x86_RBP: "BP",
+ x86_RSI: "SI",
+ x86_RDI: "DI",
+ x86_R8: "R8",
+ x86_R9: "R9",
+ x86_R10: "R10",
+ x86_R11: "R11",
+ x86_R12: "R12",
+ x86_R13: "R13",
+ x86_R14: "R14",
+ x86_R15: "R15",
+ x86_IP: "IP",
+ x86_EIP: "IP",
+ x86_RIP: "IP",
+ x86_F0: "F0",
+ x86_F1: "F1",
+ x86_F2: "F2",
+ x86_F3: "F3",
+ x86_F4: "F4",
+ x86_F5: "F5",
+ x86_F6: "F6",
+ x86_F7: "F7",
+ x86_M0: "M0",
+ x86_M1: "M1",
+ x86_M2: "M2",
+ x86_M3: "M3",
+ x86_M4: "M4",
+ x86_M5: "M5",
+ x86_M6: "M6",
+ x86_M7: "M7",
+ x86_X0: "X0",
+ x86_X1: "X1",
+ x86_X2: "X2",
+ x86_X3: "X3",
+ x86_X4: "X4",
+ x86_X5: "X5",
+ x86_X6: "X6",
+ x86_X7: "X7",
+ x86_X8: "X8",
+ x86_X9: "X9",
+ x86_X10: "X10",
+ x86_X11: "X11",
+ x86_X12: "X12",
+ x86_X13: "X13",
+ x86_X14: "X14",
+ x86_X15: "X15",
+ x86_CS: "CS",
+ x86_SS: "SS",
+ x86_DS: "DS",
+ x86_ES: "ES",
+ x86_FS: "FS",
+ x86_GS: "GS",
+ x86_GDTR: "GDTR",
+ x86_IDTR: "IDTR",
+ x86_LDTR: "LDTR",
+ x86_MSW: "MSW",
+ x86_TASK: "TASK",
+ x86_CR0: "CR0",
+ x86_CR1: "CR1",
+ x86_CR2: "CR2",
+ x86_CR3: "CR3",
+ x86_CR4: "CR4",
+ x86_CR5: "CR5",
+ x86_CR6: "CR6",
+ x86_CR7: "CR7",
+ x86_CR8: "CR8",
+ x86_CR9: "CR9",
+ x86_CR10: "CR10",
+ x86_CR11: "CR11",
+ x86_CR12: "CR12",
+ x86_CR13: "CR13",
+ x86_CR14: "CR14",
+ x86_CR15: "CR15",
+ x86_DR0: "DR0",
+ x86_DR1: "DR1",
+ x86_DR2: "DR2",
+ x86_DR3: "DR3",
+ x86_DR4: "DR4",
+ x86_DR5: "DR5",
+ x86_DR6: "DR6",
+ x86_DR7: "DR7",
+ x86_DR8: "DR8",
+ x86_DR9: "DR9",
+ x86_DR10: "DR10",
+ x86_DR11: "DR11",
+ x86_DR12: "DR12",
+ x86_DR13: "DR13",
+ x86_DR14: "DR14",
+ x86_DR15: "DR15",
+ x86_TR0: "TR0",
+ x86_TR1: "TR1",
+ x86_TR2: "TR2",
+ x86_TR3: "TR3",
+ x86_TR4: "TR4",
+ x86_TR5: "TR5",
+ x86_TR6: "TR6",
+ x86_TR7: "TR7",
+}
+
+/* tables.go */
+
+// DO NOT EDIT
+// generated by: x86map -fmt=decoder ../x86.csv
+
+var x86_decoder = [...]uint16{
+ uint16(x86_xFail),
+ /*1*/ uint16(x86_xCondByte), 243,
+ 0x00, 490,
+ 0x01, 496,
+ 0x02, 525,
+ 0x03, 531,
+ 0x04, 560,
+ 0x05, 566,
+ 0x06, 595,
+ 0x07, 602,
+ 0x08, 609,
+ 0x09, 615,
+ 0x0A, 644,
+ 0x0B, 650,
+ 0x0C, 679,
+ 0x0D, 685,
+ 0x0E, 714,
+ 0x0F, 721,
+ 0x10, 8026,
+ 0x11, 8032,
+ 0x12, 8061,
+ 0x13, 8067,
+ 0x14, 8096,
+ 0x15, 8102,
+ 0x16, 8131,
+ 0x17, 8138,
+ 0x18, 8145,
+ 0x19, 8151,
+ 0x1A, 8180,
+ 0x1B, 8186,
+ 0x1C, 8215,
+ 0x1D, 8221,
+ 0x1E, 8250,
+ 0x1F, 8257,
+ 0x20, 8264,
+ 0x21, 8270,
+ 0x22, 8299,
+ 0x23, 8305,
+ 0x24, 8334,
+ 0x25, 8340,
+ 0x27, 8369,
+ 0x28, 8375,
+ 0x29, 8381,
+ 0x2A, 8410,
+ 0x2B, 8416,
+ 0x2C, 8445,
+ 0x2D, 8451,
+ 0x2F, 8480,
+ 0x30, 8486,
+ 0x31, 8492,
+ 0x32, 8521,
+ 0x33, 8527,
+ 0x34, 8556,
+ 0x35, 8562,
+ 0x37, 8591,
+ 0x38, 8597,
+ 0x39, 8603,
+ 0x3A, 8632,
+ 0x3B, 8638,
+ 0x3C, 8667,
+ 0x3D, 8673,
+ 0x3F, 8702,
+ 0x40, 8708,
+ 0x41, 8708,
+ 0x42, 8708,
+ 0x43, 8708,
+ 0x44, 8708,
+ 0x45, 8708,
+ 0x46, 8708,
+ 0x47, 8708,
+ 0x48, 8723,
+ 0x49, 8723,
+ 0x4a, 8723,
+ 0x4b, 8723,
+ 0x4c, 8723,
+ 0x4d, 8723,
+ 0x4e, 8723,
+ 0x4f, 8723,
+ 0x50, 8738,
+ 0x51, 8738,
+ 0x52, 8738,
+ 0x53, 8738,
+ 0x54, 8738,
+ 0x55, 8738,
+ 0x56, 8738,
+ 0x57, 8738,
+ 0x58, 8765,
+ 0x59, 8765,
+ 0x5a, 8765,
+ 0x5b, 8765,
+ 0x5c, 8765,
+ 0x5d, 8765,
+ 0x5e, 8765,
+ 0x5f, 8765,
+ 0x60, 8792,
+ 0x61, 8805,
+ 0x62, 8818,
+ 0x63, 8837,
+ 0x68, 8868,
+ 0x69, 8887,
+ 0x6A, 8922,
+ 0x6B, 8927,
+ 0x6C, 8962,
+ 0x6D, 8965,
+ 0x6E, 8978,
+ 0x6F, 8981,
+ 0x70, 8994,
+ 0x71, 8999,
+ 0x72, 9004,
+ 0x73, 9009,
+ 0x74, 9014,
+ 0x75, 9019,
+ 0x76, 9024,
+ 0x77, 9029,
+ 0x78, 9034,
+ 0x79, 9039,
+ 0x7A, 9044,
+ 0x7B, 9049,
+ 0x7C, 9054,
+ 0x7D, 9059,
+ 0x7E, 9064,
+ 0x7F, 9069,
+ 0x80, 9074,
+ 0x81, 9131,
+ 0x83, 9372,
+ 0x84, 9613,
+ 0x85, 9619,
+ 0x86, 9648,
+ 0x87, 9654,
+ 0x88, 9683,
+ 0x89, 9689,
+ 0x8A, 9711,
+ 0x8B, 9717,
+ 0x8C, 9739,
+ 0x8D, 9768,
+ 0x8E, 9797,
+ 0x8F, 9826,
+ 0x90, 9862,
+ 0x91, 9862,
+ 0x92, 9862,
+ 0x93, 9862,
+ 0x94, 9862,
+ 0x95, 9862,
+ 0x96, 9862,
+ 0x97, 9862,
+ 0x98, 9888,
+ 0x99, 9908,
+ 0x9A, 9928,
+ 0x9B, 9945,
+ 0x9C, 9948,
+ 0x9D, 9971,
+ 0x9E, 9994,
+ 0x9F, 9997,
+ 0xA0, 10000,
+ 0xA1, 10019,
+ 0xA2, 10041,
+ 0xA3, 10060,
+ 0xA4, 10082,
+ 0xA5, 10085,
+ 0xA6, 10105,
+ 0xA7, 10108,
+ 0xA8, 10128,
+ 0xA9, 10134,
+ 0xAA, 10163,
+ 0xAB, 10166,
+ 0xAC, 10186,
+ 0xAD, 10189,
+ 0xAE, 10209,
+ 0xAF, 10212,
+ 0xb0, 10232,
+ 0xb1, 10232,
+ 0xb2, 10232,
+ 0xb3, 10232,
+ 0xb4, 10232,
+ 0xb5, 10232,
+ 0xb6, 10232,
+ 0xb7, 10232,
+ 0xb8, 10238,
+ 0xb9, 10238,
+ 0xba, 10238,
+ 0xbb, 10238,
+ 0xbc, 10238,
+ 0xbd, 10238,
+ 0xbe, 10238,
+ 0xbf, 10238,
+ 0xC0, 10267,
+ 0xC1, 10318,
+ 0xC2, 10516,
+ 0xC3, 10521,
+ 0xC4, 10524,
+ 0xC5, 10543,
+ 0xC6, 10562,
+ 0xC7, 10586,
+ 0xC8, 10647,
+ 0xC9, 10654,
+ 0xCA, 10677,
+ 0xCB, 10682,
+ 0xCC, 10685,
+ 0xCD, 10689,
+ 0xCE, 10694,
+ 0xCF, 10700,
+ 0xD0, 10720,
+ 0xD1, 10764,
+ 0xD2, 10955,
+ 0xD3, 10999,
+ 0xD4, 11190,
+ 0xD5, 11198,
+ 0xD7, 11206,
+ 0xD8, 11219,
+ 0xD9, 11428,
+ 0xDA, 11637,
+ 0xDB, 11769,
+ 0xDC, 11940,
+ 0xDD, 12109,
+ 0xDE, 12248,
+ 0xDF, 12422,
+ 0xE0, 12533,
+ 0xE1, 12538,
+ 0xE2, 12543,
+ 0xE3, 12548,
+ 0xE4, 12574,
+ 0xE5, 12580,
+ 0xE6, 12602,
+ 0xE7, 12608,
+ 0xE8, 12630,
+ 0xE9, 12661,
+ 0xEA, 12692,
+ 0xEB, 12709,
+ 0xEC, 12714,
+ 0xED, 12719,
+ 0xEE, 12738,
+ 0xEF, 12743,
+ 0xF1, 12762,
+ 0xF4, 12765,
+ 0xF5, 12768,
+ 0xF6, 12771,
+ 0xF7, 12810,
+ 0xF8, 12986,
+ 0xF9, 12989,
+ 0xFA, 12992,
+ 0xFB, 12995,
+ 0xFC, 12998,
+ 0xFD, 13001,
+ 0xFE, 13004,
+ 0xFF, 13021,
+ uint16(x86_xFail),
+ /*490*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*492*/ uint16(x86_xReadSlashR),
+ /*493*/ uint16(x86_xArgRM8),
+ /*494*/ uint16(x86_xArgR8),
+ /*495*/ uint16(x86_xMatch),
+ /*496*/ uint16(x86_xCondIs64), 499, 515,
+ /*499*/ uint16(x86_xCondDataSize), 503, 509, 0,
+ /*503*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*505*/ uint16(x86_xReadSlashR),
+ /*506*/ uint16(x86_xArgRM16),
+ /*507*/ uint16(x86_xArgR16),
+ /*508*/ uint16(x86_xMatch),
+ /*509*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*511*/ uint16(x86_xReadSlashR),
+ /*512*/ uint16(x86_xArgRM32),
+ /*513*/ uint16(x86_xArgR32),
+ /*514*/ uint16(x86_xMatch),
+ /*515*/ uint16(x86_xCondDataSize), 503, 509, 519,
+ /*519*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*521*/ uint16(x86_xReadSlashR),
+ /*522*/ uint16(x86_xArgRM64),
+ /*523*/ uint16(x86_xArgR64),
+ /*524*/ uint16(x86_xMatch),
+ /*525*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*527*/ uint16(x86_xReadSlashR),
+ /*528*/ uint16(x86_xArgR8),
+ /*529*/ uint16(x86_xArgRM8),
+ /*530*/ uint16(x86_xMatch),
+ /*531*/ uint16(x86_xCondIs64), 534, 550,
+ /*534*/ uint16(x86_xCondDataSize), 538, 544, 0,
+ /*538*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*540*/ uint16(x86_xReadSlashR),
+ /*541*/ uint16(x86_xArgR16),
+ /*542*/ uint16(x86_xArgRM16),
+ /*543*/ uint16(x86_xMatch),
+ /*544*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*546*/ uint16(x86_xReadSlashR),
+ /*547*/ uint16(x86_xArgR32),
+ /*548*/ uint16(x86_xArgRM32),
+ /*549*/ uint16(x86_xMatch),
+ /*550*/ uint16(x86_xCondDataSize), 538, 544, 554,
+ /*554*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*556*/ uint16(x86_xReadSlashR),
+ /*557*/ uint16(x86_xArgR64),
+ /*558*/ uint16(x86_xArgRM64),
+ /*559*/ uint16(x86_xMatch),
+ /*560*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*562*/ uint16(x86_xReadIb),
+ /*563*/ uint16(x86_xArgAL),
+ /*564*/ uint16(x86_xArgImm8u),
+ /*565*/ uint16(x86_xMatch),
+ /*566*/ uint16(x86_xCondIs64), 569, 585,
+ /*569*/ uint16(x86_xCondDataSize), 573, 579, 0,
+ /*573*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*575*/ uint16(x86_xReadIw),
+ /*576*/ uint16(x86_xArgAX),
+ /*577*/ uint16(x86_xArgImm16),
+ /*578*/ uint16(x86_xMatch),
+ /*579*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*581*/ uint16(x86_xReadId),
+ /*582*/ uint16(x86_xArgEAX),
+ /*583*/ uint16(x86_xArgImm32),
+ /*584*/ uint16(x86_xMatch),
+ /*585*/ uint16(x86_xCondDataSize), 573, 579, 589,
+ /*589*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*591*/ uint16(x86_xReadId),
+ /*592*/ uint16(x86_xArgRAX),
+ /*593*/ uint16(x86_xArgImm32),
+ /*594*/ uint16(x86_xMatch),
+ /*595*/ uint16(x86_xCondIs64), 598, 0,
+ /*598*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*600*/ uint16(x86_xArgES),
+ /*601*/ uint16(x86_xMatch),
+ /*602*/ uint16(x86_xCondIs64), 605, 0,
+ /*605*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*607*/ uint16(x86_xArgES),
+ /*608*/ uint16(x86_xMatch),
+ /*609*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*611*/ uint16(x86_xReadSlashR),
+ /*612*/ uint16(x86_xArgRM8),
+ /*613*/ uint16(x86_xArgR8),
+ /*614*/ uint16(x86_xMatch),
+ /*615*/ uint16(x86_xCondIs64), 618, 634,
+ /*618*/ uint16(x86_xCondDataSize), 622, 628, 0,
+ /*622*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*624*/ uint16(x86_xReadSlashR),
+ /*625*/ uint16(x86_xArgRM16),
+ /*626*/ uint16(x86_xArgR16),
+ /*627*/ uint16(x86_xMatch),
+ /*628*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*630*/ uint16(x86_xReadSlashR),
+ /*631*/ uint16(x86_xArgRM32),
+ /*632*/ uint16(x86_xArgR32),
+ /*633*/ uint16(x86_xMatch),
+ /*634*/ uint16(x86_xCondDataSize), 622, 628, 638,
+ /*638*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*640*/ uint16(x86_xReadSlashR),
+ /*641*/ uint16(x86_xArgRM64),
+ /*642*/ uint16(x86_xArgR64),
+ /*643*/ uint16(x86_xMatch),
+ /*644*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*646*/ uint16(x86_xReadSlashR),
+ /*647*/ uint16(x86_xArgR8),
+ /*648*/ uint16(x86_xArgRM8),
+ /*649*/ uint16(x86_xMatch),
+ /*650*/ uint16(x86_xCondIs64), 653, 669,
+ /*653*/ uint16(x86_xCondDataSize), 657, 663, 0,
+ /*657*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*659*/ uint16(x86_xReadSlashR),
+ /*660*/ uint16(x86_xArgR16),
+ /*661*/ uint16(x86_xArgRM16),
+ /*662*/ uint16(x86_xMatch),
+ /*663*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*665*/ uint16(x86_xReadSlashR),
+ /*666*/ uint16(x86_xArgR32),
+ /*667*/ uint16(x86_xArgRM32),
+ /*668*/ uint16(x86_xMatch),
+ /*669*/ uint16(x86_xCondDataSize), 657, 663, 673,
+ /*673*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*675*/ uint16(x86_xReadSlashR),
+ /*676*/ uint16(x86_xArgR64),
+ /*677*/ uint16(x86_xArgRM64),
+ /*678*/ uint16(x86_xMatch),
+ /*679*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*681*/ uint16(x86_xReadIb),
+ /*682*/ uint16(x86_xArgAL),
+ /*683*/ uint16(x86_xArgImm8u),
+ /*684*/ uint16(x86_xMatch),
+ /*685*/ uint16(x86_xCondIs64), 688, 704,
+ /*688*/ uint16(x86_xCondDataSize), 692, 698, 0,
+ /*692*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*694*/ uint16(x86_xReadIw),
+ /*695*/ uint16(x86_xArgAX),
+ /*696*/ uint16(x86_xArgImm16),
+ /*697*/ uint16(x86_xMatch),
+ /*698*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*700*/ uint16(x86_xReadId),
+ /*701*/ uint16(x86_xArgEAX),
+ /*702*/ uint16(x86_xArgImm32),
+ /*703*/ uint16(x86_xMatch),
+ /*704*/ uint16(x86_xCondDataSize), 692, 698, 708,
+ /*708*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*710*/ uint16(x86_xReadId),
+ /*711*/ uint16(x86_xArgRAX),
+ /*712*/ uint16(x86_xArgImm32),
+ /*713*/ uint16(x86_xMatch),
+ /*714*/ uint16(x86_xCondIs64), 717, 0,
+ /*717*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*719*/ uint16(x86_xArgCS),
+ /*720*/ uint16(x86_xMatch),
+ /*721*/ uint16(x86_xCondByte), 228,
+ 0x00, 1180,
+ 0x01, 1237,
+ 0x02, 1345,
+ 0x03, 1367,
+ 0x05, 1389,
+ 0x06, 1395,
+ 0x07, 1398,
+ 0x08, 1404,
+ 0x09, 1407,
+ 0x0B, 1410,
+ 0x0D, 1413,
+ 0x10, 1426,
+ 0x11, 1460,
+ 0x12, 1494,
+ 0x13, 1537,
+ 0x14, 1555,
+ 0x15, 1573,
+ 0x16, 1591,
+ 0x17, 1626,
+ 0x18, 1644,
+ 0x1F, 1669,
+ 0x20, 1690,
+ 0x21, 1705,
+ 0x22, 1720,
+ 0x23, 1735,
+ 0x24, 1750,
+ 0x26, 1765,
+ 0x28, 1780,
+ 0x29, 1798,
+ 0x2A, 1816,
+ 0x2B, 1903,
+ 0x2C, 1937,
+ 0x2D, 2024,
+ 0x2E, 2111,
+ 0x2F, 2129,
+ 0x30, 2147,
+ 0x31, 2150,
+ 0x32, 2153,
+ 0x33, 2156,
+ 0x34, 2159,
+ 0x35, 2162,
+ 0x38, 2172,
+ 0x3A, 3073,
+ 0x40, 3484,
+ 0x41, 3513,
+ 0x42, 3542,
+ 0x43, 3571,
+ 0x44, 3600,
+ 0x45, 3629,
+ 0x46, 3658,
+ 0x47, 3687,
+ 0x48, 3716,
+ 0x49, 3745,
+ 0x4A, 3774,
+ 0x4B, 3803,
+ 0x4C, 3832,
+ 0x4D, 3861,
+ 0x4E, 3890,
+ 0x4F, 3919,
+ 0x50, 3948,
+ 0x51, 3966,
+ 0x52, 4000,
+ 0x53, 4018,
+ 0x54, 4036,
+ 0x55, 4054,
+ 0x56, 4072,
+ 0x57, 4090,
+ 0x58, 4108,
+ 0x59, 4142,
+ 0x5A, 4176,
+ 0x5B, 4210,
+ 0x5C, 4236,
+ 0x5D, 4270,
+ 0x5E, 4304,
+ 0x5F, 4338,
+ 0x60, 4372,
+ 0x61, 4390,
+ 0x62, 4408,
+ 0x63, 4426,
+ 0x64, 4444,
+ 0x65, 4462,
+ 0x66, 4480,
+ 0x67, 4498,
+ 0x68, 4516,
+ 0x69, 4534,
+ 0x6A, 4552,
+ 0x6B, 4570,
+ 0x6C, 4588,
+ 0x6D, 4598,
+ 0x6E, 4608,
+ 0x6F, 4675,
+ 0x70, 4701,
+ 0x71, 4743,
+ 0x72, 4806,
+ 0x73, 4869,
+ 0x74, 4934,
+ 0x75, 4952,
+ 0x76, 4970,
+ 0x77, 4988,
+ 0x7C, 4991,
+ 0x7D, 5009,
+ 0x7E, 5027,
+ 0x7F, 5104,
+ 0x80, 5130,
+ 0x81, 5161,
+ 0x82, 5192,
+ 0x83, 5223,
+ 0x84, 5254,
+ 0x85, 5285,
+ 0x86, 5316,
+ 0x87, 5347,
+ 0x88, 5378,
+ 0x89, 5409,
+ 0x8A, 5440,
+ 0x8B, 5471,
+ 0x8C, 5502,
+ 0x8D, 5533,
+ 0x8E, 5564,
+ 0x8F, 5595,
+ 0x90, 5626,
+ 0x91, 5631,
+ 0x92, 5636,
+ 0x93, 5641,
+ 0x94, 5646,
+ 0x95, 5651,
+ 0x96, 5656,
+ 0x97, 5661,
+ 0x98, 5666,
+ 0x99, 5671,
+ 0x9A, 5676,
+ 0x9B, 5681,
+ 0x9C, 5686,
+ 0x9D, 5691,
+ 0x9E, 5696,
+ 0x9F, 5701,
+ 0xA0, 5706,
+ 0xA1, 5710,
+ 0xA2, 5737,
+ 0xA3, 5740,
+ 0xA4, 5769,
+ 0xA5, 5804,
+ 0xA8, 5836,
+ 0xA9, 5840,
+ 0xAA, 5867,
+ 0xAB, 5870,
+ 0xAC, 5899,
+ 0xAD, 5934,
+ 0xAE, 5966,
+ 0xAF, 6224,
+ 0xB0, 6253,
+ 0xB1, 6259,
+ 0xB2, 6288,
+ 0xB3, 6317,
+ 0xB4, 6346,
+ 0xB5, 6375,
+ 0xB6, 6404,
+ 0xB7, 6433,
+ 0xB8, 6462,
+ 0xB9, 6499,
+ 0xBA, 6502,
+ 0xBB, 6627,
+ 0xBC, 6656,
+ 0xBD, 6723,
+ 0xBE, 6790,
+ 0xBF, 6819,
+ 0xC0, 6848,
+ 0xC1, 6854,
+ 0xC2, 6883,
+ 0xC3, 6925,
+ 0xC4, 6954,
+ 0xC5, 6976,
+ 0xC6, 6998,
+ 0xC7, 7020,
+ 0xc8, 7149,
+ 0xc9, 7149,
+ 0xca, 7149,
+ 0xcb, 7149,
+ 0xcc, 7149,
+ 0xcd, 7149,
+ 0xce, 7149,
+ 0xcf, 7149,
+ 0xD0, 7172,
+ 0xD1, 7190,
+ 0xD2, 7208,
+ 0xD3, 7226,
+ 0xD4, 7244,
+ 0xD5, 7262,
+ 0xD6, 7280,
+ 0xD7, 7306,
+ 0xD8, 7324,
+ 0xD9, 7342,
+ 0xDA, 7360,
+ 0xDB, 7378,
+ 0xDC, 7396,
+ 0xDD, 7414,
+ 0xDE, 7432,
+ 0xDF, 7450,
+ 0xE0, 7468,
+ 0xE1, 7486,
+ 0xE2, 7504,
+ 0xE3, 7522,
+ 0xE4, 7540,
+ 0xE5, 7558,
+ 0xE6, 7576,
+ 0xE7, 7602,
+ 0xE8, 7620,
+ 0xE9, 7638,
+ 0xEA, 7656,
+ 0xEB, 7674,
+ 0xEC, 7692,
+ 0xED, 7710,
+ 0xEE, 7728,
+ 0xEF, 7746,
+ 0xF0, 7764,
+ 0xF1, 7774,
+ 0xF2, 7792,
+ 0xF3, 7810,
+ 0xF4, 7828,
+ 0xF5, 7846,
+ 0xF6, 7864,
+ 0xF7, 7882,
+ 0xF8, 7900,
+ 0xF9, 7918,
+ 0xFA, 7936,
+ 0xFB, 7954,
+ 0xFC, 7972,
+ 0xFD, 7990,
+ 0xFE, 8008,
+ uint16(x86_xFail),
+ /*1180*/ uint16(x86_xCondSlashR),
+ 1189, // 0
+ 1205, // 1
+ 1221, // 2
+ 1225, // 3
+ 1229, // 4
+ 1233, // 5
+ 0, // 6
+ 0, // 7
+ /*1189*/ uint16(x86_xCondDataSize), 1193, 1197, 1201,
+ /*1193*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+ /*1195*/ uint16(x86_xArgRM16),
+ /*1196*/ uint16(x86_xMatch),
+ /*1197*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+ /*1199*/ uint16(x86_xArgR32M16),
+ /*1200*/ uint16(x86_xMatch),
+ /*1201*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+ /*1203*/ uint16(x86_xArgR64M16),
+ /*1204*/ uint16(x86_xMatch),
+ /*1205*/ uint16(x86_xCondDataSize), 1209, 1213, 1217,
+ /*1209*/ uint16(x86_xSetOp), uint16(x86_STR),
+ /*1211*/ uint16(x86_xArgRM16),
+ /*1212*/ uint16(x86_xMatch),
+ /*1213*/ uint16(x86_xSetOp), uint16(x86_STR),
+ /*1215*/ uint16(x86_xArgR32M16),
+ /*1216*/ uint16(x86_xMatch),
+ /*1217*/ uint16(x86_xSetOp), uint16(x86_STR),
+ /*1219*/ uint16(x86_xArgR64M16),
+ /*1220*/ uint16(x86_xMatch),
+ /*1221*/ uint16(x86_xSetOp), uint16(x86_LLDT),
+ /*1223*/ uint16(x86_xArgRM16),
+ /*1224*/ uint16(x86_xMatch),
+ /*1225*/ uint16(x86_xSetOp), uint16(x86_LTR),
+ /*1227*/ uint16(x86_xArgRM16),
+ /*1228*/ uint16(x86_xMatch),
+ /*1229*/ uint16(x86_xSetOp), uint16(x86_VERR),
+ /*1231*/ uint16(x86_xArgRM16),
+ /*1232*/ uint16(x86_xMatch),
+ /*1233*/ uint16(x86_xSetOp), uint16(x86_VERW),
+ /*1235*/ uint16(x86_xArgRM16),
+ /*1236*/ uint16(x86_xMatch),
+ /*1237*/ uint16(x86_xCondByte), 8,
+ 0xC8, 1318,
+ 0xC9, 1321,
+ 0xD0, 1324,
+ 0xD1, 1327,
+ 0xD5, 1330,
+ 0xD6, 1333,
+ 0xF8, 1336,
+ 0xF9, 1342,
+ /*1255*/ uint16(x86_xCondSlashR),
+ 1264, // 0
+ 1268, // 1
+ 1272, // 2
+ 1283, // 3
+ 1294, // 4
+ 0, // 5
+ 1310, // 6
+ 1314, // 7
+ /*1264*/ uint16(x86_xSetOp), uint16(x86_SGDT),
+ /*1266*/ uint16(x86_xArgM),
+ /*1267*/ uint16(x86_xMatch),
+ /*1268*/ uint16(x86_xSetOp), uint16(x86_SIDT),
+ /*1270*/ uint16(x86_xArgM),
+ /*1271*/ uint16(x86_xMatch),
+ /*1272*/ uint16(x86_xCondIs64), 1275, 1279,
+ /*1275*/ uint16(x86_xSetOp), uint16(x86_LGDT),
+ /*1277*/ uint16(x86_xArgM16and32),
+ /*1278*/ uint16(x86_xMatch),
+ /*1279*/ uint16(x86_xSetOp), uint16(x86_LGDT),
+ /*1281*/ uint16(x86_xArgM16and64),
+ /*1282*/ uint16(x86_xMatch),
+ /*1283*/ uint16(x86_xCondIs64), 1286, 1290,
+ /*1286*/ uint16(x86_xSetOp), uint16(x86_LIDT),
+ /*1288*/ uint16(x86_xArgM16and32),
+ /*1289*/ uint16(x86_xMatch),
+ /*1290*/ uint16(x86_xSetOp), uint16(x86_LIDT),
+ /*1292*/ uint16(x86_xArgM16and64),
+ /*1293*/ uint16(x86_xMatch),
+ /*1294*/ uint16(x86_xCondDataSize), 1298, 1302, 1306,
+ /*1298*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+ /*1300*/ uint16(x86_xArgRM16),
+ /*1301*/ uint16(x86_xMatch),
+ /*1302*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+ /*1304*/ uint16(x86_xArgR32M16),
+ /*1305*/ uint16(x86_xMatch),
+ /*1306*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+ /*1308*/ uint16(x86_xArgR64M16),
+ /*1309*/ uint16(x86_xMatch),
+ /*1310*/ uint16(x86_xSetOp), uint16(x86_LMSW),
+ /*1312*/ uint16(x86_xArgRM16),
+ /*1313*/ uint16(x86_xMatch),
+ /*1314*/ uint16(x86_xSetOp), uint16(x86_INVLPG),
+ /*1316*/ uint16(x86_xArgM),
+ /*1317*/ uint16(x86_xMatch),
+ /*1318*/ uint16(x86_xSetOp), uint16(x86_MONITOR),
+ /*1320*/ uint16(x86_xMatch),
+ /*1321*/ uint16(x86_xSetOp), uint16(x86_MWAIT),
+ /*1323*/ uint16(x86_xMatch),
+ /*1324*/ uint16(x86_xSetOp), uint16(x86_XGETBV),
+ /*1326*/ uint16(x86_xMatch),
+ /*1327*/ uint16(x86_xSetOp), uint16(x86_XSETBV),
+ /*1329*/ uint16(x86_xMatch),
+ /*1330*/ uint16(x86_xSetOp), uint16(x86_XEND),
+ /*1332*/ uint16(x86_xMatch),
+ /*1333*/ uint16(x86_xSetOp), uint16(x86_XTEST),
+ /*1335*/ uint16(x86_xMatch),
+ /*1336*/ uint16(x86_xCondIs64), 0, 1339,
+ /*1339*/ uint16(x86_xSetOp), uint16(x86_SWAPGS),
+ /*1341*/ uint16(x86_xMatch),
+ /*1342*/ uint16(x86_xSetOp), uint16(x86_RDTSCP),
+ /*1344*/ uint16(x86_xMatch),
+ /*1345*/ uint16(x86_xCondDataSize), 1349, 1355, 1361,
+ /*1349*/ uint16(x86_xSetOp), uint16(x86_LAR),
+ /*1351*/ uint16(x86_xReadSlashR),
+ /*1352*/ uint16(x86_xArgR16),
+ /*1353*/ uint16(x86_xArgRM16),
+ /*1354*/ uint16(x86_xMatch),
+ /*1355*/ uint16(x86_xSetOp), uint16(x86_LAR),
+ /*1357*/ uint16(x86_xReadSlashR),
+ /*1358*/ uint16(x86_xArgR32),
+ /*1359*/ uint16(x86_xArgR32M16),
+ /*1360*/ uint16(x86_xMatch),
+ /*1361*/ uint16(x86_xSetOp), uint16(x86_LAR),
+ /*1363*/ uint16(x86_xReadSlashR),
+ /*1364*/ uint16(x86_xArgR64),
+ /*1365*/ uint16(x86_xArgR64M16),
+ /*1366*/ uint16(x86_xMatch),
+ /*1367*/ uint16(x86_xCondDataSize), 1371, 1377, 1383,
+ /*1371*/ uint16(x86_xSetOp), uint16(x86_LSL),
+ /*1373*/ uint16(x86_xReadSlashR),
+ /*1374*/ uint16(x86_xArgR16),
+ /*1375*/ uint16(x86_xArgRM16),
+ /*1376*/ uint16(x86_xMatch),
+ /*1377*/ uint16(x86_xSetOp), uint16(x86_LSL),
+ /*1379*/ uint16(x86_xReadSlashR),
+ /*1380*/ uint16(x86_xArgR32),
+ /*1381*/ uint16(x86_xArgR32M16),
+ /*1382*/ uint16(x86_xMatch),
+ /*1383*/ uint16(x86_xSetOp), uint16(x86_LSL),
+ /*1385*/ uint16(x86_xReadSlashR),
+ /*1386*/ uint16(x86_xArgR64),
+ /*1387*/ uint16(x86_xArgR32M16),
+ /*1388*/ uint16(x86_xMatch),
+ /*1389*/ uint16(x86_xCondIs64), 0, 1392,
+ /*1392*/ uint16(x86_xSetOp), uint16(x86_SYSCALL),
+ /*1394*/ uint16(x86_xMatch),
+ /*1395*/ uint16(x86_xSetOp), uint16(x86_CLTS),
+ /*1397*/ uint16(x86_xMatch),
+ /*1398*/ uint16(x86_xCondIs64), 0, 1401,
+ /*1401*/ uint16(x86_xSetOp), uint16(x86_SYSRET),
+ /*1403*/ uint16(x86_xMatch),
+ /*1404*/ uint16(x86_xSetOp), uint16(x86_INVD),
+ /*1406*/ uint16(x86_xMatch),
+ /*1407*/ uint16(x86_xSetOp), uint16(x86_WBINVD),
+ /*1409*/ uint16(x86_xMatch),
+ /*1410*/ uint16(x86_xSetOp), uint16(x86_UD2),
+ /*1412*/ uint16(x86_xMatch),
+ /*1413*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 1422, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*1422*/ uint16(x86_xSetOp), uint16(x86_PREFETCHW),
+ /*1424*/ uint16(x86_xArgM8),
+ /*1425*/ uint16(x86_xMatch),
+ /*1426*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1454,
+ 0xF2, 1448,
+ 0x66, 1442,
+ 0x0, 1436,
+ /*1436*/ uint16(x86_xSetOp), uint16(x86_MOVUPS),
+ /*1438*/ uint16(x86_xReadSlashR),
+ /*1439*/ uint16(x86_xArgXmm1),
+ /*1440*/ uint16(x86_xArgXmm2M128),
+ /*1441*/ uint16(x86_xMatch),
+ /*1442*/ uint16(x86_xSetOp), uint16(x86_MOVUPD),
+ /*1444*/ uint16(x86_xReadSlashR),
+ /*1445*/ uint16(x86_xArgXmm1),
+ /*1446*/ uint16(x86_xArgXmm2M128),
+ /*1447*/ uint16(x86_xMatch),
+ /*1448*/ uint16(x86_xSetOp), uint16(x86_MOVSD_XMM),
+ /*1450*/ uint16(x86_xReadSlashR),
+ /*1451*/ uint16(x86_xArgXmm1),
+ /*1452*/ uint16(x86_xArgXmm2M64),
+ /*1453*/ uint16(x86_xMatch),
+ /*1454*/ uint16(x86_xSetOp), uint16(x86_MOVSS),
+ /*1456*/ uint16(x86_xReadSlashR),
+ /*1457*/ uint16(x86_xArgXmm1),
+ /*1458*/ uint16(x86_xArgXmm2M32),
+ /*1459*/ uint16(x86_xMatch),
+ /*1460*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1488,
+ 0xF2, 1482,
+ 0x66, 1476,
+ 0x0, 1470,
+ /*1470*/ uint16(x86_xSetOp), uint16(x86_MOVUPS),
+ /*1472*/ uint16(x86_xReadSlashR),
+ /*1473*/ uint16(x86_xArgXmm2M128),
+ /*1474*/ uint16(x86_xArgXmm1),
+ /*1475*/ uint16(x86_xMatch),
+ /*1476*/ uint16(x86_xSetOp), uint16(x86_MOVUPD),
+ /*1478*/ uint16(x86_xReadSlashR),
+ /*1479*/ uint16(x86_xArgXmm2M128),
+ /*1480*/ uint16(x86_xArgXmm),
+ /*1481*/ uint16(x86_xMatch),
+ /*1482*/ uint16(x86_xSetOp), uint16(x86_MOVSD_XMM),
+ /*1484*/ uint16(x86_xReadSlashR),
+ /*1485*/ uint16(x86_xArgXmm2M64),
+ /*1486*/ uint16(x86_xArgXmm1),
+ /*1487*/ uint16(x86_xMatch),
+ /*1488*/ uint16(x86_xSetOp), uint16(x86_MOVSS),
+ /*1490*/ uint16(x86_xReadSlashR),
+ /*1491*/ uint16(x86_xArgXmm2M32),
+ /*1492*/ uint16(x86_xArgXmm),
+ /*1493*/ uint16(x86_xMatch),
+ /*1494*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1531,
+ 0xF2, 1525,
+ 0x66, 1519,
+ 0x0, 1504,
+ /*1504*/ uint16(x86_xCondIsMem), 1507, 1513,
+ /*1507*/ uint16(x86_xSetOp), uint16(x86_MOVHLPS),
+ /*1509*/ uint16(x86_xReadSlashR),
+ /*1510*/ uint16(x86_xArgXmm1),
+ /*1511*/ uint16(x86_xArgXmm2),
+ /*1512*/ uint16(x86_xMatch),
+ /*1513*/ uint16(x86_xSetOp), uint16(x86_MOVLPS),
+ /*1515*/ uint16(x86_xReadSlashR),
+ /*1516*/ uint16(x86_xArgXmm),
+ /*1517*/ uint16(x86_xArgM64),
+ /*1518*/ uint16(x86_xMatch),
+ /*1519*/ uint16(x86_xSetOp), uint16(x86_MOVLPD),
+ /*1521*/ uint16(x86_xReadSlashR),
+ /*1522*/ uint16(x86_xArgXmm),
+ /*1523*/ uint16(x86_xArgXmm2M64),
+ /*1524*/ uint16(x86_xMatch),
+ /*1525*/ uint16(x86_xSetOp), uint16(x86_MOVDDUP),
+ /*1527*/ uint16(x86_xReadSlashR),
+ /*1528*/ uint16(x86_xArgXmm1),
+ /*1529*/ uint16(x86_xArgXmm2M64),
+ /*1530*/ uint16(x86_xMatch),
+ /*1531*/ uint16(x86_xSetOp), uint16(x86_MOVSLDUP),
+ /*1533*/ uint16(x86_xReadSlashR),
+ /*1534*/ uint16(x86_xArgXmm1),
+ /*1535*/ uint16(x86_xArgXmm2M128),
+ /*1536*/ uint16(x86_xMatch),
+ /*1537*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1549,
+ 0x0, 1543,
+ /*1543*/ uint16(x86_xSetOp), uint16(x86_MOVLPS),
+ /*1545*/ uint16(x86_xReadSlashR),
+ /*1546*/ uint16(x86_xArgM64),
+ /*1547*/ uint16(x86_xArgXmm),
+ /*1548*/ uint16(x86_xMatch),
+ /*1549*/ uint16(x86_xSetOp), uint16(x86_MOVLPD),
+ /*1551*/ uint16(x86_xReadSlashR),
+ /*1552*/ uint16(x86_xArgXmm2M64),
+ /*1553*/ uint16(x86_xArgXmm),
+ /*1554*/ uint16(x86_xMatch),
+ /*1555*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1567,
+ 0x0, 1561,
+ /*1561*/ uint16(x86_xSetOp), uint16(x86_UNPCKLPS),
+ /*1563*/ uint16(x86_xReadSlashR),
+ /*1564*/ uint16(x86_xArgXmm1),
+ /*1565*/ uint16(x86_xArgXmm2M128),
+ /*1566*/ uint16(x86_xMatch),
+ /*1567*/ uint16(x86_xSetOp), uint16(x86_UNPCKLPD),
+ /*1569*/ uint16(x86_xReadSlashR),
+ /*1570*/ uint16(x86_xArgXmm1),
+ /*1571*/ uint16(x86_xArgXmm2M128),
+ /*1572*/ uint16(x86_xMatch),
+ /*1573*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1585,
+ 0x0, 1579,
+ /*1579*/ uint16(x86_xSetOp), uint16(x86_UNPCKHPS),
+ /*1581*/ uint16(x86_xReadSlashR),
+ /*1582*/ uint16(x86_xArgXmm1),
+ /*1583*/ uint16(x86_xArgXmm2M128),
+ /*1584*/ uint16(x86_xMatch),
+ /*1585*/ uint16(x86_xSetOp), uint16(x86_UNPCKHPD),
+ /*1587*/ uint16(x86_xReadSlashR),
+ /*1588*/ uint16(x86_xArgXmm1),
+ /*1589*/ uint16(x86_xArgXmm2M128),
+ /*1590*/ uint16(x86_xMatch),
+ /*1591*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 1620,
+ 0x66, 1614,
+ 0x0, 1599,
+ /*1599*/ uint16(x86_xCondIsMem), 1602, 1608,
+ /*1602*/ uint16(x86_xSetOp), uint16(x86_MOVLHPS),
+ /*1604*/ uint16(x86_xReadSlashR),
+ /*1605*/ uint16(x86_xArgXmm1),
+ /*1606*/ uint16(x86_xArgXmm2),
+ /*1607*/ uint16(x86_xMatch),
+ /*1608*/ uint16(x86_xSetOp), uint16(x86_MOVHPS),
+ /*1610*/ uint16(x86_xReadSlashR),
+ /*1611*/ uint16(x86_xArgXmm),
+ /*1612*/ uint16(x86_xArgM64),
+ /*1613*/ uint16(x86_xMatch),
+ /*1614*/ uint16(x86_xSetOp), uint16(x86_MOVHPD),
+ /*1616*/ uint16(x86_xReadSlashR),
+ /*1617*/ uint16(x86_xArgXmm),
+ /*1618*/ uint16(x86_xArgXmm2M64),
+ /*1619*/ uint16(x86_xMatch),
+ /*1620*/ uint16(x86_xSetOp), uint16(x86_MOVSHDUP),
+ /*1622*/ uint16(x86_xReadSlashR),
+ /*1623*/ uint16(x86_xArgXmm1),
+ /*1624*/ uint16(x86_xArgXmm2M128),
+ /*1625*/ uint16(x86_xMatch),
+ /*1626*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1638,
+ 0x0, 1632,
+ /*1632*/ uint16(x86_xSetOp), uint16(x86_MOVHPS),
+ /*1634*/ uint16(x86_xReadSlashR),
+ /*1635*/ uint16(x86_xArgM64),
+ /*1636*/ uint16(x86_xArgXmm),
+ /*1637*/ uint16(x86_xMatch),
+ /*1638*/ uint16(x86_xSetOp), uint16(x86_MOVHPD),
+ /*1640*/ uint16(x86_xReadSlashR),
+ /*1641*/ uint16(x86_xArgXmm2M64),
+ /*1642*/ uint16(x86_xArgXmm),
+ /*1643*/ uint16(x86_xMatch),
+ /*1644*/ uint16(x86_xCondSlashR),
+ 1653, // 0
+ 1657, // 1
+ 1661, // 2
+ 1665, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*1653*/ uint16(x86_xSetOp), uint16(x86_PREFETCHNTA),
+ /*1655*/ uint16(x86_xArgM8),
+ /*1656*/ uint16(x86_xMatch),
+ /*1657*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT0),
+ /*1659*/ uint16(x86_xArgM8),
+ /*1660*/ uint16(x86_xMatch),
+ /*1661*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT1),
+ /*1663*/ uint16(x86_xArgM8),
+ /*1664*/ uint16(x86_xMatch),
+ /*1665*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT2),
+ /*1667*/ uint16(x86_xArgM8),
+ /*1668*/ uint16(x86_xMatch),
+ /*1669*/ uint16(x86_xCondSlashR),
+ 1678, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*1678*/ uint16(x86_xCondDataSize), 1682, 1686, 0,
+ /*1682*/ uint16(x86_xSetOp), uint16(x86_NOP),
+ /*1684*/ uint16(x86_xArgRM16),
+ /*1685*/ uint16(x86_xMatch),
+ /*1686*/ uint16(x86_xSetOp), uint16(x86_NOP),
+ /*1688*/ uint16(x86_xArgRM32),
+ /*1689*/ uint16(x86_xMatch),
+ /*1690*/ uint16(x86_xCondIs64), 1693, 1699,
+ /*1693*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1695*/ uint16(x86_xReadSlashR),
+ /*1696*/ uint16(x86_xArgRmf32),
+ /*1697*/ uint16(x86_xArgCR0dashCR7),
+ /*1698*/ uint16(x86_xMatch),
+ /*1699*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1701*/ uint16(x86_xReadSlashR),
+ /*1702*/ uint16(x86_xArgRmf64),
+ /*1703*/ uint16(x86_xArgCR0dashCR7),
+ /*1704*/ uint16(x86_xMatch),
+ /*1705*/ uint16(x86_xCondIs64), 1708, 1714,
+ /*1708*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1710*/ uint16(x86_xReadSlashR),
+ /*1711*/ uint16(x86_xArgRmf32),
+ /*1712*/ uint16(x86_xArgDR0dashDR7),
+ /*1713*/ uint16(x86_xMatch),
+ /*1714*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1716*/ uint16(x86_xReadSlashR),
+ /*1717*/ uint16(x86_xArgRmf64),
+ /*1718*/ uint16(x86_xArgDR0dashDR7),
+ /*1719*/ uint16(x86_xMatch),
+ /*1720*/ uint16(x86_xCondIs64), 1723, 1729,
+ /*1723*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1725*/ uint16(x86_xReadSlashR),
+ /*1726*/ uint16(x86_xArgCR0dashCR7),
+ /*1727*/ uint16(x86_xArgRmf32),
+ /*1728*/ uint16(x86_xMatch),
+ /*1729*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1731*/ uint16(x86_xReadSlashR),
+ /*1732*/ uint16(x86_xArgCR0dashCR7),
+ /*1733*/ uint16(x86_xArgRmf64),
+ /*1734*/ uint16(x86_xMatch),
+ /*1735*/ uint16(x86_xCondIs64), 1738, 1744,
+ /*1738*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1740*/ uint16(x86_xReadSlashR),
+ /*1741*/ uint16(x86_xArgDR0dashDR7),
+ /*1742*/ uint16(x86_xArgRmf32),
+ /*1743*/ uint16(x86_xMatch),
+ /*1744*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1746*/ uint16(x86_xReadSlashR),
+ /*1747*/ uint16(x86_xArgDR0dashDR7),
+ /*1748*/ uint16(x86_xArgRmf64),
+ /*1749*/ uint16(x86_xMatch),
+ /*1750*/ uint16(x86_xCondIs64), 1753, 1759,
+ /*1753*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1755*/ uint16(x86_xReadSlashR),
+ /*1756*/ uint16(x86_xArgRmf32),
+ /*1757*/ uint16(x86_xArgTR0dashTR7),
+ /*1758*/ uint16(x86_xMatch),
+ /*1759*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1761*/ uint16(x86_xReadSlashR),
+ /*1762*/ uint16(x86_xArgRmf64),
+ /*1763*/ uint16(x86_xArgTR0dashTR7),
+ /*1764*/ uint16(x86_xMatch),
+ /*1765*/ uint16(x86_xCondIs64), 1768, 1774,
+ /*1768*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1770*/ uint16(x86_xReadSlashR),
+ /*1771*/ uint16(x86_xArgTR0dashTR7),
+ /*1772*/ uint16(x86_xArgRmf32),
+ /*1773*/ uint16(x86_xMatch),
+ /*1774*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*1776*/ uint16(x86_xReadSlashR),
+ /*1777*/ uint16(x86_xArgTR0dashTR7),
+ /*1778*/ uint16(x86_xArgRmf64),
+ /*1779*/ uint16(x86_xMatch),
+ /*1780*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1792,
+ 0x0, 1786,
+ /*1786*/ uint16(x86_xSetOp), uint16(x86_MOVAPS),
+ /*1788*/ uint16(x86_xReadSlashR),
+ /*1789*/ uint16(x86_xArgXmm1),
+ /*1790*/ uint16(x86_xArgXmm2M128),
+ /*1791*/ uint16(x86_xMatch),
+ /*1792*/ uint16(x86_xSetOp), uint16(x86_MOVAPD),
+ /*1794*/ uint16(x86_xReadSlashR),
+ /*1795*/ uint16(x86_xArgXmm1),
+ /*1796*/ uint16(x86_xArgXmm2M128),
+ /*1797*/ uint16(x86_xMatch),
+ /*1798*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 1810,
+ 0x0, 1804,
+ /*1804*/ uint16(x86_xSetOp), uint16(x86_MOVAPS),
+ /*1806*/ uint16(x86_xReadSlashR),
+ /*1807*/ uint16(x86_xArgXmm2M128),
+ /*1808*/ uint16(x86_xArgXmm1),
+ /*1809*/ uint16(x86_xMatch),
+ /*1810*/ uint16(x86_xSetOp), uint16(x86_MOVAPD),
+ /*1812*/ uint16(x86_xReadSlashR),
+ /*1813*/ uint16(x86_xArgXmm2M128),
+ /*1814*/ uint16(x86_xArgXmm1),
+ /*1815*/ uint16(x86_xMatch),
+ /*1816*/ uint16(x86_xCondIs64), 1819, 1873,
+ /*1819*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1857,
+ 0xF2, 1841,
+ 0x66, 1835,
+ 0x0, 1829,
+ /*1829*/ uint16(x86_xSetOp), uint16(x86_CVTPI2PS),
+ /*1831*/ uint16(x86_xReadSlashR),
+ /*1832*/ uint16(x86_xArgXmm),
+ /*1833*/ uint16(x86_xArgMmM64),
+ /*1834*/ uint16(x86_xMatch),
+ /*1835*/ uint16(x86_xSetOp), uint16(x86_CVTPI2PD),
+ /*1837*/ uint16(x86_xReadSlashR),
+ /*1838*/ uint16(x86_xArgXmm),
+ /*1839*/ uint16(x86_xArgMmM64),
+ /*1840*/ uint16(x86_xMatch),
+ /*1841*/ uint16(x86_xCondDataSize), 1845, 1851, 0,
+ /*1845*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+ /*1847*/ uint16(x86_xReadSlashR),
+ /*1848*/ uint16(x86_xArgXmm),
+ /*1849*/ uint16(x86_xArgRM32),
+ /*1850*/ uint16(x86_xMatch),
+ /*1851*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+ /*1853*/ uint16(x86_xReadSlashR),
+ /*1854*/ uint16(x86_xArgXmm),
+ /*1855*/ uint16(x86_xArgRM32),
+ /*1856*/ uint16(x86_xMatch),
+ /*1857*/ uint16(x86_xCondDataSize), 1861, 1867, 0,
+ /*1861*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+ /*1863*/ uint16(x86_xReadSlashR),
+ /*1864*/ uint16(x86_xArgXmm),
+ /*1865*/ uint16(x86_xArgRM32),
+ /*1866*/ uint16(x86_xMatch),
+ /*1867*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+ /*1869*/ uint16(x86_xReadSlashR),
+ /*1870*/ uint16(x86_xArgXmm),
+ /*1871*/ uint16(x86_xArgRM32),
+ /*1872*/ uint16(x86_xMatch),
+ /*1873*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1893,
+ 0xF2, 1883,
+ 0x66, 1835,
+ 0x0, 1829,
+ /*1883*/ uint16(x86_xCondDataSize), 1845, 1851, 1887,
+ /*1887*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+ /*1889*/ uint16(x86_xReadSlashR),
+ /*1890*/ uint16(x86_xArgXmm),
+ /*1891*/ uint16(x86_xArgRM64),
+ /*1892*/ uint16(x86_xMatch),
+ /*1893*/ uint16(x86_xCondDataSize), 1861, 1867, 1897,
+ /*1897*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+ /*1899*/ uint16(x86_xReadSlashR),
+ /*1900*/ uint16(x86_xArgXmm),
+ /*1901*/ uint16(x86_xArgRM64),
+ /*1902*/ uint16(x86_xMatch),
+ /*1903*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1931,
+ 0xF2, 1925,
+ 0x66, 1919,
+ 0x0, 1913,
+ /*1913*/ uint16(x86_xSetOp), uint16(x86_MOVNTPS),
+ /*1915*/ uint16(x86_xReadSlashR),
+ /*1916*/ uint16(x86_xArgM128),
+ /*1917*/ uint16(x86_xArgXmm),
+ /*1918*/ uint16(x86_xMatch),
+ /*1919*/ uint16(x86_xSetOp), uint16(x86_MOVNTPD),
+ /*1921*/ uint16(x86_xReadSlashR),
+ /*1922*/ uint16(x86_xArgM128),
+ /*1923*/ uint16(x86_xArgXmm),
+ /*1924*/ uint16(x86_xMatch),
+ /*1925*/ uint16(x86_xSetOp), uint16(x86_MOVNTSD),
+ /*1927*/ uint16(x86_xReadSlashR),
+ /*1928*/ uint16(x86_xArgM64),
+ /*1929*/ uint16(x86_xArgXmm),
+ /*1930*/ uint16(x86_xMatch),
+ /*1931*/ uint16(x86_xSetOp), uint16(x86_MOVNTSS),
+ /*1933*/ uint16(x86_xReadSlashR),
+ /*1934*/ uint16(x86_xArgM32),
+ /*1935*/ uint16(x86_xArgXmm),
+ /*1936*/ uint16(x86_xMatch),
+ /*1937*/ uint16(x86_xCondIs64), 1940, 1994,
+ /*1940*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 1978,
+ 0xF2, 1962,
+ 0x66, 1956,
+ 0x0, 1950,
+ /*1950*/ uint16(x86_xSetOp), uint16(x86_CVTTPS2PI),
+ /*1952*/ uint16(x86_xReadSlashR),
+ /*1953*/ uint16(x86_xArgMm),
+ /*1954*/ uint16(x86_xArgXmmM64),
+ /*1955*/ uint16(x86_xMatch),
+ /*1956*/ uint16(x86_xSetOp), uint16(x86_CVTTPD2PI),
+ /*1958*/ uint16(x86_xReadSlashR),
+ /*1959*/ uint16(x86_xArgMm),
+ /*1960*/ uint16(x86_xArgXmmM128),
+ /*1961*/ uint16(x86_xMatch),
+ /*1962*/ uint16(x86_xCondDataSize), 1966, 1972, 0,
+ /*1966*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+ /*1968*/ uint16(x86_xReadSlashR),
+ /*1969*/ uint16(x86_xArgR32),
+ /*1970*/ uint16(x86_xArgXmmM64),
+ /*1971*/ uint16(x86_xMatch),
+ /*1972*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+ /*1974*/ uint16(x86_xReadSlashR),
+ /*1975*/ uint16(x86_xArgR32),
+ /*1976*/ uint16(x86_xArgXmmM64),
+ /*1977*/ uint16(x86_xMatch),
+ /*1978*/ uint16(x86_xCondDataSize), 1982, 1988, 0,
+ /*1982*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+ /*1984*/ uint16(x86_xReadSlashR),
+ /*1985*/ uint16(x86_xArgR32),
+ /*1986*/ uint16(x86_xArgXmmM32),
+ /*1987*/ uint16(x86_xMatch),
+ /*1988*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+ /*1990*/ uint16(x86_xReadSlashR),
+ /*1991*/ uint16(x86_xArgR32),
+ /*1992*/ uint16(x86_xArgXmmM32),
+ /*1993*/ uint16(x86_xMatch),
+ /*1994*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 2014,
+ 0xF2, 2004,
+ 0x66, 1956,
+ 0x0, 1950,
+ /*2004*/ uint16(x86_xCondDataSize), 1966, 1972, 2008,
+ /*2008*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+ /*2010*/ uint16(x86_xReadSlashR),
+ /*2011*/ uint16(x86_xArgR64),
+ /*2012*/ uint16(x86_xArgXmmM64),
+ /*2013*/ uint16(x86_xMatch),
+ /*2014*/ uint16(x86_xCondDataSize), 1982, 1988, 2018,
+ /*2018*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+ /*2020*/ uint16(x86_xReadSlashR),
+ /*2021*/ uint16(x86_xArgR64),
+ /*2022*/ uint16(x86_xArgXmmM32),
+ /*2023*/ uint16(x86_xMatch),
+ /*2024*/ uint16(x86_xCondIs64), 2027, 2081,
+ /*2027*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 2065,
+ 0xF2, 2049,
+ 0x66, 2043,
+ 0x0, 2037,
+ /*2037*/ uint16(x86_xSetOp), uint16(x86_CVTPS2PI),
+ /*2039*/ uint16(x86_xReadSlashR),
+ /*2040*/ uint16(x86_xArgMm),
+ /*2041*/ uint16(x86_xArgXmmM64),
+ /*2042*/ uint16(x86_xMatch),
+ /*2043*/ uint16(x86_xSetOp), uint16(x86_CVTPD2PI),
+ /*2045*/ uint16(x86_xReadSlashR),
+ /*2046*/ uint16(x86_xArgMm),
+ /*2047*/ uint16(x86_xArgXmmM128),
+ /*2048*/ uint16(x86_xMatch),
+ /*2049*/ uint16(x86_xCondDataSize), 2053, 2059, 0,
+ /*2053*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+ /*2055*/ uint16(x86_xReadSlashR),
+ /*2056*/ uint16(x86_xArgR32),
+ /*2057*/ uint16(x86_xArgXmmM64),
+ /*2058*/ uint16(x86_xMatch),
+ /*2059*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+ /*2061*/ uint16(x86_xReadSlashR),
+ /*2062*/ uint16(x86_xArgR32),
+ /*2063*/ uint16(x86_xArgXmmM64),
+ /*2064*/ uint16(x86_xMatch),
+ /*2065*/ uint16(x86_xCondDataSize), 2069, 2075, 0,
+ /*2069*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+ /*2071*/ uint16(x86_xReadSlashR),
+ /*2072*/ uint16(x86_xArgR32),
+ /*2073*/ uint16(x86_xArgXmmM32),
+ /*2074*/ uint16(x86_xMatch),
+ /*2075*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+ /*2077*/ uint16(x86_xReadSlashR),
+ /*2078*/ uint16(x86_xArgR32),
+ /*2079*/ uint16(x86_xArgXmmM32),
+ /*2080*/ uint16(x86_xMatch),
+ /*2081*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 2101,
+ 0xF2, 2091,
+ 0x66, 2043,
+ 0x0, 2037,
+ /*2091*/ uint16(x86_xCondDataSize), 2053, 2059, 2095,
+ /*2095*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+ /*2097*/ uint16(x86_xReadSlashR),
+ /*2098*/ uint16(x86_xArgR64),
+ /*2099*/ uint16(x86_xArgXmmM64),
+ /*2100*/ uint16(x86_xMatch),
+ /*2101*/ uint16(x86_xCondDataSize), 2069, 2075, 2105,
+ /*2105*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+ /*2107*/ uint16(x86_xReadSlashR),
+ /*2108*/ uint16(x86_xArgR64),
+ /*2109*/ uint16(x86_xArgXmmM32),
+ /*2110*/ uint16(x86_xMatch),
+ /*2111*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2123,
+ 0x0, 2117,
+ /*2117*/ uint16(x86_xSetOp), uint16(x86_UCOMISS),
+ /*2119*/ uint16(x86_xReadSlashR),
+ /*2120*/ uint16(x86_xArgXmm1),
+ /*2121*/ uint16(x86_xArgXmm2M32),
+ /*2122*/ uint16(x86_xMatch),
+ /*2123*/ uint16(x86_xSetOp), uint16(x86_UCOMISD),
+ /*2125*/ uint16(x86_xReadSlashR),
+ /*2126*/ uint16(x86_xArgXmm1),
+ /*2127*/ uint16(x86_xArgXmm2M64),
+ /*2128*/ uint16(x86_xMatch),
+ /*2129*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2141,
+ 0x0, 2135,
+ /*2135*/ uint16(x86_xSetOp), uint16(x86_COMISS),
+ /*2137*/ uint16(x86_xReadSlashR),
+ /*2138*/ uint16(x86_xArgXmm1),
+ /*2139*/ uint16(x86_xArgXmm2M32),
+ /*2140*/ uint16(x86_xMatch),
+ /*2141*/ uint16(x86_xSetOp), uint16(x86_COMISD),
+ /*2143*/ uint16(x86_xReadSlashR),
+ /*2144*/ uint16(x86_xArgXmm1),
+ /*2145*/ uint16(x86_xArgXmm2M64),
+ /*2146*/ uint16(x86_xMatch),
+ /*2147*/ uint16(x86_xSetOp), uint16(x86_WRMSR),
+ /*2149*/ uint16(x86_xMatch),
+ /*2150*/ uint16(x86_xSetOp), uint16(x86_RDTSC),
+ /*2152*/ uint16(x86_xMatch),
+ /*2153*/ uint16(x86_xSetOp), uint16(x86_RDMSR),
+ /*2155*/ uint16(x86_xMatch),
+ /*2156*/ uint16(x86_xSetOp), uint16(x86_RDPMC),
+ /*2158*/ uint16(x86_xMatch),
+ /*2159*/ uint16(x86_xSetOp), uint16(x86_SYSENTER),
+ /*2161*/ uint16(x86_xMatch),
+ /*2162*/ uint16(x86_xCondDataSize), 2166, 2166, 2169,
+ /*2166*/ uint16(x86_xSetOp), uint16(x86_SYSEXIT),
+ /*2168*/ uint16(x86_xMatch),
+ /*2169*/ uint16(x86_xSetOp), uint16(x86_SYSEXIT),
+ /*2171*/ uint16(x86_xMatch),
+ /*2172*/ uint16(x86_xCondByte), 54,
+ 0x00, 2283,
+ 0x01, 2301,
+ 0x02, 2319,
+ 0x03, 2337,
+ 0x04, 2355,
+ 0x05, 2373,
+ 0x06, 2391,
+ 0x07, 2409,
+ 0x08, 2427,
+ 0x09, 2445,
+ 0x0A, 2463,
+ 0x0B, 2481,
+ 0x10, 2499,
+ 0x14, 2510,
+ 0x15, 2521,
+ 0x17, 2532,
+ 0x1C, 2542,
+ 0x1D, 2560,
+ 0x1E, 2578,
+ 0x20, 2596,
+ 0x21, 2606,
+ 0x22, 2616,
+ 0x23, 2626,
+ 0x24, 2636,
+ 0x25, 2646,
+ 0x28, 2656,
+ 0x29, 2666,
+ 0x2A, 2676,
+ 0x2B, 2686,
+ 0x30, 2696,
+ 0x31, 2706,
+ 0x32, 2716,
+ 0x33, 2726,
+ 0x34, 2736,
+ 0x35, 2746,
+ 0x37, 2756,
+ 0x38, 2766,
+ 0x39, 2776,
+ 0x3A, 2786,
+ 0x3B, 2796,
+ 0x3C, 2806,
+ 0x3D, 2816,
+ 0x3E, 2826,
+ 0x3F, 2836,
+ 0x40, 2846,
+ 0x41, 2856,
+ 0x82, 2866,
+ 0xDB, 2889,
+ 0xDC, 2899,
+ 0xDD, 2909,
+ 0xDE, 2919,
+ 0xDF, 2929,
+ 0xF0, 2939,
+ 0xF1, 3006,
+ uint16(x86_xFail),
+ /*2283*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2295,
+ 0x0, 2289,
+ /*2289*/ uint16(x86_xSetOp), uint16(x86_PSHUFB),
+ /*2291*/ uint16(x86_xReadSlashR),
+ /*2292*/ uint16(x86_xArgMm1),
+ /*2293*/ uint16(x86_xArgMm2M64),
+ /*2294*/ uint16(x86_xMatch),
+ /*2295*/ uint16(x86_xSetOp), uint16(x86_PSHUFB),
+ /*2297*/ uint16(x86_xReadSlashR),
+ /*2298*/ uint16(x86_xArgXmm1),
+ /*2299*/ uint16(x86_xArgXmm2M128),
+ /*2300*/ uint16(x86_xMatch),
+ /*2301*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2313,
+ 0x0, 2307,
+ /*2307*/ uint16(x86_xSetOp), uint16(x86_PHADDW),
+ /*2309*/ uint16(x86_xReadSlashR),
+ /*2310*/ uint16(x86_xArgMm1),
+ /*2311*/ uint16(x86_xArgMm2M64),
+ /*2312*/ uint16(x86_xMatch),
+ /*2313*/ uint16(x86_xSetOp), uint16(x86_PHADDW),
+ /*2315*/ uint16(x86_xReadSlashR),
+ /*2316*/ uint16(x86_xArgXmm1),
+ /*2317*/ uint16(x86_xArgXmm2M128),
+ /*2318*/ uint16(x86_xMatch),
+ /*2319*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2331,
+ 0x0, 2325,
+ /*2325*/ uint16(x86_xSetOp), uint16(x86_PHADDD),
+ /*2327*/ uint16(x86_xReadSlashR),
+ /*2328*/ uint16(x86_xArgMm1),
+ /*2329*/ uint16(x86_xArgMm2M64),
+ /*2330*/ uint16(x86_xMatch),
+ /*2331*/ uint16(x86_xSetOp), uint16(x86_PHADDD),
+ /*2333*/ uint16(x86_xReadSlashR),
+ /*2334*/ uint16(x86_xArgXmm1),
+ /*2335*/ uint16(x86_xArgXmm2M128),
+ /*2336*/ uint16(x86_xMatch),
+ /*2337*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2349,
+ 0x0, 2343,
+ /*2343*/ uint16(x86_xSetOp), uint16(x86_PHADDSW),
+ /*2345*/ uint16(x86_xReadSlashR),
+ /*2346*/ uint16(x86_xArgMm1),
+ /*2347*/ uint16(x86_xArgMm2M64),
+ /*2348*/ uint16(x86_xMatch),
+ /*2349*/ uint16(x86_xSetOp), uint16(x86_PHADDSW),
+ /*2351*/ uint16(x86_xReadSlashR),
+ /*2352*/ uint16(x86_xArgXmm1),
+ /*2353*/ uint16(x86_xArgXmm2M128),
+ /*2354*/ uint16(x86_xMatch),
+ /*2355*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2367,
+ 0x0, 2361,
+ /*2361*/ uint16(x86_xSetOp), uint16(x86_PMADDUBSW),
+ /*2363*/ uint16(x86_xReadSlashR),
+ /*2364*/ uint16(x86_xArgMm1),
+ /*2365*/ uint16(x86_xArgMm2M64),
+ /*2366*/ uint16(x86_xMatch),
+ /*2367*/ uint16(x86_xSetOp), uint16(x86_PMADDUBSW),
+ /*2369*/ uint16(x86_xReadSlashR),
+ /*2370*/ uint16(x86_xArgXmm1),
+ /*2371*/ uint16(x86_xArgXmm2M128),
+ /*2372*/ uint16(x86_xMatch),
+ /*2373*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2385,
+ 0x0, 2379,
+ /*2379*/ uint16(x86_xSetOp), uint16(x86_PHSUBW),
+ /*2381*/ uint16(x86_xReadSlashR),
+ /*2382*/ uint16(x86_xArgMm1),
+ /*2383*/ uint16(x86_xArgMm2M64),
+ /*2384*/ uint16(x86_xMatch),
+ /*2385*/ uint16(x86_xSetOp), uint16(x86_PHSUBW),
+ /*2387*/ uint16(x86_xReadSlashR),
+ /*2388*/ uint16(x86_xArgXmm1),
+ /*2389*/ uint16(x86_xArgXmm2M128),
+ /*2390*/ uint16(x86_xMatch),
+ /*2391*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2403,
+ 0x0, 2397,
+ /*2397*/ uint16(x86_xSetOp), uint16(x86_PHSUBD),
+ /*2399*/ uint16(x86_xReadSlashR),
+ /*2400*/ uint16(x86_xArgMm1),
+ /*2401*/ uint16(x86_xArgMm2M64),
+ /*2402*/ uint16(x86_xMatch),
+ /*2403*/ uint16(x86_xSetOp), uint16(x86_PHSUBD),
+ /*2405*/ uint16(x86_xReadSlashR),
+ /*2406*/ uint16(x86_xArgXmm1),
+ /*2407*/ uint16(x86_xArgXmm2M128),
+ /*2408*/ uint16(x86_xMatch),
+ /*2409*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2421,
+ 0x0, 2415,
+ /*2415*/ uint16(x86_xSetOp), uint16(x86_PHSUBSW),
+ /*2417*/ uint16(x86_xReadSlashR),
+ /*2418*/ uint16(x86_xArgMm1),
+ /*2419*/ uint16(x86_xArgMm2M64),
+ /*2420*/ uint16(x86_xMatch),
+ /*2421*/ uint16(x86_xSetOp), uint16(x86_PHSUBSW),
+ /*2423*/ uint16(x86_xReadSlashR),
+ /*2424*/ uint16(x86_xArgXmm1),
+ /*2425*/ uint16(x86_xArgXmm2M128),
+ /*2426*/ uint16(x86_xMatch),
+ /*2427*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2439,
+ 0x0, 2433,
+ /*2433*/ uint16(x86_xSetOp), uint16(x86_PSIGNB),
+ /*2435*/ uint16(x86_xReadSlashR),
+ /*2436*/ uint16(x86_xArgMm1),
+ /*2437*/ uint16(x86_xArgMm2M64),
+ /*2438*/ uint16(x86_xMatch),
+ /*2439*/ uint16(x86_xSetOp), uint16(x86_PSIGNB),
+ /*2441*/ uint16(x86_xReadSlashR),
+ /*2442*/ uint16(x86_xArgXmm1),
+ /*2443*/ uint16(x86_xArgXmm2M128),
+ /*2444*/ uint16(x86_xMatch),
+ /*2445*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2457,
+ 0x0, 2451,
+ /*2451*/ uint16(x86_xSetOp), uint16(x86_PSIGNW),
+ /*2453*/ uint16(x86_xReadSlashR),
+ /*2454*/ uint16(x86_xArgMm1),
+ /*2455*/ uint16(x86_xArgMm2M64),
+ /*2456*/ uint16(x86_xMatch),
+ /*2457*/ uint16(x86_xSetOp), uint16(x86_PSIGNW),
+ /*2459*/ uint16(x86_xReadSlashR),
+ /*2460*/ uint16(x86_xArgXmm1),
+ /*2461*/ uint16(x86_xArgXmm2M128),
+ /*2462*/ uint16(x86_xMatch),
+ /*2463*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2475,
+ 0x0, 2469,
+ /*2469*/ uint16(x86_xSetOp), uint16(x86_PSIGND),
+ /*2471*/ uint16(x86_xReadSlashR),
+ /*2472*/ uint16(x86_xArgMm1),
+ /*2473*/ uint16(x86_xArgMm2M64),
+ /*2474*/ uint16(x86_xMatch),
+ /*2475*/ uint16(x86_xSetOp), uint16(x86_PSIGND),
+ /*2477*/ uint16(x86_xReadSlashR),
+ /*2478*/ uint16(x86_xArgXmm1),
+ /*2479*/ uint16(x86_xArgXmm2M128),
+ /*2480*/ uint16(x86_xMatch),
+ /*2481*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2493,
+ 0x0, 2487,
+ /*2487*/ uint16(x86_xSetOp), uint16(x86_PMULHRSW),
+ /*2489*/ uint16(x86_xReadSlashR),
+ /*2490*/ uint16(x86_xArgMm1),
+ /*2491*/ uint16(x86_xArgMm2M64),
+ /*2492*/ uint16(x86_xMatch),
+ /*2493*/ uint16(x86_xSetOp), uint16(x86_PMULHRSW),
+ /*2495*/ uint16(x86_xReadSlashR),
+ /*2496*/ uint16(x86_xArgXmm1),
+ /*2497*/ uint16(x86_xArgXmm2M128),
+ /*2498*/ uint16(x86_xMatch),
+ /*2499*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2503,
+ /*2503*/ uint16(x86_xSetOp), uint16(x86_PBLENDVB),
+ /*2505*/ uint16(x86_xReadSlashR),
+ /*2506*/ uint16(x86_xArgXmm1),
+ /*2507*/ uint16(x86_xArgXmm2M128),
+ /*2508*/ uint16(x86_xArgXMM0),
+ /*2509*/ uint16(x86_xMatch),
+ /*2510*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2514,
+ /*2514*/ uint16(x86_xSetOp), uint16(x86_BLENDVPS),
+ /*2516*/ uint16(x86_xReadSlashR),
+ /*2517*/ uint16(x86_xArgXmm1),
+ /*2518*/ uint16(x86_xArgXmm2M128),
+ /*2519*/ uint16(x86_xArgXMM0),
+ /*2520*/ uint16(x86_xMatch),
+ /*2521*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2525,
+ /*2525*/ uint16(x86_xSetOp), uint16(x86_BLENDVPD),
+ /*2527*/ uint16(x86_xReadSlashR),
+ /*2528*/ uint16(x86_xArgXmm1),
+ /*2529*/ uint16(x86_xArgXmm2M128),
+ /*2530*/ uint16(x86_xArgXMM0),
+ /*2531*/ uint16(x86_xMatch),
+ /*2532*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2536,
+ /*2536*/ uint16(x86_xSetOp), uint16(x86_PTEST),
+ /*2538*/ uint16(x86_xReadSlashR),
+ /*2539*/ uint16(x86_xArgXmm1),
+ /*2540*/ uint16(x86_xArgXmm2M128),
+ /*2541*/ uint16(x86_xMatch),
+ /*2542*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2554,
+ 0x0, 2548,
+ /*2548*/ uint16(x86_xSetOp), uint16(x86_PABSB),
+ /*2550*/ uint16(x86_xReadSlashR),
+ /*2551*/ uint16(x86_xArgMm1),
+ /*2552*/ uint16(x86_xArgMm2M64),
+ /*2553*/ uint16(x86_xMatch),
+ /*2554*/ uint16(x86_xSetOp), uint16(x86_PABSB),
+ /*2556*/ uint16(x86_xReadSlashR),
+ /*2557*/ uint16(x86_xArgXmm1),
+ /*2558*/ uint16(x86_xArgXmm2M128),
+ /*2559*/ uint16(x86_xMatch),
+ /*2560*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2572,
+ 0x0, 2566,
+ /*2566*/ uint16(x86_xSetOp), uint16(x86_PABSW),
+ /*2568*/ uint16(x86_xReadSlashR),
+ /*2569*/ uint16(x86_xArgMm1),
+ /*2570*/ uint16(x86_xArgMm2M64),
+ /*2571*/ uint16(x86_xMatch),
+ /*2572*/ uint16(x86_xSetOp), uint16(x86_PABSW),
+ /*2574*/ uint16(x86_xReadSlashR),
+ /*2575*/ uint16(x86_xArgXmm1),
+ /*2576*/ uint16(x86_xArgXmm2M128),
+ /*2577*/ uint16(x86_xMatch),
+ /*2578*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 2590,
+ 0x0, 2584,
+ /*2584*/ uint16(x86_xSetOp), uint16(x86_PABSD),
+ /*2586*/ uint16(x86_xReadSlashR),
+ /*2587*/ uint16(x86_xArgMm1),
+ /*2588*/ uint16(x86_xArgMm2M64),
+ /*2589*/ uint16(x86_xMatch),
+ /*2590*/ uint16(x86_xSetOp), uint16(x86_PABSD),
+ /*2592*/ uint16(x86_xReadSlashR),
+ /*2593*/ uint16(x86_xArgXmm1),
+ /*2594*/ uint16(x86_xArgXmm2M128),
+ /*2595*/ uint16(x86_xMatch),
+ /*2596*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2600,
+ /*2600*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBW),
+ /*2602*/ uint16(x86_xReadSlashR),
+ /*2603*/ uint16(x86_xArgXmm1),
+ /*2604*/ uint16(x86_xArgXmm2M64),
+ /*2605*/ uint16(x86_xMatch),
+ /*2606*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2610,
+ /*2610*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBD),
+ /*2612*/ uint16(x86_xReadSlashR),
+ /*2613*/ uint16(x86_xArgXmm1),
+ /*2614*/ uint16(x86_xArgXmm2M32),
+ /*2615*/ uint16(x86_xMatch),
+ /*2616*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2620,
+ /*2620*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBQ),
+ /*2622*/ uint16(x86_xReadSlashR),
+ /*2623*/ uint16(x86_xArgXmm1),
+ /*2624*/ uint16(x86_xArgXmm2M16),
+ /*2625*/ uint16(x86_xMatch),
+ /*2626*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2630,
+ /*2630*/ uint16(x86_xSetOp), uint16(x86_PMOVSXWD),
+ /*2632*/ uint16(x86_xReadSlashR),
+ /*2633*/ uint16(x86_xArgXmm1),
+ /*2634*/ uint16(x86_xArgXmm2M64),
+ /*2635*/ uint16(x86_xMatch),
+ /*2636*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2640,
+ /*2640*/ uint16(x86_xSetOp), uint16(x86_PMOVSXWQ),
+ /*2642*/ uint16(x86_xReadSlashR),
+ /*2643*/ uint16(x86_xArgXmm1),
+ /*2644*/ uint16(x86_xArgXmm2M32),
+ /*2645*/ uint16(x86_xMatch),
+ /*2646*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2650,
+ /*2650*/ uint16(x86_xSetOp), uint16(x86_PMOVSXDQ),
+ /*2652*/ uint16(x86_xReadSlashR),
+ /*2653*/ uint16(x86_xArgXmm1),
+ /*2654*/ uint16(x86_xArgXmm2M64),
+ /*2655*/ uint16(x86_xMatch),
+ /*2656*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2660,
+ /*2660*/ uint16(x86_xSetOp), uint16(x86_PMULDQ),
+ /*2662*/ uint16(x86_xReadSlashR),
+ /*2663*/ uint16(x86_xArgXmm1),
+ /*2664*/ uint16(x86_xArgXmm2M128),
+ /*2665*/ uint16(x86_xMatch),
+ /*2666*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2670,
+ /*2670*/ uint16(x86_xSetOp), uint16(x86_PCMPEQQ),
+ /*2672*/ uint16(x86_xReadSlashR),
+ /*2673*/ uint16(x86_xArgXmm1),
+ /*2674*/ uint16(x86_xArgXmm2M128),
+ /*2675*/ uint16(x86_xMatch),
+ /*2676*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2680,
+ /*2680*/ uint16(x86_xSetOp), uint16(x86_MOVNTDQA),
+ /*2682*/ uint16(x86_xReadSlashR),
+ /*2683*/ uint16(x86_xArgXmm1),
+ /*2684*/ uint16(x86_xArgM128),
+ /*2685*/ uint16(x86_xMatch),
+ /*2686*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2690,
+ /*2690*/ uint16(x86_xSetOp), uint16(x86_PACKUSDW),
+ /*2692*/ uint16(x86_xReadSlashR),
+ /*2693*/ uint16(x86_xArgXmm1),
+ /*2694*/ uint16(x86_xArgXmm2M128),
+ /*2695*/ uint16(x86_xMatch),
+ /*2696*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2700,
+ /*2700*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBW),
+ /*2702*/ uint16(x86_xReadSlashR),
+ /*2703*/ uint16(x86_xArgXmm1),
+ /*2704*/ uint16(x86_xArgXmm2M64),
+ /*2705*/ uint16(x86_xMatch),
+ /*2706*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2710,
+ /*2710*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBD),
+ /*2712*/ uint16(x86_xReadSlashR),
+ /*2713*/ uint16(x86_xArgXmm1),
+ /*2714*/ uint16(x86_xArgXmm2M32),
+ /*2715*/ uint16(x86_xMatch),
+ /*2716*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2720,
+ /*2720*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBQ),
+ /*2722*/ uint16(x86_xReadSlashR),
+ /*2723*/ uint16(x86_xArgXmm1),
+ /*2724*/ uint16(x86_xArgXmm2M16),
+ /*2725*/ uint16(x86_xMatch),
+ /*2726*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2730,
+ /*2730*/ uint16(x86_xSetOp), uint16(x86_PMOVZXWD),
+ /*2732*/ uint16(x86_xReadSlashR),
+ /*2733*/ uint16(x86_xArgXmm1),
+ /*2734*/ uint16(x86_xArgXmm2M64),
+ /*2735*/ uint16(x86_xMatch),
+ /*2736*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2740,
+ /*2740*/ uint16(x86_xSetOp), uint16(x86_PMOVZXWQ),
+ /*2742*/ uint16(x86_xReadSlashR),
+ /*2743*/ uint16(x86_xArgXmm1),
+ /*2744*/ uint16(x86_xArgXmm2M32),
+ /*2745*/ uint16(x86_xMatch),
+ /*2746*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2750,
+ /*2750*/ uint16(x86_xSetOp), uint16(x86_PMOVZXDQ),
+ /*2752*/ uint16(x86_xReadSlashR),
+ /*2753*/ uint16(x86_xArgXmm1),
+ /*2754*/ uint16(x86_xArgXmm2M64),
+ /*2755*/ uint16(x86_xMatch),
+ /*2756*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2760,
+ /*2760*/ uint16(x86_xSetOp), uint16(x86_PCMPGTQ),
+ /*2762*/ uint16(x86_xReadSlashR),
+ /*2763*/ uint16(x86_xArgXmm1),
+ /*2764*/ uint16(x86_xArgXmm2M128),
+ /*2765*/ uint16(x86_xMatch),
+ /*2766*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2770,
+ /*2770*/ uint16(x86_xSetOp), uint16(x86_PMINSB),
+ /*2772*/ uint16(x86_xReadSlashR),
+ /*2773*/ uint16(x86_xArgXmm1),
+ /*2774*/ uint16(x86_xArgXmm2M128),
+ /*2775*/ uint16(x86_xMatch),
+ /*2776*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2780,
+ /*2780*/ uint16(x86_xSetOp), uint16(x86_PMINSD),
+ /*2782*/ uint16(x86_xReadSlashR),
+ /*2783*/ uint16(x86_xArgXmm1),
+ /*2784*/ uint16(x86_xArgXmm2M128),
+ /*2785*/ uint16(x86_xMatch),
+ /*2786*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2790,
+ /*2790*/ uint16(x86_xSetOp), uint16(x86_PMINUW),
+ /*2792*/ uint16(x86_xReadSlashR),
+ /*2793*/ uint16(x86_xArgXmm1),
+ /*2794*/ uint16(x86_xArgXmm2M128),
+ /*2795*/ uint16(x86_xMatch),
+ /*2796*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2800,
+ /*2800*/ uint16(x86_xSetOp), uint16(x86_PMINUD),
+ /*2802*/ uint16(x86_xReadSlashR),
+ /*2803*/ uint16(x86_xArgXmm1),
+ /*2804*/ uint16(x86_xArgXmm2M128),
+ /*2805*/ uint16(x86_xMatch),
+ /*2806*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2810,
+ /*2810*/ uint16(x86_xSetOp), uint16(x86_PMAXSB),
+ /*2812*/ uint16(x86_xReadSlashR),
+ /*2813*/ uint16(x86_xArgXmm1),
+ /*2814*/ uint16(x86_xArgXmm2M128),
+ /*2815*/ uint16(x86_xMatch),
+ /*2816*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2820,
+ /*2820*/ uint16(x86_xSetOp), uint16(x86_PMAXSD),
+ /*2822*/ uint16(x86_xReadSlashR),
+ /*2823*/ uint16(x86_xArgXmm1),
+ /*2824*/ uint16(x86_xArgXmm2M128),
+ /*2825*/ uint16(x86_xMatch),
+ /*2826*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2830,
+ /*2830*/ uint16(x86_xSetOp), uint16(x86_PMAXUW),
+ /*2832*/ uint16(x86_xReadSlashR),
+ /*2833*/ uint16(x86_xArgXmm1),
+ /*2834*/ uint16(x86_xArgXmm2M128),
+ /*2835*/ uint16(x86_xMatch),
+ /*2836*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2840,
+ /*2840*/ uint16(x86_xSetOp), uint16(x86_PMAXUD),
+ /*2842*/ uint16(x86_xReadSlashR),
+ /*2843*/ uint16(x86_xArgXmm1),
+ /*2844*/ uint16(x86_xArgXmm2M128),
+ /*2845*/ uint16(x86_xMatch),
+ /*2846*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2850,
+ /*2850*/ uint16(x86_xSetOp), uint16(x86_PMULLD),
+ /*2852*/ uint16(x86_xReadSlashR),
+ /*2853*/ uint16(x86_xArgXmm1),
+ /*2854*/ uint16(x86_xArgXmm2M128),
+ /*2855*/ uint16(x86_xMatch),
+ /*2856*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2860,
+ /*2860*/ uint16(x86_xSetOp), uint16(x86_PHMINPOSUW),
+ /*2862*/ uint16(x86_xReadSlashR),
+ /*2863*/ uint16(x86_xArgXmm1),
+ /*2864*/ uint16(x86_xArgXmm2M128),
+ /*2865*/ uint16(x86_xMatch),
+ /*2866*/ uint16(x86_xCondIs64), 2869, 2879,
+ /*2869*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2873,
+ /*2873*/ uint16(x86_xSetOp), uint16(x86_INVPCID),
+ /*2875*/ uint16(x86_xReadSlashR),
+ /*2876*/ uint16(x86_xArgR32),
+ /*2877*/ uint16(x86_xArgM128),
+ /*2878*/ uint16(x86_xMatch),
+ /*2879*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2883,
+ /*2883*/ uint16(x86_xSetOp), uint16(x86_INVPCID),
+ /*2885*/ uint16(x86_xReadSlashR),
+ /*2886*/ uint16(x86_xArgR64),
+ /*2887*/ uint16(x86_xArgM128),
+ /*2888*/ uint16(x86_xMatch),
+ /*2889*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2893,
+ /*2893*/ uint16(x86_xSetOp), uint16(x86_AESIMC),
+ /*2895*/ uint16(x86_xReadSlashR),
+ /*2896*/ uint16(x86_xArgXmm1),
+ /*2897*/ uint16(x86_xArgXmm2M128),
+ /*2898*/ uint16(x86_xMatch),
+ /*2899*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2903,
+ /*2903*/ uint16(x86_xSetOp), uint16(x86_AESENC),
+ /*2905*/ uint16(x86_xReadSlashR),
+ /*2906*/ uint16(x86_xArgXmm1),
+ /*2907*/ uint16(x86_xArgXmm2M128),
+ /*2908*/ uint16(x86_xMatch),
+ /*2909*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2913,
+ /*2913*/ uint16(x86_xSetOp), uint16(x86_AESENCLAST),
+ /*2915*/ uint16(x86_xReadSlashR),
+ /*2916*/ uint16(x86_xArgXmm1),
+ /*2917*/ uint16(x86_xArgXmm2M128),
+ /*2918*/ uint16(x86_xMatch),
+ /*2919*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2923,
+ /*2923*/ uint16(x86_xSetOp), uint16(x86_AESDEC),
+ /*2925*/ uint16(x86_xReadSlashR),
+ /*2926*/ uint16(x86_xArgXmm1),
+ /*2927*/ uint16(x86_xArgXmm2M128),
+ /*2928*/ uint16(x86_xMatch),
+ /*2929*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 2933,
+ /*2933*/ uint16(x86_xSetOp), uint16(x86_AESDECLAST),
+ /*2935*/ uint16(x86_xReadSlashR),
+ /*2936*/ uint16(x86_xArgXmm1),
+ /*2937*/ uint16(x86_xArgXmm2M128),
+ /*2938*/ uint16(x86_xMatch),
+ /*2939*/ uint16(x86_xCondIs64), 2942, 2980,
+ /*2942*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 2964,
+ 0x0, 2948,
+ /*2948*/ uint16(x86_xCondDataSize), 2952, 2958, 0,
+ /*2952*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*2954*/ uint16(x86_xReadSlashR),
+ /*2955*/ uint16(x86_xArgR16),
+ /*2956*/ uint16(x86_xArgM16),
+ /*2957*/ uint16(x86_xMatch),
+ /*2958*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*2960*/ uint16(x86_xReadSlashR),
+ /*2961*/ uint16(x86_xArgR32),
+ /*2962*/ uint16(x86_xArgM32),
+ /*2963*/ uint16(x86_xMatch),
+ /*2964*/ uint16(x86_xCondDataSize), 2968, 2974, 0,
+ /*2968*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*2970*/ uint16(x86_xReadSlashR),
+ /*2971*/ uint16(x86_xArgR32),
+ /*2972*/ uint16(x86_xArgRM8),
+ /*2973*/ uint16(x86_xMatch),
+ /*2974*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*2976*/ uint16(x86_xReadSlashR),
+ /*2977*/ uint16(x86_xArgR32),
+ /*2978*/ uint16(x86_xArgRM8),
+ /*2979*/ uint16(x86_xMatch),
+ /*2980*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 2996,
+ 0x0, 2986,
+ /*2986*/ uint16(x86_xCondDataSize), 2952, 2958, 2990,
+ /*2990*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*2992*/ uint16(x86_xReadSlashR),
+ /*2993*/ uint16(x86_xArgR64),
+ /*2994*/ uint16(x86_xArgM64),
+ /*2995*/ uint16(x86_xMatch),
+ /*2996*/ uint16(x86_xCondDataSize), 2968, 2974, 3000,
+ /*3000*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*3002*/ uint16(x86_xReadSlashR),
+ /*3003*/ uint16(x86_xArgR64),
+ /*3004*/ uint16(x86_xArgRM8),
+ /*3005*/ uint16(x86_xMatch),
+ /*3006*/ uint16(x86_xCondIs64), 3009, 3047,
+ /*3009*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 3031,
+ 0x0, 3015,
+ /*3015*/ uint16(x86_xCondDataSize), 3019, 3025, 0,
+ /*3019*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*3021*/ uint16(x86_xReadSlashR),
+ /*3022*/ uint16(x86_xArgM16),
+ /*3023*/ uint16(x86_xArgR16),
+ /*3024*/ uint16(x86_xMatch),
+ /*3025*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*3027*/ uint16(x86_xReadSlashR),
+ /*3028*/ uint16(x86_xArgM32),
+ /*3029*/ uint16(x86_xArgR32),
+ /*3030*/ uint16(x86_xMatch),
+ /*3031*/ uint16(x86_xCondDataSize), 3035, 3041, 0,
+ /*3035*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*3037*/ uint16(x86_xReadSlashR),
+ /*3038*/ uint16(x86_xArgR32),
+ /*3039*/ uint16(x86_xArgRM16),
+ /*3040*/ uint16(x86_xMatch),
+ /*3041*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*3043*/ uint16(x86_xReadSlashR),
+ /*3044*/ uint16(x86_xArgR32),
+ /*3045*/ uint16(x86_xArgRM32),
+ /*3046*/ uint16(x86_xMatch),
+ /*3047*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 3063,
+ 0x0, 3053,
+ /*3053*/ uint16(x86_xCondDataSize), 3019, 3025, 3057,
+ /*3057*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+ /*3059*/ uint16(x86_xReadSlashR),
+ /*3060*/ uint16(x86_xArgM64),
+ /*3061*/ uint16(x86_xArgR64),
+ /*3062*/ uint16(x86_xMatch),
+ /*3063*/ uint16(x86_xCondDataSize), 3035, 3041, 3067,
+ /*3067*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+ /*3069*/ uint16(x86_xReadSlashR),
+ /*3070*/ uint16(x86_xArgR64),
+ /*3071*/ uint16(x86_xArgRM64),
+ /*3072*/ uint16(x86_xMatch),
+ /*3073*/ uint16(x86_xCondByte), 24,
+ 0x08, 3124,
+ 0x09, 3136,
+ 0x0A, 3148,
+ 0x0B, 3160,
+ 0x0C, 3172,
+ 0x0D, 3184,
+ 0x0E, 3196,
+ 0x0F, 3208,
+ 0x14, 3230,
+ 0x15, 3242,
+ 0x16, 3254,
+ 0x17, 3297,
+ 0x20, 3309,
+ 0x21, 3321,
+ 0x22, 3333,
+ 0x40, 3376,
+ 0x41, 3388,
+ 0x42, 3400,
+ 0x44, 3412,
+ 0x60, 3424,
+ 0x61, 3436,
+ 0x62, 3448,
+ 0x63, 3460,
+ 0xDF, 3472,
+ uint16(x86_xFail),
+ /*3124*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3128,
+ /*3128*/ uint16(x86_xSetOp), uint16(x86_ROUNDPS),
+ /*3130*/ uint16(x86_xReadSlashR),
+ /*3131*/ uint16(x86_xReadIb),
+ /*3132*/ uint16(x86_xArgXmm1),
+ /*3133*/ uint16(x86_xArgXmm2M128),
+ /*3134*/ uint16(x86_xArgImm8u),
+ /*3135*/ uint16(x86_xMatch),
+ /*3136*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3140,
+ /*3140*/ uint16(x86_xSetOp), uint16(x86_ROUNDPD),
+ /*3142*/ uint16(x86_xReadSlashR),
+ /*3143*/ uint16(x86_xReadIb),
+ /*3144*/ uint16(x86_xArgXmm1),
+ /*3145*/ uint16(x86_xArgXmm2M128),
+ /*3146*/ uint16(x86_xArgImm8u),
+ /*3147*/ uint16(x86_xMatch),
+ /*3148*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3152,
+ /*3152*/ uint16(x86_xSetOp), uint16(x86_ROUNDSS),
+ /*3154*/ uint16(x86_xReadSlashR),
+ /*3155*/ uint16(x86_xReadIb),
+ /*3156*/ uint16(x86_xArgXmm1),
+ /*3157*/ uint16(x86_xArgXmm2M32),
+ /*3158*/ uint16(x86_xArgImm8u),
+ /*3159*/ uint16(x86_xMatch),
+ /*3160*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3164,
+ /*3164*/ uint16(x86_xSetOp), uint16(x86_ROUNDSD),
+ /*3166*/ uint16(x86_xReadSlashR),
+ /*3167*/ uint16(x86_xReadIb),
+ /*3168*/ uint16(x86_xArgXmm1),
+ /*3169*/ uint16(x86_xArgXmm2M64),
+ /*3170*/ uint16(x86_xArgImm8u),
+ /*3171*/ uint16(x86_xMatch),
+ /*3172*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3176,
+ /*3176*/ uint16(x86_xSetOp), uint16(x86_BLENDPS),
+ /*3178*/ uint16(x86_xReadSlashR),
+ /*3179*/ uint16(x86_xReadIb),
+ /*3180*/ uint16(x86_xArgXmm1),
+ /*3181*/ uint16(x86_xArgXmm2M128),
+ /*3182*/ uint16(x86_xArgImm8u),
+ /*3183*/ uint16(x86_xMatch),
+ /*3184*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3188,
+ /*3188*/ uint16(x86_xSetOp), uint16(x86_BLENDPD),
+ /*3190*/ uint16(x86_xReadSlashR),
+ /*3191*/ uint16(x86_xReadIb),
+ /*3192*/ uint16(x86_xArgXmm1),
+ /*3193*/ uint16(x86_xArgXmm2M128),
+ /*3194*/ uint16(x86_xArgImm8u),
+ /*3195*/ uint16(x86_xMatch),
+ /*3196*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3200,
+ /*3200*/ uint16(x86_xSetOp), uint16(x86_PBLENDW),
+ /*3202*/ uint16(x86_xReadSlashR),
+ /*3203*/ uint16(x86_xReadIb),
+ /*3204*/ uint16(x86_xArgXmm1),
+ /*3205*/ uint16(x86_xArgXmm2M128),
+ /*3206*/ uint16(x86_xArgImm8u),
+ /*3207*/ uint16(x86_xMatch),
+ /*3208*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 3222,
+ 0x0, 3214,
+ /*3214*/ uint16(x86_xSetOp), uint16(x86_PALIGNR),
+ /*3216*/ uint16(x86_xReadSlashR),
+ /*3217*/ uint16(x86_xReadIb),
+ /*3218*/ uint16(x86_xArgMm1),
+ /*3219*/ uint16(x86_xArgMm2M64),
+ /*3220*/ uint16(x86_xArgImm8u),
+ /*3221*/ uint16(x86_xMatch),
+ /*3222*/ uint16(x86_xSetOp), uint16(x86_PALIGNR),
+ /*3224*/ uint16(x86_xReadSlashR),
+ /*3225*/ uint16(x86_xReadIb),
+ /*3226*/ uint16(x86_xArgXmm1),
+ /*3227*/ uint16(x86_xArgXmm2M128),
+ /*3228*/ uint16(x86_xArgImm8u),
+ /*3229*/ uint16(x86_xMatch),
+ /*3230*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3234,
+ /*3234*/ uint16(x86_xSetOp), uint16(x86_PEXTRB),
+ /*3236*/ uint16(x86_xReadSlashR),
+ /*3237*/ uint16(x86_xReadIb),
+ /*3238*/ uint16(x86_xArgR32M8),
+ /*3239*/ uint16(x86_xArgXmm1),
+ /*3240*/ uint16(x86_xArgImm8u),
+ /*3241*/ uint16(x86_xMatch),
+ /*3242*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3246,
+ /*3246*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+ /*3248*/ uint16(x86_xReadSlashR),
+ /*3249*/ uint16(x86_xReadIb),
+ /*3250*/ uint16(x86_xArgR32M16),
+ /*3251*/ uint16(x86_xArgXmm1),
+ /*3252*/ uint16(x86_xArgImm8u),
+ /*3253*/ uint16(x86_xMatch),
+ /*3254*/ uint16(x86_xCondIs64), 3257, 3281,
+ /*3257*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3261,
+ /*3261*/ uint16(x86_xCondDataSize), 3265, 3273, 0,
+ /*3265*/ uint16(x86_xSetOp), uint16(x86_PEXTRD),
+ /*3267*/ uint16(x86_xReadSlashR),
+ /*3268*/ uint16(x86_xReadIb),
+ /*3269*/ uint16(x86_xArgRM32),
+ /*3270*/ uint16(x86_xArgXmm1),
+ /*3271*/ uint16(x86_xArgImm8u),
+ /*3272*/ uint16(x86_xMatch),
+ /*3273*/ uint16(x86_xSetOp), uint16(x86_PEXTRD),
+ /*3275*/ uint16(x86_xReadSlashR),
+ /*3276*/ uint16(x86_xReadIb),
+ /*3277*/ uint16(x86_xArgRM32),
+ /*3278*/ uint16(x86_xArgXmm1),
+ /*3279*/ uint16(x86_xArgImm8u),
+ /*3280*/ uint16(x86_xMatch),
+ /*3281*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3285,
+ /*3285*/ uint16(x86_xCondDataSize), 3265, 3273, 3289,
+ /*3289*/ uint16(x86_xSetOp), uint16(x86_PEXTRQ),
+ /*3291*/ uint16(x86_xReadSlashR),
+ /*3292*/ uint16(x86_xReadIb),
+ /*3293*/ uint16(x86_xArgRM64),
+ /*3294*/ uint16(x86_xArgXmm1),
+ /*3295*/ uint16(x86_xArgImm8u),
+ /*3296*/ uint16(x86_xMatch),
+ /*3297*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3301,
+ /*3301*/ uint16(x86_xSetOp), uint16(x86_EXTRACTPS),
+ /*3303*/ uint16(x86_xReadSlashR),
+ /*3304*/ uint16(x86_xReadIb),
+ /*3305*/ uint16(x86_xArgRM32),
+ /*3306*/ uint16(x86_xArgXmm1),
+ /*3307*/ uint16(x86_xArgImm8u),
+ /*3308*/ uint16(x86_xMatch),
+ /*3309*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3313,
+ /*3313*/ uint16(x86_xSetOp), uint16(x86_PINSRB),
+ /*3315*/ uint16(x86_xReadSlashR),
+ /*3316*/ uint16(x86_xReadIb),
+ /*3317*/ uint16(x86_xArgXmm1),
+ /*3318*/ uint16(x86_xArgR32M8),
+ /*3319*/ uint16(x86_xArgImm8u),
+ /*3320*/ uint16(x86_xMatch),
+ /*3321*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3325,
+ /*3325*/ uint16(x86_xSetOp), uint16(x86_INSERTPS),
+ /*3327*/ uint16(x86_xReadSlashR),
+ /*3328*/ uint16(x86_xReadIb),
+ /*3329*/ uint16(x86_xArgXmm1),
+ /*3330*/ uint16(x86_xArgXmm2M32),
+ /*3331*/ uint16(x86_xArgImm8u),
+ /*3332*/ uint16(x86_xMatch),
+ /*3333*/ uint16(x86_xCondIs64), 3336, 3360,
+ /*3336*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3340,
+ /*3340*/ uint16(x86_xCondDataSize), 3344, 3352, 0,
+ /*3344*/ uint16(x86_xSetOp), uint16(x86_PINSRD),
+ /*3346*/ uint16(x86_xReadSlashR),
+ /*3347*/ uint16(x86_xReadIb),
+ /*3348*/ uint16(x86_xArgXmm1),
+ /*3349*/ uint16(x86_xArgRM32),
+ /*3350*/ uint16(x86_xArgImm8u),
+ /*3351*/ uint16(x86_xMatch),
+ /*3352*/ uint16(x86_xSetOp), uint16(x86_PINSRD),
+ /*3354*/ uint16(x86_xReadSlashR),
+ /*3355*/ uint16(x86_xReadIb),
+ /*3356*/ uint16(x86_xArgXmm1),
+ /*3357*/ uint16(x86_xArgRM32),
+ /*3358*/ uint16(x86_xArgImm8u),
+ /*3359*/ uint16(x86_xMatch),
+ /*3360*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3364,
+ /*3364*/ uint16(x86_xCondDataSize), 3344, 3352, 3368,
+ /*3368*/ uint16(x86_xSetOp), uint16(x86_PINSRQ),
+ /*3370*/ uint16(x86_xReadSlashR),
+ /*3371*/ uint16(x86_xReadIb),
+ /*3372*/ uint16(x86_xArgXmm1),
+ /*3373*/ uint16(x86_xArgRM64),
+ /*3374*/ uint16(x86_xArgImm8u),
+ /*3375*/ uint16(x86_xMatch),
+ /*3376*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3380,
+ /*3380*/ uint16(x86_xSetOp), uint16(x86_DPPS),
+ /*3382*/ uint16(x86_xReadSlashR),
+ /*3383*/ uint16(x86_xReadIb),
+ /*3384*/ uint16(x86_xArgXmm1),
+ /*3385*/ uint16(x86_xArgXmm2M128),
+ /*3386*/ uint16(x86_xArgImm8u),
+ /*3387*/ uint16(x86_xMatch),
+ /*3388*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3392,
+ /*3392*/ uint16(x86_xSetOp), uint16(x86_DPPD),
+ /*3394*/ uint16(x86_xReadSlashR),
+ /*3395*/ uint16(x86_xReadIb),
+ /*3396*/ uint16(x86_xArgXmm1),
+ /*3397*/ uint16(x86_xArgXmm2M128),
+ /*3398*/ uint16(x86_xArgImm8u),
+ /*3399*/ uint16(x86_xMatch),
+ /*3400*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3404,
+ /*3404*/ uint16(x86_xSetOp), uint16(x86_MPSADBW),
+ /*3406*/ uint16(x86_xReadSlashR),
+ /*3407*/ uint16(x86_xReadIb),
+ /*3408*/ uint16(x86_xArgXmm1),
+ /*3409*/ uint16(x86_xArgXmm2M128),
+ /*3410*/ uint16(x86_xArgImm8u),
+ /*3411*/ uint16(x86_xMatch),
+ /*3412*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3416,
+ /*3416*/ uint16(x86_xSetOp), uint16(x86_PCLMULQDQ),
+ /*3418*/ uint16(x86_xReadSlashR),
+ /*3419*/ uint16(x86_xReadIb),
+ /*3420*/ uint16(x86_xArgXmm1),
+ /*3421*/ uint16(x86_xArgXmm2M128),
+ /*3422*/ uint16(x86_xArgImm8u),
+ /*3423*/ uint16(x86_xMatch),
+ /*3424*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3428,
+ /*3428*/ uint16(x86_xSetOp), uint16(x86_PCMPESTRM),
+ /*3430*/ uint16(x86_xReadSlashR),
+ /*3431*/ uint16(x86_xReadIb),
+ /*3432*/ uint16(x86_xArgXmm1),
+ /*3433*/ uint16(x86_xArgXmm2M128),
+ /*3434*/ uint16(x86_xArgImm8u),
+ /*3435*/ uint16(x86_xMatch),
+ /*3436*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3440,
+ /*3440*/ uint16(x86_xSetOp), uint16(x86_PCMPESTRI),
+ /*3442*/ uint16(x86_xReadSlashR),
+ /*3443*/ uint16(x86_xReadIb),
+ /*3444*/ uint16(x86_xArgXmm1),
+ /*3445*/ uint16(x86_xArgXmm2M128),
+ /*3446*/ uint16(x86_xArgImm8u),
+ /*3447*/ uint16(x86_xMatch),
+ /*3448*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3452,
+ /*3452*/ uint16(x86_xSetOp), uint16(x86_PCMPISTRM),
+ /*3454*/ uint16(x86_xReadSlashR),
+ /*3455*/ uint16(x86_xReadIb),
+ /*3456*/ uint16(x86_xArgXmm1),
+ /*3457*/ uint16(x86_xArgXmm2M128),
+ /*3458*/ uint16(x86_xArgImm8u),
+ /*3459*/ uint16(x86_xMatch),
+ /*3460*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3464,
+ /*3464*/ uint16(x86_xSetOp), uint16(x86_PCMPISTRI),
+ /*3466*/ uint16(x86_xReadSlashR),
+ /*3467*/ uint16(x86_xReadIb),
+ /*3468*/ uint16(x86_xArgXmm1),
+ /*3469*/ uint16(x86_xArgXmm2M128),
+ /*3470*/ uint16(x86_xArgImm8u),
+ /*3471*/ uint16(x86_xMatch),
+ /*3472*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 3476,
+ /*3476*/ uint16(x86_xSetOp), uint16(x86_AESKEYGENASSIST),
+ /*3478*/ uint16(x86_xReadSlashR),
+ /*3479*/ uint16(x86_xReadIb),
+ /*3480*/ uint16(x86_xArgXmm1),
+ /*3481*/ uint16(x86_xArgXmm2M128),
+ /*3482*/ uint16(x86_xArgImm8u),
+ /*3483*/ uint16(x86_xMatch),
+ /*3484*/ uint16(x86_xCondIs64), 3487, 3503,
+ /*3487*/ uint16(x86_xCondDataSize), 3491, 3497, 0,
+ /*3491*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+ /*3493*/ uint16(x86_xReadSlashR),
+ /*3494*/ uint16(x86_xArgR16),
+ /*3495*/ uint16(x86_xArgRM16),
+ /*3496*/ uint16(x86_xMatch),
+ /*3497*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+ /*3499*/ uint16(x86_xReadSlashR),
+ /*3500*/ uint16(x86_xArgR32),
+ /*3501*/ uint16(x86_xArgRM32),
+ /*3502*/ uint16(x86_xMatch),
+ /*3503*/ uint16(x86_xCondDataSize), 3491, 3497, 3507,
+ /*3507*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+ /*3509*/ uint16(x86_xReadSlashR),
+ /*3510*/ uint16(x86_xArgR64),
+ /*3511*/ uint16(x86_xArgRM64),
+ /*3512*/ uint16(x86_xMatch),
+ /*3513*/ uint16(x86_xCondIs64), 3516, 3532,
+ /*3516*/ uint16(x86_xCondDataSize), 3520, 3526, 0,
+ /*3520*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+ /*3522*/ uint16(x86_xReadSlashR),
+ /*3523*/ uint16(x86_xArgR16),
+ /*3524*/ uint16(x86_xArgRM16),
+ /*3525*/ uint16(x86_xMatch),
+ /*3526*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+ /*3528*/ uint16(x86_xReadSlashR),
+ /*3529*/ uint16(x86_xArgR32),
+ /*3530*/ uint16(x86_xArgRM32),
+ /*3531*/ uint16(x86_xMatch),
+ /*3532*/ uint16(x86_xCondDataSize), 3520, 3526, 3536,
+ /*3536*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+ /*3538*/ uint16(x86_xReadSlashR),
+ /*3539*/ uint16(x86_xArgR64),
+ /*3540*/ uint16(x86_xArgRM64),
+ /*3541*/ uint16(x86_xMatch),
+ /*3542*/ uint16(x86_xCondIs64), 3545, 3561,
+ /*3545*/ uint16(x86_xCondDataSize), 3549, 3555, 0,
+ /*3549*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+ /*3551*/ uint16(x86_xReadSlashR),
+ /*3552*/ uint16(x86_xArgR16),
+ /*3553*/ uint16(x86_xArgRM16),
+ /*3554*/ uint16(x86_xMatch),
+ /*3555*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+ /*3557*/ uint16(x86_xReadSlashR),
+ /*3558*/ uint16(x86_xArgR32),
+ /*3559*/ uint16(x86_xArgRM32),
+ /*3560*/ uint16(x86_xMatch),
+ /*3561*/ uint16(x86_xCondDataSize), 3549, 3555, 3565,
+ /*3565*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+ /*3567*/ uint16(x86_xReadSlashR),
+ /*3568*/ uint16(x86_xArgR64),
+ /*3569*/ uint16(x86_xArgRM64),
+ /*3570*/ uint16(x86_xMatch),
+ /*3571*/ uint16(x86_xCondIs64), 3574, 3590,
+ /*3574*/ uint16(x86_xCondDataSize), 3578, 3584, 0,
+ /*3578*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+ /*3580*/ uint16(x86_xReadSlashR),
+ /*3581*/ uint16(x86_xArgR16),
+ /*3582*/ uint16(x86_xArgRM16),
+ /*3583*/ uint16(x86_xMatch),
+ /*3584*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+ /*3586*/ uint16(x86_xReadSlashR),
+ /*3587*/ uint16(x86_xArgR32),
+ /*3588*/ uint16(x86_xArgRM32),
+ /*3589*/ uint16(x86_xMatch),
+ /*3590*/ uint16(x86_xCondDataSize), 3578, 3584, 3594,
+ /*3594*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+ /*3596*/ uint16(x86_xReadSlashR),
+ /*3597*/ uint16(x86_xArgR64),
+ /*3598*/ uint16(x86_xArgRM64),
+ /*3599*/ uint16(x86_xMatch),
+ /*3600*/ uint16(x86_xCondIs64), 3603, 3619,
+ /*3603*/ uint16(x86_xCondDataSize), 3607, 3613, 0,
+ /*3607*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+ /*3609*/ uint16(x86_xReadSlashR),
+ /*3610*/ uint16(x86_xArgR16),
+ /*3611*/ uint16(x86_xArgRM16),
+ /*3612*/ uint16(x86_xMatch),
+ /*3613*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+ /*3615*/ uint16(x86_xReadSlashR),
+ /*3616*/ uint16(x86_xArgR32),
+ /*3617*/ uint16(x86_xArgRM32),
+ /*3618*/ uint16(x86_xMatch),
+ /*3619*/ uint16(x86_xCondDataSize), 3607, 3613, 3623,
+ /*3623*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+ /*3625*/ uint16(x86_xReadSlashR),
+ /*3626*/ uint16(x86_xArgR64),
+ /*3627*/ uint16(x86_xArgRM64),
+ /*3628*/ uint16(x86_xMatch),
+ /*3629*/ uint16(x86_xCondIs64), 3632, 3648,
+ /*3632*/ uint16(x86_xCondDataSize), 3636, 3642, 0,
+ /*3636*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+ /*3638*/ uint16(x86_xReadSlashR),
+ /*3639*/ uint16(x86_xArgR16),
+ /*3640*/ uint16(x86_xArgRM16),
+ /*3641*/ uint16(x86_xMatch),
+ /*3642*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+ /*3644*/ uint16(x86_xReadSlashR),
+ /*3645*/ uint16(x86_xArgR32),
+ /*3646*/ uint16(x86_xArgRM32),
+ /*3647*/ uint16(x86_xMatch),
+ /*3648*/ uint16(x86_xCondDataSize), 3636, 3642, 3652,
+ /*3652*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+ /*3654*/ uint16(x86_xReadSlashR),
+ /*3655*/ uint16(x86_xArgR64),
+ /*3656*/ uint16(x86_xArgRM64),
+ /*3657*/ uint16(x86_xMatch),
+ /*3658*/ uint16(x86_xCondIs64), 3661, 3677,
+ /*3661*/ uint16(x86_xCondDataSize), 3665, 3671, 0,
+ /*3665*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+ /*3667*/ uint16(x86_xReadSlashR),
+ /*3668*/ uint16(x86_xArgR16),
+ /*3669*/ uint16(x86_xArgRM16),
+ /*3670*/ uint16(x86_xMatch),
+ /*3671*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+ /*3673*/ uint16(x86_xReadSlashR),
+ /*3674*/ uint16(x86_xArgR32),
+ /*3675*/ uint16(x86_xArgRM32),
+ /*3676*/ uint16(x86_xMatch),
+ /*3677*/ uint16(x86_xCondDataSize), 3665, 3671, 3681,
+ /*3681*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+ /*3683*/ uint16(x86_xReadSlashR),
+ /*3684*/ uint16(x86_xArgR64),
+ /*3685*/ uint16(x86_xArgRM64),
+ /*3686*/ uint16(x86_xMatch),
+ /*3687*/ uint16(x86_xCondIs64), 3690, 3706,
+ /*3690*/ uint16(x86_xCondDataSize), 3694, 3700, 0,
+ /*3694*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+ /*3696*/ uint16(x86_xReadSlashR),
+ /*3697*/ uint16(x86_xArgR16),
+ /*3698*/ uint16(x86_xArgRM16),
+ /*3699*/ uint16(x86_xMatch),
+ /*3700*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+ /*3702*/ uint16(x86_xReadSlashR),
+ /*3703*/ uint16(x86_xArgR32),
+ /*3704*/ uint16(x86_xArgRM32),
+ /*3705*/ uint16(x86_xMatch),
+ /*3706*/ uint16(x86_xCondDataSize), 3694, 3700, 3710,
+ /*3710*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+ /*3712*/ uint16(x86_xReadSlashR),
+ /*3713*/ uint16(x86_xArgR64),
+ /*3714*/ uint16(x86_xArgRM64),
+ /*3715*/ uint16(x86_xMatch),
+ /*3716*/ uint16(x86_xCondIs64), 3719, 3735,
+ /*3719*/ uint16(x86_xCondDataSize), 3723, 3729, 0,
+ /*3723*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+ /*3725*/ uint16(x86_xReadSlashR),
+ /*3726*/ uint16(x86_xArgR16),
+ /*3727*/ uint16(x86_xArgRM16),
+ /*3728*/ uint16(x86_xMatch),
+ /*3729*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+ /*3731*/ uint16(x86_xReadSlashR),
+ /*3732*/ uint16(x86_xArgR32),
+ /*3733*/ uint16(x86_xArgRM32),
+ /*3734*/ uint16(x86_xMatch),
+ /*3735*/ uint16(x86_xCondDataSize), 3723, 3729, 3739,
+ /*3739*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+ /*3741*/ uint16(x86_xReadSlashR),
+ /*3742*/ uint16(x86_xArgR64),
+ /*3743*/ uint16(x86_xArgRM64),
+ /*3744*/ uint16(x86_xMatch),
+ /*3745*/ uint16(x86_xCondIs64), 3748, 3764,
+ /*3748*/ uint16(x86_xCondDataSize), 3752, 3758, 0,
+ /*3752*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+ /*3754*/ uint16(x86_xReadSlashR),
+ /*3755*/ uint16(x86_xArgR16),
+ /*3756*/ uint16(x86_xArgRM16),
+ /*3757*/ uint16(x86_xMatch),
+ /*3758*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+ /*3760*/ uint16(x86_xReadSlashR),
+ /*3761*/ uint16(x86_xArgR32),
+ /*3762*/ uint16(x86_xArgRM32),
+ /*3763*/ uint16(x86_xMatch),
+ /*3764*/ uint16(x86_xCondDataSize), 3752, 3758, 3768,
+ /*3768*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+ /*3770*/ uint16(x86_xReadSlashR),
+ /*3771*/ uint16(x86_xArgR64),
+ /*3772*/ uint16(x86_xArgRM64),
+ /*3773*/ uint16(x86_xMatch),
+ /*3774*/ uint16(x86_xCondIs64), 3777, 3793,
+ /*3777*/ uint16(x86_xCondDataSize), 3781, 3787, 0,
+ /*3781*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+ /*3783*/ uint16(x86_xReadSlashR),
+ /*3784*/ uint16(x86_xArgR16),
+ /*3785*/ uint16(x86_xArgRM16),
+ /*3786*/ uint16(x86_xMatch),
+ /*3787*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+ /*3789*/ uint16(x86_xReadSlashR),
+ /*3790*/ uint16(x86_xArgR32),
+ /*3791*/ uint16(x86_xArgRM32),
+ /*3792*/ uint16(x86_xMatch),
+ /*3793*/ uint16(x86_xCondDataSize), 3781, 3787, 3797,
+ /*3797*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+ /*3799*/ uint16(x86_xReadSlashR),
+ /*3800*/ uint16(x86_xArgR64),
+ /*3801*/ uint16(x86_xArgRM64),
+ /*3802*/ uint16(x86_xMatch),
+ /*3803*/ uint16(x86_xCondIs64), 3806, 3822,
+ /*3806*/ uint16(x86_xCondDataSize), 3810, 3816, 0,
+ /*3810*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+ /*3812*/ uint16(x86_xReadSlashR),
+ /*3813*/ uint16(x86_xArgR16),
+ /*3814*/ uint16(x86_xArgRM16),
+ /*3815*/ uint16(x86_xMatch),
+ /*3816*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+ /*3818*/ uint16(x86_xReadSlashR),
+ /*3819*/ uint16(x86_xArgR32),
+ /*3820*/ uint16(x86_xArgRM32),
+ /*3821*/ uint16(x86_xMatch),
+ /*3822*/ uint16(x86_xCondDataSize), 3810, 3816, 3826,
+ /*3826*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+ /*3828*/ uint16(x86_xReadSlashR),
+ /*3829*/ uint16(x86_xArgR64),
+ /*3830*/ uint16(x86_xArgRM64),
+ /*3831*/ uint16(x86_xMatch),
+ /*3832*/ uint16(x86_xCondIs64), 3835, 3851,
+ /*3835*/ uint16(x86_xCondDataSize), 3839, 3845, 0,
+ /*3839*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+ /*3841*/ uint16(x86_xReadSlashR),
+ /*3842*/ uint16(x86_xArgR16),
+ /*3843*/ uint16(x86_xArgRM16),
+ /*3844*/ uint16(x86_xMatch),
+ /*3845*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+ /*3847*/ uint16(x86_xReadSlashR),
+ /*3848*/ uint16(x86_xArgR32),
+ /*3849*/ uint16(x86_xArgRM32),
+ /*3850*/ uint16(x86_xMatch),
+ /*3851*/ uint16(x86_xCondDataSize), 3839, 3845, 3855,
+ /*3855*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+ /*3857*/ uint16(x86_xReadSlashR),
+ /*3858*/ uint16(x86_xArgR64),
+ /*3859*/ uint16(x86_xArgRM64),
+ /*3860*/ uint16(x86_xMatch),
+ /*3861*/ uint16(x86_xCondIs64), 3864, 3880,
+ /*3864*/ uint16(x86_xCondDataSize), 3868, 3874, 0,
+ /*3868*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+ /*3870*/ uint16(x86_xReadSlashR),
+ /*3871*/ uint16(x86_xArgR16),
+ /*3872*/ uint16(x86_xArgRM16),
+ /*3873*/ uint16(x86_xMatch),
+ /*3874*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+ /*3876*/ uint16(x86_xReadSlashR),
+ /*3877*/ uint16(x86_xArgR32),
+ /*3878*/ uint16(x86_xArgRM32),
+ /*3879*/ uint16(x86_xMatch),
+ /*3880*/ uint16(x86_xCondDataSize), 3868, 3874, 3884,
+ /*3884*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+ /*3886*/ uint16(x86_xReadSlashR),
+ /*3887*/ uint16(x86_xArgR64),
+ /*3888*/ uint16(x86_xArgRM64),
+ /*3889*/ uint16(x86_xMatch),
+ /*3890*/ uint16(x86_xCondIs64), 3893, 3909,
+ /*3893*/ uint16(x86_xCondDataSize), 3897, 3903, 0,
+ /*3897*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+ /*3899*/ uint16(x86_xReadSlashR),
+ /*3900*/ uint16(x86_xArgR16),
+ /*3901*/ uint16(x86_xArgRM16),
+ /*3902*/ uint16(x86_xMatch),
+ /*3903*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+ /*3905*/ uint16(x86_xReadSlashR),
+ /*3906*/ uint16(x86_xArgR32),
+ /*3907*/ uint16(x86_xArgRM32),
+ /*3908*/ uint16(x86_xMatch),
+ /*3909*/ uint16(x86_xCondDataSize), 3897, 3903, 3913,
+ /*3913*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+ /*3915*/ uint16(x86_xReadSlashR),
+ /*3916*/ uint16(x86_xArgR64),
+ /*3917*/ uint16(x86_xArgRM64),
+ /*3918*/ uint16(x86_xMatch),
+ /*3919*/ uint16(x86_xCondIs64), 3922, 3938,
+ /*3922*/ uint16(x86_xCondDataSize), 3926, 3932, 0,
+ /*3926*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+ /*3928*/ uint16(x86_xReadSlashR),
+ /*3929*/ uint16(x86_xArgR16),
+ /*3930*/ uint16(x86_xArgRM16),
+ /*3931*/ uint16(x86_xMatch),
+ /*3932*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+ /*3934*/ uint16(x86_xReadSlashR),
+ /*3935*/ uint16(x86_xArgR32),
+ /*3936*/ uint16(x86_xArgRM32),
+ /*3937*/ uint16(x86_xMatch),
+ /*3938*/ uint16(x86_xCondDataSize), 3926, 3932, 3942,
+ /*3942*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+ /*3944*/ uint16(x86_xReadSlashR),
+ /*3945*/ uint16(x86_xArgR64),
+ /*3946*/ uint16(x86_xArgRM64),
+ /*3947*/ uint16(x86_xMatch),
+ /*3948*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 3960,
+ 0x0, 3954,
+ /*3954*/ uint16(x86_xSetOp), uint16(x86_MOVMSKPS),
+ /*3956*/ uint16(x86_xReadSlashR),
+ /*3957*/ uint16(x86_xArgR32),
+ /*3958*/ uint16(x86_xArgXmm2),
+ /*3959*/ uint16(x86_xMatch),
+ /*3960*/ uint16(x86_xSetOp), uint16(x86_MOVMSKPD),
+ /*3962*/ uint16(x86_xReadSlashR),
+ /*3963*/ uint16(x86_xArgR32),
+ /*3964*/ uint16(x86_xArgXmm2),
+ /*3965*/ uint16(x86_xMatch),
+ /*3966*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 3994,
+ 0xF2, 3988,
+ 0x66, 3982,
+ 0x0, 3976,
+ /*3976*/ uint16(x86_xSetOp), uint16(x86_SQRTPS),
+ /*3978*/ uint16(x86_xReadSlashR),
+ /*3979*/ uint16(x86_xArgXmm1),
+ /*3980*/ uint16(x86_xArgXmm2M128),
+ /*3981*/ uint16(x86_xMatch),
+ /*3982*/ uint16(x86_xSetOp), uint16(x86_SQRTPD),
+ /*3984*/ uint16(x86_xReadSlashR),
+ /*3985*/ uint16(x86_xArgXmm1),
+ /*3986*/ uint16(x86_xArgXmm2M128),
+ /*3987*/ uint16(x86_xMatch),
+ /*3988*/ uint16(x86_xSetOp), uint16(x86_SQRTSD),
+ /*3990*/ uint16(x86_xReadSlashR),
+ /*3991*/ uint16(x86_xArgXmm1),
+ /*3992*/ uint16(x86_xArgXmm2M64),
+ /*3993*/ uint16(x86_xMatch),
+ /*3994*/ uint16(x86_xSetOp), uint16(x86_SQRTSS),
+ /*3996*/ uint16(x86_xReadSlashR),
+ /*3997*/ uint16(x86_xArgXmm1),
+ /*3998*/ uint16(x86_xArgXmm2M32),
+ /*3999*/ uint16(x86_xMatch),
+ /*4000*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 4012,
+ 0x0, 4006,
+ /*4006*/ uint16(x86_xSetOp), uint16(x86_RSQRTPS),
+ /*4008*/ uint16(x86_xReadSlashR),
+ /*4009*/ uint16(x86_xArgXmm1),
+ /*4010*/ uint16(x86_xArgXmm2M128),
+ /*4011*/ uint16(x86_xMatch),
+ /*4012*/ uint16(x86_xSetOp), uint16(x86_RSQRTSS),
+ /*4014*/ uint16(x86_xReadSlashR),
+ /*4015*/ uint16(x86_xArgXmm1),
+ /*4016*/ uint16(x86_xArgXmm2M32),
+ /*4017*/ uint16(x86_xMatch),
+ /*4018*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 4030,
+ 0x0, 4024,
+ /*4024*/ uint16(x86_xSetOp), uint16(x86_RCPPS),
+ /*4026*/ uint16(x86_xReadSlashR),
+ /*4027*/ uint16(x86_xArgXmm1),
+ /*4028*/ uint16(x86_xArgXmm2M128),
+ /*4029*/ uint16(x86_xMatch),
+ /*4030*/ uint16(x86_xSetOp), uint16(x86_RCPSS),
+ /*4032*/ uint16(x86_xReadSlashR),
+ /*4033*/ uint16(x86_xArgXmm1),
+ /*4034*/ uint16(x86_xArgXmm2M32),
+ /*4035*/ uint16(x86_xMatch),
+ /*4036*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4048,
+ 0x0, 4042,
+ /*4042*/ uint16(x86_xSetOp), uint16(x86_ANDPS),
+ /*4044*/ uint16(x86_xReadSlashR),
+ /*4045*/ uint16(x86_xArgXmm1),
+ /*4046*/ uint16(x86_xArgXmm2M128),
+ /*4047*/ uint16(x86_xMatch),
+ /*4048*/ uint16(x86_xSetOp), uint16(x86_ANDPD),
+ /*4050*/ uint16(x86_xReadSlashR),
+ /*4051*/ uint16(x86_xArgXmm1),
+ /*4052*/ uint16(x86_xArgXmm2M128),
+ /*4053*/ uint16(x86_xMatch),
+ /*4054*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4066,
+ 0x0, 4060,
+ /*4060*/ uint16(x86_xSetOp), uint16(x86_ANDNPS),
+ /*4062*/ uint16(x86_xReadSlashR),
+ /*4063*/ uint16(x86_xArgXmm1),
+ /*4064*/ uint16(x86_xArgXmm2M128),
+ /*4065*/ uint16(x86_xMatch),
+ /*4066*/ uint16(x86_xSetOp), uint16(x86_ANDNPD),
+ /*4068*/ uint16(x86_xReadSlashR),
+ /*4069*/ uint16(x86_xArgXmm1),
+ /*4070*/ uint16(x86_xArgXmm2M128),
+ /*4071*/ uint16(x86_xMatch),
+ /*4072*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4084,
+ 0x0, 4078,
+ /*4078*/ uint16(x86_xSetOp), uint16(x86_ORPS),
+ /*4080*/ uint16(x86_xReadSlashR),
+ /*4081*/ uint16(x86_xArgXmm1),
+ /*4082*/ uint16(x86_xArgXmm2M128),
+ /*4083*/ uint16(x86_xMatch),
+ /*4084*/ uint16(x86_xSetOp), uint16(x86_ORPD),
+ /*4086*/ uint16(x86_xReadSlashR),
+ /*4087*/ uint16(x86_xArgXmm1),
+ /*4088*/ uint16(x86_xArgXmm2M128),
+ /*4089*/ uint16(x86_xMatch),
+ /*4090*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4102,
+ 0x0, 4096,
+ /*4096*/ uint16(x86_xSetOp), uint16(x86_XORPS),
+ /*4098*/ uint16(x86_xReadSlashR),
+ /*4099*/ uint16(x86_xArgXmm1),
+ /*4100*/ uint16(x86_xArgXmm2M128),
+ /*4101*/ uint16(x86_xMatch),
+ /*4102*/ uint16(x86_xSetOp), uint16(x86_XORPD),
+ /*4104*/ uint16(x86_xReadSlashR),
+ /*4105*/ uint16(x86_xArgXmm1),
+ /*4106*/ uint16(x86_xArgXmm2M128),
+ /*4107*/ uint16(x86_xMatch),
+ /*4108*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4136,
+ 0xF2, 4130,
+ 0x66, 4124,
+ 0x0, 4118,
+ /*4118*/ uint16(x86_xSetOp), uint16(x86_ADDPS),
+ /*4120*/ uint16(x86_xReadSlashR),
+ /*4121*/ uint16(x86_xArgXmm1),
+ /*4122*/ uint16(x86_xArgXmm2M128),
+ /*4123*/ uint16(x86_xMatch),
+ /*4124*/ uint16(x86_xSetOp), uint16(x86_ADDPD),
+ /*4126*/ uint16(x86_xReadSlashR),
+ /*4127*/ uint16(x86_xArgXmm1),
+ /*4128*/ uint16(x86_xArgXmm2M128),
+ /*4129*/ uint16(x86_xMatch),
+ /*4130*/ uint16(x86_xSetOp), uint16(x86_ADDSD),
+ /*4132*/ uint16(x86_xReadSlashR),
+ /*4133*/ uint16(x86_xArgXmm1),
+ /*4134*/ uint16(x86_xArgXmm2M64),
+ /*4135*/ uint16(x86_xMatch),
+ /*4136*/ uint16(x86_xSetOp), uint16(x86_ADDSS),
+ /*4138*/ uint16(x86_xReadSlashR),
+ /*4139*/ uint16(x86_xArgXmm1),
+ /*4140*/ uint16(x86_xArgXmm2M32),
+ /*4141*/ uint16(x86_xMatch),
+ /*4142*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4170,
+ 0xF2, 4164,
+ 0x66, 4158,
+ 0x0, 4152,
+ /*4152*/ uint16(x86_xSetOp), uint16(x86_MULPS),
+ /*4154*/ uint16(x86_xReadSlashR),
+ /*4155*/ uint16(x86_xArgXmm1),
+ /*4156*/ uint16(x86_xArgXmm2M128),
+ /*4157*/ uint16(x86_xMatch),
+ /*4158*/ uint16(x86_xSetOp), uint16(x86_MULPD),
+ /*4160*/ uint16(x86_xReadSlashR),
+ /*4161*/ uint16(x86_xArgXmm1),
+ /*4162*/ uint16(x86_xArgXmm2M128),
+ /*4163*/ uint16(x86_xMatch),
+ /*4164*/ uint16(x86_xSetOp), uint16(x86_MULSD),
+ /*4166*/ uint16(x86_xReadSlashR),
+ /*4167*/ uint16(x86_xArgXmm1),
+ /*4168*/ uint16(x86_xArgXmm2M64),
+ /*4169*/ uint16(x86_xMatch),
+ /*4170*/ uint16(x86_xSetOp), uint16(x86_MULSS),
+ /*4172*/ uint16(x86_xReadSlashR),
+ /*4173*/ uint16(x86_xArgXmm1),
+ /*4174*/ uint16(x86_xArgXmm2M32),
+ /*4175*/ uint16(x86_xMatch),
+ /*4176*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4204,
+ 0xF2, 4198,
+ 0x66, 4192,
+ 0x0, 4186,
+ /*4186*/ uint16(x86_xSetOp), uint16(x86_CVTPS2PD),
+ /*4188*/ uint16(x86_xReadSlashR),
+ /*4189*/ uint16(x86_xArgXmm1),
+ /*4190*/ uint16(x86_xArgXmm2M64),
+ /*4191*/ uint16(x86_xMatch),
+ /*4192*/ uint16(x86_xSetOp), uint16(x86_CVTPD2PS),
+ /*4194*/ uint16(x86_xReadSlashR),
+ /*4195*/ uint16(x86_xArgXmm1),
+ /*4196*/ uint16(x86_xArgXmm2M128),
+ /*4197*/ uint16(x86_xMatch),
+ /*4198*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SS),
+ /*4200*/ uint16(x86_xReadSlashR),
+ /*4201*/ uint16(x86_xArgXmm1),
+ /*4202*/ uint16(x86_xArgXmm2M64),
+ /*4203*/ uint16(x86_xMatch),
+ /*4204*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SD),
+ /*4206*/ uint16(x86_xReadSlashR),
+ /*4207*/ uint16(x86_xArgXmm1),
+ /*4208*/ uint16(x86_xArgXmm2M32),
+ /*4209*/ uint16(x86_xMatch),
+ /*4210*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 4230,
+ 0x66, 4224,
+ 0x0, 4218,
+ /*4218*/ uint16(x86_xSetOp), uint16(x86_CVTDQ2PS),
+ /*4220*/ uint16(x86_xReadSlashR),
+ /*4221*/ uint16(x86_xArgXmm1),
+ /*4222*/ uint16(x86_xArgXmm2M128),
+ /*4223*/ uint16(x86_xMatch),
+ /*4224*/ uint16(x86_xSetOp), uint16(x86_CVTPS2DQ),
+ /*4226*/ uint16(x86_xReadSlashR),
+ /*4227*/ uint16(x86_xArgXmm1),
+ /*4228*/ uint16(x86_xArgXmm2M128),
+ /*4229*/ uint16(x86_xMatch),
+ /*4230*/ uint16(x86_xSetOp), uint16(x86_CVTTPS2DQ),
+ /*4232*/ uint16(x86_xReadSlashR),
+ /*4233*/ uint16(x86_xArgXmm1),
+ /*4234*/ uint16(x86_xArgXmm2M128),
+ /*4235*/ uint16(x86_xMatch),
+ /*4236*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4264,
+ 0xF2, 4258,
+ 0x66, 4252,
+ 0x0, 4246,
+ /*4246*/ uint16(x86_xSetOp), uint16(x86_SUBPS),
+ /*4248*/ uint16(x86_xReadSlashR),
+ /*4249*/ uint16(x86_xArgXmm1),
+ /*4250*/ uint16(x86_xArgXmm2M128),
+ /*4251*/ uint16(x86_xMatch),
+ /*4252*/ uint16(x86_xSetOp), uint16(x86_SUBPD),
+ /*4254*/ uint16(x86_xReadSlashR),
+ /*4255*/ uint16(x86_xArgXmm1),
+ /*4256*/ uint16(x86_xArgXmm2M128),
+ /*4257*/ uint16(x86_xMatch),
+ /*4258*/ uint16(x86_xSetOp), uint16(x86_SUBSD),
+ /*4260*/ uint16(x86_xReadSlashR),
+ /*4261*/ uint16(x86_xArgXmm1),
+ /*4262*/ uint16(x86_xArgXmm2M64),
+ /*4263*/ uint16(x86_xMatch),
+ /*4264*/ uint16(x86_xSetOp), uint16(x86_SUBSS),
+ /*4266*/ uint16(x86_xReadSlashR),
+ /*4267*/ uint16(x86_xArgXmm1),
+ /*4268*/ uint16(x86_xArgXmm2M32),
+ /*4269*/ uint16(x86_xMatch),
+ /*4270*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4298,
+ 0xF2, 4292,
+ 0x66, 4286,
+ 0x0, 4280,
+ /*4280*/ uint16(x86_xSetOp), uint16(x86_MINPS),
+ /*4282*/ uint16(x86_xReadSlashR),
+ /*4283*/ uint16(x86_xArgXmm1),
+ /*4284*/ uint16(x86_xArgXmm2M128),
+ /*4285*/ uint16(x86_xMatch),
+ /*4286*/ uint16(x86_xSetOp), uint16(x86_MINPD),
+ /*4288*/ uint16(x86_xReadSlashR),
+ /*4289*/ uint16(x86_xArgXmm1),
+ /*4290*/ uint16(x86_xArgXmm2M128),
+ /*4291*/ uint16(x86_xMatch),
+ /*4292*/ uint16(x86_xSetOp), uint16(x86_MINSD),
+ /*4294*/ uint16(x86_xReadSlashR),
+ /*4295*/ uint16(x86_xArgXmm1),
+ /*4296*/ uint16(x86_xArgXmm2M64),
+ /*4297*/ uint16(x86_xMatch),
+ /*4298*/ uint16(x86_xSetOp), uint16(x86_MINSS),
+ /*4300*/ uint16(x86_xReadSlashR),
+ /*4301*/ uint16(x86_xArgXmm1),
+ /*4302*/ uint16(x86_xArgXmm2M32),
+ /*4303*/ uint16(x86_xMatch),
+ /*4304*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4332,
+ 0xF2, 4326,
+ 0x66, 4320,
+ 0x0, 4314,
+ /*4314*/ uint16(x86_xSetOp), uint16(x86_DIVPS),
+ /*4316*/ uint16(x86_xReadSlashR),
+ /*4317*/ uint16(x86_xArgXmm1),
+ /*4318*/ uint16(x86_xArgXmm2M128),
+ /*4319*/ uint16(x86_xMatch),
+ /*4320*/ uint16(x86_xSetOp), uint16(x86_DIVPD),
+ /*4322*/ uint16(x86_xReadSlashR),
+ /*4323*/ uint16(x86_xArgXmm1),
+ /*4324*/ uint16(x86_xArgXmm2M128),
+ /*4325*/ uint16(x86_xMatch),
+ /*4326*/ uint16(x86_xSetOp), uint16(x86_DIVSD),
+ /*4328*/ uint16(x86_xReadSlashR),
+ /*4329*/ uint16(x86_xArgXmm1),
+ /*4330*/ uint16(x86_xArgXmm2M64),
+ /*4331*/ uint16(x86_xMatch),
+ /*4332*/ uint16(x86_xSetOp), uint16(x86_DIVSS),
+ /*4334*/ uint16(x86_xReadSlashR),
+ /*4335*/ uint16(x86_xArgXmm1),
+ /*4336*/ uint16(x86_xArgXmm2M32),
+ /*4337*/ uint16(x86_xMatch),
+ /*4338*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4366,
+ 0xF2, 4360,
+ 0x66, 4354,
+ 0x0, 4348,
+ /*4348*/ uint16(x86_xSetOp), uint16(x86_MAXPS),
+ /*4350*/ uint16(x86_xReadSlashR),
+ /*4351*/ uint16(x86_xArgXmm1),
+ /*4352*/ uint16(x86_xArgXmm2M128),
+ /*4353*/ uint16(x86_xMatch),
+ /*4354*/ uint16(x86_xSetOp), uint16(x86_MAXPD),
+ /*4356*/ uint16(x86_xReadSlashR),
+ /*4357*/ uint16(x86_xArgXmm1),
+ /*4358*/ uint16(x86_xArgXmm2M128),
+ /*4359*/ uint16(x86_xMatch),
+ /*4360*/ uint16(x86_xSetOp), uint16(x86_MAXSD),
+ /*4362*/ uint16(x86_xReadSlashR),
+ /*4363*/ uint16(x86_xArgXmm1),
+ /*4364*/ uint16(x86_xArgXmm2M64),
+ /*4365*/ uint16(x86_xMatch),
+ /*4366*/ uint16(x86_xSetOp), uint16(x86_MAXSS),
+ /*4368*/ uint16(x86_xReadSlashR),
+ /*4369*/ uint16(x86_xArgXmm1),
+ /*4370*/ uint16(x86_xArgXmm2M32),
+ /*4371*/ uint16(x86_xMatch),
+ /*4372*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4384,
+ 0x0, 4378,
+ /*4378*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLBW),
+ /*4380*/ uint16(x86_xReadSlashR),
+ /*4381*/ uint16(x86_xArgMm),
+ /*4382*/ uint16(x86_xArgMmM32),
+ /*4383*/ uint16(x86_xMatch),
+ /*4384*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLBW),
+ /*4386*/ uint16(x86_xReadSlashR),
+ /*4387*/ uint16(x86_xArgXmm1),
+ /*4388*/ uint16(x86_xArgXmm2M128),
+ /*4389*/ uint16(x86_xMatch),
+ /*4390*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4402,
+ 0x0, 4396,
+ /*4396*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLWD),
+ /*4398*/ uint16(x86_xReadSlashR),
+ /*4399*/ uint16(x86_xArgMm),
+ /*4400*/ uint16(x86_xArgMmM32),
+ /*4401*/ uint16(x86_xMatch),
+ /*4402*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLWD),
+ /*4404*/ uint16(x86_xReadSlashR),
+ /*4405*/ uint16(x86_xArgXmm1),
+ /*4406*/ uint16(x86_xArgXmm2M128),
+ /*4407*/ uint16(x86_xMatch),
+ /*4408*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4420,
+ 0x0, 4414,
+ /*4414*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLDQ),
+ /*4416*/ uint16(x86_xReadSlashR),
+ /*4417*/ uint16(x86_xArgMm),
+ /*4418*/ uint16(x86_xArgMmM32),
+ /*4419*/ uint16(x86_xMatch),
+ /*4420*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLDQ),
+ /*4422*/ uint16(x86_xReadSlashR),
+ /*4423*/ uint16(x86_xArgXmm1),
+ /*4424*/ uint16(x86_xArgXmm2M128),
+ /*4425*/ uint16(x86_xMatch),
+ /*4426*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4438,
+ 0x0, 4432,
+ /*4432*/ uint16(x86_xSetOp), uint16(x86_PACKSSWB),
+ /*4434*/ uint16(x86_xReadSlashR),
+ /*4435*/ uint16(x86_xArgMm1),
+ /*4436*/ uint16(x86_xArgMm2M64),
+ /*4437*/ uint16(x86_xMatch),
+ /*4438*/ uint16(x86_xSetOp), uint16(x86_PACKSSWB),
+ /*4440*/ uint16(x86_xReadSlashR),
+ /*4441*/ uint16(x86_xArgXmm1),
+ /*4442*/ uint16(x86_xArgXmm2M128),
+ /*4443*/ uint16(x86_xMatch),
+ /*4444*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4456,
+ 0x0, 4450,
+ /*4450*/ uint16(x86_xSetOp), uint16(x86_PCMPGTB),
+ /*4452*/ uint16(x86_xReadSlashR),
+ /*4453*/ uint16(x86_xArgMm),
+ /*4454*/ uint16(x86_xArgMmM64),
+ /*4455*/ uint16(x86_xMatch),
+ /*4456*/ uint16(x86_xSetOp), uint16(x86_PCMPGTB),
+ /*4458*/ uint16(x86_xReadSlashR),
+ /*4459*/ uint16(x86_xArgXmm1),
+ /*4460*/ uint16(x86_xArgXmm2M128),
+ /*4461*/ uint16(x86_xMatch),
+ /*4462*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4474,
+ 0x0, 4468,
+ /*4468*/ uint16(x86_xSetOp), uint16(x86_PCMPGTW),
+ /*4470*/ uint16(x86_xReadSlashR),
+ /*4471*/ uint16(x86_xArgMm),
+ /*4472*/ uint16(x86_xArgMmM64),
+ /*4473*/ uint16(x86_xMatch),
+ /*4474*/ uint16(x86_xSetOp), uint16(x86_PCMPGTW),
+ /*4476*/ uint16(x86_xReadSlashR),
+ /*4477*/ uint16(x86_xArgXmm1),
+ /*4478*/ uint16(x86_xArgXmm2M128),
+ /*4479*/ uint16(x86_xMatch),
+ /*4480*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4492,
+ 0x0, 4486,
+ /*4486*/ uint16(x86_xSetOp), uint16(x86_PCMPGTD),
+ /*4488*/ uint16(x86_xReadSlashR),
+ /*4489*/ uint16(x86_xArgMm),
+ /*4490*/ uint16(x86_xArgMmM64),
+ /*4491*/ uint16(x86_xMatch),
+ /*4492*/ uint16(x86_xSetOp), uint16(x86_PCMPGTD),
+ /*4494*/ uint16(x86_xReadSlashR),
+ /*4495*/ uint16(x86_xArgXmm1),
+ /*4496*/ uint16(x86_xArgXmm2M128),
+ /*4497*/ uint16(x86_xMatch),
+ /*4498*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4510,
+ 0x0, 4504,
+ /*4504*/ uint16(x86_xSetOp), uint16(x86_PACKUSWB),
+ /*4506*/ uint16(x86_xReadSlashR),
+ /*4507*/ uint16(x86_xArgMm),
+ /*4508*/ uint16(x86_xArgMmM64),
+ /*4509*/ uint16(x86_xMatch),
+ /*4510*/ uint16(x86_xSetOp), uint16(x86_PACKUSWB),
+ /*4512*/ uint16(x86_xReadSlashR),
+ /*4513*/ uint16(x86_xArgXmm1),
+ /*4514*/ uint16(x86_xArgXmm2M128),
+ /*4515*/ uint16(x86_xMatch),
+ /*4516*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4528,
+ 0x0, 4522,
+ /*4522*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHBW),
+ /*4524*/ uint16(x86_xReadSlashR),
+ /*4525*/ uint16(x86_xArgMm),
+ /*4526*/ uint16(x86_xArgMmM64),
+ /*4527*/ uint16(x86_xMatch),
+ /*4528*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHBW),
+ /*4530*/ uint16(x86_xReadSlashR),
+ /*4531*/ uint16(x86_xArgXmm1),
+ /*4532*/ uint16(x86_xArgXmm2M128),
+ /*4533*/ uint16(x86_xMatch),
+ /*4534*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4546,
+ 0x0, 4540,
+ /*4540*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHWD),
+ /*4542*/ uint16(x86_xReadSlashR),
+ /*4543*/ uint16(x86_xArgMm),
+ /*4544*/ uint16(x86_xArgMmM64),
+ /*4545*/ uint16(x86_xMatch),
+ /*4546*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHWD),
+ /*4548*/ uint16(x86_xReadSlashR),
+ /*4549*/ uint16(x86_xArgXmm1),
+ /*4550*/ uint16(x86_xArgXmm2M128),
+ /*4551*/ uint16(x86_xMatch),
+ /*4552*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4564,
+ 0x0, 4558,
+ /*4558*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHDQ),
+ /*4560*/ uint16(x86_xReadSlashR),
+ /*4561*/ uint16(x86_xArgMm),
+ /*4562*/ uint16(x86_xArgMmM64),
+ /*4563*/ uint16(x86_xMatch),
+ /*4564*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHDQ),
+ /*4566*/ uint16(x86_xReadSlashR),
+ /*4567*/ uint16(x86_xArgXmm1),
+ /*4568*/ uint16(x86_xArgXmm2M128),
+ /*4569*/ uint16(x86_xMatch),
+ /*4570*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4582,
+ 0x0, 4576,
+ /*4576*/ uint16(x86_xSetOp), uint16(x86_PACKSSDW),
+ /*4578*/ uint16(x86_xReadSlashR),
+ /*4579*/ uint16(x86_xArgMm1),
+ /*4580*/ uint16(x86_xArgMm2M64),
+ /*4581*/ uint16(x86_xMatch),
+ /*4582*/ uint16(x86_xSetOp), uint16(x86_PACKSSDW),
+ /*4584*/ uint16(x86_xReadSlashR),
+ /*4585*/ uint16(x86_xArgXmm1),
+ /*4586*/ uint16(x86_xArgXmm2M128),
+ /*4587*/ uint16(x86_xMatch),
+ /*4588*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 4592,
+ /*4592*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLQDQ),
+ /*4594*/ uint16(x86_xReadSlashR),
+ /*4595*/ uint16(x86_xArgXmm1),
+ /*4596*/ uint16(x86_xArgXmm2M128),
+ /*4597*/ uint16(x86_xMatch),
+ /*4598*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 4602,
+ /*4602*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHQDQ),
+ /*4604*/ uint16(x86_xReadSlashR),
+ /*4605*/ uint16(x86_xArgXmm1),
+ /*4606*/ uint16(x86_xArgXmm2M128),
+ /*4607*/ uint16(x86_xMatch),
+ /*4608*/ uint16(x86_xCondIs64), 4611, 4649,
+ /*4611*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4633,
+ 0x0, 4617,
+ /*4617*/ uint16(x86_xCondDataSize), 4621, 4627, 0,
+ /*4621*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*4623*/ uint16(x86_xReadSlashR),
+ /*4624*/ uint16(x86_xArgMm),
+ /*4625*/ uint16(x86_xArgRM32),
+ /*4626*/ uint16(x86_xMatch),
+ /*4627*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*4629*/ uint16(x86_xReadSlashR),
+ /*4630*/ uint16(x86_xArgMm),
+ /*4631*/ uint16(x86_xArgRM32),
+ /*4632*/ uint16(x86_xMatch),
+ /*4633*/ uint16(x86_xCondDataSize), 4637, 4643, 0,
+ /*4637*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*4639*/ uint16(x86_xReadSlashR),
+ /*4640*/ uint16(x86_xArgXmm),
+ /*4641*/ uint16(x86_xArgRM32),
+ /*4642*/ uint16(x86_xMatch),
+ /*4643*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*4645*/ uint16(x86_xReadSlashR),
+ /*4646*/ uint16(x86_xArgXmm),
+ /*4647*/ uint16(x86_xArgRM32),
+ /*4648*/ uint16(x86_xMatch),
+ /*4649*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4665,
+ 0x0, 4655,
+ /*4655*/ uint16(x86_xCondDataSize), 4621, 4627, 4659,
+ /*4659*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*4661*/ uint16(x86_xReadSlashR),
+ /*4662*/ uint16(x86_xArgMm),
+ /*4663*/ uint16(x86_xArgRM64),
+ /*4664*/ uint16(x86_xMatch),
+ /*4665*/ uint16(x86_xCondDataSize), 4637, 4643, 4669,
+ /*4669*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*4671*/ uint16(x86_xReadSlashR),
+ /*4672*/ uint16(x86_xArgXmm),
+ /*4673*/ uint16(x86_xArgRM64),
+ /*4674*/ uint16(x86_xMatch),
+ /*4675*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 4695,
+ 0x66, 4689,
+ 0x0, 4683,
+ /*4683*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*4685*/ uint16(x86_xReadSlashR),
+ /*4686*/ uint16(x86_xArgMm),
+ /*4687*/ uint16(x86_xArgMmM64),
+ /*4688*/ uint16(x86_xMatch),
+ /*4689*/ uint16(x86_xSetOp), uint16(x86_MOVDQA),
+ /*4691*/ uint16(x86_xReadSlashR),
+ /*4692*/ uint16(x86_xArgXmm1),
+ /*4693*/ uint16(x86_xArgXmm2M128),
+ /*4694*/ uint16(x86_xMatch),
+ /*4695*/ uint16(x86_xSetOp), uint16(x86_MOVDQU),
+ /*4697*/ uint16(x86_xReadSlashR),
+ /*4698*/ uint16(x86_xArgXmm1),
+ /*4699*/ uint16(x86_xArgXmm2M128),
+ /*4700*/ uint16(x86_xMatch),
+ /*4701*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 4735,
+ 0xF2, 4727,
+ 0x66, 4719,
+ 0x0, 4711,
+ /*4711*/ uint16(x86_xSetOp), uint16(x86_PSHUFW),
+ /*4713*/ uint16(x86_xReadSlashR),
+ /*4714*/ uint16(x86_xReadIb),
+ /*4715*/ uint16(x86_xArgMm1),
+ /*4716*/ uint16(x86_xArgMm2M64),
+ /*4717*/ uint16(x86_xArgImm8u),
+ /*4718*/ uint16(x86_xMatch),
+ /*4719*/ uint16(x86_xSetOp), uint16(x86_PSHUFD),
+ /*4721*/ uint16(x86_xReadSlashR),
+ /*4722*/ uint16(x86_xReadIb),
+ /*4723*/ uint16(x86_xArgXmm1),
+ /*4724*/ uint16(x86_xArgXmm2M128),
+ /*4725*/ uint16(x86_xArgImm8u),
+ /*4726*/ uint16(x86_xMatch),
+ /*4727*/ uint16(x86_xSetOp), uint16(x86_PSHUFLW),
+ /*4729*/ uint16(x86_xReadSlashR),
+ /*4730*/ uint16(x86_xReadIb),
+ /*4731*/ uint16(x86_xArgXmm1),
+ /*4732*/ uint16(x86_xArgXmm2M128),
+ /*4733*/ uint16(x86_xArgImm8u),
+ /*4734*/ uint16(x86_xMatch),
+ /*4735*/ uint16(x86_xSetOp), uint16(x86_PSHUFHW),
+ /*4737*/ uint16(x86_xReadSlashR),
+ /*4738*/ uint16(x86_xReadIb),
+ /*4739*/ uint16(x86_xArgXmm1),
+ /*4740*/ uint16(x86_xArgXmm2M128),
+ /*4741*/ uint16(x86_xArgImm8u),
+ /*4742*/ uint16(x86_xMatch),
+ /*4743*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 0, // 1
+ 4752, // 2
+ 0, // 3
+ 4770, // 4
+ 0, // 5
+ 4788, // 6
+ 0, // 7
+ /*4752*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4764,
+ 0x0, 4758,
+ /*4758*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+ /*4760*/ uint16(x86_xReadIb),
+ /*4761*/ uint16(x86_xArgMm2),
+ /*4762*/ uint16(x86_xArgImm8u),
+ /*4763*/ uint16(x86_xMatch),
+ /*4764*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+ /*4766*/ uint16(x86_xReadIb),
+ /*4767*/ uint16(x86_xArgXmm2),
+ /*4768*/ uint16(x86_xArgImm8u),
+ /*4769*/ uint16(x86_xMatch),
+ /*4770*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4782,
+ 0x0, 4776,
+ /*4776*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+ /*4778*/ uint16(x86_xReadIb),
+ /*4779*/ uint16(x86_xArgMm2),
+ /*4780*/ uint16(x86_xArgImm8u),
+ /*4781*/ uint16(x86_xMatch),
+ /*4782*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+ /*4784*/ uint16(x86_xReadIb),
+ /*4785*/ uint16(x86_xArgXmm2),
+ /*4786*/ uint16(x86_xArgImm8u),
+ /*4787*/ uint16(x86_xMatch),
+ /*4788*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4800,
+ 0x0, 4794,
+ /*4794*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+ /*4796*/ uint16(x86_xReadIb),
+ /*4797*/ uint16(x86_xArgMm2),
+ /*4798*/ uint16(x86_xArgImm8u),
+ /*4799*/ uint16(x86_xMatch),
+ /*4800*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+ /*4802*/ uint16(x86_xReadIb),
+ /*4803*/ uint16(x86_xArgXmm2),
+ /*4804*/ uint16(x86_xArgImm8u),
+ /*4805*/ uint16(x86_xMatch),
+ /*4806*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 0, // 1
+ 4815, // 2
+ 0, // 3
+ 4833, // 4
+ 0, // 5
+ 4851, // 6
+ 0, // 7
+ /*4815*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4827,
+ 0x0, 4821,
+ /*4821*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+ /*4823*/ uint16(x86_xReadIb),
+ /*4824*/ uint16(x86_xArgMm2),
+ /*4825*/ uint16(x86_xArgImm8u),
+ /*4826*/ uint16(x86_xMatch),
+ /*4827*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+ /*4829*/ uint16(x86_xReadIb),
+ /*4830*/ uint16(x86_xArgXmm2),
+ /*4831*/ uint16(x86_xArgImm8u),
+ /*4832*/ uint16(x86_xMatch),
+ /*4833*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4845,
+ 0x0, 4839,
+ /*4839*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+ /*4841*/ uint16(x86_xReadIb),
+ /*4842*/ uint16(x86_xArgMm2),
+ /*4843*/ uint16(x86_xArgImm8u),
+ /*4844*/ uint16(x86_xMatch),
+ /*4845*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+ /*4847*/ uint16(x86_xReadIb),
+ /*4848*/ uint16(x86_xArgXmm2),
+ /*4849*/ uint16(x86_xArgImm8u),
+ /*4850*/ uint16(x86_xMatch),
+ /*4851*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4863,
+ 0x0, 4857,
+ /*4857*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+ /*4859*/ uint16(x86_xReadIb),
+ /*4860*/ uint16(x86_xArgMm2),
+ /*4861*/ uint16(x86_xArgImm8u),
+ /*4862*/ uint16(x86_xMatch),
+ /*4863*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+ /*4865*/ uint16(x86_xReadIb),
+ /*4866*/ uint16(x86_xArgXmm2),
+ /*4867*/ uint16(x86_xArgImm8u),
+ /*4868*/ uint16(x86_xMatch),
+ /*4869*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 0, // 1
+ 4878, // 2
+ 4896, // 3
+ 0, // 4
+ 0, // 5
+ 4906, // 6
+ 4924, // 7
+ /*4878*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4890,
+ 0x0, 4884,
+ /*4884*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+ /*4886*/ uint16(x86_xReadIb),
+ /*4887*/ uint16(x86_xArgMm2),
+ /*4888*/ uint16(x86_xArgImm8u),
+ /*4889*/ uint16(x86_xMatch),
+ /*4890*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+ /*4892*/ uint16(x86_xReadIb),
+ /*4893*/ uint16(x86_xArgXmm2),
+ /*4894*/ uint16(x86_xArgImm8u),
+ /*4895*/ uint16(x86_xMatch),
+ /*4896*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 4900,
+ /*4900*/ uint16(x86_xSetOp), uint16(x86_PSRLDQ),
+ /*4902*/ uint16(x86_xReadIb),
+ /*4903*/ uint16(x86_xArgXmm2),
+ /*4904*/ uint16(x86_xArgImm8u),
+ /*4905*/ uint16(x86_xMatch),
+ /*4906*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4918,
+ 0x0, 4912,
+ /*4912*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+ /*4914*/ uint16(x86_xReadIb),
+ /*4915*/ uint16(x86_xArgMm2),
+ /*4916*/ uint16(x86_xArgImm8u),
+ /*4917*/ uint16(x86_xMatch),
+ /*4918*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+ /*4920*/ uint16(x86_xReadIb),
+ /*4921*/ uint16(x86_xArgXmm2),
+ /*4922*/ uint16(x86_xArgImm8u),
+ /*4923*/ uint16(x86_xMatch),
+ /*4924*/ uint16(x86_xCondPrefix), 1,
+ 0x66, 4928,
+ /*4928*/ uint16(x86_xSetOp), uint16(x86_PSLLDQ),
+ /*4930*/ uint16(x86_xReadIb),
+ /*4931*/ uint16(x86_xArgXmm2),
+ /*4932*/ uint16(x86_xArgImm8u),
+ /*4933*/ uint16(x86_xMatch),
+ /*4934*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4946,
+ 0x0, 4940,
+ /*4940*/ uint16(x86_xSetOp), uint16(x86_PCMPEQB),
+ /*4942*/ uint16(x86_xReadSlashR),
+ /*4943*/ uint16(x86_xArgMm),
+ /*4944*/ uint16(x86_xArgMmM64),
+ /*4945*/ uint16(x86_xMatch),
+ /*4946*/ uint16(x86_xSetOp), uint16(x86_PCMPEQB),
+ /*4948*/ uint16(x86_xReadSlashR),
+ /*4949*/ uint16(x86_xArgXmm1),
+ /*4950*/ uint16(x86_xArgXmm2M128),
+ /*4951*/ uint16(x86_xMatch),
+ /*4952*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4964,
+ 0x0, 4958,
+ /*4958*/ uint16(x86_xSetOp), uint16(x86_PCMPEQW),
+ /*4960*/ uint16(x86_xReadSlashR),
+ /*4961*/ uint16(x86_xArgMm),
+ /*4962*/ uint16(x86_xArgMmM64),
+ /*4963*/ uint16(x86_xMatch),
+ /*4964*/ uint16(x86_xSetOp), uint16(x86_PCMPEQW),
+ /*4966*/ uint16(x86_xReadSlashR),
+ /*4967*/ uint16(x86_xArgXmm1),
+ /*4968*/ uint16(x86_xArgXmm2M128),
+ /*4969*/ uint16(x86_xMatch),
+ /*4970*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 4982,
+ 0x0, 4976,
+ /*4976*/ uint16(x86_xSetOp), uint16(x86_PCMPEQD),
+ /*4978*/ uint16(x86_xReadSlashR),
+ /*4979*/ uint16(x86_xArgMm),
+ /*4980*/ uint16(x86_xArgMmM64),
+ /*4981*/ uint16(x86_xMatch),
+ /*4982*/ uint16(x86_xSetOp), uint16(x86_PCMPEQD),
+ /*4984*/ uint16(x86_xReadSlashR),
+ /*4985*/ uint16(x86_xArgXmm1),
+ /*4986*/ uint16(x86_xArgXmm2M128),
+ /*4987*/ uint16(x86_xMatch),
+ /*4988*/ uint16(x86_xSetOp), uint16(x86_EMMS),
+ /*4990*/ uint16(x86_xMatch),
+ /*4991*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 5003,
+ 0x66, 4997,
+ /*4997*/ uint16(x86_xSetOp), uint16(x86_HADDPD),
+ /*4999*/ uint16(x86_xReadSlashR),
+ /*5000*/ uint16(x86_xArgXmm1),
+ /*5001*/ uint16(x86_xArgXmm2M128),
+ /*5002*/ uint16(x86_xMatch),
+ /*5003*/ uint16(x86_xSetOp), uint16(x86_HADDPS),
+ /*5005*/ uint16(x86_xReadSlashR),
+ /*5006*/ uint16(x86_xArgXmm1),
+ /*5007*/ uint16(x86_xArgXmm2M128),
+ /*5008*/ uint16(x86_xMatch),
+ /*5009*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 5021,
+ 0x66, 5015,
+ /*5015*/ uint16(x86_xSetOp), uint16(x86_HSUBPD),
+ /*5017*/ uint16(x86_xReadSlashR),
+ /*5018*/ uint16(x86_xArgXmm1),
+ /*5019*/ uint16(x86_xArgXmm2M128),
+ /*5020*/ uint16(x86_xMatch),
+ /*5021*/ uint16(x86_xSetOp), uint16(x86_HSUBPS),
+ /*5023*/ uint16(x86_xReadSlashR),
+ /*5024*/ uint16(x86_xArgXmm1),
+ /*5025*/ uint16(x86_xArgXmm2M128),
+ /*5026*/ uint16(x86_xMatch),
+ /*5027*/ uint16(x86_xCondIs64), 5030, 5076,
+ /*5030*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 5070,
+ 0x66, 5054,
+ 0x0, 5038,
+ /*5038*/ uint16(x86_xCondDataSize), 5042, 5048, 0,
+ /*5042*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*5044*/ uint16(x86_xReadSlashR),
+ /*5045*/ uint16(x86_xArgRM32),
+ /*5046*/ uint16(x86_xArgMm),
+ /*5047*/ uint16(x86_xMatch),
+ /*5048*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*5050*/ uint16(x86_xReadSlashR),
+ /*5051*/ uint16(x86_xArgRM32),
+ /*5052*/ uint16(x86_xArgMm),
+ /*5053*/ uint16(x86_xMatch),
+ /*5054*/ uint16(x86_xCondDataSize), 5058, 5064, 0,
+ /*5058*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*5060*/ uint16(x86_xReadSlashR),
+ /*5061*/ uint16(x86_xArgRM32),
+ /*5062*/ uint16(x86_xArgXmm),
+ /*5063*/ uint16(x86_xMatch),
+ /*5064*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+ /*5066*/ uint16(x86_xReadSlashR),
+ /*5067*/ uint16(x86_xArgRM32),
+ /*5068*/ uint16(x86_xArgXmm),
+ /*5069*/ uint16(x86_xMatch),
+ /*5070*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*5072*/ uint16(x86_xReadSlashR),
+ /*5073*/ uint16(x86_xArgXmm1),
+ /*5074*/ uint16(x86_xArgXmm2M64),
+ /*5075*/ uint16(x86_xMatch),
+ /*5076*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 5070,
+ 0x66, 5094,
+ 0x0, 5084,
+ /*5084*/ uint16(x86_xCondDataSize), 5042, 5048, 5088,
+ /*5088*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*5090*/ uint16(x86_xReadSlashR),
+ /*5091*/ uint16(x86_xArgRM64),
+ /*5092*/ uint16(x86_xArgMm),
+ /*5093*/ uint16(x86_xMatch),
+ /*5094*/ uint16(x86_xCondDataSize), 5058, 5064, 5098,
+ /*5098*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*5100*/ uint16(x86_xReadSlashR),
+ /*5101*/ uint16(x86_xArgRM64),
+ /*5102*/ uint16(x86_xArgXmm),
+ /*5103*/ uint16(x86_xMatch),
+ /*5104*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 5124,
+ 0x66, 5118,
+ 0x0, 5112,
+ /*5112*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*5114*/ uint16(x86_xReadSlashR),
+ /*5115*/ uint16(x86_xArgMmM64),
+ /*5116*/ uint16(x86_xArgMm),
+ /*5117*/ uint16(x86_xMatch),
+ /*5118*/ uint16(x86_xSetOp), uint16(x86_MOVDQA),
+ /*5120*/ uint16(x86_xReadSlashR),
+ /*5121*/ uint16(x86_xArgXmm2M128),
+ /*5122*/ uint16(x86_xArgXmm1),
+ /*5123*/ uint16(x86_xMatch),
+ /*5124*/ uint16(x86_xSetOp), uint16(x86_MOVDQU),
+ /*5126*/ uint16(x86_xReadSlashR),
+ /*5127*/ uint16(x86_xArgXmm2M128),
+ /*5128*/ uint16(x86_xArgXmm1),
+ /*5129*/ uint16(x86_xMatch),
+ /*5130*/ uint16(x86_xCondIs64), 5133, 5147,
+ /*5133*/ uint16(x86_xCondDataSize), 5137, 5142, 0,
+ /*5137*/ uint16(x86_xSetOp), uint16(x86_JO),
+ /*5139*/ uint16(x86_xReadCw),
+ /*5140*/ uint16(x86_xArgRel16),
+ /*5141*/ uint16(x86_xMatch),
+ /*5142*/ uint16(x86_xSetOp), uint16(x86_JO),
+ /*5144*/ uint16(x86_xReadCd),
+ /*5145*/ uint16(x86_xArgRel32),
+ /*5146*/ uint16(x86_xMatch),
+ /*5147*/ uint16(x86_xCondDataSize), 5151, 5142, 5156,
+ /*5151*/ uint16(x86_xSetOp), uint16(x86_JO),
+ /*5153*/ uint16(x86_xReadCd),
+ /*5154*/ uint16(x86_xArgRel32),
+ /*5155*/ uint16(x86_xMatch),
+ /*5156*/ uint16(x86_xSetOp), uint16(x86_JO),
+ /*5158*/ uint16(x86_xReadCd),
+ /*5159*/ uint16(x86_xArgRel32),
+ /*5160*/ uint16(x86_xMatch),
+ /*5161*/ uint16(x86_xCondIs64), 5164, 5178,
+ /*5164*/ uint16(x86_xCondDataSize), 5168, 5173, 0,
+ /*5168*/ uint16(x86_xSetOp), uint16(x86_JNO),
+ /*5170*/ uint16(x86_xReadCw),
+ /*5171*/ uint16(x86_xArgRel16),
+ /*5172*/ uint16(x86_xMatch),
+ /*5173*/ uint16(x86_xSetOp), uint16(x86_JNO),
+ /*5175*/ uint16(x86_xReadCd),
+ /*5176*/ uint16(x86_xArgRel32),
+ /*5177*/ uint16(x86_xMatch),
+ /*5178*/ uint16(x86_xCondDataSize), 5182, 5173, 5187,
+ /*5182*/ uint16(x86_xSetOp), uint16(x86_JNO),
+ /*5184*/ uint16(x86_xReadCd),
+ /*5185*/ uint16(x86_xArgRel32),
+ /*5186*/ uint16(x86_xMatch),
+ /*5187*/ uint16(x86_xSetOp), uint16(x86_JNO),
+ /*5189*/ uint16(x86_xReadCd),
+ /*5190*/ uint16(x86_xArgRel32),
+ /*5191*/ uint16(x86_xMatch),
+ /*5192*/ uint16(x86_xCondIs64), 5195, 5209,
+ /*5195*/ uint16(x86_xCondDataSize), 5199, 5204, 0,
+ /*5199*/ uint16(x86_xSetOp), uint16(x86_JB),
+ /*5201*/ uint16(x86_xReadCw),
+ /*5202*/ uint16(x86_xArgRel16),
+ /*5203*/ uint16(x86_xMatch),
+ /*5204*/ uint16(x86_xSetOp), uint16(x86_JB),
+ /*5206*/ uint16(x86_xReadCd),
+ /*5207*/ uint16(x86_xArgRel32),
+ /*5208*/ uint16(x86_xMatch),
+ /*5209*/ uint16(x86_xCondDataSize), 5213, 5204, 5218,
+ /*5213*/ uint16(x86_xSetOp), uint16(x86_JB),
+ /*5215*/ uint16(x86_xReadCd),
+ /*5216*/ uint16(x86_xArgRel32),
+ /*5217*/ uint16(x86_xMatch),
+ /*5218*/ uint16(x86_xSetOp), uint16(x86_JB),
+ /*5220*/ uint16(x86_xReadCd),
+ /*5221*/ uint16(x86_xArgRel32),
+ /*5222*/ uint16(x86_xMatch),
+ /*5223*/ uint16(x86_xCondIs64), 5226, 5240,
+ /*5226*/ uint16(x86_xCondDataSize), 5230, 5235, 0,
+ /*5230*/ uint16(x86_xSetOp), uint16(x86_JAE),
+ /*5232*/ uint16(x86_xReadCw),
+ /*5233*/ uint16(x86_xArgRel16),
+ /*5234*/ uint16(x86_xMatch),
+ /*5235*/ uint16(x86_xSetOp), uint16(x86_JAE),
+ /*5237*/ uint16(x86_xReadCd),
+ /*5238*/ uint16(x86_xArgRel32),
+ /*5239*/ uint16(x86_xMatch),
+ /*5240*/ uint16(x86_xCondDataSize), 5244, 5235, 5249,
+ /*5244*/ uint16(x86_xSetOp), uint16(x86_JAE),
+ /*5246*/ uint16(x86_xReadCd),
+ /*5247*/ uint16(x86_xArgRel32),
+ /*5248*/ uint16(x86_xMatch),
+ /*5249*/ uint16(x86_xSetOp), uint16(x86_JAE),
+ /*5251*/ uint16(x86_xReadCd),
+ /*5252*/ uint16(x86_xArgRel32),
+ /*5253*/ uint16(x86_xMatch),
+ /*5254*/ uint16(x86_xCondIs64), 5257, 5271,
+ /*5257*/ uint16(x86_xCondDataSize), 5261, 5266, 0,
+ /*5261*/ uint16(x86_xSetOp), uint16(x86_JE),
+ /*5263*/ uint16(x86_xReadCw),
+ /*5264*/ uint16(x86_xArgRel16),
+ /*5265*/ uint16(x86_xMatch),
+ /*5266*/ uint16(x86_xSetOp), uint16(x86_JE),
+ /*5268*/ uint16(x86_xReadCd),
+ /*5269*/ uint16(x86_xArgRel32),
+ /*5270*/ uint16(x86_xMatch),
+ /*5271*/ uint16(x86_xCondDataSize), 5275, 5266, 5280,
+ /*5275*/ uint16(x86_xSetOp), uint16(x86_JE),
+ /*5277*/ uint16(x86_xReadCd),
+ /*5278*/ uint16(x86_xArgRel32),
+ /*5279*/ uint16(x86_xMatch),
+ /*5280*/ uint16(x86_xSetOp), uint16(x86_JE),
+ /*5282*/ uint16(x86_xReadCd),
+ /*5283*/ uint16(x86_xArgRel32),
+ /*5284*/ uint16(x86_xMatch),
+ /*5285*/ uint16(x86_xCondIs64), 5288, 5302,
+ /*5288*/ uint16(x86_xCondDataSize), 5292, 5297, 0,
+ /*5292*/ uint16(x86_xSetOp), uint16(x86_JNE),
+ /*5294*/ uint16(x86_xReadCw),
+ /*5295*/ uint16(x86_xArgRel16),
+ /*5296*/ uint16(x86_xMatch),
+ /*5297*/ uint16(x86_xSetOp), uint16(x86_JNE),
+ /*5299*/ uint16(x86_xReadCd),
+ /*5300*/ uint16(x86_xArgRel32),
+ /*5301*/ uint16(x86_xMatch),
+ /*5302*/ uint16(x86_xCondDataSize), 5306, 5297, 5311,
+ /*5306*/ uint16(x86_xSetOp), uint16(x86_JNE),
+ /*5308*/ uint16(x86_xReadCd),
+ /*5309*/ uint16(x86_xArgRel32),
+ /*5310*/ uint16(x86_xMatch),
+ /*5311*/ uint16(x86_xSetOp), uint16(x86_JNE),
+ /*5313*/ uint16(x86_xReadCd),
+ /*5314*/ uint16(x86_xArgRel32),
+ /*5315*/ uint16(x86_xMatch),
+ /*5316*/ uint16(x86_xCondIs64), 5319, 5333,
+ /*5319*/ uint16(x86_xCondDataSize), 5323, 5328, 0,
+ /*5323*/ uint16(x86_xSetOp), uint16(x86_JBE),
+ /*5325*/ uint16(x86_xReadCw),
+ /*5326*/ uint16(x86_xArgRel16),
+ /*5327*/ uint16(x86_xMatch),
+ /*5328*/ uint16(x86_xSetOp), uint16(x86_JBE),
+ /*5330*/ uint16(x86_xReadCd),
+ /*5331*/ uint16(x86_xArgRel32),
+ /*5332*/ uint16(x86_xMatch),
+ /*5333*/ uint16(x86_xCondDataSize), 5337, 5328, 5342,
+ /*5337*/ uint16(x86_xSetOp), uint16(x86_JBE),
+ /*5339*/ uint16(x86_xReadCd),
+ /*5340*/ uint16(x86_xArgRel32),
+ /*5341*/ uint16(x86_xMatch),
+ /*5342*/ uint16(x86_xSetOp), uint16(x86_JBE),
+ /*5344*/ uint16(x86_xReadCd),
+ /*5345*/ uint16(x86_xArgRel32),
+ /*5346*/ uint16(x86_xMatch),
+ /*5347*/ uint16(x86_xCondIs64), 5350, 5364,
+ /*5350*/ uint16(x86_xCondDataSize), 5354, 5359, 0,
+ /*5354*/ uint16(x86_xSetOp), uint16(x86_JA),
+ /*5356*/ uint16(x86_xReadCw),
+ /*5357*/ uint16(x86_xArgRel16),
+ /*5358*/ uint16(x86_xMatch),
+ /*5359*/ uint16(x86_xSetOp), uint16(x86_JA),
+ /*5361*/ uint16(x86_xReadCd),
+ /*5362*/ uint16(x86_xArgRel32),
+ /*5363*/ uint16(x86_xMatch),
+ /*5364*/ uint16(x86_xCondDataSize), 5368, 5359, 5373,
+ /*5368*/ uint16(x86_xSetOp), uint16(x86_JA),
+ /*5370*/ uint16(x86_xReadCd),
+ /*5371*/ uint16(x86_xArgRel32),
+ /*5372*/ uint16(x86_xMatch),
+ /*5373*/ uint16(x86_xSetOp), uint16(x86_JA),
+ /*5375*/ uint16(x86_xReadCd),
+ /*5376*/ uint16(x86_xArgRel32),
+ /*5377*/ uint16(x86_xMatch),
+ /*5378*/ uint16(x86_xCondIs64), 5381, 5395,
+ /*5381*/ uint16(x86_xCondDataSize), 5385, 5390, 0,
+ /*5385*/ uint16(x86_xSetOp), uint16(x86_JS),
+ /*5387*/ uint16(x86_xReadCw),
+ /*5388*/ uint16(x86_xArgRel16),
+ /*5389*/ uint16(x86_xMatch),
+ /*5390*/ uint16(x86_xSetOp), uint16(x86_JS),
+ /*5392*/ uint16(x86_xReadCd),
+ /*5393*/ uint16(x86_xArgRel32),
+ /*5394*/ uint16(x86_xMatch),
+ /*5395*/ uint16(x86_xCondDataSize), 5399, 5390, 5404,
+ /*5399*/ uint16(x86_xSetOp), uint16(x86_JS),
+ /*5401*/ uint16(x86_xReadCd),
+ /*5402*/ uint16(x86_xArgRel32),
+ /*5403*/ uint16(x86_xMatch),
+ /*5404*/ uint16(x86_xSetOp), uint16(x86_JS),
+ /*5406*/ uint16(x86_xReadCd),
+ /*5407*/ uint16(x86_xArgRel32),
+ /*5408*/ uint16(x86_xMatch),
+ /*5409*/ uint16(x86_xCondIs64), 5412, 5426,
+ /*5412*/ uint16(x86_xCondDataSize), 5416, 5421, 0,
+ /*5416*/ uint16(x86_xSetOp), uint16(x86_JNS),
+ /*5418*/ uint16(x86_xReadCw),
+ /*5419*/ uint16(x86_xArgRel16),
+ /*5420*/ uint16(x86_xMatch),
+ /*5421*/ uint16(x86_xSetOp), uint16(x86_JNS),
+ /*5423*/ uint16(x86_xReadCd),
+ /*5424*/ uint16(x86_xArgRel32),
+ /*5425*/ uint16(x86_xMatch),
+ /*5426*/ uint16(x86_xCondDataSize), 5430, 5421, 5435,
+ /*5430*/ uint16(x86_xSetOp), uint16(x86_JNS),
+ /*5432*/ uint16(x86_xReadCd),
+ /*5433*/ uint16(x86_xArgRel32),
+ /*5434*/ uint16(x86_xMatch),
+ /*5435*/ uint16(x86_xSetOp), uint16(x86_JNS),
+ /*5437*/ uint16(x86_xReadCd),
+ /*5438*/ uint16(x86_xArgRel32),
+ /*5439*/ uint16(x86_xMatch),
+ /*5440*/ uint16(x86_xCondIs64), 5443, 5457,
+ /*5443*/ uint16(x86_xCondDataSize), 5447, 5452, 0,
+ /*5447*/ uint16(x86_xSetOp), uint16(x86_JP),
+ /*5449*/ uint16(x86_xReadCw),
+ /*5450*/ uint16(x86_xArgRel16),
+ /*5451*/ uint16(x86_xMatch),
+ /*5452*/ uint16(x86_xSetOp), uint16(x86_JP),
+ /*5454*/ uint16(x86_xReadCd),
+ /*5455*/ uint16(x86_xArgRel32),
+ /*5456*/ uint16(x86_xMatch),
+ /*5457*/ uint16(x86_xCondDataSize), 5461, 5452, 5466,
+ /*5461*/ uint16(x86_xSetOp), uint16(x86_JP),
+ /*5463*/ uint16(x86_xReadCd),
+ /*5464*/ uint16(x86_xArgRel32),
+ /*5465*/ uint16(x86_xMatch),
+ /*5466*/ uint16(x86_xSetOp), uint16(x86_JP),
+ /*5468*/ uint16(x86_xReadCd),
+ /*5469*/ uint16(x86_xArgRel32),
+ /*5470*/ uint16(x86_xMatch),
+ /*5471*/ uint16(x86_xCondIs64), 5474, 5488,
+ /*5474*/ uint16(x86_xCondDataSize), 5478, 5483, 0,
+ /*5478*/ uint16(x86_xSetOp), uint16(x86_JNP),
+ /*5480*/ uint16(x86_xReadCw),
+ /*5481*/ uint16(x86_xArgRel16),
+ /*5482*/ uint16(x86_xMatch),
+ /*5483*/ uint16(x86_xSetOp), uint16(x86_JNP),
+ /*5485*/ uint16(x86_xReadCd),
+ /*5486*/ uint16(x86_xArgRel32),
+ /*5487*/ uint16(x86_xMatch),
+ /*5488*/ uint16(x86_xCondDataSize), 5492, 5483, 5497,
+ /*5492*/ uint16(x86_xSetOp), uint16(x86_JNP),
+ /*5494*/ uint16(x86_xReadCd),
+ /*5495*/ uint16(x86_xArgRel32),
+ /*5496*/ uint16(x86_xMatch),
+ /*5497*/ uint16(x86_xSetOp), uint16(x86_JNP),
+ /*5499*/ uint16(x86_xReadCd),
+ /*5500*/ uint16(x86_xArgRel32),
+ /*5501*/ uint16(x86_xMatch),
+ /*5502*/ uint16(x86_xCondIs64), 5505, 5519,
+ /*5505*/ uint16(x86_xCondDataSize), 5509, 5514, 0,
+ /*5509*/ uint16(x86_xSetOp), uint16(x86_JL),
+ /*5511*/ uint16(x86_xReadCw),
+ /*5512*/ uint16(x86_xArgRel16),
+ /*5513*/ uint16(x86_xMatch),
+ /*5514*/ uint16(x86_xSetOp), uint16(x86_JL),
+ /*5516*/ uint16(x86_xReadCd),
+ /*5517*/ uint16(x86_xArgRel32),
+ /*5518*/ uint16(x86_xMatch),
+ /*5519*/ uint16(x86_xCondDataSize), 5523, 5514, 5528,
+ /*5523*/ uint16(x86_xSetOp), uint16(x86_JL),
+ /*5525*/ uint16(x86_xReadCd),
+ /*5526*/ uint16(x86_xArgRel32),
+ /*5527*/ uint16(x86_xMatch),
+ /*5528*/ uint16(x86_xSetOp), uint16(x86_JL),
+ /*5530*/ uint16(x86_xReadCd),
+ /*5531*/ uint16(x86_xArgRel32),
+ /*5532*/ uint16(x86_xMatch),
+ /*5533*/ uint16(x86_xCondIs64), 5536, 5550,
+ /*5536*/ uint16(x86_xCondDataSize), 5540, 5545, 0,
+ /*5540*/ uint16(x86_xSetOp), uint16(x86_JGE),
+ /*5542*/ uint16(x86_xReadCw),
+ /*5543*/ uint16(x86_xArgRel16),
+ /*5544*/ uint16(x86_xMatch),
+ /*5545*/ uint16(x86_xSetOp), uint16(x86_JGE),
+ /*5547*/ uint16(x86_xReadCd),
+ /*5548*/ uint16(x86_xArgRel32),
+ /*5549*/ uint16(x86_xMatch),
+ /*5550*/ uint16(x86_xCondDataSize), 5554, 5545, 5559,
+ /*5554*/ uint16(x86_xSetOp), uint16(x86_JGE),
+ /*5556*/ uint16(x86_xReadCd),
+ /*5557*/ uint16(x86_xArgRel32),
+ /*5558*/ uint16(x86_xMatch),
+ /*5559*/ uint16(x86_xSetOp), uint16(x86_JGE),
+ /*5561*/ uint16(x86_xReadCd),
+ /*5562*/ uint16(x86_xArgRel32),
+ /*5563*/ uint16(x86_xMatch),
+ /*5564*/ uint16(x86_xCondIs64), 5567, 5581,
+ /*5567*/ uint16(x86_xCondDataSize), 5571, 5576, 0,
+ /*5571*/ uint16(x86_xSetOp), uint16(x86_JLE),
+ /*5573*/ uint16(x86_xReadCw),
+ /*5574*/ uint16(x86_xArgRel16),
+ /*5575*/ uint16(x86_xMatch),
+ /*5576*/ uint16(x86_xSetOp), uint16(x86_JLE),
+ /*5578*/ uint16(x86_xReadCd),
+ /*5579*/ uint16(x86_xArgRel32),
+ /*5580*/ uint16(x86_xMatch),
+ /*5581*/ uint16(x86_xCondDataSize), 5585, 5576, 5590,
+ /*5585*/ uint16(x86_xSetOp), uint16(x86_JLE),
+ /*5587*/ uint16(x86_xReadCd),
+ /*5588*/ uint16(x86_xArgRel32),
+ /*5589*/ uint16(x86_xMatch),
+ /*5590*/ uint16(x86_xSetOp), uint16(x86_JLE),
+ /*5592*/ uint16(x86_xReadCd),
+ /*5593*/ uint16(x86_xArgRel32),
+ /*5594*/ uint16(x86_xMatch),
+ /*5595*/ uint16(x86_xCondIs64), 5598, 5612,
+ /*5598*/ uint16(x86_xCondDataSize), 5602, 5607, 0,
+ /*5602*/ uint16(x86_xSetOp), uint16(x86_JG),
+ /*5604*/ uint16(x86_xReadCw),
+ /*5605*/ uint16(x86_xArgRel16),
+ /*5606*/ uint16(x86_xMatch),
+ /*5607*/ uint16(x86_xSetOp), uint16(x86_JG),
+ /*5609*/ uint16(x86_xReadCd),
+ /*5610*/ uint16(x86_xArgRel32),
+ /*5611*/ uint16(x86_xMatch),
+ /*5612*/ uint16(x86_xCondDataSize), 5616, 5607, 5621,
+ /*5616*/ uint16(x86_xSetOp), uint16(x86_JG),
+ /*5618*/ uint16(x86_xReadCd),
+ /*5619*/ uint16(x86_xArgRel32),
+ /*5620*/ uint16(x86_xMatch),
+ /*5621*/ uint16(x86_xSetOp), uint16(x86_JG),
+ /*5623*/ uint16(x86_xReadCd),
+ /*5624*/ uint16(x86_xArgRel32),
+ /*5625*/ uint16(x86_xMatch),
+ /*5626*/ uint16(x86_xSetOp), uint16(x86_SETO),
+ /*5628*/ uint16(x86_xReadSlashR),
+ /*5629*/ uint16(x86_xArgRM8),
+ /*5630*/ uint16(x86_xMatch),
+ /*5631*/ uint16(x86_xSetOp), uint16(x86_SETNO),
+ /*5633*/ uint16(x86_xReadSlashR),
+ /*5634*/ uint16(x86_xArgRM8),
+ /*5635*/ uint16(x86_xMatch),
+ /*5636*/ uint16(x86_xSetOp), uint16(x86_SETB),
+ /*5638*/ uint16(x86_xReadSlashR),
+ /*5639*/ uint16(x86_xArgRM8),
+ /*5640*/ uint16(x86_xMatch),
+ /*5641*/ uint16(x86_xSetOp), uint16(x86_SETAE),
+ /*5643*/ uint16(x86_xReadSlashR),
+ /*5644*/ uint16(x86_xArgRM8),
+ /*5645*/ uint16(x86_xMatch),
+ /*5646*/ uint16(x86_xSetOp), uint16(x86_SETE),
+ /*5648*/ uint16(x86_xReadSlashR),
+ /*5649*/ uint16(x86_xArgRM8),
+ /*5650*/ uint16(x86_xMatch),
+ /*5651*/ uint16(x86_xSetOp), uint16(x86_SETNE),
+ /*5653*/ uint16(x86_xReadSlashR),
+ /*5654*/ uint16(x86_xArgRM8),
+ /*5655*/ uint16(x86_xMatch),
+ /*5656*/ uint16(x86_xSetOp), uint16(x86_SETBE),
+ /*5658*/ uint16(x86_xReadSlashR),
+ /*5659*/ uint16(x86_xArgRM8),
+ /*5660*/ uint16(x86_xMatch),
+ /*5661*/ uint16(x86_xSetOp), uint16(x86_SETA),
+ /*5663*/ uint16(x86_xReadSlashR),
+ /*5664*/ uint16(x86_xArgRM8),
+ /*5665*/ uint16(x86_xMatch),
+ /*5666*/ uint16(x86_xSetOp), uint16(x86_SETS),
+ /*5668*/ uint16(x86_xReadSlashR),
+ /*5669*/ uint16(x86_xArgRM8),
+ /*5670*/ uint16(x86_xMatch),
+ /*5671*/ uint16(x86_xSetOp), uint16(x86_SETNS),
+ /*5673*/ uint16(x86_xReadSlashR),
+ /*5674*/ uint16(x86_xArgRM8),
+ /*5675*/ uint16(x86_xMatch),
+ /*5676*/ uint16(x86_xSetOp), uint16(x86_SETP),
+ /*5678*/ uint16(x86_xReadSlashR),
+ /*5679*/ uint16(x86_xArgRM8),
+ /*5680*/ uint16(x86_xMatch),
+ /*5681*/ uint16(x86_xSetOp), uint16(x86_SETNP),
+ /*5683*/ uint16(x86_xReadSlashR),
+ /*5684*/ uint16(x86_xArgRM8),
+ /*5685*/ uint16(x86_xMatch),
+ /*5686*/ uint16(x86_xSetOp), uint16(x86_SETL),
+ /*5688*/ uint16(x86_xReadSlashR),
+ /*5689*/ uint16(x86_xArgRM8),
+ /*5690*/ uint16(x86_xMatch),
+ /*5691*/ uint16(x86_xSetOp), uint16(x86_SETGE),
+ /*5693*/ uint16(x86_xReadSlashR),
+ /*5694*/ uint16(x86_xArgRM8),
+ /*5695*/ uint16(x86_xMatch),
+ /*5696*/ uint16(x86_xSetOp), uint16(x86_SETLE),
+ /*5698*/ uint16(x86_xReadSlashR),
+ /*5699*/ uint16(x86_xArgRM8),
+ /*5700*/ uint16(x86_xMatch),
+ /*5701*/ uint16(x86_xSetOp), uint16(x86_SETG),
+ /*5703*/ uint16(x86_xReadSlashR),
+ /*5704*/ uint16(x86_xArgRM8),
+ /*5705*/ uint16(x86_xMatch),
+ /*5706*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*5708*/ uint16(x86_xArgFS),
+ /*5709*/ uint16(x86_xMatch),
+ /*5710*/ uint16(x86_xCondIs64), 5713, 5725,
+ /*5713*/ uint16(x86_xCondDataSize), 5717, 5721, 0,
+ /*5717*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5719*/ uint16(x86_xArgFS),
+ /*5720*/ uint16(x86_xMatch),
+ /*5721*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5723*/ uint16(x86_xArgFS),
+ /*5724*/ uint16(x86_xMatch),
+ /*5725*/ uint16(x86_xCondDataSize), 5717, 5729, 5733,
+ /*5729*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5731*/ uint16(x86_xArgFS),
+ /*5732*/ uint16(x86_xMatch),
+ /*5733*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5735*/ uint16(x86_xArgFS),
+ /*5736*/ uint16(x86_xMatch),
+ /*5737*/ uint16(x86_xSetOp), uint16(x86_CPUID),
+ /*5739*/ uint16(x86_xMatch),
+ /*5740*/ uint16(x86_xCondIs64), 5743, 5759,
+ /*5743*/ uint16(x86_xCondDataSize), 5747, 5753, 0,
+ /*5747*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*5749*/ uint16(x86_xReadSlashR),
+ /*5750*/ uint16(x86_xArgRM16),
+ /*5751*/ uint16(x86_xArgR16),
+ /*5752*/ uint16(x86_xMatch),
+ /*5753*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*5755*/ uint16(x86_xReadSlashR),
+ /*5756*/ uint16(x86_xArgRM32),
+ /*5757*/ uint16(x86_xArgR32),
+ /*5758*/ uint16(x86_xMatch),
+ /*5759*/ uint16(x86_xCondDataSize), 5747, 5753, 5763,
+ /*5763*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*5765*/ uint16(x86_xReadSlashR),
+ /*5766*/ uint16(x86_xArgRM64),
+ /*5767*/ uint16(x86_xArgR64),
+ /*5768*/ uint16(x86_xMatch),
+ /*5769*/ uint16(x86_xCondIs64), 5772, 5792,
+ /*5772*/ uint16(x86_xCondDataSize), 5776, 5784, 0,
+ /*5776*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5778*/ uint16(x86_xReadSlashR),
+ /*5779*/ uint16(x86_xReadIb),
+ /*5780*/ uint16(x86_xArgRM16),
+ /*5781*/ uint16(x86_xArgR16),
+ /*5782*/ uint16(x86_xArgImm8u),
+ /*5783*/ uint16(x86_xMatch),
+ /*5784*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5786*/ uint16(x86_xReadSlashR),
+ /*5787*/ uint16(x86_xReadIb),
+ /*5788*/ uint16(x86_xArgRM32),
+ /*5789*/ uint16(x86_xArgR32),
+ /*5790*/ uint16(x86_xArgImm8u),
+ /*5791*/ uint16(x86_xMatch),
+ /*5792*/ uint16(x86_xCondDataSize), 5776, 5784, 5796,
+ /*5796*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5798*/ uint16(x86_xReadSlashR),
+ /*5799*/ uint16(x86_xReadIb),
+ /*5800*/ uint16(x86_xArgRM64),
+ /*5801*/ uint16(x86_xArgR64),
+ /*5802*/ uint16(x86_xArgImm8u),
+ /*5803*/ uint16(x86_xMatch),
+ /*5804*/ uint16(x86_xCondIs64), 5807, 5825,
+ /*5807*/ uint16(x86_xCondDataSize), 5811, 5818, 0,
+ /*5811*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5813*/ uint16(x86_xReadSlashR),
+ /*5814*/ uint16(x86_xArgRM16),
+ /*5815*/ uint16(x86_xArgR16),
+ /*5816*/ uint16(x86_xArgCL),
+ /*5817*/ uint16(x86_xMatch),
+ /*5818*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5820*/ uint16(x86_xReadSlashR),
+ /*5821*/ uint16(x86_xArgRM32),
+ /*5822*/ uint16(x86_xArgR32),
+ /*5823*/ uint16(x86_xArgCL),
+ /*5824*/ uint16(x86_xMatch),
+ /*5825*/ uint16(x86_xCondDataSize), 5811, 5818, 5829,
+ /*5829*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+ /*5831*/ uint16(x86_xReadSlashR),
+ /*5832*/ uint16(x86_xArgRM64),
+ /*5833*/ uint16(x86_xArgR64),
+ /*5834*/ uint16(x86_xArgCL),
+ /*5835*/ uint16(x86_xMatch),
+ /*5836*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*5838*/ uint16(x86_xArgGS),
+ /*5839*/ uint16(x86_xMatch),
+ /*5840*/ uint16(x86_xCondIs64), 5843, 5855,
+ /*5843*/ uint16(x86_xCondDataSize), 5847, 5851, 0,
+ /*5847*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5849*/ uint16(x86_xArgGS),
+ /*5850*/ uint16(x86_xMatch),
+ /*5851*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5853*/ uint16(x86_xArgGS),
+ /*5854*/ uint16(x86_xMatch),
+ /*5855*/ uint16(x86_xCondDataSize), 5847, 5859, 5863,
+ /*5859*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5861*/ uint16(x86_xArgGS),
+ /*5862*/ uint16(x86_xMatch),
+ /*5863*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*5865*/ uint16(x86_xArgGS),
+ /*5866*/ uint16(x86_xMatch),
+ /*5867*/ uint16(x86_xSetOp), uint16(x86_RSM),
+ /*5869*/ uint16(x86_xMatch),
+ /*5870*/ uint16(x86_xCondIs64), 5873, 5889,
+ /*5873*/ uint16(x86_xCondDataSize), 5877, 5883, 0,
+ /*5877*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*5879*/ uint16(x86_xReadSlashR),
+ /*5880*/ uint16(x86_xArgRM16),
+ /*5881*/ uint16(x86_xArgR16),
+ /*5882*/ uint16(x86_xMatch),
+ /*5883*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*5885*/ uint16(x86_xReadSlashR),
+ /*5886*/ uint16(x86_xArgRM32),
+ /*5887*/ uint16(x86_xArgR32),
+ /*5888*/ uint16(x86_xMatch),
+ /*5889*/ uint16(x86_xCondDataSize), 5877, 5883, 5893,
+ /*5893*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*5895*/ uint16(x86_xReadSlashR),
+ /*5896*/ uint16(x86_xArgRM64),
+ /*5897*/ uint16(x86_xArgR64),
+ /*5898*/ uint16(x86_xMatch),
+ /*5899*/ uint16(x86_xCondIs64), 5902, 5922,
+ /*5902*/ uint16(x86_xCondDataSize), 5906, 5914, 0,
+ /*5906*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5908*/ uint16(x86_xReadSlashR),
+ /*5909*/ uint16(x86_xReadIb),
+ /*5910*/ uint16(x86_xArgRM16),
+ /*5911*/ uint16(x86_xArgR16),
+ /*5912*/ uint16(x86_xArgImm8u),
+ /*5913*/ uint16(x86_xMatch),
+ /*5914*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5916*/ uint16(x86_xReadSlashR),
+ /*5917*/ uint16(x86_xReadIb),
+ /*5918*/ uint16(x86_xArgRM32),
+ /*5919*/ uint16(x86_xArgR32),
+ /*5920*/ uint16(x86_xArgImm8u),
+ /*5921*/ uint16(x86_xMatch),
+ /*5922*/ uint16(x86_xCondDataSize), 5906, 5914, 5926,
+ /*5926*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5928*/ uint16(x86_xReadSlashR),
+ /*5929*/ uint16(x86_xReadIb),
+ /*5930*/ uint16(x86_xArgRM64),
+ /*5931*/ uint16(x86_xArgR64),
+ /*5932*/ uint16(x86_xArgImm8u),
+ /*5933*/ uint16(x86_xMatch),
+ /*5934*/ uint16(x86_xCondIs64), 5937, 5955,
+ /*5937*/ uint16(x86_xCondDataSize), 5941, 5948, 0,
+ /*5941*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5943*/ uint16(x86_xReadSlashR),
+ /*5944*/ uint16(x86_xArgRM16),
+ /*5945*/ uint16(x86_xArgR16),
+ /*5946*/ uint16(x86_xArgCL),
+ /*5947*/ uint16(x86_xMatch),
+ /*5948*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5950*/ uint16(x86_xReadSlashR),
+ /*5951*/ uint16(x86_xArgRM32),
+ /*5952*/ uint16(x86_xArgR32),
+ /*5953*/ uint16(x86_xArgCL),
+ /*5954*/ uint16(x86_xMatch),
+ /*5955*/ uint16(x86_xCondDataSize), 5941, 5948, 5959,
+ /*5959*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+ /*5961*/ uint16(x86_xReadSlashR),
+ /*5962*/ uint16(x86_xArgRM64),
+ /*5963*/ uint16(x86_xArgR64),
+ /*5964*/ uint16(x86_xArgCL),
+ /*5965*/ uint16(x86_xMatch),
+ /*5966*/ uint16(x86_xCondByte), 3,
+ 0xE8, 6215,
+ 0xF0, 6218,
+ 0xF8, 6221,
+ /*5974*/ uint16(x86_xCondSlashR),
+ 5983, // 0
+ 6037, // 1
+ 6091, // 2
+ 6120, // 3
+ 6149, // 4
+ 6172, // 5
+ 6195, // 6
+ 6211, // 7
+ /*5983*/ uint16(x86_xCondIs64), 5986, 5998,
+ /*5986*/ uint16(x86_xCondDataSize), 5990, 5994, 0,
+ /*5990*/ uint16(x86_xSetOp), uint16(x86_FXSAVE),
+ /*5992*/ uint16(x86_xArgM512byte),
+ /*5993*/ uint16(x86_xMatch),
+ /*5994*/ uint16(x86_xSetOp), uint16(x86_FXSAVE),
+ /*5996*/ uint16(x86_xArgM512byte),
+ /*5997*/ uint16(x86_xMatch),
+ /*5998*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6012,
+ 0x0, 6004,
+ /*6004*/ uint16(x86_xCondDataSize), 5990, 5994, 6008,
+ /*6008*/ uint16(x86_xSetOp), uint16(x86_FXSAVE64),
+ /*6010*/ uint16(x86_xArgM512byte),
+ /*6011*/ uint16(x86_xMatch),
+ /*6012*/ uint16(x86_xCondDataSize), 6016, 6023, 6030,
+ /*6016*/ uint16(x86_xCondIsMem), 6019, 0,
+ /*6019*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+ /*6021*/ uint16(x86_xArgRM32),
+ /*6022*/ uint16(x86_xMatch),
+ /*6023*/ uint16(x86_xCondIsMem), 6026, 0,
+ /*6026*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+ /*6028*/ uint16(x86_xArgRM32),
+ /*6029*/ uint16(x86_xMatch),
+ /*6030*/ uint16(x86_xCondIsMem), 6033, 0,
+ /*6033*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+ /*6035*/ uint16(x86_xArgRM64),
+ /*6036*/ uint16(x86_xMatch),
+ /*6037*/ uint16(x86_xCondIs64), 6040, 6052,
+ /*6040*/ uint16(x86_xCondDataSize), 6044, 6048, 0,
+ /*6044*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR),
+ /*6046*/ uint16(x86_xArgM512byte),
+ /*6047*/ uint16(x86_xMatch),
+ /*6048*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR),
+ /*6050*/ uint16(x86_xArgM512byte),
+ /*6051*/ uint16(x86_xMatch),
+ /*6052*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6066,
+ 0x0, 6058,
+ /*6058*/ uint16(x86_xCondDataSize), 6044, 6048, 6062,
+ /*6062*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR64),
+ /*6064*/ uint16(x86_xArgM512byte),
+ /*6065*/ uint16(x86_xMatch),
+ /*6066*/ uint16(x86_xCondDataSize), 6070, 6077, 6084,
+ /*6070*/ uint16(x86_xCondIsMem), 6073, 0,
+ /*6073*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+ /*6075*/ uint16(x86_xArgRM32),
+ /*6076*/ uint16(x86_xMatch),
+ /*6077*/ uint16(x86_xCondIsMem), 6080, 0,
+ /*6080*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+ /*6082*/ uint16(x86_xArgRM32),
+ /*6083*/ uint16(x86_xMatch),
+ /*6084*/ uint16(x86_xCondIsMem), 6087, 0,
+ /*6087*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+ /*6089*/ uint16(x86_xArgRM64),
+ /*6090*/ uint16(x86_xMatch),
+ /*6091*/ uint16(x86_xCondIs64), 6094, 6098,
+ /*6094*/ uint16(x86_xSetOp), uint16(x86_LDMXCSR),
+ /*6096*/ uint16(x86_xArgM32),
+ /*6097*/ uint16(x86_xMatch),
+ /*6098*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6104,
+ 0x0, 6094,
+ /*6104*/ uint16(x86_xCondDataSize), 6108, 6112, 6116,
+ /*6108*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+ /*6110*/ uint16(x86_xArgRM32),
+ /*6111*/ uint16(x86_xMatch),
+ /*6112*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+ /*6114*/ uint16(x86_xArgRM32),
+ /*6115*/ uint16(x86_xMatch),
+ /*6116*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+ /*6118*/ uint16(x86_xArgRM64),
+ /*6119*/ uint16(x86_xMatch),
+ /*6120*/ uint16(x86_xCondIs64), 6123, 6127,
+ /*6123*/ uint16(x86_xSetOp), uint16(x86_STMXCSR),
+ /*6125*/ uint16(x86_xArgM32),
+ /*6126*/ uint16(x86_xMatch),
+ /*6127*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6133,
+ 0x0, 6123,
+ /*6133*/ uint16(x86_xCondDataSize), 6137, 6141, 6145,
+ /*6137*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+ /*6139*/ uint16(x86_xArgRM32),
+ /*6140*/ uint16(x86_xMatch),
+ /*6141*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+ /*6143*/ uint16(x86_xArgRM32),
+ /*6144*/ uint16(x86_xMatch),
+ /*6145*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+ /*6147*/ uint16(x86_xArgRM64),
+ /*6148*/ uint16(x86_xMatch),
+ /*6149*/ uint16(x86_xCondIs64), 6152, 6164,
+ /*6152*/ uint16(x86_xCondDataSize), 6156, 6160, 0,
+ /*6156*/ uint16(x86_xSetOp), uint16(x86_XSAVE),
+ /*6158*/ uint16(x86_xArgMem),
+ /*6159*/ uint16(x86_xMatch),
+ /*6160*/ uint16(x86_xSetOp), uint16(x86_XSAVE),
+ /*6162*/ uint16(x86_xArgMem),
+ /*6163*/ uint16(x86_xMatch),
+ /*6164*/ uint16(x86_xCondDataSize), 6156, 6160, 6168,
+ /*6168*/ uint16(x86_xSetOp), uint16(x86_XSAVE64),
+ /*6170*/ uint16(x86_xArgMem),
+ /*6171*/ uint16(x86_xMatch),
+ /*6172*/ uint16(x86_xCondIs64), 6175, 6187,
+ /*6175*/ uint16(x86_xCondDataSize), 6179, 6183, 0,
+ /*6179*/ uint16(x86_xSetOp), uint16(x86_XRSTOR),
+ /*6181*/ uint16(x86_xArgMem),
+ /*6182*/ uint16(x86_xMatch),
+ /*6183*/ uint16(x86_xSetOp), uint16(x86_XRSTOR),
+ /*6185*/ uint16(x86_xArgMem),
+ /*6186*/ uint16(x86_xMatch),
+ /*6187*/ uint16(x86_xCondDataSize), 6179, 6183, 6191,
+ /*6191*/ uint16(x86_xSetOp), uint16(x86_XRSTOR64),
+ /*6193*/ uint16(x86_xArgMem),
+ /*6194*/ uint16(x86_xMatch),
+ /*6195*/ uint16(x86_xCondDataSize), 6199, 6203, 6207,
+ /*6199*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT),
+ /*6201*/ uint16(x86_xArgMem),
+ /*6202*/ uint16(x86_xMatch),
+ /*6203*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT),
+ /*6205*/ uint16(x86_xArgMem),
+ /*6206*/ uint16(x86_xMatch),
+ /*6207*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT64),
+ /*6209*/ uint16(x86_xArgMem),
+ /*6210*/ uint16(x86_xMatch),
+ /*6211*/ uint16(x86_xSetOp), uint16(x86_CLFLUSH),
+ /*6213*/ uint16(x86_xArgM8),
+ /*6214*/ uint16(x86_xMatch),
+ /*6215*/ uint16(x86_xSetOp), uint16(x86_LFENCE),
+ /*6217*/ uint16(x86_xMatch),
+ /*6218*/ uint16(x86_xSetOp), uint16(x86_MFENCE),
+ /*6220*/ uint16(x86_xMatch),
+ /*6221*/ uint16(x86_xSetOp), uint16(x86_SFENCE),
+ /*6223*/ uint16(x86_xMatch),
+ /*6224*/ uint16(x86_xCondIs64), 6227, 6243,
+ /*6227*/ uint16(x86_xCondDataSize), 6231, 6237, 0,
+ /*6231*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*6233*/ uint16(x86_xReadSlashR),
+ /*6234*/ uint16(x86_xArgR16),
+ /*6235*/ uint16(x86_xArgRM16),
+ /*6236*/ uint16(x86_xMatch),
+ /*6237*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*6239*/ uint16(x86_xReadSlashR),
+ /*6240*/ uint16(x86_xArgR32),
+ /*6241*/ uint16(x86_xArgRM32),
+ /*6242*/ uint16(x86_xMatch),
+ /*6243*/ uint16(x86_xCondDataSize), 6231, 6237, 6247,
+ /*6247*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*6249*/ uint16(x86_xReadSlashR),
+ /*6250*/ uint16(x86_xArgR64),
+ /*6251*/ uint16(x86_xArgRM64),
+ /*6252*/ uint16(x86_xMatch),
+ /*6253*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+ /*6255*/ uint16(x86_xReadSlashR),
+ /*6256*/ uint16(x86_xArgRM8),
+ /*6257*/ uint16(x86_xArgR8),
+ /*6258*/ uint16(x86_xMatch),
+ /*6259*/ uint16(x86_xCondIs64), 6262, 6278,
+ /*6262*/ uint16(x86_xCondDataSize), 6266, 6272, 0,
+ /*6266*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+ /*6268*/ uint16(x86_xReadSlashR),
+ /*6269*/ uint16(x86_xArgRM16),
+ /*6270*/ uint16(x86_xArgR16),
+ /*6271*/ uint16(x86_xMatch),
+ /*6272*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+ /*6274*/ uint16(x86_xReadSlashR),
+ /*6275*/ uint16(x86_xArgRM32),
+ /*6276*/ uint16(x86_xArgR32),
+ /*6277*/ uint16(x86_xMatch),
+ /*6278*/ uint16(x86_xCondDataSize), 6266, 6272, 6282,
+ /*6282*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+ /*6284*/ uint16(x86_xReadSlashR),
+ /*6285*/ uint16(x86_xArgRM64),
+ /*6286*/ uint16(x86_xArgR64),
+ /*6287*/ uint16(x86_xMatch),
+ /*6288*/ uint16(x86_xCondIs64), 6291, 6307,
+ /*6291*/ uint16(x86_xCondDataSize), 6295, 6301, 0,
+ /*6295*/ uint16(x86_xSetOp), uint16(x86_LSS),
+ /*6297*/ uint16(x86_xReadSlashR),
+ /*6298*/ uint16(x86_xArgR16),
+ /*6299*/ uint16(x86_xArgM16colon16),
+ /*6300*/ uint16(x86_xMatch),
+ /*6301*/ uint16(x86_xSetOp), uint16(x86_LSS),
+ /*6303*/ uint16(x86_xReadSlashR),
+ /*6304*/ uint16(x86_xArgR32),
+ /*6305*/ uint16(x86_xArgM16colon32),
+ /*6306*/ uint16(x86_xMatch),
+ /*6307*/ uint16(x86_xCondDataSize), 6295, 6301, 6311,
+ /*6311*/ uint16(x86_xSetOp), uint16(x86_LSS),
+ /*6313*/ uint16(x86_xReadSlashR),
+ /*6314*/ uint16(x86_xArgR64),
+ /*6315*/ uint16(x86_xArgM16colon64),
+ /*6316*/ uint16(x86_xMatch),
+ /*6317*/ uint16(x86_xCondIs64), 6320, 6336,
+ /*6320*/ uint16(x86_xCondDataSize), 6324, 6330, 0,
+ /*6324*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6326*/ uint16(x86_xReadSlashR),
+ /*6327*/ uint16(x86_xArgRM16),
+ /*6328*/ uint16(x86_xArgR16),
+ /*6329*/ uint16(x86_xMatch),
+ /*6330*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6332*/ uint16(x86_xReadSlashR),
+ /*6333*/ uint16(x86_xArgRM32),
+ /*6334*/ uint16(x86_xArgR32),
+ /*6335*/ uint16(x86_xMatch),
+ /*6336*/ uint16(x86_xCondDataSize), 6324, 6330, 6340,
+ /*6340*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6342*/ uint16(x86_xReadSlashR),
+ /*6343*/ uint16(x86_xArgRM64),
+ /*6344*/ uint16(x86_xArgR64),
+ /*6345*/ uint16(x86_xMatch),
+ /*6346*/ uint16(x86_xCondIs64), 6349, 6365,
+ /*6349*/ uint16(x86_xCondDataSize), 6353, 6359, 0,
+ /*6353*/ uint16(x86_xSetOp), uint16(x86_LFS),
+ /*6355*/ uint16(x86_xReadSlashR),
+ /*6356*/ uint16(x86_xArgR16),
+ /*6357*/ uint16(x86_xArgM16colon16),
+ /*6358*/ uint16(x86_xMatch),
+ /*6359*/ uint16(x86_xSetOp), uint16(x86_LFS),
+ /*6361*/ uint16(x86_xReadSlashR),
+ /*6362*/ uint16(x86_xArgR32),
+ /*6363*/ uint16(x86_xArgM16colon32),
+ /*6364*/ uint16(x86_xMatch),
+ /*6365*/ uint16(x86_xCondDataSize), 6353, 6359, 6369,
+ /*6369*/ uint16(x86_xSetOp), uint16(x86_LFS),
+ /*6371*/ uint16(x86_xReadSlashR),
+ /*6372*/ uint16(x86_xArgR64),
+ /*6373*/ uint16(x86_xArgM16colon64),
+ /*6374*/ uint16(x86_xMatch),
+ /*6375*/ uint16(x86_xCondIs64), 6378, 6394,
+ /*6378*/ uint16(x86_xCondDataSize), 6382, 6388, 0,
+ /*6382*/ uint16(x86_xSetOp), uint16(x86_LGS),
+ /*6384*/ uint16(x86_xReadSlashR),
+ /*6385*/ uint16(x86_xArgR16),
+ /*6386*/ uint16(x86_xArgM16colon16),
+ /*6387*/ uint16(x86_xMatch),
+ /*6388*/ uint16(x86_xSetOp), uint16(x86_LGS),
+ /*6390*/ uint16(x86_xReadSlashR),
+ /*6391*/ uint16(x86_xArgR32),
+ /*6392*/ uint16(x86_xArgM16colon32),
+ /*6393*/ uint16(x86_xMatch),
+ /*6394*/ uint16(x86_xCondDataSize), 6382, 6388, 6398,
+ /*6398*/ uint16(x86_xSetOp), uint16(x86_LGS),
+ /*6400*/ uint16(x86_xReadSlashR),
+ /*6401*/ uint16(x86_xArgR64),
+ /*6402*/ uint16(x86_xArgM16colon64),
+ /*6403*/ uint16(x86_xMatch),
+ /*6404*/ uint16(x86_xCondIs64), 6407, 6423,
+ /*6407*/ uint16(x86_xCondDataSize), 6411, 6417, 0,
+ /*6411*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6413*/ uint16(x86_xReadSlashR),
+ /*6414*/ uint16(x86_xArgR16),
+ /*6415*/ uint16(x86_xArgRM8),
+ /*6416*/ uint16(x86_xMatch),
+ /*6417*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6419*/ uint16(x86_xReadSlashR),
+ /*6420*/ uint16(x86_xArgR32),
+ /*6421*/ uint16(x86_xArgRM8),
+ /*6422*/ uint16(x86_xMatch),
+ /*6423*/ uint16(x86_xCondDataSize), 6411, 6417, 6427,
+ /*6427*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6429*/ uint16(x86_xReadSlashR),
+ /*6430*/ uint16(x86_xArgR64),
+ /*6431*/ uint16(x86_xArgRM8),
+ /*6432*/ uint16(x86_xMatch),
+ /*6433*/ uint16(x86_xCondIs64), 6436, 6452,
+ /*6436*/ uint16(x86_xCondDataSize), 6440, 6446, 0,
+ /*6440*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6442*/ uint16(x86_xReadSlashR),
+ /*6443*/ uint16(x86_xArgR16),
+ /*6444*/ uint16(x86_xArgRM16),
+ /*6445*/ uint16(x86_xMatch),
+ /*6446*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6448*/ uint16(x86_xReadSlashR),
+ /*6449*/ uint16(x86_xArgR32),
+ /*6450*/ uint16(x86_xArgRM16),
+ /*6451*/ uint16(x86_xMatch),
+ /*6452*/ uint16(x86_xCondDataSize), 6440, 6446, 6456,
+ /*6456*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+ /*6458*/ uint16(x86_xReadSlashR),
+ /*6459*/ uint16(x86_xArgR64),
+ /*6460*/ uint16(x86_xArgRM16),
+ /*6461*/ uint16(x86_xMatch),
+ /*6462*/ uint16(x86_xCondIs64), 6465, 6485,
+ /*6465*/ uint16(x86_xCondPrefix), 1,
+ 0xF3, 6469,
+ /*6469*/ uint16(x86_xCondDataSize), 6473, 6479, 0,
+ /*6473*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+ /*6475*/ uint16(x86_xReadSlashR),
+ /*6476*/ uint16(x86_xArgR16),
+ /*6477*/ uint16(x86_xArgRM16),
+ /*6478*/ uint16(x86_xMatch),
+ /*6479*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+ /*6481*/ uint16(x86_xReadSlashR),
+ /*6482*/ uint16(x86_xArgR32),
+ /*6483*/ uint16(x86_xArgRM32),
+ /*6484*/ uint16(x86_xMatch),
+ /*6485*/ uint16(x86_xCondPrefix), 1,
+ 0xF3, 6489,
+ /*6489*/ uint16(x86_xCondDataSize), 6473, 6479, 6493,
+ /*6493*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+ /*6495*/ uint16(x86_xReadSlashR),
+ /*6496*/ uint16(x86_xArgR64),
+ /*6497*/ uint16(x86_xArgRM64),
+ /*6498*/ uint16(x86_xMatch),
+ /*6499*/ uint16(x86_xSetOp), uint16(x86_UD1),
+ /*6501*/ uint16(x86_xMatch),
+ /*6502*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 6511, // 4
+ 6540, // 5
+ 6569, // 6
+ 6598, // 7
+ /*6511*/ uint16(x86_xCondIs64), 6514, 6530,
+ /*6514*/ uint16(x86_xCondDataSize), 6518, 6524, 0,
+ /*6518*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*6520*/ uint16(x86_xReadIb),
+ /*6521*/ uint16(x86_xArgRM16),
+ /*6522*/ uint16(x86_xArgImm8u),
+ /*6523*/ uint16(x86_xMatch),
+ /*6524*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*6526*/ uint16(x86_xReadIb),
+ /*6527*/ uint16(x86_xArgRM32),
+ /*6528*/ uint16(x86_xArgImm8u),
+ /*6529*/ uint16(x86_xMatch),
+ /*6530*/ uint16(x86_xCondDataSize), 6518, 6524, 6534,
+ /*6534*/ uint16(x86_xSetOp), uint16(x86_BT),
+ /*6536*/ uint16(x86_xReadIb),
+ /*6537*/ uint16(x86_xArgRM64),
+ /*6538*/ uint16(x86_xArgImm8u),
+ /*6539*/ uint16(x86_xMatch),
+ /*6540*/ uint16(x86_xCondIs64), 6543, 6559,
+ /*6543*/ uint16(x86_xCondDataSize), 6547, 6553, 0,
+ /*6547*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*6549*/ uint16(x86_xReadIb),
+ /*6550*/ uint16(x86_xArgRM16),
+ /*6551*/ uint16(x86_xArgImm8u),
+ /*6552*/ uint16(x86_xMatch),
+ /*6553*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*6555*/ uint16(x86_xReadIb),
+ /*6556*/ uint16(x86_xArgRM32),
+ /*6557*/ uint16(x86_xArgImm8u),
+ /*6558*/ uint16(x86_xMatch),
+ /*6559*/ uint16(x86_xCondDataSize), 6547, 6553, 6563,
+ /*6563*/ uint16(x86_xSetOp), uint16(x86_BTS),
+ /*6565*/ uint16(x86_xReadIb),
+ /*6566*/ uint16(x86_xArgRM64),
+ /*6567*/ uint16(x86_xArgImm8u),
+ /*6568*/ uint16(x86_xMatch),
+ /*6569*/ uint16(x86_xCondIs64), 6572, 6588,
+ /*6572*/ uint16(x86_xCondDataSize), 6576, 6582, 0,
+ /*6576*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6578*/ uint16(x86_xReadIb),
+ /*6579*/ uint16(x86_xArgRM16),
+ /*6580*/ uint16(x86_xArgImm8u),
+ /*6581*/ uint16(x86_xMatch),
+ /*6582*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6584*/ uint16(x86_xReadIb),
+ /*6585*/ uint16(x86_xArgRM32),
+ /*6586*/ uint16(x86_xArgImm8u),
+ /*6587*/ uint16(x86_xMatch),
+ /*6588*/ uint16(x86_xCondDataSize), 6576, 6582, 6592,
+ /*6592*/ uint16(x86_xSetOp), uint16(x86_BTR),
+ /*6594*/ uint16(x86_xReadIb),
+ /*6595*/ uint16(x86_xArgRM64),
+ /*6596*/ uint16(x86_xArgImm8u),
+ /*6597*/ uint16(x86_xMatch),
+ /*6598*/ uint16(x86_xCondIs64), 6601, 6617,
+ /*6601*/ uint16(x86_xCondDataSize), 6605, 6611, 0,
+ /*6605*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6607*/ uint16(x86_xReadIb),
+ /*6608*/ uint16(x86_xArgRM16),
+ /*6609*/ uint16(x86_xArgImm8u),
+ /*6610*/ uint16(x86_xMatch),
+ /*6611*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6613*/ uint16(x86_xReadIb),
+ /*6614*/ uint16(x86_xArgRM32),
+ /*6615*/ uint16(x86_xArgImm8u),
+ /*6616*/ uint16(x86_xMatch),
+ /*6617*/ uint16(x86_xCondDataSize), 6605, 6611, 6621,
+ /*6621*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6623*/ uint16(x86_xReadIb),
+ /*6624*/ uint16(x86_xArgRM64),
+ /*6625*/ uint16(x86_xArgImm8u),
+ /*6626*/ uint16(x86_xMatch),
+ /*6627*/ uint16(x86_xCondIs64), 6630, 6646,
+ /*6630*/ uint16(x86_xCondDataSize), 6634, 6640, 0,
+ /*6634*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6636*/ uint16(x86_xReadSlashR),
+ /*6637*/ uint16(x86_xArgRM16),
+ /*6638*/ uint16(x86_xArgR16),
+ /*6639*/ uint16(x86_xMatch),
+ /*6640*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6642*/ uint16(x86_xReadSlashR),
+ /*6643*/ uint16(x86_xArgRM32),
+ /*6644*/ uint16(x86_xArgR32),
+ /*6645*/ uint16(x86_xMatch),
+ /*6646*/ uint16(x86_xCondDataSize), 6634, 6640, 6650,
+ /*6650*/ uint16(x86_xSetOp), uint16(x86_BTC),
+ /*6652*/ uint16(x86_xReadSlashR),
+ /*6653*/ uint16(x86_xArgRM64),
+ /*6654*/ uint16(x86_xArgR64),
+ /*6655*/ uint16(x86_xMatch),
+ /*6656*/ uint16(x86_xCondIs64), 6659, 6697,
+ /*6659*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6681,
+ 0x0, 6665,
+ /*6665*/ uint16(x86_xCondDataSize), 6669, 6675, 0,
+ /*6669*/ uint16(x86_xSetOp), uint16(x86_BSF),
+ /*6671*/ uint16(x86_xReadSlashR),
+ /*6672*/ uint16(x86_xArgR16),
+ /*6673*/ uint16(x86_xArgRM16),
+ /*6674*/ uint16(x86_xMatch),
+ /*6675*/ uint16(x86_xSetOp), uint16(x86_BSF),
+ /*6677*/ uint16(x86_xReadSlashR),
+ /*6678*/ uint16(x86_xArgR32),
+ /*6679*/ uint16(x86_xArgRM32),
+ /*6680*/ uint16(x86_xMatch),
+ /*6681*/ uint16(x86_xCondDataSize), 6685, 6691, 0,
+ /*6685*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+ /*6687*/ uint16(x86_xReadSlashR),
+ /*6688*/ uint16(x86_xArgR16),
+ /*6689*/ uint16(x86_xArgRM16),
+ /*6690*/ uint16(x86_xMatch),
+ /*6691*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+ /*6693*/ uint16(x86_xReadSlashR),
+ /*6694*/ uint16(x86_xArgR32),
+ /*6695*/ uint16(x86_xArgRM32),
+ /*6696*/ uint16(x86_xMatch),
+ /*6697*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6713,
+ 0x0, 6703,
+ /*6703*/ uint16(x86_xCondDataSize), 6669, 6675, 6707,
+ /*6707*/ uint16(x86_xSetOp), uint16(x86_BSF),
+ /*6709*/ uint16(x86_xReadSlashR),
+ /*6710*/ uint16(x86_xArgR64),
+ /*6711*/ uint16(x86_xArgRM64),
+ /*6712*/ uint16(x86_xMatch),
+ /*6713*/ uint16(x86_xCondDataSize), 6685, 6691, 6717,
+ /*6717*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+ /*6719*/ uint16(x86_xReadSlashR),
+ /*6720*/ uint16(x86_xArgR64),
+ /*6721*/ uint16(x86_xArgRM64),
+ /*6722*/ uint16(x86_xMatch),
+ /*6723*/ uint16(x86_xCondIs64), 6726, 6764,
+ /*6726*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6748,
+ 0x0, 6732,
+ /*6732*/ uint16(x86_xCondDataSize), 6736, 6742, 0,
+ /*6736*/ uint16(x86_xSetOp), uint16(x86_BSR),
+ /*6738*/ uint16(x86_xReadSlashR),
+ /*6739*/ uint16(x86_xArgR16),
+ /*6740*/ uint16(x86_xArgRM16),
+ /*6741*/ uint16(x86_xMatch),
+ /*6742*/ uint16(x86_xSetOp), uint16(x86_BSR),
+ /*6744*/ uint16(x86_xReadSlashR),
+ /*6745*/ uint16(x86_xArgR32),
+ /*6746*/ uint16(x86_xArgRM32),
+ /*6747*/ uint16(x86_xMatch),
+ /*6748*/ uint16(x86_xCondDataSize), 6752, 6758, 0,
+ /*6752*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+ /*6754*/ uint16(x86_xReadSlashR),
+ /*6755*/ uint16(x86_xArgR16),
+ /*6756*/ uint16(x86_xArgRM16),
+ /*6757*/ uint16(x86_xMatch),
+ /*6758*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+ /*6760*/ uint16(x86_xReadSlashR),
+ /*6761*/ uint16(x86_xArgR32),
+ /*6762*/ uint16(x86_xArgRM32),
+ /*6763*/ uint16(x86_xMatch),
+ /*6764*/ uint16(x86_xCondPrefix), 2,
+ 0xF3, 6780,
+ 0x0, 6770,
+ /*6770*/ uint16(x86_xCondDataSize), 6736, 6742, 6774,
+ /*6774*/ uint16(x86_xSetOp), uint16(x86_BSR),
+ /*6776*/ uint16(x86_xReadSlashR),
+ /*6777*/ uint16(x86_xArgR64),
+ /*6778*/ uint16(x86_xArgRM64),
+ /*6779*/ uint16(x86_xMatch),
+ /*6780*/ uint16(x86_xCondDataSize), 6752, 6758, 6784,
+ /*6784*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+ /*6786*/ uint16(x86_xReadSlashR),
+ /*6787*/ uint16(x86_xArgR64),
+ /*6788*/ uint16(x86_xArgRM64),
+ /*6789*/ uint16(x86_xMatch),
+ /*6790*/ uint16(x86_xCondIs64), 6793, 6809,
+ /*6793*/ uint16(x86_xCondDataSize), 6797, 6803, 0,
+ /*6797*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6799*/ uint16(x86_xReadSlashR),
+ /*6800*/ uint16(x86_xArgR16),
+ /*6801*/ uint16(x86_xArgRM8),
+ /*6802*/ uint16(x86_xMatch),
+ /*6803*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6805*/ uint16(x86_xReadSlashR),
+ /*6806*/ uint16(x86_xArgR32),
+ /*6807*/ uint16(x86_xArgRM8),
+ /*6808*/ uint16(x86_xMatch),
+ /*6809*/ uint16(x86_xCondDataSize), 6797, 6803, 6813,
+ /*6813*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6815*/ uint16(x86_xReadSlashR),
+ /*6816*/ uint16(x86_xArgR64),
+ /*6817*/ uint16(x86_xArgRM8),
+ /*6818*/ uint16(x86_xMatch),
+ /*6819*/ uint16(x86_xCondIs64), 6822, 6838,
+ /*6822*/ uint16(x86_xCondDataSize), 6826, 6832, 0,
+ /*6826*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6828*/ uint16(x86_xReadSlashR),
+ /*6829*/ uint16(x86_xArgR16),
+ /*6830*/ uint16(x86_xArgRM16),
+ /*6831*/ uint16(x86_xMatch),
+ /*6832*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6834*/ uint16(x86_xReadSlashR),
+ /*6835*/ uint16(x86_xArgR32),
+ /*6836*/ uint16(x86_xArgRM16),
+ /*6837*/ uint16(x86_xMatch),
+ /*6838*/ uint16(x86_xCondDataSize), 6826, 6832, 6842,
+ /*6842*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+ /*6844*/ uint16(x86_xReadSlashR),
+ /*6845*/ uint16(x86_xArgR64),
+ /*6846*/ uint16(x86_xArgRM16),
+ /*6847*/ uint16(x86_xMatch),
+ /*6848*/ uint16(x86_xSetOp), uint16(x86_XADD),
+ /*6850*/ uint16(x86_xReadSlashR),
+ /*6851*/ uint16(x86_xArgRM8),
+ /*6852*/ uint16(x86_xArgR8),
+ /*6853*/ uint16(x86_xMatch),
+ /*6854*/ uint16(x86_xCondIs64), 6857, 6873,
+ /*6857*/ uint16(x86_xCondDataSize), 6861, 6867, 0,
+ /*6861*/ uint16(x86_xSetOp), uint16(x86_XADD),
+ /*6863*/ uint16(x86_xReadSlashR),
+ /*6864*/ uint16(x86_xArgRM16),
+ /*6865*/ uint16(x86_xArgR16),
+ /*6866*/ uint16(x86_xMatch),
+ /*6867*/ uint16(x86_xSetOp), uint16(x86_XADD),
+ /*6869*/ uint16(x86_xReadSlashR),
+ /*6870*/ uint16(x86_xArgRM32),
+ /*6871*/ uint16(x86_xArgR32),
+ /*6872*/ uint16(x86_xMatch),
+ /*6873*/ uint16(x86_xCondDataSize), 6861, 6867, 6877,
+ /*6877*/ uint16(x86_xSetOp), uint16(x86_XADD),
+ /*6879*/ uint16(x86_xReadSlashR),
+ /*6880*/ uint16(x86_xArgRM64),
+ /*6881*/ uint16(x86_xArgR64),
+ /*6882*/ uint16(x86_xMatch),
+ /*6883*/ uint16(x86_xCondPrefix), 4,
+ 0xF3, 6917,
+ 0xF2, 6909,
+ 0x66, 6901,
+ 0x0, 6893,
+ /*6893*/ uint16(x86_xSetOp), uint16(x86_CMPPS),
+ /*6895*/ uint16(x86_xReadSlashR),
+ /*6896*/ uint16(x86_xReadIb),
+ /*6897*/ uint16(x86_xArgXmm1),
+ /*6898*/ uint16(x86_xArgXmm2M128),
+ /*6899*/ uint16(x86_xArgImm8u),
+ /*6900*/ uint16(x86_xMatch),
+ /*6901*/ uint16(x86_xSetOp), uint16(x86_CMPPD),
+ /*6903*/ uint16(x86_xReadSlashR),
+ /*6904*/ uint16(x86_xReadIb),
+ /*6905*/ uint16(x86_xArgXmm1),
+ /*6906*/ uint16(x86_xArgXmm2M128),
+ /*6907*/ uint16(x86_xArgImm8u),
+ /*6908*/ uint16(x86_xMatch),
+ /*6909*/ uint16(x86_xSetOp), uint16(x86_CMPSD_XMM),
+ /*6911*/ uint16(x86_xReadSlashR),
+ /*6912*/ uint16(x86_xReadIb),
+ /*6913*/ uint16(x86_xArgXmm1),
+ /*6914*/ uint16(x86_xArgXmm2M64),
+ /*6915*/ uint16(x86_xArgImm8u),
+ /*6916*/ uint16(x86_xMatch),
+ /*6917*/ uint16(x86_xSetOp), uint16(x86_CMPSS),
+ /*6919*/ uint16(x86_xReadSlashR),
+ /*6920*/ uint16(x86_xReadIb),
+ /*6921*/ uint16(x86_xArgXmm1),
+ /*6922*/ uint16(x86_xArgXmm2M32),
+ /*6923*/ uint16(x86_xArgImm8u),
+ /*6924*/ uint16(x86_xMatch),
+ /*6925*/ uint16(x86_xCondIs64), 6928, 6944,
+ /*6928*/ uint16(x86_xCondDataSize), 6932, 6938, 0,
+ /*6932*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+ /*6934*/ uint16(x86_xReadSlashR),
+ /*6935*/ uint16(x86_xArgM32),
+ /*6936*/ uint16(x86_xArgR32),
+ /*6937*/ uint16(x86_xMatch),
+ /*6938*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+ /*6940*/ uint16(x86_xReadSlashR),
+ /*6941*/ uint16(x86_xArgM32),
+ /*6942*/ uint16(x86_xArgR32),
+ /*6943*/ uint16(x86_xMatch),
+ /*6944*/ uint16(x86_xCondDataSize), 6932, 6938, 6948,
+ /*6948*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+ /*6950*/ uint16(x86_xReadSlashR),
+ /*6951*/ uint16(x86_xArgM64),
+ /*6952*/ uint16(x86_xArgR64),
+ /*6953*/ uint16(x86_xMatch),
+ /*6954*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 6968,
+ 0x0, 6960,
+ /*6960*/ uint16(x86_xSetOp), uint16(x86_PINSRW),
+ /*6962*/ uint16(x86_xReadSlashR),
+ /*6963*/ uint16(x86_xReadIb),
+ /*6964*/ uint16(x86_xArgMm),
+ /*6965*/ uint16(x86_xArgR32M16),
+ /*6966*/ uint16(x86_xArgImm8u),
+ /*6967*/ uint16(x86_xMatch),
+ /*6968*/ uint16(x86_xSetOp), uint16(x86_PINSRW),
+ /*6970*/ uint16(x86_xReadSlashR),
+ /*6971*/ uint16(x86_xReadIb),
+ /*6972*/ uint16(x86_xArgXmm),
+ /*6973*/ uint16(x86_xArgR32M16),
+ /*6974*/ uint16(x86_xArgImm8u),
+ /*6975*/ uint16(x86_xMatch),
+ /*6976*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 6990,
+ 0x0, 6982,
+ /*6982*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+ /*6984*/ uint16(x86_xReadSlashR),
+ /*6985*/ uint16(x86_xReadIb),
+ /*6986*/ uint16(x86_xArgR32),
+ /*6987*/ uint16(x86_xArgMm2),
+ /*6988*/ uint16(x86_xArgImm8u),
+ /*6989*/ uint16(x86_xMatch),
+ /*6990*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+ /*6992*/ uint16(x86_xReadSlashR),
+ /*6993*/ uint16(x86_xReadIb),
+ /*6994*/ uint16(x86_xArgR32),
+ /*6995*/ uint16(x86_xArgXmm2),
+ /*6996*/ uint16(x86_xArgImm8u),
+ /*6997*/ uint16(x86_xMatch),
+ /*6998*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7012,
+ 0x0, 7004,
+ /*7004*/ uint16(x86_xSetOp), uint16(x86_SHUFPS),
+ /*7006*/ uint16(x86_xReadSlashR),
+ /*7007*/ uint16(x86_xReadIb),
+ /*7008*/ uint16(x86_xArgXmm1),
+ /*7009*/ uint16(x86_xArgXmm2M128),
+ /*7010*/ uint16(x86_xArgImm8u),
+ /*7011*/ uint16(x86_xMatch),
+ /*7012*/ uint16(x86_xSetOp), uint16(x86_SHUFPD),
+ /*7014*/ uint16(x86_xReadSlashR),
+ /*7015*/ uint16(x86_xReadIb),
+ /*7016*/ uint16(x86_xArgXmm1),
+ /*7017*/ uint16(x86_xArgXmm2M128),
+ /*7018*/ uint16(x86_xArgImm8u),
+ /*7019*/ uint16(x86_xMatch),
+ /*7020*/ uint16(x86_xCondSlashR),
+ 0, // 0
+ 7029, // 1
+ 0, // 2
+ 7052, // 3
+ 7075, // 4
+ 7098, // 5
+ 7121, // 6
+ 0, // 7
+ /*7029*/ uint16(x86_xCondIs64), 7032, 7044,
+ /*7032*/ uint16(x86_xCondDataSize), 7036, 7040, 0,
+ /*7036*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG8B),
+ /*7038*/ uint16(x86_xArgM64),
+ /*7039*/ uint16(x86_xMatch),
+ /*7040*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG8B),
+ /*7042*/ uint16(x86_xArgM64),
+ /*7043*/ uint16(x86_xMatch),
+ /*7044*/ uint16(x86_xCondDataSize), 7036, 7040, 7048,
+ /*7048*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG16B),
+ /*7050*/ uint16(x86_xArgM128),
+ /*7051*/ uint16(x86_xMatch),
+ /*7052*/ uint16(x86_xCondIs64), 7055, 7067,
+ /*7055*/ uint16(x86_xCondDataSize), 7059, 7063, 0,
+ /*7059*/ uint16(x86_xSetOp), uint16(x86_XRSTORS),
+ /*7061*/ uint16(x86_xArgMem),
+ /*7062*/ uint16(x86_xMatch),
+ /*7063*/ uint16(x86_xSetOp), uint16(x86_XRSTORS),
+ /*7065*/ uint16(x86_xArgMem),
+ /*7066*/ uint16(x86_xMatch),
+ /*7067*/ uint16(x86_xCondDataSize), 7059, 7063, 7071,
+ /*7071*/ uint16(x86_xSetOp), uint16(x86_XRSTORS64),
+ /*7073*/ uint16(x86_xArgMem),
+ /*7074*/ uint16(x86_xMatch),
+ /*7075*/ uint16(x86_xCondIs64), 7078, 7090,
+ /*7078*/ uint16(x86_xCondDataSize), 7082, 7086, 0,
+ /*7082*/ uint16(x86_xSetOp), uint16(x86_XSAVEC),
+ /*7084*/ uint16(x86_xArgMem),
+ /*7085*/ uint16(x86_xMatch),
+ /*7086*/ uint16(x86_xSetOp), uint16(x86_XSAVEC),
+ /*7088*/ uint16(x86_xArgMem),
+ /*7089*/ uint16(x86_xMatch),
+ /*7090*/ uint16(x86_xCondDataSize), 7082, 7086, 7094,
+ /*7094*/ uint16(x86_xSetOp), uint16(x86_XSAVEC64),
+ /*7096*/ uint16(x86_xArgMem),
+ /*7097*/ uint16(x86_xMatch),
+ /*7098*/ uint16(x86_xCondIs64), 7101, 7113,
+ /*7101*/ uint16(x86_xCondDataSize), 7105, 7109, 0,
+ /*7105*/ uint16(x86_xSetOp), uint16(x86_XSAVES),
+ /*7107*/ uint16(x86_xArgMem),
+ /*7108*/ uint16(x86_xMatch),
+ /*7109*/ uint16(x86_xSetOp), uint16(x86_XSAVES),
+ /*7111*/ uint16(x86_xArgMem),
+ /*7112*/ uint16(x86_xMatch),
+ /*7113*/ uint16(x86_xCondDataSize), 7105, 7109, 7117,
+ /*7117*/ uint16(x86_xSetOp), uint16(x86_XSAVES64),
+ /*7119*/ uint16(x86_xArgMem),
+ /*7120*/ uint16(x86_xMatch),
+ /*7121*/ uint16(x86_xCondIs64), 7124, 7142,
+ /*7124*/ uint16(x86_xCondDataSize), 7128, 7135, 0,
+ /*7128*/ uint16(x86_xCondIsMem), 7131, 0,
+ /*7131*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+ /*7133*/ uint16(x86_xArgRmf16),
+ /*7134*/ uint16(x86_xMatch),
+ /*7135*/ uint16(x86_xCondIsMem), 7138, 0,
+ /*7138*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+ /*7140*/ uint16(x86_xArgRmf32),
+ /*7141*/ uint16(x86_xMatch),
+ /*7142*/ uint16(x86_xCondDataSize), 7128, 7135, 7146,
+ /*7146*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+ /*7148*/ uint16(x86_xMatch),
+ /*7149*/ uint16(x86_xCondIs64), 7152, 7164,
+ /*7152*/ uint16(x86_xCondDataSize), 7156, 7160, 0,
+ /*7156*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+ /*7158*/ uint16(x86_xArgR16op),
+ /*7159*/ uint16(x86_xMatch),
+ /*7160*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+ /*7162*/ uint16(x86_xArgR32op),
+ /*7163*/ uint16(x86_xMatch),
+ /*7164*/ uint16(x86_xCondDataSize), 7156, 7160, 7168,
+ /*7168*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+ /*7170*/ uint16(x86_xArgR64op),
+ /*7171*/ uint16(x86_xMatch),
+ /*7172*/ uint16(x86_xCondPrefix), 2,
+ 0xF2, 7184,
+ 0x66, 7178,
+ /*7178*/ uint16(x86_xSetOp), uint16(x86_ADDSUBPD),
+ /*7180*/ uint16(x86_xReadSlashR),
+ /*7181*/ uint16(x86_xArgXmm1),
+ /*7182*/ uint16(x86_xArgXmm2M128),
+ /*7183*/ uint16(x86_xMatch),
+ /*7184*/ uint16(x86_xSetOp), uint16(x86_ADDSUBPS),
+ /*7186*/ uint16(x86_xReadSlashR),
+ /*7187*/ uint16(x86_xArgXmm1),
+ /*7188*/ uint16(x86_xArgXmm2M128),
+ /*7189*/ uint16(x86_xMatch),
+ /*7190*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7202,
+ 0x0, 7196,
+ /*7196*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+ /*7198*/ uint16(x86_xReadSlashR),
+ /*7199*/ uint16(x86_xArgMm),
+ /*7200*/ uint16(x86_xArgMmM64),
+ /*7201*/ uint16(x86_xMatch),
+ /*7202*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+ /*7204*/ uint16(x86_xReadSlashR),
+ /*7205*/ uint16(x86_xArgXmm1),
+ /*7206*/ uint16(x86_xArgXmm2M128),
+ /*7207*/ uint16(x86_xMatch),
+ /*7208*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7220,
+ 0x0, 7214,
+ /*7214*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+ /*7216*/ uint16(x86_xReadSlashR),
+ /*7217*/ uint16(x86_xArgMm),
+ /*7218*/ uint16(x86_xArgMmM64),
+ /*7219*/ uint16(x86_xMatch),
+ /*7220*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+ /*7222*/ uint16(x86_xReadSlashR),
+ /*7223*/ uint16(x86_xArgXmm1),
+ /*7224*/ uint16(x86_xArgXmm2M128),
+ /*7225*/ uint16(x86_xMatch),
+ /*7226*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7238,
+ 0x0, 7232,
+ /*7232*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+ /*7234*/ uint16(x86_xReadSlashR),
+ /*7235*/ uint16(x86_xArgMm),
+ /*7236*/ uint16(x86_xArgMmM64),
+ /*7237*/ uint16(x86_xMatch),
+ /*7238*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+ /*7240*/ uint16(x86_xReadSlashR),
+ /*7241*/ uint16(x86_xArgXmm1),
+ /*7242*/ uint16(x86_xArgXmm2M128),
+ /*7243*/ uint16(x86_xMatch),
+ /*7244*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7256,
+ 0x0, 7250,
+ /*7250*/ uint16(x86_xSetOp), uint16(x86_PADDQ),
+ /*7252*/ uint16(x86_xReadSlashR),
+ /*7253*/ uint16(x86_xArgMm1),
+ /*7254*/ uint16(x86_xArgMm2M64),
+ /*7255*/ uint16(x86_xMatch),
+ /*7256*/ uint16(x86_xSetOp), uint16(x86_PADDQ),
+ /*7258*/ uint16(x86_xReadSlashR),
+ /*7259*/ uint16(x86_xArgXmm1),
+ /*7260*/ uint16(x86_xArgXmm2M128),
+ /*7261*/ uint16(x86_xMatch),
+ /*7262*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7274,
+ 0x0, 7268,
+ /*7268*/ uint16(x86_xSetOp), uint16(x86_PMULLW),
+ /*7270*/ uint16(x86_xReadSlashR),
+ /*7271*/ uint16(x86_xArgMm),
+ /*7272*/ uint16(x86_xArgMmM64),
+ /*7273*/ uint16(x86_xMatch),
+ /*7274*/ uint16(x86_xSetOp), uint16(x86_PMULLW),
+ /*7276*/ uint16(x86_xReadSlashR),
+ /*7277*/ uint16(x86_xArgXmm1),
+ /*7278*/ uint16(x86_xArgXmm2M128),
+ /*7279*/ uint16(x86_xMatch),
+ /*7280*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 7300,
+ 0xF2, 7294,
+ 0x66, 7288,
+ /*7288*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+ /*7290*/ uint16(x86_xReadSlashR),
+ /*7291*/ uint16(x86_xArgXmm2M64),
+ /*7292*/ uint16(x86_xArgXmm1),
+ /*7293*/ uint16(x86_xMatch),
+ /*7294*/ uint16(x86_xSetOp), uint16(x86_MOVDQ2Q),
+ /*7296*/ uint16(x86_xReadSlashR),
+ /*7297*/ uint16(x86_xArgMm),
+ /*7298*/ uint16(x86_xArgXmm2),
+ /*7299*/ uint16(x86_xMatch),
+ /*7300*/ uint16(x86_xSetOp), uint16(x86_MOVQ2DQ),
+ /*7302*/ uint16(x86_xReadSlashR),
+ /*7303*/ uint16(x86_xArgXmm1),
+ /*7304*/ uint16(x86_xArgMm2),
+ /*7305*/ uint16(x86_xMatch),
+ /*7306*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7318,
+ 0x0, 7312,
+ /*7312*/ uint16(x86_xSetOp), uint16(x86_PMOVMSKB),
+ /*7314*/ uint16(x86_xReadSlashR),
+ /*7315*/ uint16(x86_xArgR32),
+ /*7316*/ uint16(x86_xArgMm2),
+ /*7317*/ uint16(x86_xMatch),
+ /*7318*/ uint16(x86_xSetOp), uint16(x86_PMOVMSKB),
+ /*7320*/ uint16(x86_xReadSlashR),
+ /*7321*/ uint16(x86_xArgR32),
+ /*7322*/ uint16(x86_xArgXmm2),
+ /*7323*/ uint16(x86_xMatch),
+ /*7324*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7336,
+ 0x0, 7330,
+ /*7330*/ uint16(x86_xSetOp), uint16(x86_PSUBUSB),
+ /*7332*/ uint16(x86_xReadSlashR),
+ /*7333*/ uint16(x86_xArgMm),
+ /*7334*/ uint16(x86_xArgMmM64),
+ /*7335*/ uint16(x86_xMatch),
+ /*7336*/ uint16(x86_xSetOp), uint16(x86_PSUBUSB),
+ /*7338*/ uint16(x86_xReadSlashR),
+ /*7339*/ uint16(x86_xArgXmm1),
+ /*7340*/ uint16(x86_xArgXmm2M128),
+ /*7341*/ uint16(x86_xMatch),
+ /*7342*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7354,
+ 0x0, 7348,
+ /*7348*/ uint16(x86_xSetOp), uint16(x86_PSUBUSW),
+ /*7350*/ uint16(x86_xReadSlashR),
+ /*7351*/ uint16(x86_xArgMm),
+ /*7352*/ uint16(x86_xArgMmM64),
+ /*7353*/ uint16(x86_xMatch),
+ /*7354*/ uint16(x86_xSetOp), uint16(x86_PSUBUSW),
+ /*7356*/ uint16(x86_xReadSlashR),
+ /*7357*/ uint16(x86_xArgXmm1),
+ /*7358*/ uint16(x86_xArgXmm2M128),
+ /*7359*/ uint16(x86_xMatch),
+ /*7360*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7372,
+ 0x0, 7366,
+ /*7366*/ uint16(x86_xSetOp), uint16(x86_PMINUB),
+ /*7368*/ uint16(x86_xReadSlashR),
+ /*7369*/ uint16(x86_xArgMm1),
+ /*7370*/ uint16(x86_xArgMm2M64),
+ /*7371*/ uint16(x86_xMatch),
+ /*7372*/ uint16(x86_xSetOp), uint16(x86_PMINUB),
+ /*7374*/ uint16(x86_xReadSlashR),
+ /*7375*/ uint16(x86_xArgXmm1),
+ /*7376*/ uint16(x86_xArgXmm2M128),
+ /*7377*/ uint16(x86_xMatch),
+ /*7378*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7390,
+ 0x0, 7384,
+ /*7384*/ uint16(x86_xSetOp), uint16(x86_PAND),
+ /*7386*/ uint16(x86_xReadSlashR),
+ /*7387*/ uint16(x86_xArgMm),
+ /*7388*/ uint16(x86_xArgMmM64),
+ /*7389*/ uint16(x86_xMatch),
+ /*7390*/ uint16(x86_xSetOp), uint16(x86_PAND),
+ /*7392*/ uint16(x86_xReadSlashR),
+ /*7393*/ uint16(x86_xArgXmm1),
+ /*7394*/ uint16(x86_xArgXmm2M128),
+ /*7395*/ uint16(x86_xMatch),
+ /*7396*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7408,
+ 0x0, 7402,
+ /*7402*/ uint16(x86_xSetOp), uint16(x86_PADDUSB),
+ /*7404*/ uint16(x86_xReadSlashR),
+ /*7405*/ uint16(x86_xArgMm),
+ /*7406*/ uint16(x86_xArgMmM64),
+ /*7407*/ uint16(x86_xMatch),
+ /*7408*/ uint16(x86_xSetOp), uint16(x86_PADDUSB),
+ /*7410*/ uint16(x86_xReadSlashR),
+ /*7411*/ uint16(x86_xArgXmm1),
+ /*7412*/ uint16(x86_xArgXmm2M128),
+ /*7413*/ uint16(x86_xMatch),
+ /*7414*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7426,
+ 0x0, 7420,
+ /*7420*/ uint16(x86_xSetOp), uint16(x86_PADDUSW),
+ /*7422*/ uint16(x86_xReadSlashR),
+ /*7423*/ uint16(x86_xArgMm),
+ /*7424*/ uint16(x86_xArgMmM64),
+ /*7425*/ uint16(x86_xMatch),
+ /*7426*/ uint16(x86_xSetOp), uint16(x86_PADDUSW),
+ /*7428*/ uint16(x86_xReadSlashR),
+ /*7429*/ uint16(x86_xArgXmm1),
+ /*7430*/ uint16(x86_xArgXmm2M128),
+ /*7431*/ uint16(x86_xMatch),
+ /*7432*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7444,
+ 0x0, 7438,
+ /*7438*/ uint16(x86_xSetOp), uint16(x86_PMAXUB),
+ /*7440*/ uint16(x86_xReadSlashR),
+ /*7441*/ uint16(x86_xArgMm1),
+ /*7442*/ uint16(x86_xArgMm2M64),
+ /*7443*/ uint16(x86_xMatch),
+ /*7444*/ uint16(x86_xSetOp), uint16(x86_PMAXUB),
+ /*7446*/ uint16(x86_xReadSlashR),
+ /*7447*/ uint16(x86_xArgXmm1),
+ /*7448*/ uint16(x86_xArgXmm2M128),
+ /*7449*/ uint16(x86_xMatch),
+ /*7450*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7462,
+ 0x0, 7456,
+ /*7456*/ uint16(x86_xSetOp), uint16(x86_PANDN),
+ /*7458*/ uint16(x86_xReadSlashR),
+ /*7459*/ uint16(x86_xArgMm),
+ /*7460*/ uint16(x86_xArgMmM64),
+ /*7461*/ uint16(x86_xMatch),
+ /*7462*/ uint16(x86_xSetOp), uint16(x86_PANDN),
+ /*7464*/ uint16(x86_xReadSlashR),
+ /*7465*/ uint16(x86_xArgXmm1),
+ /*7466*/ uint16(x86_xArgXmm2M128),
+ /*7467*/ uint16(x86_xMatch),
+ /*7468*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7480,
+ 0x0, 7474,
+ /*7474*/ uint16(x86_xSetOp), uint16(x86_PAVGB),
+ /*7476*/ uint16(x86_xReadSlashR),
+ /*7477*/ uint16(x86_xArgMm1),
+ /*7478*/ uint16(x86_xArgMm2M64),
+ /*7479*/ uint16(x86_xMatch),
+ /*7480*/ uint16(x86_xSetOp), uint16(x86_PAVGB),
+ /*7482*/ uint16(x86_xReadSlashR),
+ /*7483*/ uint16(x86_xArgXmm1),
+ /*7484*/ uint16(x86_xArgXmm2M128),
+ /*7485*/ uint16(x86_xMatch),
+ /*7486*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7498,
+ 0x0, 7492,
+ /*7492*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+ /*7494*/ uint16(x86_xReadSlashR),
+ /*7495*/ uint16(x86_xArgMm),
+ /*7496*/ uint16(x86_xArgMmM64),
+ /*7497*/ uint16(x86_xMatch),
+ /*7498*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+ /*7500*/ uint16(x86_xReadSlashR),
+ /*7501*/ uint16(x86_xArgXmm1),
+ /*7502*/ uint16(x86_xArgXmm2M128),
+ /*7503*/ uint16(x86_xMatch),
+ /*7504*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7516,
+ 0x0, 7510,
+ /*7510*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+ /*7512*/ uint16(x86_xReadSlashR),
+ /*7513*/ uint16(x86_xArgMm),
+ /*7514*/ uint16(x86_xArgMmM64),
+ /*7515*/ uint16(x86_xMatch),
+ /*7516*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+ /*7518*/ uint16(x86_xReadSlashR),
+ /*7519*/ uint16(x86_xArgXmm1),
+ /*7520*/ uint16(x86_xArgXmm2M128),
+ /*7521*/ uint16(x86_xMatch),
+ /*7522*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7534,
+ 0x0, 7528,
+ /*7528*/ uint16(x86_xSetOp), uint16(x86_PAVGW),
+ /*7530*/ uint16(x86_xReadSlashR),
+ /*7531*/ uint16(x86_xArgMm1),
+ /*7532*/ uint16(x86_xArgMm2M64),
+ /*7533*/ uint16(x86_xMatch),
+ /*7534*/ uint16(x86_xSetOp), uint16(x86_PAVGW),
+ /*7536*/ uint16(x86_xReadSlashR),
+ /*7537*/ uint16(x86_xArgXmm1),
+ /*7538*/ uint16(x86_xArgXmm2M128),
+ /*7539*/ uint16(x86_xMatch),
+ /*7540*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7552,
+ 0x0, 7546,
+ /*7546*/ uint16(x86_xSetOp), uint16(x86_PMULHUW),
+ /*7548*/ uint16(x86_xReadSlashR),
+ /*7549*/ uint16(x86_xArgMm1),
+ /*7550*/ uint16(x86_xArgMm2M64),
+ /*7551*/ uint16(x86_xMatch),
+ /*7552*/ uint16(x86_xSetOp), uint16(x86_PMULHUW),
+ /*7554*/ uint16(x86_xReadSlashR),
+ /*7555*/ uint16(x86_xArgXmm1),
+ /*7556*/ uint16(x86_xArgXmm2M128),
+ /*7557*/ uint16(x86_xMatch),
+ /*7558*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7570,
+ 0x0, 7564,
+ /*7564*/ uint16(x86_xSetOp), uint16(x86_PMULHW),
+ /*7566*/ uint16(x86_xReadSlashR),
+ /*7567*/ uint16(x86_xArgMm),
+ /*7568*/ uint16(x86_xArgMmM64),
+ /*7569*/ uint16(x86_xMatch),
+ /*7570*/ uint16(x86_xSetOp), uint16(x86_PMULHW),
+ /*7572*/ uint16(x86_xReadSlashR),
+ /*7573*/ uint16(x86_xArgXmm1),
+ /*7574*/ uint16(x86_xArgXmm2M128),
+ /*7575*/ uint16(x86_xMatch),
+ /*7576*/ uint16(x86_xCondPrefix), 3,
+ 0xF3, 7596,
+ 0xF2, 7590,
+ 0x66, 7584,
+ /*7584*/ uint16(x86_xSetOp), uint16(x86_CVTTPD2DQ),
+ /*7586*/ uint16(x86_xReadSlashR),
+ /*7587*/ uint16(x86_xArgXmm1),
+ /*7588*/ uint16(x86_xArgXmm2M128),
+ /*7589*/ uint16(x86_xMatch),
+ /*7590*/ uint16(x86_xSetOp), uint16(x86_CVTPD2DQ),
+ /*7592*/ uint16(x86_xReadSlashR),
+ /*7593*/ uint16(x86_xArgXmm1),
+ /*7594*/ uint16(x86_xArgXmm2M128),
+ /*7595*/ uint16(x86_xMatch),
+ /*7596*/ uint16(x86_xSetOp), uint16(x86_CVTDQ2PD),
+ /*7598*/ uint16(x86_xReadSlashR),
+ /*7599*/ uint16(x86_xArgXmm1),
+ /*7600*/ uint16(x86_xArgXmm2M64),
+ /*7601*/ uint16(x86_xMatch),
+ /*7602*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7614,
+ 0x0, 7608,
+ /*7608*/ uint16(x86_xSetOp), uint16(x86_MOVNTQ),
+ /*7610*/ uint16(x86_xReadSlashR),
+ /*7611*/ uint16(x86_xArgM64),
+ /*7612*/ uint16(x86_xArgMm),
+ /*7613*/ uint16(x86_xMatch),
+ /*7614*/ uint16(x86_xSetOp), uint16(x86_MOVNTDQ),
+ /*7616*/ uint16(x86_xReadSlashR),
+ /*7617*/ uint16(x86_xArgM128),
+ /*7618*/ uint16(x86_xArgXmm),
+ /*7619*/ uint16(x86_xMatch),
+ /*7620*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7632,
+ 0x0, 7626,
+ /*7626*/ uint16(x86_xSetOp), uint16(x86_PSUBSB),
+ /*7628*/ uint16(x86_xReadSlashR),
+ /*7629*/ uint16(x86_xArgMm),
+ /*7630*/ uint16(x86_xArgMmM64),
+ /*7631*/ uint16(x86_xMatch),
+ /*7632*/ uint16(x86_xSetOp), uint16(x86_PSUBSB),
+ /*7634*/ uint16(x86_xReadSlashR),
+ /*7635*/ uint16(x86_xArgXmm1),
+ /*7636*/ uint16(x86_xArgXmm2M128),
+ /*7637*/ uint16(x86_xMatch),
+ /*7638*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7650,
+ 0x0, 7644,
+ /*7644*/ uint16(x86_xSetOp), uint16(x86_PSUBSW),
+ /*7646*/ uint16(x86_xReadSlashR),
+ /*7647*/ uint16(x86_xArgMm),
+ /*7648*/ uint16(x86_xArgMmM64),
+ /*7649*/ uint16(x86_xMatch),
+ /*7650*/ uint16(x86_xSetOp), uint16(x86_PSUBSW),
+ /*7652*/ uint16(x86_xReadSlashR),
+ /*7653*/ uint16(x86_xArgXmm1),
+ /*7654*/ uint16(x86_xArgXmm2M128),
+ /*7655*/ uint16(x86_xMatch),
+ /*7656*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7668,
+ 0x0, 7662,
+ /*7662*/ uint16(x86_xSetOp), uint16(x86_PMINSW),
+ /*7664*/ uint16(x86_xReadSlashR),
+ /*7665*/ uint16(x86_xArgMm1),
+ /*7666*/ uint16(x86_xArgMm2M64),
+ /*7667*/ uint16(x86_xMatch),
+ /*7668*/ uint16(x86_xSetOp), uint16(x86_PMINSW),
+ /*7670*/ uint16(x86_xReadSlashR),
+ /*7671*/ uint16(x86_xArgXmm1),
+ /*7672*/ uint16(x86_xArgXmm2M128),
+ /*7673*/ uint16(x86_xMatch),
+ /*7674*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7686,
+ 0x0, 7680,
+ /*7680*/ uint16(x86_xSetOp), uint16(x86_POR),
+ /*7682*/ uint16(x86_xReadSlashR),
+ /*7683*/ uint16(x86_xArgMm),
+ /*7684*/ uint16(x86_xArgMmM64),
+ /*7685*/ uint16(x86_xMatch),
+ /*7686*/ uint16(x86_xSetOp), uint16(x86_POR),
+ /*7688*/ uint16(x86_xReadSlashR),
+ /*7689*/ uint16(x86_xArgXmm1),
+ /*7690*/ uint16(x86_xArgXmm2M128),
+ /*7691*/ uint16(x86_xMatch),
+ /*7692*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7704,
+ 0x0, 7698,
+ /*7698*/ uint16(x86_xSetOp), uint16(x86_PADDSB),
+ /*7700*/ uint16(x86_xReadSlashR),
+ /*7701*/ uint16(x86_xArgMm),
+ /*7702*/ uint16(x86_xArgMmM64),
+ /*7703*/ uint16(x86_xMatch),
+ /*7704*/ uint16(x86_xSetOp), uint16(x86_PADDSB),
+ /*7706*/ uint16(x86_xReadSlashR),
+ /*7707*/ uint16(x86_xArgXmm1),
+ /*7708*/ uint16(x86_xArgXmm2M128),
+ /*7709*/ uint16(x86_xMatch),
+ /*7710*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7722,
+ 0x0, 7716,
+ /*7716*/ uint16(x86_xSetOp), uint16(x86_PADDSW),
+ /*7718*/ uint16(x86_xReadSlashR),
+ /*7719*/ uint16(x86_xArgMm),
+ /*7720*/ uint16(x86_xArgMmM64),
+ /*7721*/ uint16(x86_xMatch),
+ /*7722*/ uint16(x86_xSetOp), uint16(x86_PADDSW),
+ /*7724*/ uint16(x86_xReadSlashR),
+ /*7725*/ uint16(x86_xArgXmm1),
+ /*7726*/ uint16(x86_xArgXmm2M128),
+ /*7727*/ uint16(x86_xMatch),
+ /*7728*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7740,
+ 0x0, 7734,
+ /*7734*/ uint16(x86_xSetOp), uint16(x86_PMAXSW),
+ /*7736*/ uint16(x86_xReadSlashR),
+ /*7737*/ uint16(x86_xArgMm1),
+ /*7738*/ uint16(x86_xArgMm2M64),
+ /*7739*/ uint16(x86_xMatch),
+ /*7740*/ uint16(x86_xSetOp), uint16(x86_PMAXSW),
+ /*7742*/ uint16(x86_xReadSlashR),
+ /*7743*/ uint16(x86_xArgXmm1),
+ /*7744*/ uint16(x86_xArgXmm2M128),
+ /*7745*/ uint16(x86_xMatch),
+ /*7746*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7758,
+ 0x0, 7752,
+ /*7752*/ uint16(x86_xSetOp), uint16(x86_PXOR),
+ /*7754*/ uint16(x86_xReadSlashR),
+ /*7755*/ uint16(x86_xArgMm),
+ /*7756*/ uint16(x86_xArgMmM64),
+ /*7757*/ uint16(x86_xMatch),
+ /*7758*/ uint16(x86_xSetOp), uint16(x86_PXOR),
+ /*7760*/ uint16(x86_xReadSlashR),
+ /*7761*/ uint16(x86_xArgXmm1),
+ /*7762*/ uint16(x86_xArgXmm2M128),
+ /*7763*/ uint16(x86_xMatch),
+ /*7764*/ uint16(x86_xCondPrefix), 1,
+ 0xF2, 7768,
+ /*7768*/ uint16(x86_xSetOp), uint16(x86_LDDQU),
+ /*7770*/ uint16(x86_xReadSlashR),
+ /*7771*/ uint16(x86_xArgXmm1),
+ /*7772*/ uint16(x86_xArgM128),
+ /*7773*/ uint16(x86_xMatch),
+ /*7774*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7786,
+ 0x0, 7780,
+ /*7780*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+ /*7782*/ uint16(x86_xReadSlashR),
+ /*7783*/ uint16(x86_xArgMm),
+ /*7784*/ uint16(x86_xArgMmM64),
+ /*7785*/ uint16(x86_xMatch),
+ /*7786*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+ /*7788*/ uint16(x86_xReadSlashR),
+ /*7789*/ uint16(x86_xArgXmm1),
+ /*7790*/ uint16(x86_xArgXmm2M128),
+ /*7791*/ uint16(x86_xMatch),
+ /*7792*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7804,
+ 0x0, 7798,
+ /*7798*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+ /*7800*/ uint16(x86_xReadSlashR),
+ /*7801*/ uint16(x86_xArgMm),
+ /*7802*/ uint16(x86_xArgMmM64),
+ /*7803*/ uint16(x86_xMatch),
+ /*7804*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+ /*7806*/ uint16(x86_xReadSlashR),
+ /*7807*/ uint16(x86_xArgXmm1),
+ /*7808*/ uint16(x86_xArgXmm2M128),
+ /*7809*/ uint16(x86_xMatch),
+ /*7810*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7822,
+ 0x0, 7816,
+ /*7816*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+ /*7818*/ uint16(x86_xReadSlashR),
+ /*7819*/ uint16(x86_xArgMm),
+ /*7820*/ uint16(x86_xArgMmM64),
+ /*7821*/ uint16(x86_xMatch),
+ /*7822*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+ /*7824*/ uint16(x86_xReadSlashR),
+ /*7825*/ uint16(x86_xArgXmm1),
+ /*7826*/ uint16(x86_xArgXmm2M128),
+ /*7827*/ uint16(x86_xMatch),
+ /*7828*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7840,
+ 0x0, 7834,
+ /*7834*/ uint16(x86_xSetOp), uint16(x86_PMULUDQ),
+ /*7836*/ uint16(x86_xReadSlashR),
+ /*7837*/ uint16(x86_xArgMm1),
+ /*7838*/ uint16(x86_xArgMm2M64),
+ /*7839*/ uint16(x86_xMatch),
+ /*7840*/ uint16(x86_xSetOp), uint16(x86_PMULUDQ),
+ /*7842*/ uint16(x86_xReadSlashR),
+ /*7843*/ uint16(x86_xArgXmm1),
+ /*7844*/ uint16(x86_xArgXmm2M128),
+ /*7845*/ uint16(x86_xMatch),
+ /*7846*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7858,
+ 0x0, 7852,
+ /*7852*/ uint16(x86_xSetOp), uint16(x86_PMADDWD),
+ /*7854*/ uint16(x86_xReadSlashR),
+ /*7855*/ uint16(x86_xArgMm),
+ /*7856*/ uint16(x86_xArgMmM64),
+ /*7857*/ uint16(x86_xMatch),
+ /*7858*/ uint16(x86_xSetOp), uint16(x86_PMADDWD),
+ /*7860*/ uint16(x86_xReadSlashR),
+ /*7861*/ uint16(x86_xArgXmm1),
+ /*7862*/ uint16(x86_xArgXmm2M128),
+ /*7863*/ uint16(x86_xMatch),
+ /*7864*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7876,
+ 0x0, 7870,
+ /*7870*/ uint16(x86_xSetOp), uint16(x86_PSADBW),
+ /*7872*/ uint16(x86_xReadSlashR),
+ /*7873*/ uint16(x86_xArgMm1),
+ /*7874*/ uint16(x86_xArgMm2M64),
+ /*7875*/ uint16(x86_xMatch),
+ /*7876*/ uint16(x86_xSetOp), uint16(x86_PSADBW),
+ /*7878*/ uint16(x86_xReadSlashR),
+ /*7879*/ uint16(x86_xArgXmm1),
+ /*7880*/ uint16(x86_xArgXmm2M128),
+ /*7881*/ uint16(x86_xMatch),
+ /*7882*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7894,
+ 0x0, 7888,
+ /*7888*/ uint16(x86_xSetOp), uint16(x86_MASKMOVQ),
+ /*7890*/ uint16(x86_xReadSlashR),
+ /*7891*/ uint16(x86_xArgMm1),
+ /*7892*/ uint16(x86_xArgMm2),
+ /*7893*/ uint16(x86_xMatch),
+ /*7894*/ uint16(x86_xSetOp), uint16(x86_MASKMOVDQU),
+ /*7896*/ uint16(x86_xReadSlashR),
+ /*7897*/ uint16(x86_xArgXmm1),
+ /*7898*/ uint16(x86_xArgXmm2),
+ /*7899*/ uint16(x86_xMatch),
+ /*7900*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7912,
+ 0x0, 7906,
+ /*7906*/ uint16(x86_xSetOp), uint16(x86_PSUBB),
+ /*7908*/ uint16(x86_xReadSlashR),
+ /*7909*/ uint16(x86_xArgMm),
+ /*7910*/ uint16(x86_xArgMmM64),
+ /*7911*/ uint16(x86_xMatch),
+ /*7912*/ uint16(x86_xSetOp), uint16(x86_PSUBB),
+ /*7914*/ uint16(x86_xReadSlashR),
+ /*7915*/ uint16(x86_xArgXmm1),
+ /*7916*/ uint16(x86_xArgXmm2M128),
+ /*7917*/ uint16(x86_xMatch),
+ /*7918*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7930,
+ 0x0, 7924,
+ /*7924*/ uint16(x86_xSetOp), uint16(x86_PSUBW),
+ /*7926*/ uint16(x86_xReadSlashR),
+ /*7927*/ uint16(x86_xArgMm),
+ /*7928*/ uint16(x86_xArgMmM64),
+ /*7929*/ uint16(x86_xMatch),
+ /*7930*/ uint16(x86_xSetOp), uint16(x86_PSUBW),
+ /*7932*/ uint16(x86_xReadSlashR),
+ /*7933*/ uint16(x86_xArgXmm1),
+ /*7934*/ uint16(x86_xArgXmm2M128),
+ /*7935*/ uint16(x86_xMatch),
+ /*7936*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7948,
+ 0x0, 7942,
+ /*7942*/ uint16(x86_xSetOp), uint16(x86_PSUBD),
+ /*7944*/ uint16(x86_xReadSlashR),
+ /*7945*/ uint16(x86_xArgMm),
+ /*7946*/ uint16(x86_xArgMmM64),
+ /*7947*/ uint16(x86_xMatch),
+ /*7948*/ uint16(x86_xSetOp), uint16(x86_PSUBD),
+ /*7950*/ uint16(x86_xReadSlashR),
+ /*7951*/ uint16(x86_xArgXmm1),
+ /*7952*/ uint16(x86_xArgXmm2M128),
+ /*7953*/ uint16(x86_xMatch),
+ /*7954*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7966,
+ 0x0, 7960,
+ /*7960*/ uint16(x86_xSetOp), uint16(x86_PSUBQ),
+ /*7962*/ uint16(x86_xReadSlashR),
+ /*7963*/ uint16(x86_xArgMm1),
+ /*7964*/ uint16(x86_xArgMm2M64),
+ /*7965*/ uint16(x86_xMatch),
+ /*7966*/ uint16(x86_xSetOp), uint16(x86_PSUBQ),
+ /*7968*/ uint16(x86_xReadSlashR),
+ /*7969*/ uint16(x86_xArgXmm1),
+ /*7970*/ uint16(x86_xArgXmm2M128),
+ /*7971*/ uint16(x86_xMatch),
+ /*7972*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 7984,
+ 0x0, 7978,
+ /*7978*/ uint16(x86_xSetOp), uint16(x86_PADDB),
+ /*7980*/ uint16(x86_xReadSlashR),
+ /*7981*/ uint16(x86_xArgMm),
+ /*7982*/ uint16(x86_xArgMmM64),
+ /*7983*/ uint16(x86_xMatch),
+ /*7984*/ uint16(x86_xSetOp), uint16(x86_PADDB),
+ /*7986*/ uint16(x86_xReadSlashR),
+ /*7987*/ uint16(x86_xArgXmm1),
+ /*7988*/ uint16(x86_xArgXmm2M128),
+ /*7989*/ uint16(x86_xMatch),
+ /*7990*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 8002,
+ 0x0, 7996,
+ /*7996*/ uint16(x86_xSetOp), uint16(x86_PADDW),
+ /*7998*/ uint16(x86_xReadSlashR),
+ /*7999*/ uint16(x86_xArgMm),
+ /*8000*/ uint16(x86_xArgMmM64),
+ /*8001*/ uint16(x86_xMatch),
+ /*8002*/ uint16(x86_xSetOp), uint16(x86_PADDW),
+ /*8004*/ uint16(x86_xReadSlashR),
+ /*8005*/ uint16(x86_xArgXmm1),
+ /*8006*/ uint16(x86_xArgXmm2M128),
+ /*8007*/ uint16(x86_xMatch),
+ /*8008*/ uint16(x86_xCondPrefix), 2,
+ 0x66, 8020,
+ 0x0, 8014,
+ /*8014*/ uint16(x86_xSetOp), uint16(x86_PADDD),
+ /*8016*/ uint16(x86_xReadSlashR),
+ /*8017*/ uint16(x86_xArgMm),
+ /*8018*/ uint16(x86_xArgMmM64),
+ /*8019*/ uint16(x86_xMatch),
+ /*8020*/ uint16(x86_xSetOp), uint16(x86_PADDD),
+ /*8022*/ uint16(x86_xReadSlashR),
+ /*8023*/ uint16(x86_xArgXmm1),
+ /*8024*/ uint16(x86_xArgXmm2M128),
+ /*8025*/ uint16(x86_xMatch),
+ /*8026*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8028*/ uint16(x86_xReadSlashR),
+ /*8029*/ uint16(x86_xArgRM8),
+ /*8030*/ uint16(x86_xArgR8),
+ /*8031*/ uint16(x86_xMatch),
+ /*8032*/ uint16(x86_xCondIs64), 8035, 8051,
+ /*8035*/ uint16(x86_xCondDataSize), 8039, 8045, 0,
+ /*8039*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8041*/ uint16(x86_xReadSlashR),
+ /*8042*/ uint16(x86_xArgRM16),
+ /*8043*/ uint16(x86_xArgR16),
+ /*8044*/ uint16(x86_xMatch),
+ /*8045*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8047*/ uint16(x86_xReadSlashR),
+ /*8048*/ uint16(x86_xArgRM32),
+ /*8049*/ uint16(x86_xArgR32),
+ /*8050*/ uint16(x86_xMatch),
+ /*8051*/ uint16(x86_xCondDataSize), 8039, 8045, 8055,
+ /*8055*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8057*/ uint16(x86_xReadSlashR),
+ /*8058*/ uint16(x86_xArgRM64),
+ /*8059*/ uint16(x86_xArgR64),
+ /*8060*/ uint16(x86_xMatch),
+ /*8061*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8063*/ uint16(x86_xReadSlashR),
+ /*8064*/ uint16(x86_xArgR8),
+ /*8065*/ uint16(x86_xArgRM8),
+ /*8066*/ uint16(x86_xMatch),
+ /*8067*/ uint16(x86_xCondIs64), 8070, 8086,
+ /*8070*/ uint16(x86_xCondDataSize), 8074, 8080, 0,
+ /*8074*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8076*/ uint16(x86_xReadSlashR),
+ /*8077*/ uint16(x86_xArgR16),
+ /*8078*/ uint16(x86_xArgRM16),
+ /*8079*/ uint16(x86_xMatch),
+ /*8080*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8082*/ uint16(x86_xReadSlashR),
+ /*8083*/ uint16(x86_xArgR32),
+ /*8084*/ uint16(x86_xArgRM32),
+ /*8085*/ uint16(x86_xMatch),
+ /*8086*/ uint16(x86_xCondDataSize), 8074, 8080, 8090,
+ /*8090*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8092*/ uint16(x86_xReadSlashR),
+ /*8093*/ uint16(x86_xArgR64),
+ /*8094*/ uint16(x86_xArgRM64),
+ /*8095*/ uint16(x86_xMatch),
+ /*8096*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8098*/ uint16(x86_xReadIb),
+ /*8099*/ uint16(x86_xArgAL),
+ /*8100*/ uint16(x86_xArgImm8u),
+ /*8101*/ uint16(x86_xMatch),
+ /*8102*/ uint16(x86_xCondIs64), 8105, 8121,
+ /*8105*/ uint16(x86_xCondDataSize), 8109, 8115, 0,
+ /*8109*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8111*/ uint16(x86_xReadIw),
+ /*8112*/ uint16(x86_xArgAX),
+ /*8113*/ uint16(x86_xArgImm16),
+ /*8114*/ uint16(x86_xMatch),
+ /*8115*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8117*/ uint16(x86_xReadId),
+ /*8118*/ uint16(x86_xArgEAX),
+ /*8119*/ uint16(x86_xArgImm32),
+ /*8120*/ uint16(x86_xMatch),
+ /*8121*/ uint16(x86_xCondDataSize), 8109, 8115, 8125,
+ /*8125*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*8127*/ uint16(x86_xReadId),
+ /*8128*/ uint16(x86_xArgRAX),
+ /*8129*/ uint16(x86_xArgImm32),
+ /*8130*/ uint16(x86_xMatch),
+ /*8131*/ uint16(x86_xCondIs64), 8134, 0,
+ /*8134*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8136*/ uint16(x86_xArgSS),
+ /*8137*/ uint16(x86_xMatch),
+ /*8138*/ uint16(x86_xCondIs64), 8141, 0,
+ /*8141*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8143*/ uint16(x86_xArgSS),
+ /*8144*/ uint16(x86_xMatch),
+ /*8145*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8147*/ uint16(x86_xReadSlashR),
+ /*8148*/ uint16(x86_xArgRM8),
+ /*8149*/ uint16(x86_xArgR8),
+ /*8150*/ uint16(x86_xMatch),
+ /*8151*/ uint16(x86_xCondIs64), 8154, 8170,
+ /*8154*/ uint16(x86_xCondDataSize), 8158, 8164, 0,
+ /*8158*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8160*/ uint16(x86_xReadSlashR),
+ /*8161*/ uint16(x86_xArgRM16),
+ /*8162*/ uint16(x86_xArgR16),
+ /*8163*/ uint16(x86_xMatch),
+ /*8164*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8166*/ uint16(x86_xReadSlashR),
+ /*8167*/ uint16(x86_xArgRM32),
+ /*8168*/ uint16(x86_xArgR32),
+ /*8169*/ uint16(x86_xMatch),
+ /*8170*/ uint16(x86_xCondDataSize), 8158, 8164, 8174,
+ /*8174*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8176*/ uint16(x86_xReadSlashR),
+ /*8177*/ uint16(x86_xArgRM64),
+ /*8178*/ uint16(x86_xArgR64),
+ /*8179*/ uint16(x86_xMatch),
+ /*8180*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8182*/ uint16(x86_xReadSlashR),
+ /*8183*/ uint16(x86_xArgR8),
+ /*8184*/ uint16(x86_xArgRM8),
+ /*8185*/ uint16(x86_xMatch),
+ /*8186*/ uint16(x86_xCondIs64), 8189, 8205,
+ /*8189*/ uint16(x86_xCondDataSize), 8193, 8199, 0,
+ /*8193*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8195*/ uint16(x86_xReadSlashR),
+ /*8196*/ uint16(x86_xArgR16),
+ /*8197*/ uint16(x86_xArgRM16),
+ /*8198*/ uint16(x86_xMatch),
+ /*8199*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8201*/ uint16(x86_xReadSlashR),
+ /*8202*/ uint16(x86_xArgR32),
+ /*8203*/ uint16(x86_xArgRM32),
+ /*8204*/ uint16(x86_xMatch),
+ /*8205*/ uint16(x86_xCondDataSize), 8193, 8199, 8209,
+ /*8209*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8211*/ uint16(x86_xReadSlashR),
+ /*8212*/ uint16(x86_xArgR64),
+ /*8213*/ uint16(x86_xArgRM64),
+ /*8214*/ uint16(x86_xMatch),
+ /*8215*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8217*/ uint16(x86_xReadIb),
+ /*8218*/ uint16(x86_xArgAL),
+ /*8219*/ uint16(x86_xArgImm8u),
+ /*8220*/ uint16(x86_xMatch),
+ /*8221*/ uint16(x86_xCondIs64), 8224, 8240,
+ /*8224*/ uint16(x86_xCondDataSize), 8228, 8234, 0,
+ /*8228*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8230*/ uint16(x86_xReadIw),
+ /*8231*/ uint16(x86_xArgAX),
+ /*8232*/ uint16(x86_xArgImm16),
+ /*8233*/ uint16(x86_xMatch),
+ /*8234*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8236*/ uint16(x86_xReadId),
+ /*8237*/ uint16(x86_xArgEAX),
+ /*8238*/ uint16(x86_xArgImm32),
+ /*8239*/ uint16(x86_xMatch),
+ /*8240*/ uint16(x86_xCondDataSize), 8228, 8234, 8244,
+ /*8244*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*8246*/ uint16(x86_xReadId),
+ /*8247*/ uint16(x86_xArgRAX),
+ /*8248*/ uint16(x86_xArgImm32),
+ /*8249*/ uint16(x86_xMatch),
+ /*8250*/ uint16(x86_xCondIs64), 8253, 0,
+ /*8253*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8255*/ uint16(x86_xArgDS),
+ /*8256*/ uint16(x86_xMatch),
+ /*8257*/ uint16(x86_xCondIs64), 8260, 0,
+ /*8260*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8262*/ uint16(x86_xArgDS),
+ /*8263*/ uint16(x86_xMatch),
+ /*8264*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8266*/ uint16(x86_xReadSlashR),
+ /*8267*/ uint16(x86_xArgRM8),
+ /*8268*/ uint16(x86_xArgR8),
+ /*8269*/ uint16(x86_xMatch),
+ /*8270*/ uint16(x86_xCondIs64), 8273, 8289,
+ /*8273*/ uint16(x86_xCondDataSize), 8277, 8283, 0,
+ /*8277*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8279*/ uint16(x86_xReadSlashR),
+ /*8280*/ uint16(x86_xArgRM16),
+ /*8281*/ uint16(x86_xArgR16),
+ /*8282*/ uint16(x86_xMatch),
+ /*8283*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8285*/ uint16(x86_xReadSlashR),
+ /*8286*/ uint16(x86_xArgRM32),
+ /*8287*/ uint16(x86_xArgR32),
+ /*8288*/ uint16(x86_xMatch),
+ /*8289*/ uint16(x86_xCondDataSize), 8277, 8283, 8293,
+ /*8293*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8295*/ uint16(x86_xReadSlashR),
+ /*8296*/ uint16(x86_xArgRM64),
+ /*8297*/ uint16(x86_xArgR64),
+ /*8298*/ uint16(x86_xMatch),
+ /*8299*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8301*/ uint16(x86_xReadSlashR),
+ /*8302*/ uint16(x86_xArgR8),
+ /*8303*/ uint16(x86_xArgRM8),
+ /*8304*/ uint16(x86_xMatch),
+ /*8305*/ uint16(x86_xCondIs64), 8308, 8324,
+ /*8308*/ uint16(x86_xCondDataSize), 8312, 8318, 0,
+ /*8312*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8314*/ uint16(x86_xReadSlashR),
+ /*8315*/ uint16(x86_xArgR16),
+ /*8316*/ uint16(x86_xArgRM16),
+ /*8317*/ uint16(x86_xMatch),
+ /*8318*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8320*/ uint16(x86_xReadSlashR),
+ /*8321*/ uint16(x86_xArgR32),
+ /*8322*/ uint16(x86_xArgRM32),
+ /*8323*/ uint16(x86_xMatch),
+ /*8324*/ uint16(x86_xCondDataSize), 8312, 8318, 8328,
+ /*8328*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8330*/ uint16(x86_xReadSlashR),
+ /*8331*/ uint16(x86_xArgR64),
+ /*8332*/ uint16(x86_xArgRM64),
+ /*8333*/ uint16(x86_xMatch),
+ /*8334*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8336*/ uint16(x86_xReadIb),
+ /*8337*/ uint16(x86_xArgAL),
+ /*8338*/ uint16(x86_xArgImm8u),
+ /*8339*/ uint16(x86_xMatch),
+ /*8340*/ uint16(x86_xCondIs64), 8343, 8359,
+ /*8343*/ uint16(x86_xCondDataSize), 8347, 8353, 0,
+ /*8347*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8349*/ uint16(x86_xReadIw),
+ /*8350*/ uint16(x86_xArgAX),
+ /*8351*/ uint16(x86_xArgImm16),
+ /*8352*/ uint16(x86_xMatch),
+ /*8353*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8355*/ uint16(x86_xReadId),
+ /*8356*/ uint16(x86_xArgEAX),
+ /*8357*/ uint16(x86_xArgImm32),
+ /*8358*/ uint16(x86_xMatch),
+ /*8359*/ uint16(x86_xCondDataSize), 8347, 8353, 8363,
+ /*8363*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*8365*/ uint16(x86_xReadId),
+ /*8366*/ uint16(x86_xArgRAX),
+ /*8367*/ uint16(x86_xArgImm32),
+ /*8368*/ uint16(x86_xMatch),
+ /*8369*/ uint16(x86_xCondIs64), 8372, 0,
+ /*8372*/ uint16(x86_xSetOp), uint16(x86_DAA),
+ /*8374*/ uint16(x86_xMatch),
+ /*8375*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8377*/ uint16(x86_xReadSlashR),
+ /*8378*/ uint16(x86_xArgRM8),
+ /*8379*/ uint16(x86_xArgR8),
+ /*8380*/ uint16(x86_xMatch),
+ /*8381*/ uint16(x86_xCondIs64), 8384, 8400,
+ /*8384*/ uint16(x86_xCondDataSize), 8388, 8394, 0,
+ /*8388*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8390*/ uint16(x86_xReadSlashR),
+ /*8391*/ uint16(x86_xArgRM16),
+ /*8392*/ uint16(x86_xArgR16),
+ /*8393*/ uint16(x86_xMatch),
+ /*8394*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8396*/ uint16(x86_xReadSlashR),
+ /*8397*/ uint16(x86_xArgRM32),
+ /*8398*/ uint16(x86_xArgR32),
+ /*8399*/ uint16(x86_xMatch),
+ /*8400*/ uint16(x86_xCondDataSize), 8388, 8394, 8404,
+ /*8404*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8406*/ uint16(x86_xReadSlashR),
+ /*8407*/ uint16(x86_xArgRM64),
+ /*8408*/ uint16(x86_xArgR64),
+ /*8409*/ uint16(x86_xMatch),
+ /*8410*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8412*/ uint16(x86_xReadSlashR),
+ /*8413*/ uint16(x86_xArgR8),
+ /*8414*/ uint16(x86_xArgRM8),
+ /*8415*/ uint16(x86_xMatch),
+ /*8416*/ uint16(x86_xCondIs64), 8419, 8435,
+ /*8419*/ uint16(x86_xCondDataSize), 8423, 8429, 0,
+ /*8423*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8425*/ uint16(x86_xReadSlashR),
+ /*8426*/ uint16(x86_xArgR16),
+ /*8427*/ uint16(x86_xArgRM16),
+ /*8428*/ uint16(x86_xMatch),
+ /*8429*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8431*/ uint16(x86_xReadSlashR),
+ /*8432*/ uint16(x86_xArgR32),
+ /*8433*/ uint16(x86_xArgRM32),
+ /*8434*/ uint16(x86_xMatch),
+ /*8435*/ uint16(x86_xCondDataSize), 8423, 8429, 8439,
+ /*8439*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8441*/ uint16(x86_xReadSlashR),
+ /*8442*/ uint16(x86_xArgR64),
+ /*8443*/ uint16(x86_xArgRM64),
+ /*8444*/ uint16(x86_xMatch),
+ /*8445*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8447*/ uint16(x86_xReadIb),
+ /*8448*/ uint16(x86_xArgAL),
+ /*8449*/ uint16(x86_xArgImm8u),
+ /*8450*/ uint16(x86_xMatch),
+ /*8451*/ uint16(x86_xCondIs64), 8454, 8470,
+ /*8454*/ uint16(x86_xCondDataSize), 8458, 8464, 0,
+ /*8458*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8460*/ uint16(x86_xReadIw),
+ /*8461*/ uint16(x86_xArgAX),
+ /*8462*/ uint16(x86_xArgImm16),
+ /*8463*/ uint16(x86_xMatch),
+ /*8464*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8466*/ uint16(x86_xReadId),
+ /*8467*/ uint16(x86_xArgEAX),
+ /*8468*/ uint16(x86_xArgImm32),
+ /*8469*/ uint16(x86_xMatch),
+ /*8470*/ uint16(x86_xCondDataSize), 8458, 8464, 8474,
+ /*8474*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*8476*/ uint16(x86_xReadId),
+ /*8477*/ uint16(x86_xArgRAX),
+ /*8478*/ uint16(x86_xArgImm32),
+ /*8479*/ uint16(x86_xMatch),
+ /*8480*/ uint16(x86_xCondIs64), 8483, 0,
+ /*8483*/ uint16(x86_xSetOp), uint16(x86_DAS),
+ /*8485*/ uint16(x86_xMatch),
+ /*8486*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8488*/ uint16(x86_xReadSlashR),
+ /*8489*/ uint16(x86_xArgRM8),
+ /*8490*/ uint16(x86_xArgR8),
+ /*8491*/ uint16(x86_xMatch),
+ /*8492*/ uint16(x86_xCondIs64), 8495, 8511,
+ /*8495*/ uint16(x86_xCondDataSize), 8499, 8505, 0,
+ /*8499*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8501*/ uint16(x86_xReadSlashR),
+ /*8502*/ uint16(x86_xArgRM16),
+ /*8503*/ uint16(x86_xArgR16),
+ /*8504*/ uint16(x86_xMatch),
+ /*8505*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8507*/ uint16(x86_xReadSlashR),
+ /*8508*/ uint16(x86_xArgRM32),
+ /*8509*/ uint16(x86_xArgR32),
+ /*8510*/ uint16(x86_xMatch),
+ /*8511*/ uint16(x86_xCondDataSize), 8499, 8505, 8515,
+ /*8515*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8517*/ uint16(x86_xReadSlashR),
+ /*8518*/ uint16(x86_xArgRM64),
+ /*8519*/ uint16(x86_xArgR64),
+ /*8520*/ uint16(x86_xMatch),
+ /*8521*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8523*/ uint16(x86_xReadSlashR),
+ /*8524*/ uint16(x86_xArgR8),
+ /*8525*/ uint16(x86_xArgRM8),
+ /*8526*/ uint16(x86_xMatch),
+ /*8527*/ uint16(x86_xCondIs64), 8530, 8546,
+ /*8530*/ uint16(x86_xCondDataSize), 8534, 8540, 0,
+ /*8534*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8536*/ uint16(x86_xReadSlashR),
+ /*8537*/ uint16(x86_xArgR16),
+ /*8538*/ uint16(x86_xArgRM16),
+ /*8539*/ uint16(x86_xMatch),
+ /*8540*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8542*/ uint16(x86_xReadSlashR),
+ /*8543*/ uint16(x86_xArgR32),
+ /*8544*/ uint16(x86_xArgRM32),
+ /*8545*/ uint16(x86_xMatch),
+ /*8546*/ uint16(x86_xCondDataSize), 8534, 8540, 8550,
+ /*8550*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8552*/ uint16(x86_xReadSlashR),
+ /*8553*/ uint16(x86_xArgR64),
+ /*8554*/ uint16(x86_xArgRM64),
+ /*8555*/ uint16(x86_xMatch),
+ /*8556*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8558*/ uint16(x86_xReadIb),
+ /*8559*/ uint16(x86_xArgAL),
+ /*8560*/ uint16(x86_xArgImm8u),
+ /*8561*/ uint16(x86_xMatch),
+ /*8562*/ uint16(x86_xCondIs64), 8565, 8581,
+ /*8565*/ uint16(x86_xCondDataSize), 8569, 8575, 0,
+ /*8569*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8571*/ uint16(x86_xReadIw),
+ /*8572*/ uint16(x86_xArgAX),
+ /*8573*/ uint16(x86_xArgImm16),
+ /*8574*/ uint16(x86_xMatch),
+ /*8575*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8577*/ uint16(x86_xReadId),
+ /*8578*/ uint16(x86_xArgEAX),
+ /*8579*/ uint16(x86_xArgImm32),
+ /*8580*/ uint16(x86_xMatch),
+ /*8581*/ uint16(x86_xCondDataSize), 8569, 8575, 8585,
+ /*8585*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*8587*/ uint16(x86_xReadId),
+ /*8588*/ uint16(x86_xArgRAX),
+ /*8589*/ uint16(x86_xArgImm32),
+ /*8590*/ uint16(x86_xMatch),
+ /*8591*/ uint16(x86_xCondIs64), 8594, 0,
+ /*8594*/ uint16(x86_xSetOp), uint16(x86_AAA),
+ /*8596*/ uint16(x86_xMatch),
+ /*8597*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8599*/ uint16(x86_xReadSlashR),
+ /*8600*/ uint16(x86_xArgRM8),
+ /*8601*/ uint16(x86_xArgR8),
+ /*8602*/ uint16(x86_xMatch),
+ /*8603*/ uint16(x86_xCondIs64), 8606, 8622,
+ /*8606*/ uint16(x86_xCondDataSize), 8610, 8616, 0,
+ /*8610*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8612*/ uint16(x86_xReadSlashR),
+ /*8613*/ uint16(x86_xArgRM16),
+ /*8614*/ uint16(x86_xArgR16),
+ /*8615*/ uint16(x86_xMatch),
+ /*8616*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8618*/ uint16(x86_xReadSlashR),
+ /*8619*/ uint16(x86_xArgRM32),
+ /*8620*/ uint16(x86_xArgR32),
+ /*8621*/ uint16(x86_xMatch),
+ /*8622*/ uint16(x86_xCondDataSize), 8610, 8616, 8626,
+ /*8626*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8628*/ uint16(x86_xReadSlashR),
+ /*8629*/ uint16(x86_xArgRM64),
+ /*8630*/ uint16(x86_xArgR64),
+ /*8631*/ uint16(x86_xMatch),
+ /*8632*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8634*/ uint16(x86_xReadSlashR),
+ /*8635*/ uint16(x86_xArgR8),
+ /*8636*/ uint16(x86_xArgRM8),
+ /*8637*/ uint16(x86_xMatch),
+ /*8638*/ uint16(x86_xCondIs64), 8641, 8657,
+ /*8641*/ uint16(x86_xCondDataSize), 8645, 8651, 0,
+ /*8645*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8647*/ uint16(x86_xReadSlashR),
+ /*8648*/ uint16(x86_xArgR16),
+ /*8649*/ uint16(x86_xArgRM16),
+ /*8650*/ uint16(x86_xMatch),
+ /*8651*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8653*/ uint16(x86_xReadSlashR),
+ /*8654*/ uint16(x86_xArgR32),
+ /*8655*/ uint16(x86_xArgRM32),
+ /*8656*/ uint16(x86_xMatch),
+ /*8657*/ uint16(x86_xCondDataSize), 8645, 8651, 8661,
+ /*8661*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8663*/ uint16(x86_xReadSlashR),
+ /*8664*/ uint16(x86_xArgR64),
+ /*8665*/ uint16(x86_xArgRM64),
+ /*8666*/ uint16(x86_xMatch),
+ /*8667*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8669*/ uint16(x86_xReadIb),
+ /*8670*/ uint16(x86_xArgAL),
+ /*8671*/ uint16(x86_xArgImm8u),
+ /*8672*/ uint16(x86_xMatch),
+ /*8673*/ uint16(x86_xCondIs64), 8676, 8692,
+ /*8676*/ uint16(x86_xCondDataSize), 8680, 8686, 0,
+ /*8680*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8682*/ uint16(x86_xReadIw),
+ /*8683*/ uint16(x86_xArgAX),
+ /*8684*/ uint16(x86_xArgImm16),
+ /*8685*/ uint16(x86_xMatch),
+ /*8686*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8688*/ uint16(x86_xReadId),
+ /*8689*/ uint16(x86_xArgEAX),
+ /*8690*/ uint16(x86_xArgImm32),
+ /*8691*/ uint16(x86_xMatch),
+ /*8692*/ uint16(x86_xCondDataSize), 8680, 8686, 8696,
+ /*8696*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*8698*/ uint16(x86_xReadId),
+ /*8699*/ uint16(x86_xArgRAX),
+ /*8700*/ uint16(x86_xArgImm32),
+ /*8701*/ uint16(x86_xMatch),
+ /*8702*/ uint16(x86_xCondIs64), 8705, 0,
+ /*8705*/ uint16(x86_xSetOp), uint16(x86_AAS),
+ /*8707*/ uint16(x86_xMatch),
+ /*8708*/ uint16(x86_xCondIs64), 8711, 0,
+ /*8711*/ uint16(x86_xCondDataSize), 8715, 8719, 0,
+ /*8715*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*8717*/ uint16(x86_xArgR16op),
+ /*8718*/ uint16(x86_xMatch),
+ /*8719*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*8721*/ uint16(x86_xArgR32op),
+ /*8722*/ uint16(x86_xMatch),
+ /*8723*/ uint16(x86_xCondIs64), 8726, 0,
+ /*8726*/ uint16(x86_xCondDataSize), 8730, 8734, 0,
+ /*8730*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*8732*/ uint16(x86_xArgR16op),
+ /*8733*/ uint16(x86_xMatch),
+ /*8734*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*8736*/ uint16(x86_xArgR32op),
+ /*8737*/ uint16(x86_xMatch),
+ /*8738*/ uint16(x86_xCondIs64), 8741, 8753,
+ /*8741*/ uint16(x86_xCondDataSize), 8745, 8749, 0,
+ /*8745*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8747*/ uint16(x86_xArgR16op),
+ /*8748*/ uint16(x86_xMatch),
+ /*8749*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8751*/ uint16(x86_xArgR32op),
+ /*8752*/ uint16(x86_xMatch),
+ /*8753*/ uint16(x86_xCondDataSize), 8745, 8757, 8761,
+ /*8757*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8759*/ uint16(x86_xArgR64op),
+ /*8760*/ uint16(x86_xMatch),
+ /*8761*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8763*/ uint16(x86_xArgR64op),
+ /*8764*/ uint16(x86_xMatch),
+ /*8765*/ uint16(x86_xCondIs64), 8768, 8780,
+ /*8768*/ uint16(x86_xCondDataSize), 8772, 8776, 0,
+ /*8772*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8774*/ uint16(x86_xArgR16op),
+ /*8775*/ uint16(x86_xMatch),
+ /*8776*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8778*/ uint16(x86_xArgR32op),
+ /*8779*/ uint16(x86_xMatch),
+ /*8780*/ uint16(x86_xCondDataSize), 8772, 8784, 8788,
+ /*8784*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8786*/ uint16(x86_xArgR64op),
+ /*8787*/ uint16(x86_xMatch),
+ /*8788*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*8790*/ uint16(x86_xArgR64op),
+ /*8791*/ uint16(x86_xMatch),
+ /*8792*/ uint16(x86_xCondIs64), 8795, 0,
+ /*8795*/ uint16(x86_xCondDataSize), 8799, 8802, 0,
+ /*8799*/ uint16(x86_xSetOp), uint16(x86_PUSHA),
+ /*8801*/ uint16(x86_xMatch),
+ /*8802*/ uint16(x86_xSetOp), uint16(x86_PUSHAD),
+ /*8804*/ uint16(x86_xMatch),
+ /*8805*/ uint16(x86_xCondIs64), 8808, 0,
+ /*8808*/ uint16(x86_xCondDataSize), 8812, 8815, 0,
+ /*8812*/ uint16(x86_xSetOp), uint16(x86_POPA),
+ /*8814*/ uint16(x86_xMatch),
+ /*8815*/ uint16(x86_xSetOp), uint16(x86_POPAD),
+ /*8817*/ uint16(x86_xMatch),
+ /*8818*/ uint16(x86_xCondIs64), 8821, 0,
+ /*8821*/ uint16(x86_xCondDataSize), 8825, 8831, 0,
+ /*8825*/ uint16(x86_xSetOp), uint16(x86_BOUND),
+ /*8827*/ uint16(x86_xReadSlashR),
+ /*8828*/ uint16(x86_xArgR16),
+ /*8829*/ uint16(x86_xArgM16and16),
+ /*8830*/ uint16(x86_xMatch),
+ /*8831*/ uint16(x86_xSetOp), uint16(x86_BOUND),
+ /*8833*/ uint16(x86_xReadSlashR),
+ /*8834*/ uint16(x86_xArgR32),
+ /*8835*/ uint16(x86_xArgM32and32),
+ /*8836*/ uint16(x86_xMatch),
+ /*8837*/ uint16(x86_xCondIs64), 8840, 8846,
+ /*8840*/ uint16(x86_xSetOp), uint16(x86_ARPL),
+ /*8842*/ uint16(x86_xReadSlashR),
+ /*8843*/ uint16(x86_xArgRM16),
+ /*8844*/ uint16(x86_xArgR16),
+ /*8845*/ uint16(x86_xMatch),
+ /*8846*/ uint16(x86_xCondDataSize), 8850, 8856, 8862,
+ /*8850*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+ /*8852*/ uint16(x86_xReadSlashR),
+ /*8853*/ uint16(x86_xArgR16),
+ /*8854*/ uint16(x86_xArgRM32),
+ /*8855*/ uint16(x86_xMatch),
+ /*8856*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+ /*8858*/ uint16(x86_xReadSlashR),
+ /*8859*/ uint16(x86_xArgR32),
+ /*8860*/ uint16(x86_xArgRM32),
+ /*8861*/ uint16(x86_xMatch),
+ /*8862*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+ /*8864*/ uint16(x86_xReadSlashR),
+ /*8865*/ uint16(x86_xArgR64),
+ /*8866*/ uint16(x86_xArgRM32),
+ /*8867*/ uint16(x86_xMatch),
+ /*8868*/ uint16(x86_xCondDataSize), 8872, 8877, 8882,
+ /*8872*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8874*/ uint16(x86_xReadIw),
+ /*8875*/ uint16(x86_xArgImm16),
+ /*8876*/ uint16(x86_xMatch),
+ /*8877*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8879*/ uint16(x86_xReadId),
+ /*8880*/ uint16(x86_xArgImm32),
+ /*8881*/ uint16(x86_xMatch),
+ /*8882*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8884*/ uint16(x86_xReadId),
+ /*8885*/ uint16(x86_xArgImm32),
+ /*8886*/ uint16(x86_xMatch),
+ /*8887*/ uint16(x86_xCondIs64), 8890, 8910,
+ /*8890*/ uint16(x86_xCondDataSize), 8894, 8902, 0,
+ /*8894*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8896*/ uint16(x86_xReadSlashR),
+ /*8897*/ uint16(x86_xReadIw),
+ /*8898*/ uint16(x86_xArgR16),
+ /*8899*/ uint16(x86_xArgRM16),
+ /*8900*/ uint16(x86_xArgImm16),
+ /*8901*/ uint16(x86_xMatch),
+ /*8902*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8904*/ uint16(x86_xReadSlashR),
+ /*8905*/ uint16(x86_xReadId),
+ /*8906*/ uint16(x86_xArgR32),
+ /*8907*/ uint16(x86_xArgRM32),
+ /*8908*/ uint16(x86_xArgImm32),
+ /*8909*/ uint16(x86_xMatch),
+ /*8910*/ uint16(x86_xCondDataSize), 8894, 8902, 8914,
+ /*8914*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8916*/ uint16(x86_xReadSlashR),
+ /*8917*/ uint16(x86_xReadId),
+ /*8918*/ uint16(x86_xArgR64),
+ /*8919*/ uint16(x86_xArgRM64),
+ /*8920*/ uint16(x86_xArgImm32),
+ /*8921*/ uint16(x86_xMatch),
+ /*8922*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*8924*/ uint16(x86_xReadIb),
+ /*8925*/ uint16(x86_xArgImm8),
+ /*8926*/ uint16(x86_xMatch),
+ /*8927*/ uint16(x86_xCondIs64), 8930, 8950,
+ /*8930*/ uint16(x86_xCondDataSize), 8934, 8942, 0,
+ /*8934*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8936*/ uint16(x86_xReadSlashR),
+ /*8937*/ uint16(x86_xReadIb),
+ /*8938*/ uint16(x86_xArgR16),
+ /*8939*/ uint16(x86_xArgRM16),
+ /*8940*/ uint16(x86_xArgImm8),
+ /*8941*/ uint16(x86_xMatch),
+ /*8942*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8944*/ uint16(x86_xReadSlashR),
+ /*8945*/ uint16(x86_xReadIb),
+ /*8946*/ uint16(x86_xArgR32),
+ /*8947*/ uint16(x86_xArgRM32),
+ /*8948*/ uint16(x86_xArgImm8),
+ /*8949*/ uint16(x86_xMatch),
+ /*8950*/ uint16(x86_xCondDataSize), 8934, 8942, 8954,
+ /*8954*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*8956*/ uint16(x86_xReadSlashR),
+ /*8957*/ uint16(x86_xReadIb),
+ /*8958*/ uint16(x86_xArgR64),
+ /*8959*/ uint16(x86_xArgRM64),
+ /*8960*/ uint16(x86_xArgImm8),
+ /*8961*/ uint16(x86_xMatch),
+ /*8962*/ uint16(x86_xSetOp), uint16(x86_INSB),
+ /*8964*/ uint16(x86_xMatch),
+ /*8965*/ uint16(x86_xCondDataSize), 8969, 8972, 8975,
+ /*8969*/ uint16(x86_xSetOp), uint16(x86_INSW),
+ /*8971*/ uint16(x86_xMatch),
+ /*8972*/ uint16(x86_xSetOp), uint16(x86_INSD),
+ /*8974*/ uint16(x86_xMatch),
+ /*8975*/ uint16(x86_xSetOp), uint16(x86_INSD),
+ /*8977*/ uint16(x86_xMatch),
+ /*8978*/ uint16(x86_xSetOp), uint16(x86_OUTSB),
+ /*8980*/ uint16(x86_xMatch),
+ /*8981*/ uint16(x86_xCondDataSize), 8985, 8988, 8991,
+ /*8985*/ uint16(x86_xSetOp), uint16(x86_OUTSW),
+ /*8987*/ uint16(x86_xMatch),
+ /*8988*/ uint16(x86_xSetOp), uint16(x86_OUTSD),
+ /*8990*/ uint16(x86_xMatch),
+ /*8991*/ uint16(x86_xSetOp), uint16(x86_OUTSD),
+ /*8993*/ uint16(x86_xMatch),
+ /*8994*/ uint16(x86_xSetOp), uint16(x86_JO),
+ /*8996*/ uint16(x86_xReadCb),
+ /*8997*/ uint16(x86_xArgRel8),
+ /*8998*/ uint16(x86_xMatch),
+ /*8999*/ uint16(x86_xSetOp), uint16(x86_JNO),
+ /*9001*/ uint16(x86_xReadCb),
+ /*9002*/ uint16(x86_xArgRel8),
+ /*9003*/ uint16(x86_xMatch),
+ /*9004*/ uint16(x86_xSetOp), uint16(x86_JB),
+ /*9006*/ uint16(x86_xReadCb),
+ /*9007*/ uint16(x86_xArgRel8),
+ /*9008*/ uint16(x86_xMatch),
+ /*9009*/ uint16(x86_xSetOp), uint16(x86_JAE),
+ /*9011*/ uint16(x86_xReadCb),
+ /*9012*/ uint16(x86_xArgRel8),
+ /*9013*/ uint16(x86_xMatch),
+ /*9014*/ uint16(x86_xSetOp), uint16(x86_JE),
+ /*9016*/ uint16(x86_xReadCb),
+ /*9017*/ uint16(x86_xArgRel8),
+ /*9018*/ uint16(x86_xMatch),
+ /*9019*/ uint16(x86_xSetOp), uint16(x86_JNE),
+ /*9021*/ uint16(x86_xReadCb),
+ /*9022*/ uint16(x86_xArgRel8),
+ /*9023*/ uint16(x86_xMatch),
+ /*9024*/ uint16(x86_xSetOp), uint16(x86_JBE),
+ /*9026*/ uint16(x86_xReadCb),
+ /*9027*/ uint16(x86_xArgRel8),
+ /*9028*/ uint16(x86_xMatch),
+ /*9029*/ uint16(x86_xSetOp), uint16(x86_JA),
+ /*9031*/ uint16(x86_xReadCb),
+ /*9032*/ uint16(x86_xArgRel8),
+ /*9033*/ uint16(x86_xMatch),
+ /*9034*/ uint16(x86_xSetOp), uint16(x86_JS),
+ /*9036*/ uint16(x86_xReadCb),
+ /*9037*/ uint16(x86_xArgRel8),
+ /*9038*/ uint16(x86_xMatch),
+ /*9039*/ uint16(x86_xSetOp), uint16(x86_JNS),
+ /*9041*/ uint16(x86_xReadCb),
+ /*9042*/ uint16(x86_xArgRel8),
+ /*9043*/ uint16(x86_xMatch),
+ /*9044*/ uint16(x86_xSetOp), uint16(x86_JP),
+ /*9046*/ uint16(x86_xReadCb),
+ /*9047*/ uint16(x86_xArgRel8),
+ /*9048*/ uint16(x86_xMatch),
+ /*9049*/ uint16(x86_xSetOp), uint16(x86_JNP),
+ /*9051*/ uint16(x86_xReadCb),
+ /*9052*/ uint16(x86_xArgRel8),
+ /*9053*/ uint16(x86_xMatch),
+ /*9054*/ uint16(x86_xSetOp), uint16(x86_JL),
+ /*9056*/ uint16(x86_xReadCb),
+ /*9057*/ uint16(x86_xArgRel8),
+ /*9058*/ uint16(x86_xMatch),
+ /*9059*/ uint16(x86_xSetOp), uint16(x86_JGE),
+ /*9061*/ uint16(x86_xReadCb),
+ /*9062*/ uint16(x86_xArgRel8),
+ /*9063*/ uint16(x86_xMatch),
+ /*9064*/ uint16(x86_xSetOp), uint16(x86_JLE),
+ /*9066*/ uint16(x86_xReadCb),
+ /*9067*/ uint16(x86_xArgRel8),
+ /*9068*/ uint16(x86_xMatch),
+ /*9069*/ uint16(x86_xSetOp), uint16(x86_JG),
+ /*9071*/ uint16(x86_xReadCb),
+ /*9072*/ uint16(x86_xArgRel8),
+ /*9073*/ uint16(x86_xMatch),
+ /*9074*/ uint16(x86_xCondSlashR),
+ 9083, // 0
+ 9089, // 1
+ 9095, // 2
+ 9101, // 3
+ 9107, // 4
+ 9113, // 5
+ 9119, // 6
+ 9125, // 7
+ /*9083*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9085*/ uint16(x86_xReadIb),
+ /*9086*/ uint16(x86_xArgRM8),
+ /*9087*/ uint16(x86_xArgImm8u),
+ /*9088*/ uint16(x86_xMatch),
+ /*9089*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9091*/ uint16(x86_xReadIb),
+ /*9092*/ uint16(x86_xArgRM8),
+ /*9093*/ uint16(x86_xArgImm8u),
+ /*9094*/ uint16(x86_xMatch),
+ /*9095*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9097*/ uint16(x86_xReadIb),
+ /*9098*/ uint16(x86_xArgRM8),
+ /*9099*/ uint16(x86_xArgImm8u),
+ /*9100*/ uint16(x86_xMatch),
+ /*9101*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9103*/ uint16(x86_xReadIb),
+ /*9104*/ uint16(x86_xArgRM8),
+ /*9105*/ uint16(x86_xArgImm8u),
+ /*9106*/ uint16(x86_xMatch),
+ /*9107*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9109*/ uint16(x86_xReadIb),
+ /*9110*/ uint16(x86_xArgRM8),
+ /*9111*/ uint16(x86_xArgImm8u),
+ /*9112*/ uint16(x86_xMatch),
+ /*9113*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9115*/ uint16(x86_xReadIb),
+ /*9116*/ uint16(x86_xArgRM8),
+ /*9117*/ uint16(x86_xArgImm8u),
+ /*9118*/ uint16(x86_xMatch),
+ /*9119*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9121*/ uint16(x86_xReadIb),
+ /*9122*/ uint16(x86_xArgRM8),
+ /*9123*/ uint16(x86_xArgImm8u),
+ /*9124*/ uint16(x86_xMatch),
+ /*9125*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9127*/ uint16(x86_xReadIb),
+ /*9128*/ uint16(x86_xArgRM8),
+ /*9129*/ uint16(x86_xArgImm8u),
+ /*9130*/ uint16(x86_xMatch),
+ /*9131*/ uint16(x86_xCondSlashR),
+ 9140, // 0
+ 9169, // 1
+ 9198, // 2
+ 9227, // 3
+ 9256, // 4
+ 9285, // 5
+ 9314, // 6
+ 9343, // 7
+ /*9140*/ uint16(x86_xCondIs64), 9143, 9159,
+ /*9143*/ uint16(x86_xCondDataSize), 9147, 9153, 0,
+ /*9147*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9149*/ uint16(x86_xReadIw),
+ /*9150*/ uint16(x86_xArgRM16),
+ /*9151*/ uint16(x86_xArgImm16),
+ /*9152*/ uint16(x86_xMatch),
+ /*9153*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9155*/ uint16(x86_xReadId),
+ /*9156*/ uint16(x86_xArgRM32),
+ /*9157*/ uint16(x86_xArgImm32),
+ /*9158*/ uint16(x86_xMatch),
+ /*9159*/ uint16(x86_xCondDataSize), 9147, 9153, 9163,
+ /*9163*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9165*/ uint16(x86_xReadId),
+ /*9166*/ uint16(x86_xArgRM64),
+ /*9167*/ uint16(x86_xArgImm32),
+ /*9168*/ uint16(x86_xMatch),
+ /*9169*/ uint16(x86_xCondIs64), 9172, 9188,
+ /*9172*/ uint16(x86_xCondDataSize), 9176, 9182, 0,
+ /*9176*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9178*/ uint16(x86_xReadIw),
+ /*9179*/ uint16(x86_xArgRM16),
+ /*9180*/ uint16(x86_xArgImm16),
+ /*9181*/ uint16(x86_xMatch),
+ /*9182*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9184*/ uint16(x86_xReadId),
+ /*9185*/ uint16(x86_xArgRM32),
+ /*9186*/ uint16(x86_xArgImm32),
+ /*9187*/ uint16(x86_xMatch),
+ /*9188*/ uint16(x86_xCondDataSize), 9176, 9182, 9192,
+ /*9192*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9194*/ uint16(x86_xReadId),
+ /*9195*/ uint16(x86_xArgRM64),
+ /*9196*/ uint16(x86_xArgImm32),
+ /*9197*/ uint16(x86_xMatch),
+ /*9198*/ uint16(x86_xCondIs64), 9201, 9217,
+ /*9201*/ uint16(x86_xCondDataSize), 9205, 9211, 0,
+ /*9205*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9207*/ uint16(x86_xReadIw),
+ /*9208*/ uint16(x86_xArgRM16),
+ /*9209*/ uint16(x86_xArgImm16),
+ /*9210*/ uint16(x86_xMatch),
+ /*9211*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9213*/ uint16(x86_xReadId),
+ /*9214*/ uint16(x86_xArgRM32),
+ /*9215*/ uint16(x86_xArgImm32),
+ /*9216*/ uint16(x86_xMatch),
+ /*9217*/ uint16(x86_xCondDataSize), 9205, 9211, 9221,
+ /*9221*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9223*/ uint16(x86_xReadId),
+ /*9224*/ uint16(x86_xArgRM64),
+ /*9225*/ uint16(x86_xArgImm32),
+ /*9226*/ uint16(x86_xMatch),
+ /*9227*/ uint16(x86_xCondIs64), 9230, 9246,
+ /*9230*/ uint16(x86_xCondDataSize), 9234, 9240, 0,
+ /*9234*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9236*/ uint16(x86_xReadIw),
+ /*9237*/ uint16(x86_xArgRM16),
+ /*9238*/ uint16(x86_xArgImm16),
+ /*9239*/ uint16(x86_xMatch),
+ /*9240*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9242*/ uint16(x86_xReadId),
+ /*9243*/ uint16(x86_xArgRM32),
+ /*9244*/ uint16(x86_xArgImm32),
+ /*9245*/ uint16(x86_xMatch),
+ /*9246*/ uint16(x86_xCondDataSize), 9234, 9240, 9250,
+ /*9250*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9252*/ uint16(x86_xReadId),
+ /*9253*/ uint16(x86_xArgRM64),
+ /*9254*/ uint16(x86_xArgImm32),
+ /*9255*/ uint16(x86_xMatch),
+ /*9256*/ uint16(x86_xCondIs64), 9259, 9275,
+ /*9259*/ uint16(x86_xCondDataSize), 9263, 9269, 0,
+ /*9263*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9265*/ uint16(x86_xReadIw),
+ /*9266*/ uint16(x86_xArgRM16),
+ /*9267*/ uint16(x86_xArgImm16),
+ /*9268*/ uint16(x86_xMatch),
+ /*9269*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9271*/ uint16(x86_xReadId),
+ /*9272*/ uint16(x86_xArgRM32),
+ /*9273*/ uint16(x86_xArgImm32),
+ /*9274*/ uint16(x86_xMatch),
+ /*9275*/ uint16(x86_xCondDataSize), 9263, 9269, 9279,
+ /*9279*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9281*/ uint16(x86_xReadId),
+ /*9282*/ uint16(x86_xArgRM64),
+ /*9283*/ uint16(x86_xArgImm32),
+ /*9284*/ uint16(x86_xMatch),
+ /*9285*/ uint16(x86_xCondIs64), 9288, 9304,
+ /*9288*/ uint16(x86_xCondDataSize), 9292, 9298, 0,
+ /*9292*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9294*/ uint16(x86_xReadIw),
+ /*9295*/ uint16(x86_xArgRM16),
+ /*9296*/ uint16(x86_xArgImm16),
+ /*9297*/ uint16(x86_xMatch),
+ /*9298*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9300*/ uint16(x86_xReadId),
+ /*9301*/ uint16(x86_xArgRM32),
+ /*9302*/ uint16(x86_xArgImm32),
+ /*9303*/ uint16(x86_xMatch),
+ /*9304*/ uint16(x86_xCondDataSize), 9292, 9298, 9308,
+ /*9308*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9310*/ uint16(x86_xReadId),
+ /*9311*/ uint16(x86_xArgRM64),
+ /*9312*/ uint16(x86_xArgImm32),
+ /*9313*/ uint16(x86_xMatch),
+ /*9314*/ uint16(x86_xCondIs64), 9317, 9333,
+ /*9317*/ uint16(x86_xCondDataSize), 9321, 9327, 0,
+ /*9321*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9323*/ uint16(x86_xReadIw),
+ /*9324*/ uint16(x86_xArgRM16),
+ /*9325*/ uint16(x86_xArgImm16),
+ /*9326*/ uint16(x86_xMatch),
+ /*9327*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9329*/ uint16(x86_xReadId),
+ /*9330*/ uint16(x86_xArgRM32),
+ /*9331*/ uint16(x86_xArgImm32),
+ /*9332*/ uint16(x86_xMatch),
+ /*9333*/ uint16(x86_xCondDataSize), 9321, 9327, 9337,
+ /*9337*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9339*/ uint16(x86_xReadId),
+ /*9340*/ uint16(x86_xArgRM64),
+ /*9341*/ uint16(x86_xArgImm32),
+ /*9342*/ uint16(x86_xMatch),
+ /*9343*/ uint16(x86_xCondIs64), 9346, 9362,
+ /*9346*/ uint16(x86_xCondDataSize), 9350, 9356, 0,
+ /*9350*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9352*/ uint16(x86_xReadIw),
+ /*9353*/ uint16(x86_xArgRM16),
+ /*9354*/ uint16(x86_xArgImm16),
+ /*9355*/ uint16(x86_xMatch),
+ /*9356*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9358*/ uint16(x86_xReadId),
+ /*9359*/ uint16(x86_xArgRM32),
+ /*9360*/ uint16(x86_xArgImm32),
+ /*9361*/ uint16(x86_xMatch),
+ /*9362*/ uint16(x86_xCondDataSize), 9350, 9356, 9366,
+ /*9366*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9368*/ uint16(x86_xReadId),
+ /*9369*/ uint16(x86_xArgRM64),
+ /*9370*/ uint16(x86_xArgImm32),
+ /*9371*/ uint16(x86_xMatch),
+ /*9372*/ uint16(x86_xCondSlashR),
+ 9381, // 0
+ 9410, // 1
+ 9439, // 2
+ 9468, // 3
+ 9497, // 4
+ 9526, // 5
+ 9555, // 6
+ 9584, // 7
+ /*9381*/ uint16(x86_xCondIs64), 9384, 9400,
+ /*9384*/ uint16(x86_xCondDataSize), 9388, 9394, 0,
+ /*9388*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9390*/ uint16(x86_xReadIb),
+ /*9391*/ uint16(x86_xArgRM16),
+ /*9392*/ uint16(x86_xArgImm8),
+ /*9393*/ uint16(x86_xMatch),
+ /*9394*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9396*/ uint16(x86_xReadIb),
+ /*9397*/ uint16(x86_xArgRM32),
+ /*9398*/ uint16(x86_xArgImm8),
+ /*9399*/ uint16(x86_xMatch),
+ /*9400*/ uint16(x86_xCondDataSize), 9388, 9394, 9404,
+ /*9404*/ uint16(x86_xSetOp), uint16(x86_ADD),
+ /*9406*/ uint16(x86_xReadIb),
+ /*9407*/ uint16(x86_xArgRM64),
+ /*9408*/ uint16(x86_xArgImm8),
+ /*9409*/ uint16(x86_xMatch),
+ /*9410*/ uint16(x86_xCondIs64), 9413, 9429,
+ /*9413*/ uint16(x86_xCondDataSize), 9417, 9423, 0,
+ /*9417*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9419*/ uint16(x86_xReadIb),
+ /*9420*/ uint16(x86_xArgRM16),
+ /*9421*/ uint16(x86_xArgImm8),
+ /*9422*/ uint16(x86_xMatch),
+ /*9423*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9425*/ uint16(x86_xReadIb),
+ /*9426*/ uint16(x86_xArgRM32),
+ /*9427*/ uint16(x86_xArgImm8),
+ /*9428*/ uint16(x86_xMatch),
+ /*9429*/ uint16(x86_xCondDataSize), 9417, 9423, 9433,
+ /*9433*/ uint16(x86_xSetOp), uint16(x86_OR),
+ /*9435*/ uint16(x86_xReadIb),
+ /*9436*/ uint16(x86_xArgRM64),
+ /*9437*/ uint16(x86_xArgImm8),
+ /*9438*/ uint16(x86_xMatch),
+ /*9439*/ uint16(x86_xCondIs64), 9442, 9458,
+ /*9442*/ uint16(x86_xCondDataSize), 9446, 9452, 0,
+ /*9446*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9448*/ uint16(x86_xReadIb),
+ /*9449*/ uint16(x86_xArgRM16),
+ /*9450*/ uint16(x86_xArgImm8),
+ /*9451*/ uint16(x86_xMatch),
+ /*9452*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9454*/ uint16(x86_xReadIb),
+ /*9455*/ uint16(x86_xArgRM32),
+ /*9456*/ uint16(x86_xArgImm8),
+ /*9457*/ uint16(x86_xMatch),
+ /*9458*/ uint16(x86_xCondDataSize), 9446, 9452, 9462,
+ /*9462*/ uint16(x86_xSetOp), uint16(x86_ADC),
+ /*9464*/ uint16(x86_xReadIb),
+ /*9465*/ uint16(x86_xArgRM64),
+ /*9466*/ uint16(x86_xArgImm8),
+ /*9467*/ uint16(x86_xMatch),
+ /*9468*/ uint16(x86_xCondIs64), 9471, 9487,
+ /*9471*/ uint16(x86_xCondDataSize), 9475, 9481, 0,
+ /*9475*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9477*/ uint16(x86_xReadIb),
+ /*9478*/ uint16(x86_xArgRM16),
+ /*9479*/ uint16(x86_xArgImm8),
+ /*9480*/ uint16(x86_xMatch),
+ /*9481*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9483*/ uint16(x86_xReadIb),
+ /*9484*/ uint16(x86_xArgRM32),
+ /*9485*/ uint16(x86_xArgImm8),
+ /*9486*/ uint16(x86_xMatch),
+ /*9487*/ uint16(x86_xCondDataSize), 9475, 9481, 9491,
+ /*9491*/ uint16(x86_xSetOp), uint16(x86_SBB),
+ /*9493*/ uint16(x86_xReadIb),
+ /*9494*/ uint16(x86_xArgRM64),
+ /*9495*/ uint16(x86_xArgImm8),
+ /*9496*/ uint16(x86_xMatch),
+ /*9497*/ uint16(x86_xCondIs64), 9500, 9516,
+ /*9500*/ uint16(x86_xCondDataSize), 9504, 9510, 0,
+ /*9504*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9506*/ uint16(x86_xReadIb),
+ /*9507*/ uint16(x86_xArgRM16),
+ /*9508*/ uint16(x86_xArgImm8),
+ /*9509*/ uint16(x86_xMatch),
+ /*9510*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9512*/ uint16(x86_xReadIb),
+ /*9513*/ uint16(x86_xArgRM32),
+ /*9514*/ uint16(x86_xArgImm8),
+ /*9515*/ uint16(x86_xMatch),
+ /*9516*/ uint16(x86_xCondDataSize), 9504, 9510, 9520,
+ /*9520*/ uint16(x86_xSetOp), uint16(x86_AND),
+ /*9522*/ uint16(x86_xReadIb),
+ /*9523*/ uint16(x86_xArgRM64),
+ /*9524*/ uint16(x86_xArgImm8),
+ /*9525*/ uint16(x86_xMatch),
+ /*9526*/ uint16(x86_xCondIs64), 9529, 9545,
+ /*9529*/ uint16(x86_xCondDataSize), 9533, 9539, 0,
+ /*9533*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9535*/ uint16(x86_xReadIb),
+ /*9536*/ uint16(x86_xArgRM16),
+ /*9537*/ uint16(x86_xArgImm8),
+ /*9538*/ uint16(x86_xMatch),
+ /*9539*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9541*/ uint16(x86_xReadIb),
+ /*9542*/ uint16(x86_xArgRM32),
+ /*9543*/ uint16(x86_xArgImm8),
+ /*9544*/ uint16(x86_xMatch),
+ /*9545*/ uint16(x86_xCondDataSize), 9533, 9539, 9549,
+ /*9549*/ uint16(x86_xSetOp), uint16(x86_SUB),
+ /*9551*/ uint16(x86_xReadIb),
+ /*9552*/ uint16(x86_xArgRM64),
+ /*9553*/ uint16(x86_xArgImm8),
+ /*9554*/ uint16(x86_xMatch),
+ /*9555*/ uint16(x86_xCondIs64), 9558, 9574,
+ /*9558*/ uint16(x86_xCondDataSize), 9562, 9568, 0,
+ /*9562*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9564*/ uint16(x86_xReadIb),
+ /*9565*/ uint16(x86_xArgRM16),
+ /*9566*/ uint16(x86_xArgImm8),
+ /*9567*/ uint16(x86_xMatch),
+ /*9568*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9570*/ uint16(x86_xReadIb),
+ /*9571*/ uint16(x86_xArgRM32),
+ /*9572*/ uint16(x86_xArgImm8),
+ /*9573*/ uint16(x86_xMatch),
+ /*9574*/ uint16(x86_xCondDataSize), 9562, 9568, 9578,
+ /*9578*/ uint16(x86_xSetOp), uint16(x86_XOR),
+ /*9580*/ uint16(x86_xReadIb),
+ /*9581*/ uint16(x86_xArgRM64),
+ /*9582*/ uint16(x86_xArgImm8),
+ /*9583*/ uint16(x86_xMatch),
+ /*9584*/ uint16(x86_xCondIs64), 9587, 9603,
+ /*9587*/ uint16(x86_xCondDataSize), 9591, 9597, 0,
+ /*9591*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9593*/ uint16(x86_xReadIb),
+ /*9594*/ uint16(x86_xArgRM16),
+ /*9595*/ uint16(x86_xArgImm8),
+ /*9596*/ uint16(x86_xMatch),
+ /*9597*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9599*/ uint16(x86_xReadIb),
+ /*9600*/ uint16(x86_xArgRM32),
+ /*9601*/ uint16(x86_xArgImm8),
+ /*9602*/ uint16(x86_xMatch),
+ /*9603*/ uint16(x86_xCondDataSize), 9591, 9597, 9607,
+ /*9607*/ uint16(x86_xSetOp), uint16(x86_CMP),
+ /*9609*/ uint16(x86_xReadIb),
+ /*9610*/ uint16(x86_xArgRM64),
+ /*9611*/ uint16(x86_xArgImm8),
+ /*9612*/ uint16(x86_xMatch),
+ /*9613*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*9615*/ uint16(x86_xReadSlashR),
+ /*9616*/ uint16(x86_xArgRM8),
+ /*9617*/ uint16(x86_xArgR8),
+ /*9618*/ uint16(x86_xMatch),
+ /*9619*/ uint16(x86_xCondIs64), 9622, 9638,
+ /*9622*/ uint16(x86_xCondDataSize), 9626, 9632, 0,
+ /*9626*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*9628*/ uint16(x86_xReadSlashR),
+ /*9629*/ uint16(x86_xArgRM16),
+ /*9630*/ uint16(x86_xArgR16),
+ /*9631*/ uint16(x86_xMatch),
+ /*9632*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*9634*/ uint16(x86_xReadSlashR),
+ /*9635*/ uint16(x86_xArgRM32),
+ /*9636*/ uint16(x86_xArgR32),
+ /*9637*/ uint16(x86_xMatch),
+ /*9638*/ uint16(x86_xCondDataSize), 9626, 9632, 9642,
+ /*9642*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*9644*/ uint16(x86_xReadSlashR),
+ /*9645*/ uint16(x86_xArgRM64),
+ /*9646*/ uint16(x86_xArgR64),
+ /*9647*/ uint16(x86_xMatch),
+ /*9648*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9650*/ uint16(x86_xReadSlashR),
+ /*9651*/ uint16(x86_xArgRM8),
+ /*9652*/ uint16(x86_xArgR8),
+ /*9653*/ uint16(x86_xMatch),
+ /*9654*/ uint16(x86_xCondIs64), 9657, 9673,
+ /*9657*/ uint16(x86_xCondDataSize), 9661, 9667, 0,
+ /*9661*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9663*/ uint16(x86_xReadSlashR),
+ /*9664*/ uint16(x86_xArgRM16),
+ /*9665*/ uint16(x86_xArgR16),
+ /*9666*/ uint16(x86_xMatch),
+ /*9667*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9669*/ uint16(x86_xReadSlashR),
+ /*9670*/ uint16(x86_xArgRM32),
+ /*9671*/ uint16(x86_xArgR32),
+ /*9672*/ uint16(x86_xMatch),
+ /*9673*/ uint16(x86_xCondDataSize), 9661, 9667, 9677,
+ /*9677*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9679*/ uint16(x86_xReadSlashR),
+ /*9680*/ uint16(x86_xArgRM64),
+ /*9681*/ uint16(x86_xArgR64),
+ /*9682*/ uint16(x86_xMatch),
+ /*9683*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9685*/ uint16(x86_xReadSlashR),
+ /*9686*/ uint16(x86_xArgRM8),
+ /*9687*/ uint16(x86_xArgR8),
+ /*9688*/ uint16(x86_xMatch),
+ /*9689*/ uint16(x86_xCondDataSize), 9693, 9699, 9705,
+ /*9693*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9695*/ uint16(x86_xReadSlashR),
+ /*9696*/ uint16(x86_xArgRM16),
+ /*9697*/ uint16(x86_xArgR16),
+ /*9698*/ uint16(x86_xMatch),
+ /*9699*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9701*/ uint16(x86_xReadSlashR),
+ /*9702*/ uint16(x86_xArgRM32),
+ /*9703*/ uint16(x86_xArgR32),
+ /*9704*/ uint16(x86_xMatch),
+ /*9705*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9707*/ uint16(x86_xReadSlashR),
+ /*9708*/ uint16(x86_xArgRM64),
+ /*9709*/ uint16(x86_xArgR64),
+ /*9710*/ uint16(x86_xMatch),
+ /*9711*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9713*/ uint16(x86_xReadSlashR),
+ /*9714*/ uint16(x86_xArgR8),
+ /*9715*/ uint16(x86_xArgRM8),
+ /*9716*/ uint16(x86_xMatch),
+ /*9717*/ uint16(x86_xCondDataSize), 9721, 9727, 9733,
+ /*9721*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9723*/ uint16(x86_xReadSlashR),
+ /*9724*/ uint16(x86_xArgR16),
+ /*9725*/ uint16(x86_xArgRM16),
+ /*9726*/ uint16(x86_xMatch),
+ /*9727*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9729*/ uint16(x86_xReadSlashR),
+ /*9730*/ uint16(x86_xArgR32),
+ /*9731*/ uint16(x86_xArgRM32),
+ /*9732*/ uint16(x86_xMatch),
+ /*9733*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9735*/ uint16(x86_xReadSlashR),
+ /*9736*/ uint16(x86_xArgR64),
+ /*9737*/ uint16(x86_xArgRM64),
+ /*9738*/ uint16(x86_xMatch),
+ /*9739*/ uint16(x86_xCondIs64), 9742, 9758,
+ /*9742*/ uint16(x86_xCondDataSize), 9746, 9752, 0,
+ /*9746*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9748*/ uint16(x86_xReadSlashR),
+ /*9749*/ uint16(x86_xArgRM16),
+ /*9750*/ uint16(x86_xArgSreg),
+ /*9751*/ uint16(x86_xMatch),
+ /*9752*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9754*/ uint16(x86_xReadSlashR),
+ /*9755*/ uint16(x86_xArgR32M16),
+ /*9756*/ uint16(x86_xArgSreg),
+ /*9757*/ uint16(x86_xMatch),
+ /*9758*/ uint16(x86_xCondDataSize), 9746, 9752, 9762,
+ /*9762*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9764*/ uint16(x86_xReadSlashR),
+ /*9765*/ uint16(x86_xArgR64M16),
+ /*9766*/ uint16(x86_xArgSreg),
+ /*9767*/ uint16(x86_xMatch),
+ /*9768*/ uint16(x86_xCondIs64), 9771, 9787,
+ /*9771*/ uint16(x86_xCondDataSize), 9775, 9781, 0,
+ /*9775*/ uint16(x86_xSetOp), uint16(x86_LEA),
+ /*9777*/ uint16(x86_xReadSlashR),
+ /*9778*/ uint16(x86_xArgR16),
+ /*9779*/ uint16(x86_xArgM),
+ /*9780*/ uint16(x86_xMatch),
+ /*9781*/ uint16(x86_xSetOp), uint16(x86_LEA),
+ /*9783*/ uint16(x86_xReadSlashR),
+ /*9784*/ uint16(x86_xArgR32),
+ /*9785*/ uint16(x86_xArgM),
+ /*9786*/ uint16(x86_xMatch),
+ /*9787*/ uint16(x86_xCondDataSize), 9775, 9781, 9791,
+ /*9791*/ uint16(x86_xSetOp), uint16(x86_LEA),
+ /*9793*/ uint16(x86_xReadSlashR),
+ /*9794*/ uint16(x86_xArgR64),
+ /*9795*/ uint16(x86_xArgM),
+ /*9796*/ uint16(x86_xMatch),
+ /*9797*/ uint16(x86_xCondIs64), 9800, 9816,
+ /*9800*/ uint16(x86_xCondDataSize), 9804, 9810, 0,
+ /*9804*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9806*/ uint16(x86_xReadSlashR),
+ /*9807*/ uint16(x86_xArgSreg),
+ /*9808*/ uint16(x86_xArgRM16),
+ /*9809*/ uint16(x86_xMatch),
+ /*9810*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9812*/ uint16(x86_xReadSlashR),
+ /*9813*/ uint16(x86_xArgSreg),
+ /*9814*/ uint16(x86_xArgR32M16),
+ /*9815*/ uint16(x86_xMatch),
+ /*9816*/ uint16(x86_xCondDataSize), 9804, 9810, 9820,
+ /*9820*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*9822*/ uint16(x86_xReadSlashR),
+ /*9823*/ uint16(x86_xArgSreg),
+ /*9824*/ uint16(x86_xArgR64M16),
+ /*9825*/ uint16(x86_xMatch),
+ /*9826*/ uint16(x86_xCondSlashR),
+ 9835, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*9835*/ uint16(x86_xCondIs64), 9838, 9850,
+ /*9838*/ uint16(x86_xCondDataSize), 9842, 9846, 0,
+ /*9842*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*9844*/ uint16(x86_xArgRM16),
+ /*9845*/ uint16(x86_xMatch),
+ /*9846*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*9848*/ uint16(x86_xArgRM32),
+ /*9849*/ uint16(x86_xMatch),
+ /*9850*/ uint16(x86_xCondDataSize), 9842, 9854, 9858,
+ /*9854*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*9856*/ uint16(x86_xArgRM64),
+ /*9857*/ uint16(x86_xMatch),
+ /*9858*/ uint16(x86_xSetOp), uint16(x86_POP),
+ /*9860*/ uint16(x86_xArgRM64),
+ /*9861*/ uint16(x86_xMatch),
+ /*9862*/ uint16(x86_xCondIs64), 9865, 9879,
+ /*9865*/ uint16(x86_xCondDataSize), 9869, 9874, 0,
+ /*9869*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9871*/ uint16(x86_xArgR16op),
+ /*9872*/ uint16(x86_xArgAX),
+ /*9873*/ uint16(x86_xMatch),
+ /*9874*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9876*/ uint16(x86_xArgR32op),
+ /*9877*/ uint16(x86_xArgEAX),
+ /*9878*/ uint16(x86_xMatch),
+ /*9879*/ uint16(x86_xCondDataSize), 9869, 9874, 9883,
+ /*9883*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+ /*9885*/ uint16(x86_xArgR64op),
+ /*9886*/ uint16(x86_xArgRAX),
+ /*9887*/ uint16(x86_xMatch),
+ /*9888*/ uint16(x86_xCondIs64), 9891, 9901,
+ /*9891*/ uint16(x86_xCondDataSize), 9895, 9898, 0,
+ /*9895*/ uint16(x86_xSetOp), uint16(x86_CBW),
+ /*9897*/ uint16(x86_xMatch),
+ /*9898*/ uint16(x86_xSetOp), uint16(x86_CWDE),
+ /*9900*/ uint16(x86_xMatch),
+ /*9901*/ uint16(x86_xCondDataSize), 9895, 9898, 9905,
+ /*9905*/ uint16(x86_xSetOp), uint16(x86_CDQE),
+ /*9907*/ uint16(x86_xMatch),
+ /*9908*/ uint16(x86_xCondIs64), 9911, 9921,
+ /*9911*/ uint16(x86_xCondDataSize), 9915, 9918, 0,
+ /*9915*/ uint16(x86_xSetOp), uint16(x86_CWD),
+ /*9917*/ uint16(x86_xMatch),
+ /*9918*/ uint16(x86_xSetOp), uint16(x86_CDQ),
+ /*9920*/ uint16(x86_xMatch),
+ /*9921*/ uint16(x86_xCondDataSize), 9915, 9918, 9925,
+ /*9925*/ uint16(x86_xSetOp), uint16(x86_CQO),
+ /*9927*/ uint16(x86_xMatch),
+ /*9928*/ uint16(x86_xCondIs64), 9931, 0,
+ /*9931*/ uint16(x86_xCondDataSize), 9935, 9940, 0,
+ /*9935*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+ /*9937*/ uint16(x86_xReadCd),
+ /*9938*/ uint16(x86_xArgPtr16colon16),
+ /*9939*/ uint16(x86_xMatch),
+ /*9940*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+ /*9942*/ uint16(x86_xReadCp),
+ /*9943*/ uint16(x86_xArgPtr16colon32),
+ /*9944*/ uint16(x86_xMatch),
+ /*9945*/ uint16(x86_xSetOp), uint16(x86_FWAIT),
+ /*9947*/ uint16(x86_xMatch),
+ /*9948*/ uint16(x86_xCondIs64), 9951, 9961,
+ /*9951*/ uint16(x86_xCondDataSize), 9955, 9958, 0,
+ /*9955*/ uint16(x86_xSetOp), uint16(x86_PUSHF),
+ /*9957*/ uint16(x86_xMatch),
+ /*9958*/ uint16(x86_xSetOp), uint16(x86_PUSHFD),
+ /*9960*/ uint16(x86_xMatch),
+ /*9961*/ uint16(x86_xCondDataSize), 9955, 9965, 9968,
+ /*9965*/ uint16(x86_xSetOp), uint16(x86_PUSHFQ),
+ /*9967*/ uint16(x86_xMatch),
+ /*9968*/ uint16(x86_xSetOp), uint16(x86_PUSHFQ),
+ /*9970*/ uint16(x86_xMatch),
+ /*9971*/ uint16(x86_xCondIs64), 9974, 9984,
+ /*9974*/ uint16(x86_xCondDataSize), 9978, 9981, 0,
+ /*9978*/ uint16(x86_xSetOp), uint16(x86_POPF),
+ /*9980*/ uint16(x86_xMatch),
+ /*9981*/ uint16(x86_xSetOp), uint16(x86_POPFD),
+ /*9983*/ uint16(x86_xMatch),
+ /*9984*/ uint16(x86_xCondDataSize), 9978, 9988, 9991,
+ /*9988*/ uint16(x86_xSetOp), uint16(x86_POPFQ),
+ /*9990*/ uint16(x86_xMatch),
+ /*9991*/ uint16(x86_xSetOp), uint16(x86_POPFQ),
+ /*9993*/ uint16(x86_xMatch),
+ /*9994*/ uint16(x86_xSetOp), uint16(x86_SAHF),
+ /*9996*/ uint16(x86_xMatch),
+ /*9997*/ uint16(x86_xSetOp), uint16(x86_LAHF),
+ /*9999*/ uint16(x86_xMatch),
+ /*10000*/ uint16(x86_xCondIs64), 10003, 10009,
+ /*10003*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10005*/ uint16(x86_xReadCm),
+ /*10006*/ uint16(x86_xArgAL),
+ /*10007*/ uint16(x86_xArgMoffs8),
+ /*10008*/ uint16(x86_xMatch),
+ /*10009*/ uint16(x86_xCondDataSize), 10003, 10003, 10013,
+ /*10013*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10015*/ uint16(x86_xReadCm),
+ /*10016*/ uint16(x86_xArgAL),
+ /*10017*/ uint16(x86_xArgMoffs8),
+ /*10018*/ uint16(x86_xMatch),
+ /*10019*/ uint16(x86_xCondDataSize), 10023, 10029, 10035,
+ /*10023*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10025*/ uint16(x86_xReadCm),
+ /*10026*/ uint16(x86_xArgAX),
+ /*10027*/ uint16(x86_xArgMoffs16),
+ /*10028*/ uint16(x86_xMatch),
+ /*10029*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10031*/ uint16(x86_xReadCm),
+ /*10032*/ uint16(x86_xArgEAX),
+ /*10033*/ uint16(x86_xArgMoffs32),
+ /*10034*/ uint16(x86_xMatch),
+ /*10035*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10037*/ uint16(x86_xReadCm),
+ /*10038*/ uint16(x86_xArgRAX),
+ /*10039*/ uint16(x86_xArgMoffs64),
+ /*10040*/ uint16(x86_xMatch),
+ /*10041*/ uint16(x86_xCondIs64), 10044, 10050,
+ /*10044*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10046*/ uint16(x86_xReadCm),
+ /*10047*/ uint16(x86_xArgMoffs8),
+ /*10048*/ uint16(x86_xArgAL),
+ /*10049*/ uint16(x86_xMatch),
+ /*10050*/ uint16(x86_xCondDataSize), 10044, 10044, 10054,
+ /*10054*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10056*/ uint16(x86_xReadCm),
+ /*10057*/ uint16(x86_xArgMoffs8),
+ /*10058*/ uint16(x86_xArgAL),
+ /*10059*/ uint16(x86_xMatch),
+ /*10060*/ uint16(x86_xCondDataSize), 10064, 10070, 10076,
+ /*10064*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10066*/ uint16(x86_xReadCm),
+ /*10067*/ uint16(x86_xArgMoffs16),
+ /*10068*/ uint16(x86_xArgAX),
+ /*10069*/ uint16(x86_xMatch),
+ /*10070*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10072*/ uint16(x86_xReadCm),
+ /*10073*/ uint16(x86_xArgMoffs32),
+ /*10074*/ uint16(x86_xArgEAX),
+ /*10075*/ uint16(x86_xMatch),
+ /*10076*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10078*/ uint16(x86_xReadCm),
+ /*10079*/ uint16(x86_xArgMoffs64),
+ /*10080*/ uint16(x86_xArgRAX),
+ /*10081*/ uint16(x86_xMatch),
+ /*10082*/ uint16(x86_xSetOp), uint16(x86_MOVSB),
+ /*10084*/ uint16(x86_xMatch),
+ /*10085*/ uint16(x86_xCondIs64), 10088, 10098,
+ /*10088*/ uint16(x86_xCondDataSize), 10092, 10095, 0,
+ /*10092*/ uint16(x86_xSetOp), uint16(x86_MOVSW),
+ /*10094*/ uint16(x86_xMatch),
+ /*10095*/ uint16(x86_xSetOp), uint16(x86_MOVSD),
+ /*10097*/ uint16(x86_xMatch),
+ /*10098*/ uint16(x86_xCondDataSize), 10092, 10095, 10102,
+ /*10102*/ uint16(x86_xSetOp), uint16(x86_MOVSQ),
+ /*10104*/ uint16(x86_xMatch),
+ /*10105*/ uint16(x86_xSetOp), uint16(x86_CMPSB),
+ /*10107*/ uint16(x86_xMatch),
+ /*10108*/ uint16(x86_xCondIs64), 10111, 10121,
+ /*10111*/ uint16(x86_xCondDataSize), 10115, 10118, 0,
+ /*10115*/ uint16(x86_xSetOp), uint16(x86_CMPSW),
+ /*10117*/ uint16(x86_xMatch),
+ /*10118*/ uint16(x86_xSetOp), uint16(x86_CMPSD),
+ /*10120*/ uint16(x86_xMatch),
+ /*10121*/ uint16(x86_xCondDataSize), 10115, 10118, 10125,
+ /*10125*/ uint16(x86_xSetOp), uint16(x86_CMPSQ),
+ /*10127*/ uint16(x86_xMatch),
+ /*10128*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*10130*/ uint16(x86_xReadIb),
+ /*10131*/ uint16(x86_xArgAL),
+ /*10132*/ uint16(x86_xArgImm8u),
+ /*10133*/ uint16(x86_xMatch),
+ /*10134*/ uint16(x86_xCondIs64), 10137, 10153,
+ /*10137*/ uint16(x86_xCondDataSize), 10141, 10147, 0,
+ /*10141*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*10143*/ uint16(x86_xReadIw),
+ /*10144*/ uint16(x86_xArgAX),
+ /*10145*/ uint16(x86_xArgImm16),
+ /*10146*/ uint16(x86_xMatch),
+ /*10147*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*10149*/ uint16(x86_xReadId),
+ /*10150*/ uint16(x86_xArgEAX),
+ /*10151*/ uint16(x86_xArgImm32),
+ /*10152*/ uint16(x86_xMatch),
+ /*10153*/ uint16(x86_xCondDataSize), 10141, 10147, 10157,
+ /*10157*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*10159*/ uint16(x86_xReadId),
+ /*10160*/ uint16(x86_xArgRAX),
+ /*10161*/ uint16(x86_xArgImm32),
+ /*10162*/ uint16(x86_xMatch),
+ /*10163*/ uint16(x86_xSetOp), uint16(x86_STOSB),
+ /*10165*/ uint16(x86_xMatch),
+ /*10166*/ uint16(x86_xCondIs64), 10169, 10179,
+ /*10169*/ uint16(x86_xCondDataSize), 10173, 10176, 0,
+ /*10173*/ uint16(x86_xSetOp), uint16(x86_STOSW),
+ /*10175*/ uint16(x86_xMatch),
+ /*10176*/ uint16(x86_xSetOp), uint16(x86_STOSD),
+ /*10178*/ uint16(x86_xMatch),
+ /*10179*/ uint16(x86_xCondDataSize), 10173, 10176, 10183,
+ /*10183*/ uint16(x86_xSetOp), uint16(x86_STOSQ),
+ /*10185*/ uint16(x86_xMatch),
+ /*10186*/ uint16(x86_xSetOp), uint16(x86_LODSB),
+ /*10188*/ uint16(x86_xMatch),
+ /*10189*/ uint16(x86_xCondIs64), 10192, 10202,
+ /*10192*/ uint16(x86_xCondDataSize), 10196, 10199, 0,
+ /*10196*/ uint16(x86_xSetOp), uint16(x86_LODSW),
+ /*10198*/ uint16(x86_xMatch),
+ /*10199*/ uint16(x86_xSetOp), uint16(x86_LODSD),
+ /*10201*/ uint16(x86_xMatch),
+ /*10202*/ uint16(x86_xCondDataSize), 10196, 10199, 10206,
+ /*10206*/ uint16(x86_xSetOp), uint16(x86_LODSQ),
+ /*10208*/ uint16(x86_xMatch),
+ /*10209*/ uint16(x86_xSetOp), uint16(x86_SCASB),
+ /*10211*/ uint16(x86_xMatch),
+ /*10212*/ uint16(x86_xCondIs64), 10215, 10225,
+ /*10215*/ uint16(x86_xCondDataSize), 10219, 10222, 0,
+ /*10219*/ uint16(x86_xSetOp), uint16(x86_SCASW),
+ /*10221*/ uint16(x86_xMatch),
+ /*10222*/ uint16(x86_xSetOp), uint16(x86_SCASD),
+ /*10224*/ uint16(x86_xMatch),
+ /*10225*/ uint16(x86_xCondDataSize), 10219, 10222, 10229,
+ /*10229*/ uint16(x86_xSetOp), uint16(x86_SCASQ),
+ /*10231*/ uint16(x86_xMatch),
+ /*10232*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10234*/ uint16(x86_xReadIb),
+ /*10235*/ uint16(x86_xArgR8op),
+ /*10236*/ uint16(x86_xArgImm8u),
+ /*10237*/ uint16(x86_xMatch),
+ /*10238*/ uint16(x86_xCondIs64), 10241, 10257,
+ /*10241*/ uint16(x86_xCondDataSize), 10245, 10251, 0,
+ /*10245*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10247*/ uint16(x86_xReadIw),
+ /*10248*/ uint16(x86_xArgR16op),
+ /*10249*/ uint16(x86_xArgImm16),
+ /*10250*/ uint16(x86_xMatch),
+ /*10251*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10253*/ uint16(x86_xReadId),
+ /*10254*/ uint16(x86_xArgR32op),
+ /*10255*/ uint16(x86_xArgImm32),
+ /*10256*/ uint16(x86_xMatch),
+ /*10257*/ uint16(x86_xCondDataSize), 10245, 10251, 10261,
+ /*10261*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10263*/ uint16(x86_xReadIo),
+ /*10264*/ uint16(x86_xArgR64op),
+ /*10265*/ uint16(x86_xArgImm64),
+ /*10266*/ uint16(x86_xMatch),
+ /*10267*/ uint16(x86_xCondSlashR),
+ 10276, // 0
+ 10282, // 1
+ 10288, // 2
+ 10294, // 3
+ 10300, // 4
+ 10306, // 5
+ 0, // 6
+ 10312, // 7
+ /*10276*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10278*/ uint16(x86_xReadIb),
+ /*10279*/ uint16(x86_xArgRM8),
+ /*10280*/ uint16(x86_xArgImm8u),
+ /*10281*/ uint16(x86_xMatch),
+ /*10282*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10284*/ uint16(x86_xReadIb),
+ /*10285*/ uint16(x86_xArgRM8),
+ /*10286*/ uint16(x86_xArgImm8u),
+ /*10287*/ uint16(x86_xMatch),
+ /*10288*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10290*/ uint16(x86_xReadIb),
+ /*10291*/ uint16(x86_xArgRM8),
+ /*10292*/ uint16(x86_xArgImm8u),
+ /*10293*/ uint16(x86_xMatch),
+ /*10294*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10296*/ uint16(x86_xReadIb),
+ /*10297*/ uint16(x86_xArgRM8),
+ /*10298*/ uint16(x86_xArgImm8u),
+ /*10299*/ uint16(x86_xMatch),
+ /*10300*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10302*/ uint16(x86_xReadIb),
+ /*10303*/ uint16(x86_xArgRM8),
+ /*10304*/ uint16(x86_xArgImm8u),
+ /*10305*/ uint16(x86_xMatch),
+ /*10306*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10308*/ uint16(x86_xReadIb),
+ /*10309*/ uint16(x86_xArgRM8),
+ /*10310*/ uint16(x86_xArgImm8u),
+ /*10311*/ uint16(x86_xMatch),
+ /*10312*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10314*/ uint16(x86_xReadIb),
+ /*10315*/ uint16(x86_xArgRM8),
+ /*10316*/ uint16(x86_xArgImm8u),
+ /*10317*/ uint16(x86_xMatch),
+ /*10318*/ uint16(x86_xCondSlashR),
+ 10327, // 0
+ 10349, // 1
+ 10371, // 2
+ 10400, // 3
+ 10429, // 4
+ 10458, // 5
+ 0, // 6
+ 10487, // 7
+ /*10327*/ uint16(x86_xCondDataSize), 10331, 10337, 10343,
+ /*10331*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10333*/ uint16(x86_xReadIb),
+ /*10334*/ uint16(x86_xArgRM16),
+ /*10335*/ uint16(x86_xArgImm8u),
+ /*10336*/ uint16(x86_xMatch),
+ /*10337*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10339*/ uint16(x86_xReadIb),
+ /*10340*/ uint16(x86_xArgRM32),
+ /*10341*/ uint16(x86_xArgImm8u),
+ /*10342*/ uint16(x86_xMatch),
+ /*10343*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10345*/ uint16(x86_xReadIb),
+ /*10346*/ uint16(x86_xArgRM64),
+ /*10347*/ uint16(x86_xArgImm8u),
+ /*10348*/ uint16(x86_xMatch),
+ /*10349*/ uint16(x86_xCondDataSize), 10353, 10359, 10365,
+ /*10353*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10355*/ uint16(x86_xReadIb),
+ /*10356*/ uint16(x86_xArgRM16),
+ /*10357*/ uint16(x86_xArgImm8u),
+ /*10358*/ uint16(x86_xMatch),
+ /*10359*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10361*/ uint16(x86_xReadIb),
+ /*10362*/ uint16(x86_xArgRM32),
+ /*10363*/ uint16(x86_xArgImm8u),
+ /*10364*/ uint16(x86_xMatch),
+ /*10365*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10367*/ uint16(x86_xReadIb),
+ /*10368*/ uint16(x86_xArgRM64),
+ /*10369*/ uint16(x86_xArgImm8u),
+ /*10370*/ uint16(x86_xMatch),
+ /*10371*/ uint16(x86_xCondIs64), 10374, 10390,
+ /*10374*/ uint16(x86_xCondDataSize), 10378, 10384, 0,
+ /*10378*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10380*/ uint16(x86_xReadIb),
+ /*10381*/ uint16(x86_xArgRM16),
+ /*10382*/ uint16(x86_xArgImm8u),
+ /*10383*/ uint16(x86_xMatch),
+ /*10384*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10386*/ uint16(x86_xReadIb),
+ /*10387*/ uint16(x86_xArgRM32),
+ /*10388*/ uint16(x86_xArgImm8u),
+ /*10389*/ uint16(x86_xMatch),
+ /*10390*/ uint16(x86_xCondDataSize), 10378, 10384, 10394,
+ /*10394*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10396*/ uint16(x86_xReadIb),
+ /*10397*/ uint16(x86_xArgRM64),
+ /*10398*/ uint16(x86_xArgImm8u),
+ /*10399*/ uint16(x86_xMatch),
+ /*10400*/ uint16(x86_xCondIs64), 10403, 10419,
+ /*10403*/ uint16(x86_xCondDataSize), 10407, 10413, 0,
+ /*10407*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10409*/ uint16(x86_xReadIb),
+ /*10410*/ uint16(x86_xArgRM16),
+ /*10411*/ uint16(x86_xArgImm8u),
+ /*10412*/ uint16(x86_xMatch),
+ /*10413*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10415*/ uint16(x86_xReadIb),
+ /*10416*/ uint16(x86_xArgRM32),
+ /*10417*/ uint16(x86_xArgImm8u),
+ /*10418*/ uint16(x86_xMatch),
+ /*10419*/ uint16(x86_xCondDataSize), 10407, 10413, 10423,
+ /*10423*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10425*/ uint16(x86_xReadIb),
+ /*10426*/ uint16(x86_xArgRM64),
+ /*10427*/ uint16(x86_xArgImm8u),
+ /*10428*/ uint16(x86_xMatch),
+ /*10429*/ uint16(x86_xCondIs64), 10432, 10448,
+ /*10432*/ uint16(x86_xCondDataSize), 10436, 10442, 0,
+ /*10436*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10438*/ uint16(x86_xReadIb),
+ /*10439*/ uint16(x86_xArgRM16),
+ /*10440*/ uint16(x86_xArgImm8u),
+ /*10441*/ uint16(x86_xMatch),
+ /*10442*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10444*/ uint16(x86_xReadIb),
+ /*10445*/ uint16(x86_xArgRM32),
+ /*10446*/ uint16(x86_xArgImm8u),
+ /*10447*/ uint16(x86_xMatch),
+ /*10448*/ uint16(x86_xCondDataSize), 10436, 10442, 10452,
+ /*10452*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10454*/ uint16(x86_xReadIb),
+ /*10455*/ uint16(x86_xArgRM64),
+ /*10456*/ uint16(x86_xArgImm8u),
+ /*10457*/ uint16(x86_xMatch),
+ /*10458*/ uint16(x86_xCondIs64), 10461, 10477,
+ /*10461*/ uint16(x86_xCondDataSize), 10465, 10471, 0,
+ /*10465*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10467*/ uint16(x86_xReadIb),
+ /*10468*/ uint16(x86_xArgRM16),
+ /*10469*/ uint16(x86_xArgImm8u),
+ /*10470*/ uint16(x86_xMatch),
+ /*10471*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10473*/ uint16(x86_xReadIb),
+ /*10474*/ uint16(x86_xArgRM32),
+ /*10475*/ uint16(x86_xArgImm8u),
+ /*10476*/ uint16(x86_xMatch),
+ /*10477*/ uint16(x86_xCondDataSize), 10465, 10471, 10481,
+ /*10481*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10483*/ uint16(x86_xReadIb),
+ /*10484*/ uint16(x86_xArgRM64),
+ /*10485*/ uint16(x86_xArgImm8u),
+ /*10486*/ uint16(x86_xMatch),
+ /*10487*/ uint16(x86_xCondIs64), 10490, 10506,
+ /*10490*/ uint16(x86_xCondDataSize), 10494, 10500, 0,
+ /*10494*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10496*/ uint16(x86_xReadIb),
+ /*10497*/ uint16(x86_xArgRM16),
+ /*10498*/ uint16(x86_xArgImm8u),
+ /*10499*/ uint16(x86_xMatch),
+ /*10500*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10502*/ uint16(x86_xReadIb),
+ /*10503*/ uint16(x86_xArgRM32),
+ /*10504*/ uint16(x86_xArgImm8u),
+ /*10505*/ uint16(x86_xMatch),
+ /*10506*/ uint16(x86_xCondDataSize), 10494, 10500, 10510,
+ /*10510*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10512*/ uint16(x86_xReadIb),
+ /*10513*/ uint16(x86_xArgRM64),
+ /*10514*/ uint16(x86_xArgImm8u),
+ /*10515*/ uint16(x86_xMatch),
+ /*10516*/ uint16(x86_xSetOp), uint16(x86_RET),
+ /*10518*/ uint16(x86_xReadIw),
+ /*10519*/ uint16(x86_xArgImm16u),
+ /*10520*/ uint16(x86_xMatch),
+ /*10521*/ uint16(x86_xSetOp), uint16(x86_RET),
+ /*10523*/ uint16(x86_xMatch),
+ /*10524*/ uint16(x86_xCondIs64), 10527, 0,
+ /*10527*/ uint16(x86_xCondDataSize), 10531, 10537, 0,
+ /*10531*/ uint16(x86_xSetOp), uint16(x86_LES),
+ /*10533*/ uint16(x86_xReadSlashR),
+ /*10534*/ uint16(x86_xArgR16),
+ /*10535*/ uint16(x86_xArgM16colon16),
+ /*10536*/ uint16(x86_xMatch),
+ /*10537*/ uint16(x86_xSetOp), uint16(x86_LES),
+ /*10539*/ uint16(x86_xReadSlashR),
+ /*10540*/ uint16(x86_xArgR32),
+ /*10541*/ uint16(x86_xArgM16colon32),
+ /*10542*/ uint16(x86_xMatch),
+ /*10543*/ uint16(x86_xCondIs64), 10546, 0,
+ /*10546*/ uint16(x86_xCondDataSize), 10550, 10556, 0,
+ /*10550*/ uint16(x86_xSetOp), uint16(x86_LDS),
+ /*10552*/ uint16(x86_xReadSlashR),
+ /*10553*/ uint16(x86_xArgR16),
+ /*10554*/ uint16(x86_xArgM16colon16),
+ /*10555*/ uint16(x86_xMatch),
+ /*10556*/ uint16(x86_xSetOp), uint16(x86_LDS),
+ /*10558*/ uint16(x86_xReadSlashR),
+ /*10559*/ uint16(x86_xArgR32),
+ /*10560*/ uint16(x86_xArgM16colon32),
+ /*10561*/ uint16(x86_xMatch),
+ /*10562*/ uint16(x86_xCondByte), 1,
+ 0xF8, 10581,
+ /*10566*/ uint16(x86_xCondSlashR),
+ 10575, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*10575*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10577*/ uint16(x86_xReadIb),
+ /*10578*/ uint16(x86_xArgRM8),
+ /*10579*/ uint16(x86_xArgImm8u),
+ /*10580*/ uint16(x86_xMatch),
+ /*10581*/ uint16(x86_xSetOp), uint16(x86_XABORT),
+ /*10583*/ uint16(x86_xReadIb),
+ /*10584*/ uint16(x86_xArgImm8u),
+ /*10585*/ uint16(x86_xMatch),
+ /*10586*/ uint16(x86_xCondByte), 1,
+ 0xF8, 10628,
+ /*10590*/ uint16(x86_xCondSlashR),
+ 10599, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*10599*/ uint16(x86_xCondIs64), 10602, 10618,
+ /*10602*/ uint16(x86_xCondDataSize), 10606, 10612, 0,
+ /*10606*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10608*/ uint16(x86_xReadIw),
+ /*10609*/ uint16(x86_xArgRM16),
+ /*10610*/ uint16(x86_xArgImm16),
+ /*10611*/ uint16(x86_xMatch),
+ /*10612*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10614*/ uint16(x86_xReadId),
+ /*10615*/ uint16(x86_xArgRM32),
+ /*10616*/ uint16(x86_xArgImm32),
+ /*10617*/ uint16(x86_xMatch),
+ /*10618*/ uint16(x86_xCondDataSize), 10606, 10612, 10622,
+ /*10622*/ uint16(x86_xSetOp), uint16(x86_MOV),
+ /*10624*/ uint16(x86_xReadId),
+ /*10625*/ uint16(x86_xArgRM64),
+ /*10626*/ uint16(x86_xArgImm32),
+ /*10627*/ uint16(x86_xMatch),
+ /*10628*/ uint16(x86_xCondDataSize), 10632, 10637, 10642,
+ /*10632*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+ /*10634*/ uint16(x86_xReadCw),
+ /*10635*/ uint16(x86_xArgRel16),
+ /*10636*/ uint16(x86_xMatch),
+ /*10637*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+ /*10639*/ uint16(x86_xReadCd),
+ /*10640*/ uint16(x86_xArgRel32),
+ /*10641*/ uint16(x86_xMatch),
+ /*10642*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+ /*10644*/ uint16(x86_xReadCd),
+ /*10645*/ uint16(x86_xArgRel32),
+ /*10646*/ uint16(x86_xMatch),
+ /*10647*/ uint16(x86_xSetOp), uint16(x86_ENTER),
+ /*10649*/ uint16(x86_xReadIw),
+ /*10650*/ uint16(x86_xReadIb),
+ /*10651*/ uint16(x86_xArgImm16u),
+ /*10652*/ uint16(x86_xArgImm8u),
+ /*10653*/ uint16(x86_xMatch),
+ /*10654*/ uint16(x86_xCondIs64), 10657, 10667,
+ /*10657*/ uint16(x86_xCondDataSize), 10661, 10664, 0,
+ /*10661*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+ /*10663*/ uint16(x86_xMatch),
+ /*10664*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+ /*10666*/ uint16(x86_xMatch),
+ /*10667*/ uint16(x86_xCondDataSize), 10661, 10671, 10674,
+ /*10671*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+ /*10673*/ uint16(x86_xMatch),
+ /*10674*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+ /*10676*/ uint16(x86_xMatch),
+ /*10677*/ uint16(x86_xSetOp), uint16(x86_LRET),
+ /*10679*/ uint16(x86_xReadIw),
+ /*10680*/ uint16(x86_xArgImm16u),
+ /*10681*/ uint16(x86_xMatch),
+ /*10682*/ uint16(x86_xSetOp), uint16(x86_LRET),
+ /*10684*/ uint16(x86_xMatch),
+ /*10685*/ uint16(x86_xSetOp), uint16(x86_INT),
+ /*10687*/ uint16(x86_xArg3),
+ /*10688*/ uint16(x86_xMatch),
+ /*10689*/ uint16(x86_xSetOp), uint16(x86_INT),
+ /*10691*/ uint16(x86_xReadIb),
+ /*10692*/ uint16(x86_xArgImm8u),
+ /*10693*/ uint16(x86_xMatch),
+ /*10694*/ uint16(x86_xCondIs64), 10697, 0,
+ /*10697*/ uint16(x86_xSetOp), uint16(x86_INTO),
+ /*10699*/ uint16(x86_xMatch),
+ /*10700*/ uint16(x86_xCondIs64), 10703, 10713,
+ /*10703*/ uint16(x86_xCondDataSize), 10707, 10710, 0,
+ /*10707*/ uint16(x86_xSetOp), uint16(x86_IRET),
+ /*10709*/ uint16(x86_xMatch),
+ /*10710*/ uint16(x86_xSetOp), uint16(x86_IRETD),
+ /*10712*/ uint16(x86_xMatch),
+ /*10713*/ uint16(x86_xCondDataSize), 10707, 10710, 10717,
+ /*10717*/ uint16(x86_xSetOp), uint16(x86_IRETQ),
+ /*10719*/ uint16(x86_xMatch),
+ /*10720*/ uint16(x86_xCondSlashR),
+ 10729, // 0
+ 10734, // 1
+ 10739, // 2
+ 10744, // 3
+ 10749, // 4
+ 10754, // 5
+ 0, // 6
+ 10759, // 7
+ /*10729*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10731*/ uint16(x86_xArgRM8),
+ /*10732*/ uint16(x86_xArg1),
+ /*10733*/ uint16(x86_xMatch),
+ /*10734*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10736*/ uint16(x86_xArgRM8),
+ /*10737*/ uint16(x86_xArg1),
+ /*10738*/ uint16(x86_xMatch),
+ /*10739*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10741*/ uint16(x86_xArgRM8),
+ /*10742*/ uint16(x86_xArg1),
+ /*10743*/ uint16(x86_xMatch),
+ /*10744*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10746*/ uint16(x86_xArgRM8),
+ /*10747*/ uint16(x86_xArg1),
+ /*10748*/ uint16(x86_xMatch),
+ /*10749*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10751*/ uint16(x86_xArgRM8),
+ /*10752*/ uint16(x86_xArg1),
+ /*10753*/ uint16(x86_xMatch),
+ /*10754*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10756*/ uint16(x86_xArgRM8),
+ /*10757*/ uint16(x86_xArg1),
+ /*10758*/ uint16(x86_xMatch),
+ /*10759*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10761*/ uint16(x86_xArgRM8),
+ /*10762*/ uint16(x86_xArg1),
+ /*10763*/ uint16(x86_xMatch),
+ /*10764*/ uint16(x86_xCondSlashR),
+ 10773, // 0
+ 10799, // 1
+ 10825, // 2
+ 10851, // 3
+ 10877, // 4
+ 10903, // 5
+ 0, // 6
+ 10929, // 7
+ /*10773*/ uint16(x86_xCondIs64), 10776, 10790,
+ /*10776*/ uint16(x86_xCondDataSize), 10780, 10785, 0,
+ /*10780*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10782*/ uint16(x86_xArgRM16),
+ /*10783*/ uint16(x86_xArg1),
+ /*10784*/ uint16(x86_xMatch),
+ /*10785*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10787*/ uint16(x86_xArgRM32),
+ /*10788*/ uint16(x86_xArg1),
+ /*10789*/ uint16(x86_xMatch),
+ /*10790*/ uint16(x86_xCondDataSize), 10780, 10785, 10794,
+ /*10794*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10796*/ uint16(x86_xArgRM64),
+ /*10797*/ uint16(x86_xArg1),
+ /*10798*/ uint16(x86_xMatch),
+ /*10799*/ uint16(x86_xCondIs64), 10802, 10816,
+ /*10802*/ uint16(x86_xCondDataSize), 10806, 10811, 0,
+ /*10806*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10808*/ uint16(x86_xArgRM16),
+ /*10809*/ uint16(x86_xArg1),
+ /*10810*/ uint16(x86_xMatch),
+ /*10811*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10813*/ uint16(x86_xArgRM32),
+ /*10814*/ uint16(x86_xArg1),
+ /*10815*/ uint16(x86_xMatch),
+ /*10816*/ uint16(x86_xCondDataSize), 10806, 10811, 10820,
+ /*10820*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10822*/ uint16(x86_xArgRM64),
+ /*10823*/ uint16(x86_xArg1),
+ /*10824*/ uint16(x86_xMatch),
+ /*10825*/ uint16(x86_xCondIs64), 10828, 10842,
+ /*10828*/ uint16(x86_xCondDataSize), 10832, 10837, 0,
+ /*10832*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10834*/ uint16(x86_xArgRM16),
+ /*10835*/ uint16(x86_xArg1),
+ /*10836*/ uint16(x86_xMatch),
+ /*10837*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10839*/ uint16(x86_xArgRM32),
+ /*10840*/ uint16(x86_xArg1),
+ /*10841*/ uint16(x86_xMatch),
+ /*10842*/ uint16(x86_xCondDataSize), 10832, 10837, 10846,
+ /*10846*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10848*/ uint16(x86_xArgRM64),
+ /*10849*/ uint16(x86_xArg1),
+ /*10850*/ uint16(x86_xMatch),
+ /*10851*/ uint16(x86_xCondIs64), 10854, 10868,
+ /*10854*/ uint16(x86_xCondDataSize), 10858, 10863, 0,
+ /*10858*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10860*/ uint16(x86_xArgRM16),
+ /*10861*/ uint16(x86_xArg1),
+ /*10862*/ uint16(x86_xMatch),
+ /*10863*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10865*/ uint16(x86_xArgRM32),
+ /*10866*/ uint16(x86_xArg1),
+ /*10867*/ uint16(x86_xMatch),
+ /*10868*/ uint16(x86_xCondDataSize), 10858, 10863, 10872,
+ /*10872*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10874*/ uint16(x86_xArgRM64),
+ /*10875*/ uint16(x86_xArg1),
+ /*10876*/ uint16(x86_xMatch),
+ /*10877*/ uint16(x86_xCondIs64), 10880, 10894,
+ /*10880*/ uint16(x86_xCondDataSize), 10884, 10889, 0,
+ /*10884*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10886*/ uint16(x86_xArgRM16),
+ /*10887*/ uint16(x86_xArg1),
+ /*10888*/ uint16(x86_xMatch),
+ /*10889*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10891*/ uint16(x86_xArgRM32),
+ /*10892*/ uint16(x86_xArg1),
+ /*10893*/ uint16(x86_xMatch),
+ /*10894*/ uint16(x86_xCondDataSize), 10884, 10889, 10898,
+ /*10898*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10900*/ uint16(x86_xArgRM64),
+ /*10901*/ uint16(x86_xArg1),
+ /*10902*/ uint16(x86_xMatch),
+ /*10903*/ uint16(x86_xCondIs64), 10906, 10920,
+ /*10906*/ uint16(x86_xCondDataSize), 10910, 10915, 0,
+ /*10910*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10912*/ uint16(x86_xArgRM16),
+ /*10913*/ uint16(x86_xArg1),
+ /*10914*/ uint16(x86_xMatch),
+ /*10915*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10917*/ uint16(x86_xArgRM32),
+ /*10918*/ uint16(x86_xArg1),
+ /*10919*/ uint16(x86_xMatch),
+ /*10920*/ uint16(x86_xCondDataSize), 10910, 10915, 10924,
+ /*10924*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10926*/ uint16(x86_xArgRM64),
+ /*10927*/ uint16(x86_xArg1),
+ /*10928*/ uint16(x86_xMatch),
+ /*10929*/ uint16(x86_xCondIs64), 10932, 10946,
+ /*10932*/ uint16(x86_xCondDataSize), 10936, 10941, 0,
+ /*10936*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10938*/ uint16(x86_xArgRM16),
+ /*10939*/ uint16(x86_xArg1),
+ /*10940*/ uint16(x86_xMatch),
+ /*10941*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10943*/ uint16(x86_xArgRM32),
+ /*10944*/ uint16(x86_xArg1),
+ /*10945*/ uint16(x86_xMatch),
+ /*10946*/ uint16(x86_xCondDataSize), 10936, 10941, 10950,
+ /*10950*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10952*/ uint16(x86_xArgRM64),
+ /*10953*/ uint16(x86_xArg1),
+ /*10954*/ uint16(x86_xMatch),
+ /*10955*/ uint16(x86_xCondSlashR),
+ 10964, // 0
+ 10969, // 1
+ 10974, // 2
+ 10979, // 3
+ 10984, // 4
+ 10989, // 5
+ 0, // 6
+ 10994, // 7
+ /*10964*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*10966*/ uint16(x86_xArgRM8),
+ /*10967*/ uint16(x86_xArgCL),
+ /*10968*/ uint16(x86_xMatch),
+ /*10969*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*10971*/ uint16(x86_xArgRM8),
+ /*10972*/ uint16(x86_xArgCL),
+ /*10973*/ uint16(x86_xMatch),
+ /*10974*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*10976*/ uint16(x86_xArgRM8),
+ /*10977*/ uint16(x86_xArgCL),
+ /*10978*/ uint16(x86_xMatch),
+ /*10979*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*10981*/ uint16(x86_xArgRM8),
+ /*10982*/ uint16(x86_xArgCL),
+ /*10983*/ uint16(x86_xMatch),
+ /*10984*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*10986*/ uint16(x86_xArgRM8),
+ /*10987*/ uint16(x86_xArgCL),
+ /*10988*/ uint16(x86_xMatch),
+ /*10989*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*10991*/ uint16(x86_xArgRM8),
+ /*10992*/ uint16(x86_xArgCL),
+ /*10993*/ uint16(x86_xMatch),
+ /*10994*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*10996*/ uint16(x86_xArgRM8),
+ /*10997*/ uint16(x86_xArgCL),
+ /*10998*/ uint16(x86_xMatch),
+ /*10999*/ uint16(x86_xCondSlashR),
+ 11008, // 0
+ 11034, // 1
+ 11060, // 2
+ 11086, // 3
+ 11112, // 4
+ 11138, // 5
+ 0, // 6
+ 11164, // 7
+ /*11008*/ uint16(x86_xCondIs64), 11011, 11025,
+ /*11011*/ uint16(x86_xCondDataSize), 11015, 11020, 0,
+ /*11015*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*11017*/ uint16(x86_xArgRM16),
+ /*11018*/ uint16(x86_xArgCL),
+ /*11019*/ uint16(x86_xMatch),
+ /*11020*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*11022*/ uint16(x86_xArgRM32),
+ /*11023*/ uint16(x86_xArgCL),
+ /*11024*/ uint16(x86_xMatch),
+ /*11025*/ uint16(x86_xCondDataSize), 11015, 11020, 11029,
+ /*11029*/ uint16(x86_xSetOp), uint16(x86_ROL),
+ /*11031*/ uint16(x86_xArgRM64),
+ /*11032*/ uint16(x86_xArgCL),
+ /*11033*/ uint16(x86_xMatch),
+ /*11034*/ uint16(x86_xCondIs64), 11037, 11051,
+ /*11037*/ uint16(x86_xCondDataSize), 11041, 11046, 0,
+ /*11041*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*11043*/ uint16(x86_xArgRM16),
+ /*11044*/ uint16(x86_xArgCL),
+ /*11045*/ uint16(x86_xMatch),
+ /*11046*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*11048*/ uint16(x86_xArgRM32),
+ /*11049*/ uint16(x86_xArgCL),
+ /*11050*/ uint16(x86_xMatch),
+ /*11051*/ uint16(x86_xCondDataSize), 11041, 11046, 11055,
+ /*11055*/ uint16(x86_xSetOp), uint16(x86_ROR),
+ /*11057*/ uint16(x86_xArgRM64),
+ /*11058*/ uint16(x86_xArgCL),
+ /*11059*/ uint16(x86_xMatch),
+ /*11060*/ uint16(x86_xCondIs64), 11063, 11077,
+ /*11063*/ uint16(x86_xCondDataSize), 11067, 11072, 0,
+ /*11067*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*11069*/ uint16(x86_xArgRM16),
+ /*11070*/ uint16(x86_xArgCL),
+ /*11071*/ uint16(x86_xMatch),
+ /*11072*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*11074*/ uint16(x86_xArgRM32),
+ /*11075*/ uint16(x86_xArgCL),
+ /*11076*/ uint16(x86_xMatch),
+ /*11077*/ uint16(x86_xCondDataSize), 11067, 11072, 11081,
+ /*11081*/ uint16(x86_xSetOp), uint16(x86_RCL),
+ /*11083*/ uint16(x86_xArgRM64),
+ /*11084*/ uint16(x86_xArgCL),
+ /*11085*/ uint16(x86_xMatch),
+ /*11086*/ uint16(x86_xCondIs64), 11089, 11103,
+ /*11089*/ uint16(x86_xCondDataSize), 11093, 11098, 0,
+ /*11093*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*11095*/ uint16(x86_xArgRM16),
+ /*11096*/ uint16(x86_xArgCL),
+ /*11097*/ uint16(x86_xMatch),
+ /*11098*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*11100*/ uint16(x86_xArgRM32),
+ /*11101*/ uint16(x86_xArgCL),
+ /*11102*/ uint16(x86_xMatch),
+ /*11103*/ uint16(x86_xCondDataSize), 11093, 11098, 11107,
+ /*11107*/ uint16(x86_xSetOp), uint16(x86_RCR),
+ /*11109*/ uint16(x86_xArgRM64),
+ /*11110*/ uint16(x86_xArgCL),
+ /*11111*/ uint16(x86_xMatch),
+ /*11112*/ uint16(x86_xCondIs64), 11115, 11129,
+ /*11115*/ uint16(x86_xCondDataSize), 11119, 11124, 0,
+ /*11119*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*11121*/ uint16(x86_xArgRM16),
+ /*11122*/ uint16(x86_xArgCL),
+ /*11123*/ uint16(x86_xMatch),
+ /*11124*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*11126*/ uint16(x86_xArgRM32),
+ /*11127*/ uint16(x86_xArgCL),
+ /*11128*/ uint16(x86_xMatch),
+ /*11129*/ uint16(x86_xCondDataSize), 11119, 11124, 11133,
+ /*11133*/ uint16(x86_xSetOp), uint16(x86_SHL),
+ /*11135*/ uint16(x86_xArgRM64),
+ /*11136*/ uint16(x86_xArgCL),
+ /*11137*/ uint16(x86_xMatch),
+ /*11138*/ uint16(x86_xCondIs64), 11141, 11155,
+ /*11141*/ uint16(x86_xCondDataSize), 11145, 11150, 0,
+ /*11145*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*11147*/ uint16(x86_xArgRM16),
+ /*11148*/ uint16(x86_xArgCL),
+ /*11149*/ uint16(x86_xMatch),
+ /*11150*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*11152*/ uint16(x86_xArgRM32),
+ /*11153*/ uint16(x86_xArgCL),
+ /*11154*/ uint16(x86_xMatch),
+ /*11155*/ uint16(x86_xCondDataSize), 11145, 11150, 11159,
+ /*11159*/ uint16(x86_xSetOp), uint16(x86_SHR),
+ /*11161*/ uint16(x86_xArgRM64),
+ /*11162*/ uint16(x86_xArgCL),
+ /*11163*/ uint16(x86_xMatch),
+ /*11164*/ uint16(x86_xCondIs64), 11167, 11181,
+ /*11167*/ uint16(x86_xCondDataSize), 11171, 11176, 0,
+ /*11171*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*11173*/ uint16(x86_xArgRM16),
+ /*11174*/ uint16(x86_xArgCL),
+ /*11175*/ uint16(x86_xMatch),
+ /*11176*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*11178*/ uint16(x86_xArgRM32),
+ /*11179*/ uint16(x86_xArgCL),
+ /*11180*/ uint16(x86_xMatch),
+ /*11181*/ uint16(x86_xCondDataSize), 11171, 11176, 11185,
+ /*11185*/ uint16(x86_xSetOp), uint16(x86_SAR),
+ /*11187*/ uint16(x86_xArgRM64),
+ /*11188*/ uint16(x86_xArgCL),
+ /*11189*/ uint16(x86_xMatch),
+ /*11190*/ uint16(x86_xCondIs64), 11193, 0,
+ /*11193*/ uint16(x86_xSetOp), uint16(x86_AAM),
+ /*11195*/ uint16(x86_xReadIb),
+ /*11196*/ uint16(x86_xArgImm8u),
+ /*11197*/ uint16(x86_xMatch),
+ /*11198*/ uint16(x86_xCondIs64), 11201, 0,
+ /*11201*/ uint16(x86_xSetOp), uint16(x86_AAD),
+ /*11203*/ uint16(x86_xReadIb),
+ /*11204*/ uint16(x86_xArgImm8u),
+ /*11205*/ uint16(x86_xMatch),
+ /*11206*/ uint16(x86_xCondIs64), 11209, 11212,
+ /*11209*/ uint16(x86_xSetOp), uint16(x86_XLATB),
+ /*11211*/ uint16(x86_xMatch),
+ /*11212*/ uint16(x86_xCondDataSize), 11209, 11209, 11216,
+ /*11216*/ uint16(x86_xSetOp), uint16(x86_XLATB),
+ /*11218*/ uint16(x86_xMatch),
+ /*11219*/ uint16(x86_xCondByte), 64,
+ 0xc0, 11390,
+ 0xc1, 11390,
+ 0xc2, 11390,
+ 0xc3, 11390,
+ 0xc4, 11390,
+ 0xc5, 11390,
+ 0xc6, 11390,
+ 0xc7, 11390,
+ 0xc8, 11395,
+ 0xc9, 11395,
+ 0xca, 11395,
+ 0xcb, 11395,
+ 0xcc, 11395,
+ 0xcd, 11395,
+ 0xce, 11395,
+ 0xcf, 11395,
+ 0xd0, 11400,
+ 0xd1, 11400,
+ 0xd2, 11400,
+ 0xd3, 11400,
+ 0xd4, 11400,
+ 0xd5, 11400,
+ 0xd6, 11400,
+ 0xd7, 11400,
+ 0xd8, 11404,
+ 0xd9, 11404,
+ 0xda, 11404,
+ 0xdb, 11404,
+ 0xdc, 11404,
+ 0xdd, 11404,
+ 0xde, 11404,
+ 0xdf, 11404,
+ 0xe0, 11408,
+ 0xe1, 11408,
+ 0xe2, 11408,
+ 0xe3, 11408,
+ 0xe4, 11408,
+ 0xe5, 11408,
+ 0xe6, 11408,
+ 0xe7, 11408,
+ 0xe8, 11413,
+ 0xe9, 11413,
+ 0xea, 11413,
+ 0xeb, 11413,
+ 0xec, 11413,
+ 0xed, 11413,
+ 0xee, 11413,
+ 0xef, 11413,
+ 0xf0, 11418,
+ 0xf1, 11418,
+ 0xf2, 11418,
+ 0xf3, 11418,
+ 0xf4, 11418,
+ 0xf5, 11418,
+ 0xf6, 11418,
+ 0xf7, 11418,
+ 0xf8, 11423,
+ 0xf9, 11423,
+ 0xfa, 11423,
+ 0xfb, 11423,
+ 0xfc, 11423,
+ 0xfd, 11423,
+ 0xfe, 11423,
+ 0xff, 11423,
+ /*11349*/ uint16(x86_xCondSlashR),
+ 11358, // 0
+ 11362, // 1
+ 11366, // 2
+ 11370, // 3
+ 11374, // 4
+ 11378, // 5
+ 11382, // 6
+ 11386, // 7
+ /*11358*/ uint16(x86_xSetOp), uint16(x86_FADD),
+ /*11360*/ uint16(x86_xArgM32fp),
+ /*11361*/ uint16(x86_xMatch),
+ /*11362*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+ /*11364*/ uint16(x86_xArgM32fp),
+ /*11365*/ uint16(x86_xMatch),
+ /*11366*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+ /*11368*/ uint16(x86_xArgM32fp),
+ /*11369*/ uint16(x86_xMatch),
+ /*11370*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+ /*11372*/ uint16(x86_xArgM32fp),
+ /*11373*/ uint16(x86_xMatch),
+ /*11374*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+ /*11376*/ uint16(x86_xArgM32fp),
+ /*11377*/ uint16(x86_xMatch),
+ /*11378*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+ /*11380*/ uint16(x86_xArgM32fp),
+ /*11381*/ uint16(x86_xMatch),
+ /*11382*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+ /*11384*/ uint16(x86_xArgM32fp),
+ /*11385*/ uint16(x86_xMatch),
+ /*11386*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+ /*11388*/ uint16(x86_xArgM32fp),
+ /*11389*/ uint16(x86_xMatch),
+ /*11390*/ uint16(x86_xSetOp), uint16(x86_FADD),
+ /*11392*/ uint16(x86_xArgST),
+ /*11393*/ uint16(x86_xArgSTi),
+ /*11394*/ uint16(x86_xMatch),
+ /*11395*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+ /*11397*/ uint16(x86_xArgST),
+ /*11398*/ uint16(x86_xArgSTi),
+ /*11399*/ uint16(x86_xMatch),
+ /*11400*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+ /*11402*/ uint16(x86_xArgSTi),
+ /*11403*/ uint16(x86_xMatch),
+ /*11404*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+ /*11406*/ uint16(x86_xArgSTi),
+ /*11407*/ uint16(x86_xMatch),
+ /*11408*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+ /*11410*/ uint16(x86_xArgST),
+ /*11411*/ uint16(x86_xArgSTi),
+ /*11412*/ uint16(x86_xMatch),
+ /*11413*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+ /*11415*/ uint16(x86_xArgST),
+ /*11416*/ uint16(x86_xArgSTi),
+ /*11417*/ uint16(x86_xMatch),
+ /*11418*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+ /*11420*/ uint16(x86_xArgST),
+ /*11421*/ uint16(x86_xArgSTi),
+ /*11422*/ uint16(x86_xMatch),
+ /*11423*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+ /*11425*/ uint16(x86_xArgST),
+ /*11426*/ uint16(x86_xArgSTi),
+ /*11427*/ uint16(x86_xMatch),
+ /*11428*/ uint16(x86_xCondByte), 42,
+ 0xc0, 11551,
+ 0xc1, 11551,
+ 0xc2, 11551,
+ 0xc3, 11551,
+ 0xc4, 11551,
+ 0xc5, 11551,
+ 0xc6, 11551,
+ 0xc7, 11551,
+ 0xc8, 11555,
+ 0xc9, 11555,
+ 0xca, 11555,
+ 0xcb, 11555,
+ 0xcc, 11555,
+ 0xcd, 11555,
+ 0xce, 11555,
+ 0xcf, 11555,
+ 0xD0, 11559,
+ 0xE0, 11562,
+ 0xE1, 11565,
+ 0xE4, 11568,
+ 0xE5, 11571,
+ 0xE8, 11574,
+ 0xE9, 11577,
+ 0xEA, 11580,
+ 0xEB, 11583,
+ 0xEC, 11586,
+ 0xF0, 11589,
+ 0xF1, 11592,
+ 0xF2, 11595,
+ 0xF3, 11598,
+ 0xF4, 11601,
+ 0xF5, 11604,
+ 0xF6, 11607,
+ 0xF7, 11610,
+ 0xF8, 11613,
+ 0xF9, 11616,
+ 0xFA, 11619,
+ 0xFB, 11622,
+ 0xFC, 11625,
+ 0xFD, 11628,
+ 0xFE, 11631,
+ 0xFF, 11634,
+ /*11514*/ uint16(x86_xCondSlashR),
+ 11523, // 0
+ 0, // 1
+ 11527, // 2
+ 11531, // 3
+ 11535, // 4
+ 11539, // 5
+ 11543, // 6
+ 11547, // 7
+ /*11523*/ uint16(x86_xSetOp), uint16(x86_FLD),
+ /*11525*/ uint16(x86_xArgM32fp),
+ /*11526*/ uint16(x86_xMatch),
+ /*11527*/ uint16(x86_xSetOp), uint16(x86_FST),
+ /*11529*/ uint16(x86_xArgM32fp),
+ /*11530*/ uint16(x86_xMatch),
+ /*11531*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+ /*11533*/ uint16(x86_xArgM32fp),
+ /*11534*/ uint16(x86_xMatch),
+ /*11535*/ uint16(x86_xSetOp), uint16(x86_FLDENV),
+ /*11537*/ uint16(x86_xArgM1428byte),
+ /*11538*/ uint16(x86_xMatch),
+ /*11539*/ uint16(x86_xSetOp), uint16(x86_FLDCW),
+ /*11541*/ uint16(x86_xArgM2byte),
+ /*11542*/ uint16(x86_xMatch),
+ /*11543*/ uint16(x86_xSetOp), uint16(x86_FNSTENV),
+ /*11545*/ uint16(x86_xArgM1428byte),
+ /*11546*/ uint16(x86_xMatch),
+ /*11547*/ uint16(x86_xSetOp), uint16(x86_FNSTCW),
+ /*11549*/ uint16(x86_xArgM2byte),
+ /*11550*/ uint16(x86_xMatch),
+ /*11551*/ uint16(x86_xSetOp), uint16(x86_FLD),
+ /*11553*/ uint16(x86_xArgSTi),
+ /*11554*/ uint16(x86_xMatch),
+ /*11555*/ uint16(x86_xSetOp), uint16(x86_FXCH),
+ /*11557*/ uint16(x86_xArgSTi),
+ /*11558*/ uint16(x86_xMatch),
+ /*11559*/ uint16(x86_xSetOp), uint16(x86_FNOP),
+ /*11561*/ uint16(x86_xMatch),
+ /*11562*/ uint16(x86_xSetOp), uint16(x86_FCHS),
+ /*11564*/ uint16(x86_xMatch),
+ /*11565*/ uint16(x86_xSetOp), uint16(x86_FABS),
+ /*11567*/ uint16(x86_xMatch),
+ /*11568*/ uint16(x86_xSetOp), uint16(x86_FTST),
+ /*11570*/ uint16(x86_xMatch),
+ /*11571*/ uint16(x86_xSetOp), uint16(x86_FXAM),
+ /*11573*/ uint16(x86_xMatch),
+ /*11574*/ uint16(x86_xSetOp), uint16(x86_FLD1),
+ /*11576*/ uint16(x86_xMatch),
+ /*11577*/ uint16(x86_xSetOp), uint16(x86_FLDL2T),
+ /*11579*/ uint16(x86_xMatch),
+ /*11580*/ uint16(x86_xSetOp), uint16(x86_FLDL2E),
+ /*11582*/ uint16(x86_xMatch),
+ /*11583*/ uint16(x86_xSetOp), uint16(x86_FLDPI),
+ /*11585*/ uint16(x86_xMatch),
+ /*11586*/ uint16(x86_xSetOp), uint16(x86_FLDLG2),
+ /*11588*/ uint16(x86_xMatch),
+ /*11589*/ uint16(x86_xSetOp), uint16(x86_F2XM1),
+ /*11591*/ uint16(x86_xMatch),
+ /*11592*/ uint16(x86_xSetOp), uint16(x86_FYL2X),
+ /*11594*/ uint16(x86_xMatch),
+ /*11595*/ uint16(x86_xSetOp), uint16(x86_FPTAN),
+ /*11597*/ uint16(x86_xMatch),
+ /*11598*/ uint16(x86_xSetOp), uint16(x86_FPATAN),
+ /*11600*/ uint16(x86_xMatch),
+ /*11601*/ uint16(x86_xSetOp), uint16(x86_FXTRACT),
+ /*11603*/ uint16(x86_xMatch),
+ /*11604*/ uint16(x86_xSetOp), uint16(x86_FPREM1),
+ /*11606*/ uint16(x86_xMatch),
+ /*11607*/ uint16(x86_xSetOp), uint16(x86_FDECSTP),
+ /*11609*/ uint16(x86_xMatch),
+ /*11610*/ uint16(x86_xSetOp), uint16(x86_FINCSTP),
+ /*11612*/ uint16(x86_xMatch),
+ /*11613*/ uint16(x86_xSetOp), uint16(x86_FPREM),
+ /*11615*/ uint16(x86_xMatch),
+ /*11616*/ uint16(x86_xSetOp), uint16(x86_FYL2XP1),
+ /*11618*/ uint16(x86_xMatch),
+ /*11619*/ uint16(x86_xSetOp), uint16(x86_FSQRT),
+ /*11621*/ uint16(x86_xMatch),
+ /*11622*/ uint16(x86_xSetOp), uint16(x86_FSINCOS),
+ /*11624*/ uint16(x86_xMatch),
+ /*11625*/ uint16(x86_xSetOp), uint16(x86_FRNDINT),
+ /*11627*/ uint16(x86_xMatch),
+ /*11628*/ uint16(x86_xSetOp), uint16(x86_FSCALE),
+ /*11630*/ uint16(x86_xMatch),
+ /*11631*/ uint16(x86_xSetOp), uint16(x86_FSIN),
+ /*11633*/ uint16(x86_xMatch),
+ /*11634*/ uint16(x86_xSetOp), uint16(x86_FCOS),
+ /*11636*/ uint16(x86_xMatch),
+ /*11637*/ uint16(x86_xCondByte), 33,
+ 0xc0, 11746,
+ 0xc1, 11746,
+ 0xc2, 11746,
+ 0xc3, 11746,
+ 0xc4, 11746,
+ 0xc5, 11746,
+ 0xc6, 11746,
+ 0xc7, 11746,
+ 0xc8, 11751,
+ 0xc9, 11751,
+ 0xca, 11751,
+ 0xcb, 11751,
+ 0xcc, 11751,
+ 0xcd, 11751,
+ 0xce, 11751,
+ 0xcf, 11751,
+ 0xd0, 11756,
+ 0xd1, 11756,
+ 0xd2, 11756,
+ 0xd3, 11756,
+ 0xd4, 11756,
+ 0xd5, 11756,
+ 0xd6, 11756,
+ 0xd7, 11756,
+ 0xd8, 11761,
+ 0xd9, 11761,
+ 0xda, 11761,
+ 0xdb, 11761,
+ 0xdc, 11761,
+ 0xdd, 11761,
+ 0xde, 11761,
+ 0xdf, 11761,
+ 0xE9, 11766,
+ /*11705*/ uint16(x86_xCondSlashR),
+ 11714, // 0
+ 11718, // 1
+ 11722, // 2
+ 11726, // 3
+ 11730, // 4
+ 11734, // 5
+ 11738, // 6
+ 11742, // 7
+ /*11714*/ uint16(x86_xSetOp), uint16(x86_FIADD),
+ /*11716*/ uint16(x86_xArgM32int),
+ /*11717*/ uint16(x86_xMatch),
+ /*11718*/ uint16(x86_xSetOp), uint16(x86_FIMUL),
+ /*11720*/ uint16(x86_xArgM32int),
+ /*11721*/ uint16(x86_xMatch),
+ /*11722*/ uint16(x86_xSetOp), uint16(x86_FICOM),
+ /*11724*/ uint16(x86_xArgM32int),
+ /*11725*/ uint16(x86_xMatch),
+ /*11726*/ uint16(x86_xSetOp), uint16(x86_FICOMP),
+ /*11728*/ uint16(x86_xArgM32int),
+ /*11729*/ uint16(x86_xMatch),
+ /*11730*/ uint16(x86_xSetOp), uint16(x86_FISUB),
+ /*11732*/ uint16(x86_xArgM32int),
+ /*11733*/ uint16(x86_xMatch),
+ /*11734*/ uint16(x86_xSetOp), uint16(x86_FISUBR),
+ /*11736*/ uint16(x86_xArgM32int),
+ /*11737*/ uint16(x86_xMatch),
+ /*11738*/ uint16(x86_xSetOp), uint16(x86_FIDIV),
+ /*11740*/ uint16(x86_xArgM32int),
+ /*11741*/ uint16(x86_xMatch),
+ /*11742*/ uint16(x86_xSetOp), uint16(x86_FIDIVR),
+ /*11744*/ uint16(x86_xArgM32int),
+ /*11745*/ uint16(x86_xMatch),
+ /*11746*/ uint16(x86_xSetOp), uint16(x86_FCMOVB),
+ /*11748*/ uint16(x86_xArgST),
+ /*11749*/ uint16(x86_xArgSTi),
+ /*11750*/ uint16(x86_xMatch),
+ /*11751*/ uint16(x86_xSetOp), uint16(x86_FCMOVE),
+ /*11753*/ uint16(x86_xArgST),
+ /*11754*/ uint16(x86_xArgSTi),
+ /*11755*/ uint16(x86_xMatch),
+ /*11756*/ uint16(x86_xSetOp), uint16(x86_FCMOVBE),
+ /*11758*/ uint16(x86_xArgST),
+ /*11759*/ uint16(x86_xArgSTi),
+ /*11760*/ uint16(x86_xMatch),
+ /*11761*/ uint16(x86_xSetOp), uint16(x86_FCMOVU),
+ /*11763*/ uint16(x86_xArgST),
+ /*11764*/ uint16(x86_xArgSTi),
+ /*11765*/ uint16(x86_xMatch),
+ /*11766*/ uint16(x86_xSetOp), uint16(x86_FUCOMPP),
+ /*11768*/ uint16(x86_xMatch),
+ /*11769*/ uint16(x86_xCondByte), 50,
+ 0xc0, 11904,
+ 0xc1, 11904,
+ 0xc2, 11904,
+ 0xc3, 11904,
+ 0xc4, 11904,
+ 0xc5, 11904,
+ 0xc6, 11904,
+ 0xc7, 11904,
+ 0xc8, 11909,
+ 0xc9, 11909,
+ 0xca, 11909,
+ 0xcb, 11909,
+ 0xcc, 11909,
+ 0xcd, 11909,
+ 0xce, 11909,
+ 0xcf, 11909,
+ 0xd0, 11914,
+ 0xd1, 11914,
+ 0xd2, 11914,
+ 0xd3, 11914,
+ 0xd4, 11914,
+ 0xd5, 11914,
+ 0xd6, 11914,
+ 0xd7, 11914,
+ 0xd8, 11919,
+ 0xd9, 11919,
+ 0xda, 11919,
+ 0xdb, 11919,
+ 0xdc, 11919,
+ 0xdd, 11919,
+ 0xde, 11919,
+ 0xdf, 11919,
+ 0xE2, 11924,
+ 0xE3, 11927,
+ 0xe8, 11930,
+ 0xe9, 11930,
+ 0xea, 11930,
+ 0xeb, 11930,
+ 0xec, 11930,
+ 0xed, 11930,
+ 0xee, 11930,
+ 0xef, 11930,
+ 0xf0, 11935,
+ 0xf1, 11935,
+ 0xf2, 11935,
+ 0xf3, 11935,
+ 0xf4, 11935,
+ 0xf5, 11935,
+ 0xf6, 11935,
+ 0xf7, 11935,
+ /*11871*/ uint16(x86_xCondSlashR),
+ 11880, // 0
+ 11884, // 1
+ 11888, // 2
+ 11892, // 3
+ 0, // 4
+ 11896, // 5
+ 0, // 6
+ 11900, // 7
+ /*11880*/ uint16(x86_xSetOp), uint16(x86_FILD),
+ /*11882*/ uint16(x86_xArgM32int),
+ /*11883*/ uint16(x86_xMatch),
+ /*11884*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+ /*11886*/ uint16(x86_xArgM32int),
+ /*11887*/ uint16(x86_xMatch),
+ /*11888*/ uint16(x86_xSetOp), uint16(x86_FIST),
+ /*11890*/ uint16(x86_xArgM32int),
+ /*11891*/ uint16(x86_xMatch),
+ /*11892*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+ /*11894*/ uint16(x86_xArgM32int),
+ /*11895*/ uint16(x86_xMatch),
+ /*11896*/ uint16(x86_xSetOp), uint16(x86_FLD),
+ /*11898*/ uint16(x86_xArgM80fp),
+ /*11899*/ uint16(x86_xMatch),
+ /*11900*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+ /*11902*/ uint16(x86_xArgM80fp),
+ /*11903*/ uint16(x86_xMatch),
+ /*11904*/ uint16(x86_xSetOp), uint16(x86_FCMOVNB),
+ /*11906*/ uint16(x86_xArgST),
+ /*11907*/ uint16(x86_xArgSTi),
+ /*11908*/ uint16(x86_xMatch),
+ /*11909*/ uint16(x86_xSetOp), uint16(x86_FCMOVNE),
+ /*11911*/ uint16(x86_xArgST),
+ /*11912*/ uint16(x86_xArgSTi),
+ /*11913*/ uint16(x86_xMatch),
+ /*11914*/ uint16(x86_xSetOp), uint16(x86_FCMOVNBE),
+ /*11916*/ uint16(x86_xArgST),
+ /*11917*/ uint16(x86_xArgSTi),
+ /*11918*/ uint16(x86_xMatch),
+ /*11919*/ uint16(x86_xSetOp), uint16(x86_FCMOVNU),
+ /*11921*/ uint16(x86_xArgST),
+ /*11922*/ uint16(x86_xArgSTi),
+ /*11923*/ uint16(x86_xMatch),
+ /*11924*/ uint16(x86_xSetOp), uint16(x86_FNCLEX),
+ /*11926*/ uint16(x86_xMatch),
+ /*11927*/ uint16(x86_xSetOp), uint16(x86_FNINIT),
+ /*11929*/ uint16(x86_xMatch),
+ /*11930*/ uint16(x86_xSetOp), uint16(x86_FUCOMI),
+ /*11932*/ uint16(x86_xArgST),
+ /*11933*/ uint16(x86_xArgSTi),
+ /*11934*/ uint16(x86_xMatch),
+ /*11935*/ uint16(x86_xSetOp), uint16(x86_FCOMI),
+ /*11937*/ uint16(x86_xArgST),
+ /*11938*/ uint16(x86_xArgSTi),
+ /*11939*/ uint16(x86_xMatch),
+ /*11940*/ uint16(x86_xCondByte), 48,
+ 0xc0, 12079,
+ 0xc1, 12079,
+ 0xc2, 12079,
+ 0xc3, 12079,
+ 0xc4, 12079,
+ 0xc5, 12079,
+ 0xc6, 12079,
+ 0xc7, 12079,
+ 0xc8, 12084,
+ 0xc9, 12084,
+ 0xca, 12084,
+ 0xcb, 12084,
+ 0xcc, 12084,
+ 0xcd, 12084,
+ 0xce, 12084,
+ 0xcf, 12084,
+ 0xe0, 12089,
+ 0xe1, 12089,
+ 0xe2, 12089,
+ 0xe3, 12089,
+ 0xe4, 12089,
+ 0xe5, 12089,
+ 0xe6, 12089,
+ 0xe7, 12089,
+ 0xe8, 12094,
+ 0xe9, 12094,
+ 0xea, 12094,
+ 0xeb, 12094,
+ 0xec, 12094,
+ 0xed, 12094,
+ 0xee, 12094,
+ 0xef, 12094,
+ 0xf0, 12099,
+ 0xf1, 12099,
+ 0xf2, 12099,
+ 0xf3, 12099,
+ 0xf4, 12099,
+ 0xf5, 12099,
+ 0xf6, 12099,
+ 0xf7, 12099,
+ 0xf8, 12104,
+ 0xf9, 12104,
+ 0xfa, 12104,
+ 0xfb, 12104,
+ 0xfc, 12104,
+ 0xfd, 12104,
+ 0xfe, 12104,
+ 0xff, 12104,
+ /*12038*/ uint16(x86_xCondSlashR),
+ 12047, // 0
+ 12051, // 1
+ 12055, // 2
+ 12059, // 3
+ 12063, // 4
+ 12067, // 5
+ 12071, // 6
+ 12075, // 7
+ /*12047*/ uint16(x86_xSetOp), uint16(x86_FADD),
+ /*12049*/ uint16(x86_xArgM64fp),
+ /*12050*/ uint16(x86_xMatch),
+ /*12051*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+ /*12053*/ uint16(x86_xArgM64fp),
+ /*12054*/ uint16(x86_xMatch),
+ /*12055*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+ /*12057*/ uint16(x86_xArgM64fp),
+ /*12058*/ uint16(x86_xMatch),
+ /*12059*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+ /*12061*/ uint16(x86_xArgM64fp),
+ /*12062*/ uint16(x86_xMatch),
+ /*12063*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+ /*12065*/ uint16(x86_xArgM64fp),
+ /*12066*/ uint16(x86_xMatch),
+ /*12067*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+ /*12069*/ uint16(x86_xArgM64fp),
+ /*12070*/ uint16(x86_xMatch),
+ /*12071*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+ /*12073*/ uint16(x86_xArgM64fp),
+ /*12074*/ uint16(x86_xMatch),
+ /*12075*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+ /*12077*/ uint16(x86_xArgM64fp),
+ /*12078*/ uint16(x86_xMatch),
+ /*12079*/ uint16(x86_xSetOp), uint16(x86_FADD),
+ /*12081*/ uint16(x86_xArgSTi),
+ /*12082*/ uint16(x86_xArgST),
+ /*12083*/ uint16(x86_xMatch),
+ /*12084*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+ /*12086*/ uint16(x86_xArgSTi),
+ /*12087*/ uint16(x86_xArgST),
+ /*12088*/ uint16(x86_xMatch),
+ /*12089*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+ /*12091*/ uint16(x86_xArgSTi),
+ /*12092*/ uint16(x86_xArgST),
+ /*12093*/ uint16(x86_xMatch),
+ /*12094*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+ /*12096*/ uint16(x86_xArgSTi),
+ /*12097*/ uint16(x86_xArgST),
+ /*12098*/ uint16(x86_xMatch),
+ /*12099*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+ /*12101*/ uint16(x86_xArgSTi),
+ /*12102*/ uint16(x86_xArgST),
+ /*12103*/ uint16(x86_xMatch),
+ /*12104*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+ /*12106*/ uint16(x86_xArgSTi),
+ /*12107*/ uint16(x86_xArgST),
+ /*12108*/ uint16(x86_xMatch),
+ /*12109*/ uint16(x86_xCondByte), 40,
+ 0xc0, 12228,
+ 0xc1, 12228,
+ 0xc2, 12228,
+ 0xc3, 12228,
+ 0xc4, 12228,
+ 0xc5, 12228,
+ 0xc6, 12228,
+ 0xc7, 12228,
+ 0xd0, 12232,
+ 0xd1, 12232,
+ 0xd2, 12232,
+ 0xd3, 12232,
+ 0xd4, 12232,
+ 0xd5, 12232,
+ 0xd6, 12232,
+ 0xd7, 12232,
+ 0xd8, 12236,
+ 0xd9, 12236,
+ 0xda, 12236,
+ 0xdb, 12236,
+ 0xdc, 12236,
+ 0xdd, 12236,
+ 0xde, 12236,
+ 0xdf, 12236,
+ 0xe0, 12240,
+ 0xe1, 12240,
+ 0xe2, 12240,
+ 0xe3, 12240,
+ 0xe4, 12240,
+ 0xe5, 12240,
+ 0xe6, 12240,
+ 0xe7, 12240,
+ 0xe8, 12244,
+ 0xe9, 12244,
+ 0xea, 12244,
+ 0xeb, 12244,
+ 0xec, 12244,
+ 0xed, 12244,
+ 0xee, 12244,
+ 0xef, 12244,
+ /*12191*/ uint16(x86_xCondSlashR),
+ 12200, // 0
+ 12204, // 1
+ 12208, // 2
+ 12212, // 3
+ 12216, // 4
+ 0, // 5
+ 12220, // 6
+ 12224, // 7
+ /*12200*/ uint16(x86_xSetOp), uint16(x86_FLD),
+ /*12202*/ uint16(x86_xArgM64fp),
+ /*12203*/ uint16(x86_xMatch),
+ /*12204*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+ /*12206*/ uint16(x86_xArgM64int),
+ /*12207*/ uint16(x86_xMatch),
+ /*12208*/ uint16(x86_xSetOp), uint16(x86_FST),
+ /*12210*/ uint16(x86_xArgM64fp),
+ /*12211*/ uint16(x86_xMatch),
+ /*12212*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+ /*12214*/ uint16(x86_xArgM64fp),
+ /*12215*/ uint16(x86_xMatch),
+ /*12216*/ uint16(x86_xSetOp), uint16(x86_FRSTOR),
+ /*12218*/ uint16(x86_xArgM94108byte),
+ /*12219*/ uint16(x86_xMatch),
+ /*12220*/ uint16(x86_xSetOp), uint16(x86_FNSAVE),
+ /*12222*/ uint16(x86_xArgM94108byte),
+ /*12223*/ uint16(x86_xMatch),
+ /*12224*/ uint16(x86_xSetOp), uint16(x86_FNSTSW),
+ /*12226*/ uint16(x86_xArgM2byte),
+ /*12227*/ uint16(x86_xMatch),
+ /*12228*/ uint16(x86_xSetOp), uint16(x86_FFREE),
+ /*12230*/ uint16(x86_xArgSTi),
+ /*12231*/ uint16(x86_xMatch),
+ /*12232*/ uint16(x86_xSetOp), uint16(x86_FST),
+ /*12234*/ uint16(x86_xArgSTi),
+ /*12235*/ uint16(x86_xMatch),
+ /*12236*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+ /*12238*/ uint16(x86_xArgSTi),
+ /*12239*/ uint16(x86_xMatch),
+ /*12240*/ uint16(x86_xSetOp), uint16(x86_FUCOM),
+ /*12242*/ uint16(x86_xArgSTi),
+ /*12243*/ uint16(x86_xMatch),
+ /*12244*/ uint16(x86_xSetOp), uint16(x86_FUCOMP),
+ /*12246*/ uint16(x86_xArgSTi),
+ /*12247*/ uint16(x86_xMatch),
+ /*12248*/ uint16(x86_xCondByte), 49,
+ 0xc0, 12389,
+ 0xc1, 12389,
+ 0xc2, 12389,
+ 0xc3, 12389,
+ 0xc4, 12389,
+ 0xc5, 12389,
+ 0xc6, 12389,
+ 0xc7, 12389,
+ 0xc8, 12394,
+ 0xc9, 12394,
+ 0xca, 12394,
+ 0xcb, 12394,
+ 0xcc, 12394,
+ 0xcd, 12394,
+ 0xce, 12394,
+ 0xcf, 12394,
+ 0xD9, 12399,
+ 0xe0, 12402,
+ 0xe1, 12402,
+ 0xe2, 12402,
+ 0xe3, 12402,
+ 0xe4, 12402,
+ 0xe5, 12402,
+ 0xe6, 12402,
+ 0xe7, 12402,
+ 0xe8, 12407,
+ 0xe9, 12407,
+ 0xea, 12407,
+ 0xeb, 12407,
+ 0xec, 12407,
+ 0xed, 12407,
+ 0xee, 12407,
+ 0xef, 12407,
+ 0xf0, 12412,
+ 0xf1, 12412,
+ 0xf2, 12412,
+ 0xf3, 12412,
+ 0xf4, 12412,
+ 0xf5, 12412,
+ 0xf6, 12412,
+ 0xf7, 12412,
+ 0xf8, 12417,
+ 0xf9, 12417,
+ 0xfa, 12417,
+ 0xfb, 12417,
+ 0xfc, 12417,
+ 0xfd, 12417,
+ 0xfe, 12417,
+ 0xff, 12417,
+ /*12348*/ uint16(x86_xCondSlashR),
+ 12357, // 0
+ 12361, // 1
+ 12365, // 2
+ 12369, // 3
+ 12373, // 4
+ 12377, // 5
+ 12381, // 6
+ 12385, // 7
+ /*12357*/ uint16(x86_xSetOp), uint16(x86_FIADD),
+ /*12359*/ uint16(x86_xArgM16int),
+ /*12360*/ uint16(x86_xMatch),
+ /*12361*/ uint16(x86_xSetOp), uint16(x86_FIMUL),
+ /*12363*/ uint16(x86_xArgM16int),
+ /*12364*/ uint16(x86_xMatch),
+ /*12365*/ uint16(x86_xSetOp), uint16(x86_FICOM),
+ /*12367*/ uint16(x86_xArgM16int),
+ /*12368*/ uint16(x86_xMatch),
+ /*12369*/ uint16(x86_xSetOp), uint16(x86_FICOMP),
+ /*12371*/ uint16(x86_xArgM16int),
+ /*12372*/ uint16(x86_xMatch),
+ /*12373*/ uint16(x86_xSetOp), uint16(x86_FISUB),
+ /*12375*/ uint16(x86_xArgM16int),
+ /*12376*/ uint16(x86_xMatch),
+ /*12377*/ uint16(x86_xSetOp), uint16(x86_FISUBR),
+ /*12379*/ uint16(x86_xArgM16int),
+ /*12380*/ uint16(x86_xMatch),
+ /*12381*/ uint16(x86_xSetOp), uint16(x86_FIDIV),
+ /*12383*/ uint16(x86_xArgM16int),
+ /*12384*/ uint16(x86_xMatch),
+ /*12385*/ uint16(x86_xSetOp), uint16(x86_FIDIVR),
+ /*12387*/ uint16(x86_xArgM16int),
+ /*12388*/ uint16(x86_xMatch),
+ /*12389*/ uint16(x86_xSetOp), uint16(x86_FADDP),
+ /*12391*/ uint16(x86_xArgSTi),
+ /*12392*/ uint16(x86_xArgST),
+ /*12393*/ uint16(x86_xMatch),
+ /*12394*/ uint16(x86_xSetOp), uint16(x86_FMULP),
+ /*12396*/ uint16(x86_xArgSTi),
+ /*12397*/ uint16(x86_xArgST),
+ /*12398*/ uint16(x86_xMatch),
+ /*12399*/ uint16(x86_xSetOp), uint16(x86_FCOMPP),
+ /*12401*/ uint16(x86_xMatch),
+ /*12402*/ uint16(x86_xSetOp), uint16(x86_FSUBRP),
+ /*12404*/ uint16(x86_xArgSTi),
+ /*12405*/ uint16(x86_xArgST),
+ /*12406*/ uint16(x86_xMatch),
+ /*12407*/ uint16(x86_xSetOp), uint16(x86_FSUBP),
+ /*12409*/ uint16(x86_xArgSTi),
+ /*12410*/ uint16(x86_xArgST),
+ /*12411*/ uint16(x86_xMatch),
+ /*12412*/ uint16(x86_xSetOp), uint16(x86_FDIVRP),
+ /*12414*/ uint16(x86_xArgSTi),
+ /*12415*/ uint16(x86_xArgST),
+ /*12416*/ uint16(x86_xMatch),
+ /*12417*/ uint16(x86_xSetOp), uint16(x86_FDIVP),
+ /*12419*/ uint16(x86_xArgSTi),
+ /*12420*/ uint16(x86_xArgST),
+ /*12421*/ uint16(x86_xMatch),
+ /*12422*/ uint16(x86_xCondByte), 25,
+ 0xc0, 12515,
+ 0xc1, 12515,
+ 0xc2, 12515,
+ 0xc3, 12515,
+ 0xc4, 12515,
+ 0xc5, 12515,
+ 0xc6, 12515,
+ 0xc7, 12515,
+ 0xE0, 12519,
+ 0xe8, 12523,
+ 0xe9, 12523,
+ 0xea, 12523,
+ 0xeb, 12523,
+ 0xec, 12523,
+ 0xed, 12523,
+ 0xee, 12523,
+ 0xef, 12523,
+ 0xf0, 12528,
+ 0xf1, 12528,
+ 0xf2, 12528,
+ 0xf3, 12528,
+ 0xf4, 12528,
+ 0xf5, 12528,
+ 0xf6, 12528,
+ 0xf7, 12528,
+ /*12474*/ uint16(x86_xCondSlashR),
+ 12483, // 0
+ 12487, // 1
+ 12491, // 2
+ 12495, // 3
+ 12499, // 4
+ 12503, // 5
+ 12507, // 6
+ 12511, // 7
+ /*12483*/ uint16(x86_xSetOp), uint16(x86_FILD),
+ /*12485*/ uint16(x86_xArgM16int),
+ /*12486*/ uint16(x86_xMatch),
+ /*12487*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+ /*12489*/ uint16(x86_xArgM16int),
+ /*12490*/ uint16(x86_xMatch),
+ /*12491*/ uint16(x86_xSetOp), uint16(x86_FIST),
+ /*12493*/ uint16(x86_xArgM16int),
+ /*12494*/ uint16(x86_xMatch),
+ /*12495*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+ /*12497*/ uint16(x86_xArgM16int),
+ /*12498*/ uint16(x86_xMatch),
+ /*12499*/ uint16(x86_xSetOp), uint16(x86_FBLD),
+ /*12501*/ uint16(x86_xArgM80dec),
+ /*12502*/ uint16(x86_xMatch),
+ /*12503*/ uint16(x86_xSetOp), uint16(x86_FILD),
+ /*12505*/ uint16(x86_xArgM64int),
+ /*12506*/ uint16(x86_xMatch),
+ /*12507*/ uint16(x86_xSetOp), uint16(x86_FBSTP),
+ /*12509*/ uint16(x86_xArgM80bcd),
+ /*12510*/ uint16(x86_xMatch),
+ /*12511*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+ /*12513*/ uint16(x86_xArgM64int),
+ /*12514*/ uint16(x86_xMatch),
+ /*12515*/ uint16(x86_xSetOp), uint16(x86_FFREEP),
+ /*12517*/ uint16(x86_xArgSTi),
+ /*12518*/ uint16(x86_xMatch),
+ /*12519*/ uint16(x86_xSetOp), uint16(x86_FNSTSW),
+ /*12521*/ uint16(x86_xArgAX),
+ /*12522*/ uint16(x86_xMatch),
+ /*12523*/ uint16(x86_xSetOp), uint16(x86_FUCOMIP),
+ /*12525*/ uint16(x86_xArgST),
+ /*12526*/ uint16(x86_xArgSTi),
+ /*12527*/ uint16(x86_xMatch),
+ /*12528*/ uint16(x86_xSetOp), uint16(x86_FCOMIP),
+ /*12530*/ uint16(x86_xArgST),
+ /*12531*/ uint16(x86_xArgSTi),
+ /*12532*/ uint16(x86_xMatch),
+ /*12533*/ uint16(x86_xSetOp), uint16(x86_LOOPNE),
+ /*12535*/ uint16(x86_xReadCb),
+ /*12536*/ uint16(x86_xArgRel8),
+ /*12537*/ uint16(x86_xMatch),
+ /*12538*/ uint16(x86_xSetOp), uint16(x86_LOOPE),
+ /*12540*/ uint16(x86_xReadCb),
+ /*12541*/ uint16(x86_xArgRel8),
+ /*12542*/ uint16(x86_xMatch),
+ /*12543*/ uint16(x86_xSetOp), uint16(x86_LOOP),
+ /*12545*/ uint16(x86_xReadCb),
+ /*12546*/ uint16(x86_xArgRel8),
+ /*12547*/ uint16(x86_xMatch),
+ /*12548*/ uint16(x86_xCondIs64), 12551, 12565,
+ /*12551*/ uint16(x86_xCondAddrSize), 12555, 12560, 0,
+ /*12555*/ uint16(x86_xSetOp), uint16(x86_JCXZ),
+ /*12557*/ uint16(x86_xReadCb),
+ /*12558*/ uint16(x86_xArgRel8),
+ /*12559*/ uint16(x86_xMatch),
+ /*12560*/ uint16(x86_xSetOp), uint16(x86_JECXZ),
+ /*12562*/ uint16(x86_xReadCb),
+ /*12563*/ uint16(x86_xArgRel8),
+ /*12564*/ uint16(x86_xMatch),
+ /*12565*/ uint16(x86_xCondAddrSize), 0, 12560, 12569,
+ /*12569*/ uint16(x86_xSetOp), uint16(x86_JRCXZ),
+ /*12571*/ uint16(x86_xReadCb),
+ /*12572*/ uint16(x86_xArgRel8),
+ /*12573*/ uint16(x86_xMatch),
+ /*12574*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12576*/ uint16(x86_xReadIb),
+ /*12577*/ uint16(x86_xArgAL),
+ /*12578*/ uint16(x86_xArgImm8u),
+ /*12579*/ uint16(x86_xMatch),
+ /*12580*/ uint16(x86_xCondDataSize), 12584, 12590, 12596,
+ /*12584*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12586*/ uint16(x86_xReadIb),
+ /*12587*/ uint16(x86_xArgAX),
+ /*12588*/ uint16(x86_xArgImm8u),
+ /*12589*/ uint16(x86_xMatch),
+ /*12590*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12592*/ uint16(x86_xReadIb),
+ /*12593*/ uint16(x86_xArgEAX),
+ /*12594*/ uint16(x86_xArgImm8u),
+ /*12595*/ uint16(x86_xMatch),
+ /*12596*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12598*/ uint16(x86_xReadIb),
+ /*12599*/ uint16(x86_xArgEAX),
+ /*12600*/ uint16(x86_xArgImm8u),
+ /*12601*/ uint16(x86_xMatch),
+ /*12602*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12604*/ uint16(x86_xReadIb),
+ /*12605*/ uint16(x86_xArgImm8u),
+ /*12606*/ uint16(x86_xArgAL),
+ /*12607*/ uint16(x86_xMatch),
+ /*12608*/ uint16(x86_xCondDataSize), 12612, 12618, 12624,
+ /*12612*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12614*/ uint16(x86_xReadIb),
+ /*12615*/ uint16(x86_xArgImm8u),
+ /*12616*/ uint16(x86_xArgAX),
+ /*12617*/ uint16(x86_xMatch),
+ /*12618*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12620*/ uint16(x86_xReadIb),
+ /*12621*/ uint16(x86_xArgImm8u),
+ /*12622*/ uint16(x86_xArgEAX),
+ /*12623*/ uint16(x86_xMatch),
+ /*12624*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12626*/ uint16(x86_xReadIb),
+ /*12627*/ uint16(x86_xArgImm8u),
+ /*12628*/ uint16(x86_xArgEAX),
+ /*12629*/ uint16(x86_xMatch),
+ /*12630*/ uint16(x86_xCondIs64), 12633, 12647,
+ /*12633*/ uint16(x86_xCondDataSize), 12637, 12642, 0,
+ /*12637*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*12639*/ uint16(x86_xReadCw),
+ /*12640*/ uint16(x86_xArgRel16),
+ /*12641*/ uint16(x86_xMatch),
+ /*12642*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*12644*/ uint16(x86_xReadCd),
+ /*12645*/ uint16(x86_xArgRel32),
+ /*12646*/ uint16(x86_xMatch),
+ /*12647*/ uint16(x86_xCondDataSize), 12651, 12642, 12656,
+ /*12651*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*12653*/ uint16(x86_xReadCd),
+ /*12654*/ uint16(x86_xArgRel32),
+ /*12655*/ uint16(x86_xMatch),
+ /*12656*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*12658*/ uint16(x86_xReadCd),
+ /*12659*/ uint16(x86_xArgRel32),
+ /*12660*/ uint16(x86_xMatch),
+ /*12661*/ uint16(x86_xCondIs64), 12664, 12678,
+ /*12664*/ uint16(x86_xCondDataSize), 12668, 12673, 0,
+ /*12668*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*12670*/ uint16(x86_xReadCw),
+ /*12671*/ uint16(x86_xArgRel16),
+ /*12672*/ uint16(x86_xMatch),
+ /*12673*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*12675*/ uint16(x86_xReadCd),
+ /*12676*/ uint16(x86_xArgRel32),
+ /*12677*/ uint16(x86_xMatch),
+ /*12678*/ uint16(x86_xCondDataSize), 12682, 12673, 12687,
+ /*12682*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*12684*/ uint16(x86_xReadCd),
+ /*12685*/ uint16(x86_xArgRel32),
+ /*12686*/ uint16(x86_xMatch),
+ /*12687*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*12689*/ uint16(x86_xReadCd),
+ /*12690*/ uint16(x86_xArgRel32),
+ /*12691*/ uint16(x86_xMatch),
+ /*12692*/ uint16(x86_xCondIs64), 12695, 0,
+ /*12695*/ uint16(x86_xCondDataSize), 12699, 12704, 0,
+ /*12699*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+ /*12701*/ uint16(x86_xReadCd),
+ /*12702*/ uint16(x86_xArgPtr16colon16),
+ /*12703*/ uint16(x86_xMatch),
+ /*12704*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+ /*12706*/ uint16(x86_xReadCp),
+ /*12707*/ uint16(x86_xArgPtr16colon32),
+ /*12708*/ uint16(x86_xMatch),
+ /*12709*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*12711*/ uint16(x86_xReadCb),
+ /*12712*/ uint16(x86_xArgRel8),
+ /*12713*/ uint16(x86_xMatch),
+ /*12714*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12716*/ uint16(x86_xArgAL),
+ /*12717*/ uint16(x86_xArgDX),
+ /*12718*/ uint16(x86_xMatch),
+ /*12719*/ uint16(x86_xCondDataSize), 12723, 12728, 12733,
+ /*12723*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12725*/ uint16(x86_xArgAX),
+ /*12726*/ uint16(x86_xArgDX),
+ /*12727*/ uint16(x86_xMatch),
+ /*12728*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12730*/ uint16(x86_xArgEAX),
+ /*12731*/ uint16(x86_xArgDX),
+ /*12732*/ uint16(x86_xMatch),
+ /*12733*/ uint16(x86_xSetOp), uint16(x86_IN),
+ /*12735*/ uint16(x86_xArgEAX),
+ /*12736*/ uint16(x86_xArgDX),
+ /*12737*/ uint16(x86_xMatch),
+ /*12738*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12740*/ uint16(x86_xArgDX),
+ /*12741*/ uint16(x86_xArgAL),
+ /*12742*/ uint16(x86_xMatch),
+ /*12743*/ uint16(x86_xCondDataSize), 12747, 12752, 12757,
+ /*12747*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12749*/ uint16(x86_xArgDX),
+ /*12750*/ uint16(x86_xArgAX),
+ /*12751*/ uint16(x86_xMatch),
+ /*12752*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12754*/ uint16(x86_xArgDX),
+ /*12755*/ uint16(x86_xArgEAX),
+ /*12756*/ uint16(x86_xMatch),
+ /*12757*/ uint16(x86_xSetOp), uint16(x86_OUT),
+ /*12759*/ uint16(x86_xArgDX),
+ /*12760*/ uint16(x86_xArgEAX),
+ /*12761*/ uint16(x86_xMatch),
+ /*12762*/ uint16(x86_xSetOp), uint16(x86_ICEBP),
+ /*12764*/ uint16(x86_xMatch),
+ /*12765*/ uint16(x86_xSetOp), uint16(x86_HLT),
+ /*12767*/ uint16(x86_xMatch),
+ /*12768*/ uint16(x86_xSetOp), uint16(x86_CMC),
+ /*12770*/ uint16(x86_xMatch),
+ /*12771*/ uint16(x86_xCondSlashR),
+ 12780, // 0
+ 0, // 1
+ 12786, // 2
+ 12790, // 3
+ 12794, // 4
+ 12798, // 5
+ 12802, // 6
+ 12806, // 7
+ /*12780*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*12782*/ uint16(x86_xReadIb),
+ /*12783*/ uint16(x86_xArgRM8),
+ /*12784*/ uint16(x86_xArgImm8u),
+ /*12785*/ uint16(x86_xMatch),
+ /*12786*/ uint16(x86_xSetOp), uint16(x86_NOT),
+ /*12788*/ uint16(x86_xArgRM8),
+ /*12789*/ uint16(x86_xMatch),
+ /*12790*/ uint16(x86_xSetOp), uint16(x86_NEG),
+ /*12792*/ uint16(x86_xArgRM8),
+ /*12793*/ uint16(x86_xMatch),
+ /*12794*/ uint16(x86_xSetOp), uint16(x86_MUL),
+ /*12796*/ uint16(x86_xArgRM8),
+ /*12797*/ uint16(x86_xMatch),
+ /*12798*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*12800*/ uint16(x86_xArgRM8),
+ /*12801*/ uint16(x86_xMatch),
+ /*12802*/ uint16(x86_xSetOp), uint16(x86_DIV),
+ /*12804*/ uint16(x86_xArgRM8),
+ /*12805*/ uint16(x86_xMatch),
+ /*12806*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+ /*12808*/ uint16(x86_xArgRM8),
+ /*12809*/ uint16(x86_xMatch),
+ /*12810*/ uint16(x86_xCondSlashR),
+ 12819, // 0
+ 0, // 1
+ 12848, // 2
+ 12871, // 3
+ 12894, // 4
+ 12917, // 5
+ 12940, // 6
+ 12963, // 7
+ /*12819*/ uint16(x86_xCondIs64), 12822, 12838,
+ /*12822*/ uint16(x86_xCondDataSize), 12826, 12832, 0,
+ /*12826*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*12828*/ uint16(x86_xReadIw),
+ /*12829*/ uint16(x86_xArgRM16),
+ /*12830*/ uint16(x86_xArgImm16),
+ /*12831*/ uint16(x86_xMatch),
+ /*12832*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*12834*/ uint16(x86_xReadId),
+ /*12835*/ uint16(x86_xArgRM32),
+ /*12836*/ uint16(x86_xArgImm32),
+ /*12837*/ uint16(x86_xMatch),
+ /*12838*/ uint16(x86_xCondDataSize), 12826, 12832, 12842,
+ /*12842*/ uint16(x86_xSetOp), uint16(x86_TEST),
+ /*12844*/ uint16(x86_xReadId),
+ /*12845*/ uint16(x86_xArgRM64),
+ /*12846*/ uint16(x86_xArgImm32),
+ /*12847*/ uint16(x86_xMatch),
+ /*12848*/ uint16(x86_xCondIs64), 12851, 12863,
+ /*12851*/ uint16(x86_xCondDataSize), 12855, 12859, 0,
+ /*12855*/ uint16(x86_xSetOp), uint16(x86_NOT),
+ /*12857*/ uint16(x86_xArgRM16),
+ /*12858*/ uint16(x86_xMatch),
+ /*12859*/ uint16(x86_xSetOp), uint16(x86_NOT),
+ /*12861*/ uint16(x86_xArgRM32),
+ /*12862*/ uint16(x86_xMatch),
+ /*12863*/ uint16(x86_xCondDataSize), 12855, 12859, 12867,
+ /*12867*/ uint16(x86_xSetOp), uint16(x86_NOT),
+ /*12869*/ uint16(x86_xArgRM64),
+ /*12870*/ uint16(x86_xMatch),
+ /*12871*/ uint16(x86_xCondIs64), 12874, 12886,
+ /*12874*/ uint16(x86_xCondDataSize), 12878, 12882, 0,
+ /*12878*/ uint16(x86_xSetOp), uint16(x86_NEG),
+ /*12880*/ uint16(x86_xArgRM16),
+ /*12881*/ uint16(x86_xMatch),
+ /*12882*/ uint16(x86_xSetOp), uint16(x86_NEG),
+ /*12884*/ uint16(x86_xArgRM32),
+ /*12885*/ uint16(x86_xMatch),
+ /*12886*/ uint16(x86_xCondDataSize), 12878, 12882, 12890,
+ /*12890*/ uint16(x86_xSetOp), uint16(x86_NEG),
+ /*12892*/ uint16(x86_xArgRM64),
+ /*12893*/ uint16(x86_xMatch),
+ /*12894*/ uint16(x86_xCondIs64), 12897, 12909,
+ /*12897*/ uint16(x86_xCondDataSize), 12901, 12905, 0,
+ /*12901*/ uint16(x86_xSetOp), uint16(x86_MUL),
+ /*12903*/ uint16(x86_xArgRM16),
+ /*12904*/ uint16(x86_xMatch),
+ /*12905*/ uint16(x86_xSetOp), uint16(x86_MUL),
+ /*12907*/ uint16(x86_xArgRM32),
+ /*12908*/ uint16(x86_xMatch),
+ /*12909*/ uint16(x86_xCondDataSize), 12901, 12905, 12913,
+ /*12913*/ uint16(x86_xSetOp), uint16(x86_MUL),
+ /*12915*/ uint16(x86_xArgRM64),
+ /*12916*/ uint16(x86_xMatch),
+ /*12917*/ uint16(x86_xCondIs64), 12920, 12932,
+ /*12920*/ uint16(x86_xCondDataSize), 12924, 12928, 0,
+ /*12924*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*12926*/ uint16(x86_xArgRM16),
+ /*12927*/ uint16(x86_xMatch),
+ /*12928*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*12930*/ uint16(x86_xArgRM32),
+ /*12931*/ uint16(x86_xMatch),
+ /*12932*/ uint16(x86_xCondDataSize), 12924, 12928, 12936,
+ /*12936*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+ /*12938*/ uint16(x86_xArgRM64),
+ /*12939*/ uint16(x86_xMatch),
+ /*12940*/ uint16(x86_xCondIs64), 12943, 12955,
+ /*12943*/ uint16(x86_xCondDataSize), 12947, 12951, 0,
+ /*12947*/ uint16(x86_xSetOp), uint16(x86_DIV),
+ /*12949*/ uint16(x86_xArgRM16),
+ /*12950*/ uint16(x86_xMatch),
+ /*12951*/ uint16(x86_xSetOp), uint16(x86_DIV),
+ /*12953*/ uint16(x86_xArgRM32),
+ /*12954*/ uint16(x86_xMatch),
+ /*12955*/ uint16(x86_xCondDataSize), 12947, 12951, 12959,
+ /*12959*/ uint16(x86_xSetOp), uint16(x86_DIV),
+ /*12961*/ uint16(x86_xArgRM64),
+ /*12962*/ uint16(x86_xMatch),
+ /*12963*/ uint16(x86_xCondIs64), 12966, 12978,
+ /*12966*/ uint16(x86_xCondDataSize), 12970, 12974, 0,
+ /*12970*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+ /*12972*/ uint16(x86_xArgRM16),
+ /*12973*/ uint16(x86_xMatch),
+ /*12974*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+ /*12976*/ uint16(x86_xArgRM32),
+ /*12977*/ uint16(x86_xMatch),
+ /*12978*/ uint16(x86_xCondDataSize), 12970, 12974, 12982,
+ /*12982*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+ /*12984*/ uint16(x86_xArgRM64),
+ /*12985*/ uint16(x86_xMatch),
+ /*12986*/ uint16(x86_xSetOp), uint16(x86_CLC),
+ /*12988*/ uint16(x86_xMatch),
+ /*12989*/ uint16(x86_xSetOp), uint16(x86_STC),
+ /*12991*/ uint16(x86_xMatch),
+ /*12992*/ uint16(x86_xSetOp), uint16(x86_CLI),
+ /*12994*/ uint16(x86_xMatch),
+ /*12995*/ uint16(x86_xSetOp), uint16(x86_STI),
+ /*12997*/ uint16(x86_xMatch),
+ /*12998*/ uint16(x86_xSetOp), uint16(x86_CLD),
+ /*13000*/ uint16(x86_xMatch),
+ /*13001*/ uint16(x86_xSetOp), uint16(x86_STD),
+ /*13003*/ uint16(x86_xMatch),
+ /*13004*/ uint16(x86_xCondSlashR),
+ 13013, // 0
+ 13017, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ /*13013*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*13015*/ uint16(x86_xArgRM8),
+ /*13016*/ uint16(x86_xMatch),
+ /*13017*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*13019*/ uint16(x86_xArgRM8),
+ /*13020*/ uint16(x86_xMatch),
+ /*13021*/ uint16(x86_xCondSlashR),
+ 13030, // 0
+ 13053, // 1
+ 13076, // 2
+ 13095, // 3
+ 13118, // 4
+ 13137, // 5
+ 13160, // 6
+ 0, // 7
+ /*13030*/ uint16(x86_xCondIs64), 13033, 13045,
+ /*13033*/ uint16(x86_xCondDataSize), 13037, 13041, 0,
+ /*13037*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*13039*/ uint16(x86_xArgRM16),
+ /*13040*/ uint16(x86_xMatch),
+ /*13041*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*13043*/ uint16(x86_xArgRM32),
+ /*13044*/ uint16(x86_xMatch),
+ /*13045*/ uint16(x86_xCondDataSize), 13037, 13041, 13049,
+ /*13049*/ uint16(x86_xSetOp), uint16(x86_INC),
+ /*13051*/ uint16(x86_xArgRM64),
+ /*13052*/ uint16(x86_xMatch),
+ /*13053*/ uint16(x86_xCondIs64), 13056, 13068,
+ /*13056*/ uint16(x86_xCondDataSize), 13060, 13064, 0,
+ /*13060*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*13062*/ uint16(x86_xArgRM16),
+ /*13063*/ uint16(x86_xMatch),
+ /*13064*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*13066*/ uint16(x86_xArgRM32),
+ /*13067*/ uint16(x86_xMatch),
+ /*13068*/ uint16(x86_xCondDataSize), 13060, 13064, 13072,
+ /*13072*/ uint16(x86_xSetOp), uint16(x86_DEC),
+ /*13074*/ uint16(x86_xArgRM64),
+ /*13075*/ uint16(x86_xMatch),
+ /*13076*/ uint16(x86_xCondIs64), 13079, 13091,
+ /*13079*/ uint16(x86_xCondDataSize), 13083, 13087, 0,
+ /*13083*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*13085*/ uint16(x86_xArgRM16),
+ /*13086*/ uint16(x86_xMatch),
+ /*13087*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*13089*/ uint16(x86_xArgRM32),
+ /*13090*/ uint16(x86_xMatch),
+ /*13091*/ uint16(x86_xSetOp), uint16(x86_CALL),
+ /*13093*/ uint16(x86_xArgRM64),
+ /*13094*/ uint16(x86_xMatch),
+ /*13095*/ uint16(x86_xCondIs64), 13098, 13110,
+ /*13098*/ uint16(x86_xCondDataSize), 13102, 13106, 0,
+ /*13102*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+ /*13104*/ uint16(x86_xArgM16colon16),
+ /*13105*/ uint16(x86_xMatch),
+ /*13106*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+ /*13108*/ uint16(x86_xArgM16colon32),
+ /*13109*/ uint16(x86_xMatch),
+ /*13110*/ uint16(x86_xCondDataSize), 13102, 13106, 13114,
+ /*13114*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+ /*13116*/ uint16(x86_xArgM16colon64),
+ /*13117*/ uint16(x86_xMatch),
+ /*13118*/ uint16(x86_xCondIs64), 13121, 13133,
+ /*13121*/ uint16(x86_xCondDataSize), 13125, 13129, 0,
+ /*13125*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*13127*/ uint16(x86_xArgRM16),
+ /*13128*/ uint16(x86_xMatch),
+ /*13129*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*13131*/ uint16(x86_xArgRM32),
+ /*13132*/ uint16(x86_xMatch),
+ /*13133*/ uint16(x86_xSetOp), uint16(x86_JMP),
+ /*13135*/ uint16(x86_xArgRM64),
+ /*13136*/ uint16(x86_xMatch),
+ /*13137*/ uint16(x86_xCondIs64), 13140, 13152,
+ /*13140*/ uint16(x86_xCondDataSize), 13144, 13148, 0,
+ /*13144*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+ /*13146*/ uint16(x86_xArgM16colon16),
+ /*13147*/ uint16(x86_xMatch),
+ /*13148*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+ /*13150*/ uint16(x86_xArgM16colon32),
+ /*13151*/ uint16(x86_xMatch),
+ /*13152*/ uint16(x86_xCondDataSize), 13144, 13148, 13156,
+ /*13156*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+ /*13158*/ uint16(x86_xArgM16colon64),
+ /*13159*/ uint16(x86_xMatch),
+ /*13160*/ uint16(x86_xCondIs64), 13163, 13175,
+ /*13163*/ uint16(x86_xCondDataSize), 13167, 13171, 0,
+ /*13167*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*13169*/ uint16(x86_xArgRM16),
+ /*13170*/ uint16(x86_xMatch),
+ /*13171*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*13173*/ uint16(x86_xArgRM32),
+ /*13174*/ uint16(x86_xMatch),
+ /*13175*/ uint16(x86_xCondDataSize), 13167, 13179, 13183,
+ /*13179*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*13181*/ uint16(x86_xArgRM64),
+ /*13182*/ uint16(x86_xMatch),
+ /*13183*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+ /*13185*/ uint16(x86_xArgRM64),
+ /*13186*/ uint16(x86_xMatch),
+}
+
+const (
+ _ x86_Op = iota
+
+ x86_AAA
+ x86_AAD
+ x86_AAM
+ x86_AAS
+ x86_ADC
+ x86_ADD
+ x86_ADDPD
+ x86_ADDPS
+ x86_ADDSD
+ x86_ADDSS
+ x86_ADDSUBPD
+ x86_ADDSUBPS
+ x86_AESDEC
+ x86_AESDECLAST
+ x86_AESENC
+ x86_AESENCLAST
+ x86_AESIMC
+ x86_AESKEYGENASSIST
+ x86_AND
+ x86_ANDNPD
+ x86_ANDNPS
+ x86_ANDPD
+ x86_ANDPS
+ x86_ARPL
+ x86_BLENDPD
+ x86_BLENDPS
+ x86_BLENDVPD
+ x86_BLENDVPS
+ x86_BOUND
+ x86_BSF
+ x86_BSR
+ x86_BSWAP
+ x86_BT
+ x86_BTC
+ x86_BTR
+ x86_BTS
+ x86_CALL
+ x86_CBW
+ x86_CDQ
+ x86_CDQE
+ x86_CLC
+ x86_CLD
+ x86_CLFLUSH
+ x86_CLI
+ x86_CLTS
+ x86_CMC
+ x86_CMOVA
+ x86_CMOVAE
+ x86_CMOVB
+ x86_CMOVBE
+ x86_CMOVE
+ x86_CMOVG
+ x86_CMOVGE
+ x86_CMOVL
+ x86_CMOVLE
+ x86_CMOVNE
+ x86_CMOVNO
+ x86_CMOVNP
+ x86_CMOVNS
+ x86_CMOVO
+ x86_CMOVP
+ x86_CMOVS
+ x86_CMP
+ x86_CMPPD
+ x86_CMPPS
+ x86_CMPSB
+ x86_CMPSD
+ x86_CMPSD_XMM
+ x86_CMPSQ
+ x86_CMPSS
+ x86_CMPSW
+ x86_CMPXCHG
+ x86_CMPXCHG16B
+ x86_CMPXCHG8B
+ x86_COMISD
+ x86_COMISS
+ x86_CPUID
+ x86_CQO
+ x86_CRC32
+ x86_CVTDQ2PD
+ x86_CVTDQ2PS
+ x86_CVTPD2DQ
+ x86_CVTPD2PI
+ x86_CVTPD2PS
+ x86_CVTPI2PD
+ x86_CVTPI2PS
+ x86_CVTPS2DQ
+ x86_CVTPS2PD
+ x86_CVTPS2PI
+ x86_CVTSD2SI
+ x86_CVTSD2SS
+ x86_CVTSI2SD
+ x86_CVTSI2SS
+ x86_CVTSS2SD
+ x86_CVTSS2SI
+ x86_CVTTPD2DQ
+ x86_CVTTPD2PI
+ x86_CVTTPS2DQ
+ x86_CVTTPS2PI
+ x86_CVTTSD2SI
+ x86_CVTTSS2SI
+ x86_CWD
+ x86_CWDE
+ x86_DAA
+ x86_DAS
+ x86_DEC
+ x86_DIV
+ x86_DIVPD
+ x86_DIVPS
+ x86_DIVSD
+ x86_DIVSS
+ x86_DPPD
+ x86_DPPS
+ x86_EMMS
+ x86_ENTER
+ x86_EXTRACTPS
+ x86_F2XM1
+ x86_FABS
+ x86_FADD
+ x86_FADDP
+ x86_FBLD
+ x86_FBSTP
+ x86_FCHS
+ x86_FCMOVB
+ x86_FCMOVBE
+ x86_FCMOVE
+ x86_FCMOVNB
+ x86_FCMOVNBE
+ x86_FCMOVNE
+ x86_FCMOVNU
+ x86_FCMOVU
+ x86_FCOM
+ x86_FCOMI
+ x86_FCOMIP
+ x86_FCOMP
+ x86_FCOMPP
+ x86_FCOS
+ x86_FDECSTP
+ x86_FDIV
+ x86_FDIVP
+ x86_FDIVR
+ x86_FDIVRP
+ x86_FFREE
+ x86_FFREEP
+ x86_FIADD
+ x86_FICOM
+ x86_FICOMP
+ x86_FIDIV
+ x86_FIDIVR
+ x86_FILD
+ x86_FIMUL
+ x86_FINCSTP
+ x86_FIST
+ x86_FISTP
+ x86_FISTTP
+ x86_FISUB
+ x86_FISUBR
+ x86_FLD
+ x86_FLD1
+ x86_FLDCW
+ x86_FLDENV
+ x86_FLDL2E
+ x86_FLDL2T
+ x86_FLDLG2
+ x86_FLDPI
+ x86_FMUL
+ x86_FMULP
+ x86_FNCLEX
+ x86_FNINIT
+ x86_FNOP
+ x86_FNSAVE
+ x86_FNSTCW
+ x86_FNSTENV
+ x86_FNSTSW
+ x86_FPATAN
+ x86_FPREM
+ x86_FPREM1
+ x86_FPTAN
+ x86_FRNDINT
+ x86_FRSTOR
+ x86_FSCALE
+ x86_FSIN
+ x86_FSINCOS
+ x86_FSQRT
+ x86_FST
+ x86_FSTP
+ x86_FSUB
+ x86_FSUBP
+ x86_FSUBR
+ x86_FSUBRP
+ x86_FTST
+ x86_FUCOM
+ x86_FUCOMI
+ x86_FUCOMIP
+ x86_FUCOMP
+ x86_FUCOMPP
+ x86_FWAIT
+ x86_FXAM
+ x86_FXCH
+ x86_FXRSTOR
+ x86_FXRSTOR64
+ x86_FXSAVE
+ x86_FXSAVE64
+ x86_FXTRACT
+ x86_FYL2X
+ x86_FYL2XP1
+ x86_HADDPD
+ x86_HADDPS
+ x86_HLT
+ x86_HSUBPD
+ x86_HSUBPS
+ x86_ICEBP
+ x86_IDIV
+ x86_IMUL
+ x86_IN
+ x86_INC
+ x86_INSB
+ x86_INSD
+ x86_INSERTPS
+ x86_INSW
+ x86_INT
+ x86_INTO
+ x86_INVD
+ x86_INVLPG
+ x86_INVPCID
+ x86_IRET
+ x86_IRETD
+ x86_IRETQ
+ x86_JA
+ x86_JAE
+ x86_JB
+ x86_JBE
+ x86_JCXZ
+ x86_JE
+ x86_JECXZ
+ x86_JG
+ x86_JGE
+ x86_JL
+ x86_JLE
+ x86_JMP
+ x86_JNE
+ x86_JNO
+ x86_JNP
+ x86_JNS
+ x86_JO
+ x86_JP
+ x86_JRCXZ
+ x86_JS
+ x86_LAHF
+ x86_LAR
+ x86_LCALL
+ x86_LDDQU
+ x86_LDMXCSR
+ x86_LDS
+ x86_LEA
+ x86_LEAVE
+ x86_LES
+ x86_LFENCE
+ x86_LFS
+ x86_LGDT
+ x86_LGS
+ x86_LIDT
+ x86_LJMP
+ x86_LLDT
+ x86_LMSW
+ x86_LODSB
+ x86_LODSD
+ x86_LODSQ
+ x86_LODSW
+ x86_LOOP
+ x86_LOOPE
+ x86_LOOPNE
+ x86_LRET
+ x86_LSL
+ x86_LSS
+ x86_LTR
+ x86_LZCNT
+ x86_MASKMOVDQU
+ x86_MASKMOVQ
+ x86_MAXPD
+ x86_MAXPS
+ x86_MAXSD
+ x86_MAXSS
+ x86_MFENCE
+ x86_MINPD
+ x86_MINPS
+ x86_MINSD
+ x86_MINSS
+ x86_MONITOR
+ x86_MOV
+ x86_MOVAPD
+ x86_MOVAPS
+ x86_MOVBE
+ x86_MOVD
+ x86_MOVDDUP
+ x86_MOVDQ2Q
+ x86_MOVDQA
+ x86_MOVDQU
+ x86_MOVHLPS
+ x86_MOVHPD
+ x86_MOVHPS
+ x86_MOVLHPS
+ x86_MOVLPD
+ x86_MOVLPS
+ x86_MOVMSKPD
+ x86_MOVMSKPS
+ x86_MOVNTDQ
+ x86_MOVNTDQA
+ x86_MOVNTI
+ x86_MOVNTPD
+ x86_MOVNTPS
+ x86_MOVNTQ
+ x86_MOVNTSD
+ x86_MOVNTSS
+ x86_MOVQ
+ x86_MOVQ2DQ
+ x86_MOVSB
+ x86_MOVSD
+ x86_MOVSD_XMM
+ x86_MOVSHDUP
+ x86_MOVSLDUP
+ x86_MOVSQ
+ x86_MOVSS
+ x86_MOVSW
+ x86_MOVSX
+ x86_MOVSXD
+ x86_MOVUPD
+ x86_MOVUPS
+ x86_MOVZX
+ x86_MPSADBW
+ x86_MUL
+ x86_MULPD
+ x86_MULPS
+ x86_MULSD
+ x86_MULSS
+ x86_MWAIT
+ x86_NEG
+ x86_NOP
+ x86_NOT
+ x86_OR
+ x86_ORPD
+ x86_ORPS
+ x86_OUT
+ x86_OUTSB
+ x86_OUTSD
+ x86_OUTSW
+ x86_PABSB
+ x86_PABSD
+ x86_PABSW
+ x86_PACKSSDW
+ x86_PACKSSWB
+ x86_PACKUSDW
+ x86_PACKUSWB
+ x86_PADDB
+ x86_PADDD
+ x86_PADDQ
+ x86_PADDSB
+ x86_PADDSW
+ x86_PADDUSB
+ x86_PADDUSW
+ x86_PADDW
+ x86_PALIGNR
+ x86_PAND
+ x86_PANDN
+ x86_PAUSE
+ x86_PAVGB
+ x86_PAVGW
+ x86_PBLENDVB
+ x86_PBLENDW
+ x86_PCLMULQDQ
+ x86_PCMPEQB
+ x86_PCMPEQD
+ x86_PCMPEQQ
+ x86_PCMPEQW
+ x86_PCMPESTRI
+ x86_PCMPESTRM
+ x86_PCMPGTB
+ x86_PCMPGTD
+ x86_PCMPGTQ
+ x86_PCMPGTW
+ x86_PCMPISTRI
+ x86_PCMPISTRM
+ x86_PEXTRB
+ x86_PEXTRD
+ x86_PEXTRQ
+ x86_PEXTRW
+ x86_PHADDD
+ x86_PHADDSW
+ x86_PHADDW
+ x86_PHMINPOSUW
+ x86_PHSUBD
+ x86_PHSUBSW
+ x86_PHSUBW
+ x86_PINSRB
+ x86_PINSRD
+ x86_PINSRQ
+ x86_PINSRW
+ x86_PMADDUBSW
+ x86_PMADDWD
+ x86_PMAXSB
+ x86_PMAXSD
+ x86_PMAXSW
+ x86_PMAXUB
+ x86_PMAXUD
+ x86_PMAXUW
+ x86_PMINSB
+ x86_PMINSD
+ x86_PMINSW
+ x86_PMINUB
+ x86_PMINUD
+ x86_PMINUW
+ x86_PMOVMSKB
+ x86_PMOVSXBD
+ x86_PMOVSXBQ
+ x86_PMOVSXBW
+ x86_PMOVSXDQ
+ x86_PMOVSXWD
+ x86_PMOVSXWQ
+ x86_PMOVZXBD
+ x86_PMOVZXBQ
+ x86_PMOVZXBW
+ x86_PMOVZXDQ
+ x86_PMOVZXWD
+ x86_PMOVZXWQ
+ x86_PMULDQ
+ x86_PMULHRSW
+ x86_PMULHUW
+ x86_PMULHW
+ x86_PMULLD
+ x86_PMULLW
+ x86_PMULUDQ
+ x86_POP
+ x86_POPA
+ x86_POPAD
+ x86_POPCNT
+ x86_POPF
+ x86_POPFD
+ x86_POPFQ
+ x86_POR
+ x86_PREFETCHNTA
+ x86_PREFETCHT0
+ x86_PREFETCHT1
+ x86_PREFETCHT2
+ x86_PREFETCHW
+ x86_PSADBW
+ x86_PSHUFB
+ x86_PSHUFD
+ x86_PSHUFHW
+ x86_PSHUFLW
+ x86_PSHUFW
+ x86_PSIGNB
+ x86_PSIGND
+ x86_PSIGNW
+ x86_PSLLD
+ x86_PSLLDQ
+ x86_PSLLQ
+ x86_PSLLW
+ x86_PSRAD
+ x86_PSRAW
+ x86_PSRLD
+ x86_PSRLDQ
+ x86_PSRLQ
+ x86_PSRLW
+ x86_PSUBB
+ x86_PSUBD
+ x86_PSUBQ
+ x86_PSUBSB
+ x86_PSUBSW
+ x86_PSUBUSB
+ x86_PSUBUSW
+ x86_PSUBW
+ x86_PTEST
+ x86_PUNPCKHBW
+ x86_PUNPCKHDQ
+ x86_PUNPCKHQDQ
+ x86_PUNPCKHWD
+ x86_PUNPCKLBW
+ x86_PUNPCKLDQ
+ x86_PUNPCKLQDQ
+ x86_PUNPCKLWD
+ x86_PUSH
+ x86_PUSHA
+ x86_PUSHAD
+ x86_PUSHF
+ x86_PUSHFD
+ x86_PUSHFQ
+ x86_PXOR
+ x86_RCL
+ x86_RCPPS
+ x86_RCPSS
+ x86_RCR
+ x86_RDFSBASE
+ x86_RDGSBASE
+ x86_RDMSR
+ x86_RDPMC
+ x86_RDRAND
+ x86_RDTSC
+ x86_RDTSCP
+ x86_RET
+ x86_ROL
+ x86_ROR
+ x86_ROUNDPD
+ x86_ROUNDPS
+ x86_ROUNDSD
+ x86_ROUNDSS
+ x86_RSM
+ x86_RSQRTPS
+ x86_RSQRTSS
+ x86_SAHF
+ x86_SAR
+ x86_SBB
+ x86_SCASB
+ x86_SCASD
+ x86_SCASQ
+ x86_SCASW
+ x86_SETA
+ x86_SETAE
+ x86_SETB
+ x86_SETBE
+ x86_SETE
+ x86_SETG
+ x86_SETGE
+ x86_SETL
+ x86_SETLE
+ x86_SETNE
+ x86_SETNO
+ x86_SETNP
+ x86_SETNS
+ x86_SETO
+ x86_SETP
+ x86_SETS
+ x86_SFENCE
+ x86_SGDT
+ x86_SHL
+ x86_SHLD
+ x86_SHR
+ x86_SHRD
+ x86_SHUFPD
+ x86_SHUFPS
+ x86_SIDT
+ x86_SLDT
+ x86_SMSW
+ x86_SQRTPD
+ x86_SQRTPS
+ x86_SQRTSD
+ x86_SQRTSS
+ x86_STC
+ x86_STD
+ x86_STI
+ x86_STMXCSR
+ x86_STOSB
+ x86_STOSD
+ x86_STOSQ
+ x86_STOSW
+ x86_STR
+ x86_SUB
+ x86_SUBPD
+ x86_SUBPS
+ x86_SUBSD
+ x86_SUBSS
+ x86_SWAPGS
+ x86_SYSCALL
+ x86_SYSENTER
+ x86_SYSEXIT
+ x86_SYSRET
+ x86_TEST
+ x86_TZCNT
+ x86_UCOMISD
+ x86_UCOMISS
+ x86_UD1
+ x86_UD2
+ x86_UNPCKHPD
+ x86_UNPCKHPS
+ x86_UNPCKLPD
+ x86_UNPCKLPS
+ x86_VERR
+ x86_VERW
+ x86_WBINVD
+ x86_WRFSBASE
+ x86_WRGSBASE
+ x86_WRMSR
+ x86_XABORT
+ x86_XADD
+ x86_XBEGIN
+ x86_XCHG
+ x86_XEND
+ x86_XGETBV
+ x86_XLATB
+ x86_XOR
+ x86_XORPD
+ x86_XORPS
+ x86_XRSTOR
+ x86_XRSTOR64
+ x86_XRSTORS
+ x86_XRSTORS64
+ x86_XSAVE
+ x86_XSAVE64
+ x86_XSAVEC
+ x86_XSAVEC64
+ x86_XSAVEOPT
+ x86_XSAVEOPT64
+ x86_XSAVES
+ x86_XSAVES64
+ x86_XSETBV
+ x86_XTEST
+)
+
+const x86_maxOp = x86_XTEST
+
+var x86_opNames = [...]string{
+ x86_AAA: "AAA",
+ x86_AAD: "AAD",
+ x86_AAM: "AAM",
+ x86_AAS: "AAS",
+ x86_ADC: "ADC",
+ x86_ADD: "ADD",
+ x86_ADDPD: "ADDPD",
+ x86_ADDPS: "ADDPS",
+ x86_ADDSD: "ADDSD",
+ x86_ADDSS: "ADDSS",
+ x86_ADDSUBPD: "ADDSUBPD",
+ x86_ADDSUBPS: "ADDSUBPS",
+ x86_AESDEC: "AESDEC",
+ x86_AESDECLAST: "AESDECLAST",
+ x86_AESENC: "AESENC",
+ x86_AESENCLAST: "AESENCLAST",
+ x86_AESIMC: "AESIMC",
+ x86_AESKEYGENASSIST: "AESKEYGENASSIST",
+ x86_AND: "AND",
+ x86_ANDNPD: "ANDNPD",
+ x86_ANDNPS: "ANDNPS",
+ x86_ANDPD: "ANDPD",
+ x86_ANDPS: "ANDPS",
+ x86_ARPL: "ARPL",
+ x86_BLENDPD: "BLENDPD",
+ x86_BLENDPS: "BLENDPS",
+ x86_BLENDVPD: "BLENDVPD",
+ x86_BLENDVPS: "BLENDVPS",
+ x86_BOUND: "BOUND",
+ x86_BSF: "BSF",
+ x86_BSR: "BSR",
+ x86_BSWAP: "BSWAP",
+ x86_BT: "BT",
+ x86_BTC: "BTC",
+ x86_BTR: "BTR",
+ x86_BTS: "BTS",
+ x86_CALL: "CALL",
+ x86_CBW: "CBW",
+ x86_CDQ: "CDQ",
+ x86_CDQE: "CDQE",
+ x86_CLC: "CLC",
+ x86_CLD: "CLD",
+ x86_CLFLUSH: "CLFLUSH",
+ x86_CLI: "CLI",
+ x86_CLTS: "CLTS",
+ x86_CMC: "CMC",
+ x86_CMOVA: "CMOVA",
+ x86_CMOVAE: "CMOVAE",
+ x86_CMOVB: "CMOVB",
+ x86_CMOVBE: "CMOVBE",
+ x86_CMOVE: "CMOVE",
+ x86_CMOVG: "CMOVG",
+ x86_CMOVGE: "CMOVGE",
+ x86_CMOVL: "CMOVL",
+ x86_CMOVLE: "CMOVLE",
+ x86_CMOVNE: "CMOVNE",
+ x86_CMOVNO: "CMOVNO",
+ x86_CMOVNP: "CMOVNP",
+ x86_CMOVNS: "CMOVNS",
+ x86_CMOVO: "CMOVO",
+ x86_CMOVP: "CMOVP",
+ x86_CMOVS: "CMOVS",
+ x86_CMP: "CMP",
+ x86_CMPPD: "CMPPD",
+ x86_CMPPS: "CMPPS",
+ x86_CMPSB: "CMPSB",
+ x86_CMPSD: "CMPSD",
+ x86_CMPSD_XMM: "CMPSD_XMM",
+ x86_CMPSQ: "CMPSQ",
+ x86_CMPSS: "CMPSS",
+ x86_CMPSW: "CMPSW",
+ x86_CMPXCHG: "CMPXCHG",
+ x86_CMPXCHG16B: "CMPXCHG16B",
+ x86_CMPXCHG8B: "CMPXCHG8B",
+ x86_COMISD: "COMISD",
+ x86_COMISS: "COMISS",
+ x86_CPUID: "CPUID",
+ x86_CQO: "CQO",
+ x86_CRC32: "CRC32",
+ x86_CVTDQ2PD: "CVTDQ2PD",
+ x86_CVTDQ2PS: "CVTDQ2PS",
+ x86_CVTPD2DQ: "CVTPD2DQ",
+ x86_CVTPD2PI: "CVTPD2PI",
+ x86_CVTPD2PS: "CVTPD2PS",
+ x86_CVTPI2PD: "CVTPI2PD",
+ x86_CVTPI2PS: "CVTPI2PS",
+ x86_CVTPS2DQ: "CVTPS2DQ",
+ x86_CVTPS2PD: "CVTPS2PD",
+ x86_CVTPS2PI: "CVTPS2PI",
+ x86_CVTSD2SI: "CVTSD2SI",
+ x86_CVTSD2SS: "CVTSD2SS",
+ x86_CVTSI2SD: "CVTSI2SD",
+ x86_CVTSI2SS: "CVTSI2SS",
+ x86_CVTSS2SD: "CVTSS2SD",
+ x86_CVTSS2SI: "CVTSS2SI",
+ x86_CVTTPD2DQ: "CVTTPD2DQ",
+ x86_CVTTPD2PI: "CVTTPD2PI",
+ x86_CVTTPS2DQ: "CVTTPS2DQ",
+ x86_CVTTPS2PI: "CVTTPS2PI",
+ x86_CVTTSD2SI: "CVTTSD2SI",
+ x86_CVTTSS2SI: "CVTTSS2SI",
+ x86_CWD: "CWD",
+ x86_CWDE: "CWDE",
+ x86_DAA: "DAA",
+ x86_DAS: "DAS",
+ x86_DEC: "DEC",
+ x86_DIV: "DIV",
+ x86_DIVPD: "DIVPD",
+ x86_DIVPS: "DIVPS",
+ x86_DIVSD: "DIVSD",
+ x86_DIVSS: "DIVSS",
+ x86_DPPD: "DPPD",
+ x86_DPPS: "DPPS",
+ x86_EMMS: "EMMS",
+ x86_ENTER: "ENTER",
+ x86_EXTRACTPS: "EXTRACTPS",
+ x86_F2XM1: "F2XM1",
+ x86_FABS: "FABS",
+ x86_FADD: "FADD",
+ x86_FADDP: "FADDP",
+ x86_FBLD: "FBLD",
+ x86_FBSTP: "FBSTP",
+ x86_FCHS: "FCHS",
+ x86_FCMOVB: "FCMOVB",
+ x86_FCMOVBE: "FCMOVBE",
+ x86_FCMOVE: "FCMOVE",
+ x86_FCMOVNB: "FCMOVNB",
+ x86_FCMOVNBE: "FCMOVNBE",
+ x86_FCMOVNE: "FCMOVNE",
+ x86_FCMOVNU: "FCMOVNU",
+ x86_FCMOVU: "FCMOVU",
+ x86_FCOM: "FCOM",
+ x86_FCOMI: "FCOMI",
+ x86_FCOMIP: "FCOMIP",
+ x86_FCOMP: "FCOMP",
+ x86_FCOMPP: "FCOMPP",
+ x86_FCOS: "FCOS",
+ x86_FDECSTP: "FDECSTP",
+ x86_FDIV: "FDIV",
+ x86_FDIVP: "FDIVP",
+ x86_FDIVR: "FDIVR",
+ x86_FDIVRP: "FDIVRP",
+ x86_FFREE: "FFREE",
+ x86_FFREEP: "FFREEP",
+ x86_FIADD: "FIADD",
+ x86_FICOM: "FICOM",
+ x86_FICOMP: "FICOMP",
+ x86_FIDIV: "FIDIV",
+ x86_FIDIVR: "FIDIVR",
+ x86_FILD: "FILD",
+ x86_FIMUL: "FIMUL",
+ x86_FINCSTP: "FINCSTP",
+ x86_FIST: "FIST",
+ x86_FISTP: "FISTP",
+ x86_FISTTP: "FISTTP",
+ x86_FISUB: "FISUB",
+ x86_FISUBR: "FISUBR",
+ x86_FLD: "FLD",
+ x86_FLD1: "FLD1",
+ x86_FLDCW: "FLDCW",
+ x86_FLDENV: "FLDENV",
+ x86_FLDL2E: "FLDL2E",
+ x86_FLDL2T: "FLDL2T",
+ x86_FLDLG2: "FLDLG2",
+ x86_FLDPI: "FLDPI",
+ x86_FMUL: "FMUL",
+ x86_FMULP: "FMULP",
+ x86_FNCLEX: "FNCLEX",
+ x86_FNINIT: "FNINIT",
+ x86_FNOP: "FNOP",
+ x86_FNSAVE: "FNSAVE",
+ x86_FNSTCW: "FNSTCW",
+ x86_FNSTENV: "FNSTENV",
+ x86_FNSTSW: "FNSTSW",
+ x86_FPATAN: "FPATAN",
+ x86_FPREM: "FPREM",
+ x86_FPREM1: "FPREM1",
+ x86_FPTAN: "FPTAN",
+ x86_FRNDINT: "FRNDINT",
+ x86_FRSTOR: "FRSTOR",
+ x86_FSCALE: "FSCALE",
+ x86_FSIN: "FSIN",
+ x86_FSINCOS: "FSINCOS",
+ x86_FSQRT: "FSQRT",
+ x86_FST: "FST",
+ x86_FSTP: "FSTP",
+ x86_FSUB: "FSUB",
+ x86_FSUBP: "FSUBP",
+ x86_FSUBR: "FSUBR",
+ x86_FSUBRP: "FSUBRP",
+ x86_FTST: "FTST",
+ x86_FUCOM: "FUCOM",
+ x86_FUCOMI: "FUCOMI",
+ x86_FUCOMIP: "FUCOMIP",
+ x86_FUCOMP: "FUCOMP",
+ x86_FUCOMPP: "FUCOMPP",
+ x86_FWAIT: "FWAIT",
+ x86_FXAM: "FXAM",
+ x86_FXCH: "FXCH",
+ x86_FXRSTOR: "FXRSTOR",
+ x86_FXRSTOR64: "FXRSTOR64",
+ x86_FXSAVE: "FXSAVE",
+ x86_FXSAVE64: "FXSAVE64",
+ x86_FXTRACT: "FXTRACT",
+ x86_FYL2X: "FYL2X",
+ x86_FYL2XP1: "FYL2XP1",
+ x86_HADDPD: "HADDPD",
+ x86_HADDPS: "HADDPS",
+ x86_HLT: "HLT",
+ x86_HSUBPD: "HSUBPD",
+ x86_HSUBPS: "HSUBPS",
+ x86_ICEBP: "ICEBP",
+ x86_IDIV: "IDIV",
+ x86_IMUL: "IMUL",
+ x86_IN: "IN",
+ x86_INC: "INC",
+ x86_INSB: "INSB",
+ x86_INSD: "INSD",
+ x86_INSERTPS: "INSERTPS",
+ x86_INSW: "INSW",
+ x86_INT: "INT",
+ x86_INTO: "INTO",
+ x86_INVD: "INVD",
+ x86_INVLPG: "INVLPG",
+ x86_INVPCID: "INVPCID",
+ x86_IRET: "IRET",
+ x86_IRETD: "IRETD",
+ x86_IRETQ: "IRETQ",
+ x86_JA: "JA",
+ x86_JAE: "JAE",
+ x86_JB: "JB",
+ x86_JBE: "JBE",
+ x86_JCXZ: "JCXZ",
+ x86_JE: "JE",
+ x86_JECXZ: "JECXZ",
+ x86_JG: "JG",
+ x86_JGE: "JGE",
+ x86_JL: "JL",
+ x86_JLE: "JLE",
+ x86_JMP: "JMP",
+ x86_JNE: "JNE",
+ x86_JNO: "JNO",
+ x86_JNP: "JNP",
+ x86_JNS: "JNS",
+ x86_JO: "JO",
+ x86_JP: "JP",
+ x86_JRCXZ: "JRCXZ",
+ x86_JS: "JS",
+ x86_LAHF: "LAHF",
+ x86_LAR: "LAR",
+ x86_LCALL: "LCALL",
+ x86_LDDQU: "LDDQU",
+ x86_LDMXCSR: "LDMXCSR",
+ x86_LDS: "LDS",
+ x86_LEA: "LEA",
+ x86_LEAVE: "LEAVE",
+ x86_LES: "LES",
+ x86_LFENCE: "LFENCE",
+ x86_LFS: "LFS",
+ x86_LGDT: "LGDT",
+ x86_LGS: "LGS",
+ x86_LIDT: "LIDT",
+ x86_LJMP: "LJMP",
+ x86_LLDT: "LLDT",
+ x86_LMSW: "LMSW",
+ x86_LODSB: "LODSB",
+ x86_LODSD: "LODSD",
+ x86_LODSQ: "LODSQ",
+ x86_LODSW: "LODSW",
+ x86_LOOP: "LOOP",
+ x86_LOOPE: "LOOPE",
+ x86_LOOPNE: "LOOPNE",
+ x86_LRET: "LRET",
+ x86_LSL: "LSL",
+ x86_LSS: "LSS",
+ x86_LTR: "LTR",
+ x86_LZCNT: "LZCNT",
+ x86_MASKMOVDQU: "MASKMOVDQU",
+ x86_MASKMOVQ: "MASKMOVQ",
+ x86_MAXPD: "MAXPD",
+ x86_MAXPS: "MAXPS",
+ x86_MAXSD: "MAXSD",
+ x86_MAXSS: "MAXSS",
+ x86_MFENCE: "MFENCE",
+ x86_MINPD: "MINPD",
+ x86_MINPS: "MINPS",
+ x86_MINSD: "MINSD",
+ x86_MINSS: "MINSS",
+ x86_MONITOR: "MONITOR",
+ x86_MOV: "MOV",
+ x86_MOVAPD: "MOVAPD",
+ x86_MOVAPS: "MOVAPS",
+ x86_MOVBE: "MOVBE",
+ x86_MOVD: "MOVD",
+ x86_MOVDDUP: "MOVDDUP",
+ x86_MOVDQ2Q: "MOVDQ2Q",
+ x86_MOVDQA: "MOVDQA",
+ x86_MOVDQU: "MOVDQU",
+ x86_MOVHLPS: "MOVHLPS",
+ x86_MOVHPD: "MOVHPD",
+ x86_MOVHPS: "MOVHPS",
+ x86_MOVLHPS: "MOVLHPS",
+ x86_MOVLPD: "MOVLPD",
+ x86_MOVLPS: "MOVLPS",
+ x86_MOVMSKPD: "MOVMSKPD",
+ x86_MOVMSKPS: "MOVMSKPS",
+ x86_MOVNTDQ: "MOVNTDQ",
+ x86_MOVNTDQA: "MOVNTDQA",
+ x86_MOVNTI: "MOVNTI",
+ x86_MOVNTPD: "MOVNTPD",
+ x86_MOVNTPS: "MOVNTPS",
+ x86_MOVNTQ: "MOVNTQ",
+ x86_MOVNTSD: "MOVNTSD",
+ x86_MOVNTSS: "MOVNTSS",
+ x86_MOVQ: "MOVQ",
+ x86_MOVQ2DQ: "MOVQ2DQ",
+ x86_MOVSB: "MOVSB",
+ x86_MOVSD: "MOVSD",
+ x86_MOVSD_XMM: "MOVSD_XMM",
+ x86_MOVSHDUP: "MOVSHDUP",
+ x86_MOVSLDUP: "MOVSLDUP",
+ x86_MOVSQ: "MOVSQ",
+ x86_MOVSS: "MOVSS",
+ x86_MOVSW: "MOVSW",
+ x86_MOVSX: "MOVSX",
+ x86_MOVSXD: "MOVSXD",
+ x86_MOVUPD: "MOVUPD",
+ x86_MOVUPS: "MOVUPS",
+ x86_MOVZX: "MOVZX",
+ x86_MPSADBW: "MPSADBW",
+ x86_MUL: "MUL",
+ x86_MULPD: "MULPD",
+ x86_MULPS: "MULPS",
+ x86_MULSD: "MULSD",
+ x86_MULSS: "MULSS",
+ x86_MWAIT: "MWAIT",
+ x86_NEG: "NEG",
+ x86_NOP: "NOP",
+ x86_NOT: "NOT",
+ x86_OR: "OR",
+ x86_ORPD: "ORPD",
+ x86_ORPS: "ORPS",
+ x86_OUT: "OUT",
+ x86_OUTSB: "OUTSB",
+ x86_OUTSD: "OUTSD",
+ x86_OUTSW: "OUTSW",
+ x86_PABSB: "PABSB",
+ x86_PABSD: "PABSD",
+ x86_PABSW: "PABSW",
+ x86_PACKSSDW: "PACKSSDW",
+ x86_PACKSSWB: "PACKSSWB",
+ x86_PACKUSDW: "PACKUSDW",
+ x86_PACKUSWB: "PACKUSWB",
+ x86_PADDB: "PADDB",
+ x86_PADDD: "PADDD",
+ x86_PADDQ: "PADDQ",
+ x86_PADDSB: "PADDSB",
+ x86_PADDSW: "PADDSW",
+ x86_PADDUSB: "PADDUSB",
+ x86_PADDUSW: "PADDUSW",
+ x86_PADDW: "PADDW",
+ x86_PALIGNR: "PALIGNR",
+ x86_PAND: "PAND",
+ x86_PANDN: "PANDN",
+ x86_PAUSE: "PAUSE",
+ x86_PAVGB: "PAVGB",
+ x86_PAVGW: "PAVGW",
+ x86_PBLENDVB: "PBLENDVB",
+ x86_PBLENDW: "PBLENDW",
+ x86_PCLMULQDQ: "PCLMULQDQ",
+ x86_PCMPEQB: "PCMPEQB",
+ x86_PCMPEQD: "PCMPEQD",
+ x86_PCMPEQQ: "PCMPEQQ",
+ x86_PCMPEQW: "PCMPEQW",
+ x86_PCMPESTRI: "PCMPESTRI",
+ x86_PCMPESTRM: "PCMPESTRM",
+ x86_PCMPGTB: "PCMPGTB",
+ x86_PCMPGTD: "PCMPGTD",
+ x86_PCMPGTQ: "PCMPGTQ",
+ x86_PCMPGTW: "PCMPGTW",
+ x86_PCMPISTRI: "PCMPISTRI",
+ x86_PCMPISTRM: "PCMPISTRM",
+ x86_PEXTRB: "PEXTRB",
+ x86_PEXTRD: "PEXTRD",
+ x86_PEXTRQ: "PEXTRQ",
+ x86_PEXTRW: "PEXTRW",
+ x86_PHADDD: "PHADDD",
+ x86_PHADDSW: "PHADDSW",
+ x86_PHADDW: "PHADDW",
+ x86_PHMINPOSUW: "PHMINPOSUW",
+ x86_PHSUBD: "PHSUBD",
+ x86_PHSUBSW: "PHSUBSW",
+ x86_PHSUBW: "PHSUBW",
+ x86_PINSRB: "PINSRB",
+ x86_PINSRD: "PINSRD",
+ x86_PINSRQ: "PINSRQ",
+ x86_PINSRW: "PINSRW",
+ x86_PMADDUBSW: "PMADDUBSW",
+ x86_PMADDWD: "PMADDWD",
+ x86_PMAXSB: "PMAXSB",
+ x86_PMAXSD: "PMAXSD",
+ x86_PMAXSW: "PMAXSW",
+ x86_PMAXUB: "PMAXUB",
+ x86_PMAXUD: "PMAXUD",
+ x86_PMAXUW: "PMAXUW",
+ x86_PMINSB: "PMINSB",
+ x86_PMINSD: "PMINSD",
+ x86_PMINSW: "PMINSW",
+ x86_PMINUB: "PMINUB",
+ x86_PMINUD: "PMINUD",
+ x86_PMINUW: "PMINUW",
+ x86_PMOVMSKB: "PMOVMSKB",
+ x86_PMOVSXBD: "PMOVSXBD",
+ x86_PMOVSXBQ: "PMOVSXBQ",
+ x86_PMOVSXBW: "PMOVSXBW",
+ x86_PMOVSXDQ: "PMOVSXDQ",
+ x86_PMOVSXWD: "PMOVSXWD",
+ x86_PMOVSXWQ: "PMOVSXWQ",
+ x86_PMOVZXBD: "PMOVZXBD",
+ x86_PMOVZXBQ: "PMOVZXBQ",
+ x86_PMOVZXBW: "PMOVZXBW",
+ x86_PMOVZXDQ: "PMOVZXDQ",
+ x86_PMOVZXWD: "PMOVZXWD",
+ x86_PMOVZXWQ: "PMOVZXWQ",
+ x86_PMULDQ: "PMULDQ",
+ x86_PMULHRSW: "PMULHRSW",
+ x86_PMULHUW: "PMULHUW",
+ x86_PMULHW: "PMULHW",
+ x86_PMULLD: "PMULLD",
+ x86_PMULLW: "PMULLW",
+ x86_PMULUDQ: "PMULUDQ",
+ x86_POP: "POP",
+ x86_POPA: "POPA",
+ x86_POPAD: "POPAD",
+ x86_POPCNT: "POPCNT",
+ x86_POPF: "POPF",
+ x86_POPFD: "POPFD",
+ x86_POPFQ: "POPFQ",
+ x86_POR: "POR",
+ x86_PREFETCHNTA: "PREFETCHNTA",
+ x86_PREFETCHT0: "PREFETCHT0",
+ x86_PREFETCHT1: "PREFETCHT1",
+ x86_PREFETCHT2: "PREFETCHT2",
+ x86_PREFETCHW: "PREFETCHW",
+ x86_PSADBW: "PSADBW",
+ x86_PSHUFB: "PSHUFB",
+ x86_PSHUFD: "PSHUFD",
+ x86_PSHUFHW: "PSHUFHW",
+ x86_PSHUFLW: "PSHUFLW",
+ x86_PSHUFW: "PSHUFW",
+ x86_PSIGNB: "PSIGNB",
+ x86_PSIGND: "PSIGND",
+ x86_PSIGNW: "PSIGNW",
+ x86_PSLLD: "PSLLD",
+ x86_PSLLDQ: "PSLLDQ",
+ x86_PSLLQ: "PSLLQ",
+ x86_PSLLW: "PSLLW",
+ x86_PSRAD: "PSRAD",
+ x86_PSRAW: "PSRAW",
+ x86_PSRLD: "PSRLD",
+ x86_PSRLDQ: "PSRLDQ",
+ x86_PSRLQ: "PSRLQ",
+ x86_PSRLW: "PSRLW",
+ x86_PSUBB: "PSUBB",
+ x86_PSUBD: "PSUBD",
+ x86_PSUBQ: "PSUBQ",
+ x86_PSUBSB: "PSUBSB",
+ x86_PSUBSW: "PSUBSW",
+ x86_PSUBUSB: "PSUBUSB",
+ x86_PSUBUSW: "PSUBUSW",
+ x86_PSUBW: "PSUBW",
+ x86_PTEST: "PTEST",
+ x86_PUNPCKHBW: "PUNPCKHBW",
+ x86_PUNPCKHDQ: "PUNPCKHDQ",
+ x86_PUNPCKHQDQ: "PUNPCKHQDQ",
+ x86_PUNPCKHWD: "PUNPCKHWD",
+ x86_PUNPCKLBW: "PUNPCKLBW",
+ x86_PUNPCKLDQ: "PUNPCKLDQ",
+ x86_PUNPCKLQDQ: "PUNPCKLQDQ",
+ x86_PUNPCKLWD: "PUNPCKLWD",
+ x86_PUSH: "PUSH",
+ x86_PUSHA: "PUSHA",
+ x86_PUSHAD: "PUSHAD",
+ x86_PUSHF: "PUSHF",
+ x86_PUSHFD: "PUSHFD",
+ x86_PUSHFQ: "PUSHFQ",
+ x86_PXOR: "PXOR",
+ x86_RCL: "RCL",
+ x86_RCPPS: "RCPPS",
+ x86_RCPSS: "RCPSS",
+ x86_RCR: "RCR",
+ x86_RDFSBASE: "RDFSBASE",
+ x86_RDGSBASE: "RDGSBASE",
+ x86_RDMSR: "RDMSR",
+ x86_RDPMC: "RDPMC",
+ x86_RDRAND: "RDRAND",
+ x86_RDTSC: "RDTSC",
+ x86_RDTSCP: "RDTSCP",
+ x86_RET: "RET",
+ x86_ROL: "ROL",
+ x86_ROR: "ROR",
+ x86_ROUNDPD: "ROUNDPD",
+ x86_ROUNDPS: "ROUNDPS",
+ x86_ROUNDSD: "ROUNDSD",
+ x86_ROUNDSS: "ROUNDSS",
+ x86_RSM: "RSM",
+ x86_RSQRTPS: "RSQRTPS",
+ x86_RSQRTSS: "RSQRTSS",
+ x86_SAHF: "SAHF",
+ x86_SAR: "SAR",
+ x86_SBB: "SBB",
+ x86_SCASB: "SCASB",
+ x86_SCASD: "SCASD",
+ x86_SCASQ: "SCASQ",
+ x86_SCASW: "SCASW",
+ x86_SETA: "SETA",
+ x86_SETAE: "SETAE",
+ x86_SETB: "SETB",
+ x86_SETBE: "SETBE",
+ x86_SETE: "SETE",
+ x86_SETG: "SETG",
+ x86_SETGE: "SETGE",
+ x86_SETL: "SETL",
+ x86_SETLE: "SETLE",
+ x86_SETNE: "SETNE",
+ x86_SETNO: "SETNO",
+ x86_SETNP: "SETNP",
+ x86_SETNS: "SETNS",
+ x86_SETO: "SETO",
+ x86_SETP: "SETP",
+ x86_SETS: "SETS",
+ x86_SFENCE: "SFENCE",
+ x86_SGDT: "SGDT",
+ x86_SHL: "SHL",
+ x86_SHLD: "SHLD",
+ x86_SHR: "SHR",
+ x86_SHRD: "SHRD",
+ x86_SHUFPD: "SHUFPD",
+ x86_SHUFPS: "SHUFPS",
+ x86_SIDT: "SIDT",
+ x86_SLDT: "SLDT",
+ x86_SMSW: "SMSW",
+ x86_SQRTPD: "SQRTPD",
+ x86_SQRTPS: "SQRTPS",
+ x86_SQRTSD: "SQRTSD",
+ x86_SQRTSS: "SQRTSS",
+ x86_STC: "STC",
+ x86_STD: "STD",
+ x86_STI: "STI",
+ x86_STMXCSR: "STMXCSR",
+ x86_STOSB: "STOSB",
+ x86_STOSD: "STOSD",
+ x86_STOSQ: "STOSQ",
+ x86_STOSW: "STOSW",
+ x86_STR: "STR",
+ x86_SUB: "SUB",
+ x86_SUBPD: "SUBPD",
+ x86_SUBPS: "SUBPS",
+ x86_SUBSD: "SUBSD",
+ x86_SUBSS: "SUBSS",
+ x86_SWAPGS: "SWAPGS",
+ x86_SYSCALL: "SYSCALL",
+ x86_SYSENTER: "SYSENTER",
+ x86_SYSEXIT: "SYSEXIT",
+ x86_SYSRET: "SYSRET",
+ x86_TEST: "TEST",
+ x86_TZCNT: "TZCNT",
+ x86_UCOMISD: "UCOMISD",
+ x86_UCOMISS: "UCOMISS",
+ x86_UD1: "UD1",
+ x86_UD2: "UD2",
+ x86_UNPCKHPD: "UNPCKHPD",
+ x86_UNPCKHPS: "UNPCKHPS",
+ x86_UNPCKLPD: "UNPCKLPD",
+ x86_UNPCKLPS: "UNPCKLPS",
+ x86_VERR: "VERR",
+ x86_VERW: "VERW",
+ x86_WBINVD: "WBINVD",
+ x86_WRFSBASE: "WRFSBASE",
+ x86_WRGSBASE: "WRGSBASE",
+ x86_WRMSR: "WRMSR",
+ x86_XABORT: "XABORT",
+ x86_XADD: "XADD",
+ x86_XBEGIN: "XBEGIN",
+ x86_XCHG: "XCHG",
+ x86_XEND: "XEND",
+ x86_XGETBV: "XGETBV",
+ x86_XLATB: "XLATB",
+ x86_XOR: "XOR",
+ x86_XORPD: "XORPD",
+ x86_XORPS: "XORPS",
+ x86_XRSTOR: "XRSTOR",
+ x86_XRSTOR64: "XRSTOR64",
+ x86_XRSTORS: "XRSTORS",
+ x86_XRSTORS64: "XRSTORS64",
+ x86_XSAVE: "XSAVE",
+ x86_XSAVE64: "XSAVE64",
+ x86_XSAVEC: "XSAVEC",
+ x86_XSAVEC64: "XSAVEC64",
+ x86_XSAVEOPT: "XSAVEOPT",
+ x86_XSAVEOPT64: "XSAVEOPT64",
+ x86_XSAVES: "XSAVES",
+ x86_XSAVES64: "XSAVES64",
+ x86_XSETBV: "XSETBV",
+ x86_XTEST: "XTEST",
+}
diff --git a/src/cmd/pack/Makefile b/src/cmd/pack/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/pack/Makefile
+++ /dev/null
@@ -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
diff --git a/src/cmd/pack/ar.c b/src/cmd/pack/ar.c
deleted file mode 100644
index 5b300dbb9..000000000
--- a/src/cmd/pack/ar.c
+++ /dev/null
@@ -1,1727 +0,0 @@
-// Inferno utils/iar/ar.c
-// http://code.google.com/p/inferno-os/source/browse/utils/iar/ar.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// 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.
-
-/*
- * ar - portable (ascii) format version
- */
-
-/* protect a couple of our names */
-#define select your_select
-#define rcmd your_rcmd
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../../libmach/obj.h"
-#include <ar.h>
-
-#undef select
-#undef rcmd
-
-/*
- * The algorithm uses up to 3 temp files. The "pivot member" is the
- * archive member specified by and a, b, or i option. The temp files are
- * astart - contains existing members up to and including the pivot member.
- * amiddle - contains new files moved or inserted behind the pivot.
- * aend - contains the existing members that follow the pivot member.
- * When all members have been processed, function 'install' streams the
- * temp files, in order, back into the archive.
- */
-
-typedef struct Arsymref
-{
- char *name;
- char *file;
- int type;
- int len;
- vlong offset;
- struct Arsymref *next;
-} Arsymref;
-
-typedef struct Armember /* Temp file entry - one per archive member */
-{
- struct Armember *next;
- struct ar_hdr hdr;
- long size;
- long date;
- void *member;
-} Armember;
-
-typedef struct Arfile /* Temp file control block - one per tempfile */
-{
- char *fname; /* paging file name */
- vlong size;
- Armember *head; /* head of member chain */
- Armember *tail; /* tail of member chain */
- Arsymref *sym; /* head of defined symbol chain */
-} Arfile;
-
-typedef struct Hashchain
-{
- char *name;
- char *file;
- struct Hashchain *next;
-} Hashchain;
-
-#define NHASH 1024
-
-/*
- * macro to portably read/write archive header.
- * 'cmd' is read/write/Bread/Bwrite, etc.
- */
-#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
- || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
- || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
- || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
- || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
- || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
- || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
-
- /* constants and flags */
-char *man = "mrxtdpq";
-char *opt = "uvnbailogS";
-char artemp[] = "/tmp/vXXXXX";
-char movtemp[] = "/tmp/v1XXXXX";
-char tailtemp[] = "/tmp/v2XXXXX";
-char symdef[] = "__.GOSYMDEF";
-char pkgdef[] = "__.PKGDEF";
-
-int aflag; /* command line flags */
-int bflag;
-int cflag;
-int gflag;
-int oflag;
-int uflag;
-int vflag;
-int Pflag; /* remove leading file prefix */
-int Sflag; /* force mark Go package as safe */
-
-int errors;
-
-Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */
-int allobj = 1; /* set when all members are object files of the same type */
-int symdefsize; /* size of symdef file */
-char *pkgstmt; /* string "package foo" */
-char *objhdr; /* string "go object darwin 386 release.2010-01-01 2345+" */
-int dupfound; /* flag for duplicate symbol */
-Hashchain *hash[NHASH]; /* hash table of text symbols */
-
-#define ARNAMESIZE sizeof(astart->tail->hdr.name)
-
-char poname[ARNAMESIZE+1]; /* name of pivot member */
-char *file; /* current file or member being worked on */
-Biobuf bout;
-Biobuf bar;
-char *prefix;
-int pkgdefsafe; /* was __.PKGDEF marked safe? */
-
-void arcopy(Biobuf*, Arfile*, Armember*);
-int arcreate(char*);
-void arfree(Arfile*);
-void arinsert(Arfile*, Armember*);
-void *armalloc(int);
-char *arstrdup(char*);
-void armove(Biobuf*, Arfile*, Armember*);
-void arread(Biobuf*, Armember*);
-void arstream(int, Arfile*);
-int arwrite(int, Armember*);
-int bamatch(char*, char*);
-int duplicate(char*, char**);
-Armember *getdir(Biobuf*);
-void getpkgdef(char**, int*);
-void install(char*, Arfile*, Arfile*, Arfile*, int);
-void loadpkgdata(char*, int);
-void longt(Armember*);
-int match(int, char**);
-void mesg(int, char*);
-Arfile *newtempfile(char*);
-Armember *newmember(void);
-void objsym(Sym*, void*);
-int openar(char*, int, int);
-void pmode(long);
-void rl(int);
-void scanobj(Biobuf*, Arfile*, long);
-void scanpkg(Biobuf*, long);
-void select(int*, long);
-void setcom(void(*)(char*, int, char**));
-void skip(Biobuf*, vlong);
-void checksafe(Biobuf*, vlong);
-int symcomp(void*, void*);
-void trim(char*, char*, int);
-void usage(void);
-void wrerr(void);
-void wrsym(Biobuf*, long, Arsymref*);
-int arread_cutprefix(Biobuf*, Armember*);
-
-void rcmd(char*, int, char**); /* command processing */
-void dcmd(char*, int, char**);
-void xcmd(char*, int, char**);
-void tcmd(char*, int, char**);
-void pcmd(char*, int, char**);
-void mcmd(char*, int, char**);
-void qcmd(char*, int, char**);
-void (*comfun)(char*, int, char**);
-
-void
-main(int argc, char *argv[])
-{
- char *cp;
-
- Binit(&bout, 1, OWRITE);
- if(argc < 3)
- usage();
- for (cp = argv[1]; *cp; cp++) {
- switch(*cp) {
- case 'a': aflag = 1; break;
- case 'b': bflag = 1; break;
- case 'c': cflag = 1; break;
- case 'd': setcom(dcmd); break;
- case 'g': gflag = 1; break;
- case 'i': bflag = 1; break;
- case 'l':
- strcpy(artemp, "vXXXXX");
- strcpy(movtemp, "v1XXXXX");
- strcpy(tailtemp, "v2XXXXX");
- break;
- case 'm': setcom(mcmd); break;
- case 'o': oflag = 1; break;
- case 'p': setcom(pcmd); break;
- case 'q': setcom(qcmd); break;
- case 'r': setcom(rcmd); break;
- case 't': setcom(tcmd); break;
- case 'u': uflag = 1; break;
- case 'v': vflag = 1; break;
- case 'x': setcom(xcmd); break;
- case 'S': Sflag = 1; break;
- case 'P': Pflag = 1; break;
- default:
- fprint(2, "pack: bad option `%c'\n", *cp);
- exits("error");
- }
- }
- if (aflag && bflag) {
- fprint(2, "pack: only one of 'a' and 'b' can be specified\n");
- usage();
- }
- if(aflag || bflag) {
- trim(argv[2], poname, sizeof(poname));
- argv++;
- argc--;
- if(argc < 3)
- usage();
- }
- if(Pflag) {
- if(argc < 4) {
- fprint(2, "pack: P flag requires prefix argument\n");
- usage();
- }
- prefix = argv[2];
- argv++;
- argc--;
- }
- if(comfun == 0) {
- if(uflag == 0) {
- fprint(2, "pack: one of [%s] must be specified\n", man);
- usage();
- }
- setcom(rcmd);
- }
- cp = argv[2];
- argc -= 3;
- argv += 3;
- (*comfun)(cp, argc, argv); /* do the command */
- if(errors && cflag)
- remove(cp);
- cp = 0;
- while (argc--) {
- if (*argv) {
- fprint(2, "pack: %s not found\n", *argv);
- cp = "error";
- }
- argv++;
- }
- if (errors)
- cp = "error";
- exits(cp);
-}
-/*
- * select a command
- */
-void
-setcom(void (*fun)(char *, int, char**))
-{
-
- if(comfun != 0) {
- fprint(2, "pack: only one of [%s] allowed\n", man);
- usage();
- }
- comfun = fun;
-}
-/*
- * perform the 'r' and 'u' commands
- */
-void
-rcmd(char *arname, int count, char **files)
-{
- int fd;
- int i;
- Arfile *ap;
- Armember *bp;
- Dir *d;
- Biobuf *bfile;
-
- fd = openar(arname, ORDWR, 1);
- if (fd >= 0) {
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- }
- astart = newtempfile(artemp);
- ap = astart;
- aend = 0;
- for(i = 0; fd >= 0; i++) {
- bp = getdir(&bar);
- if (!bp)
- break;
- if (bamatch(file, poname)) { /* check for pivot */
- aend = newtempfile(tailtemp);
- ap = aend;
- }
- /* pitch symdef file */
- if (i == 0 && strcmp(file, symdef) == 0) {
- skip(&bar, bp->size);
- continue;
- }
- /* pitch pkgdef file but remember whether it was marked safe */
- if (gflag && strcmp(file, pkgdef) == 0) {
- checksafe(&bar, bp->size);
- continue;
- }
- /*
- * the plan 9 ar treats count == 0 as equivalent
- * to listing all the archive's files on the command line:
- * it will try to open every file name in the archive
- * and copy that file into the archive if it exists.
- * for go we disable that behavior, because we use
- * r with no files to make changes to the archive itself,
- * using the S or P flags.
- */
- if (!match(count, files)) {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- continue;
- }
- bfile = Bopen(file, OREAD);
- if (!bfile) {
- if (count != 0) {
- fprint(2, "pack: cannot open %s\n", file);
- errors++;
- }
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- continue;
- }
- d = dirfstat(Bfildes(bfile));
- if(d == nil)
- fprint(2, "pack: cannot stat %s: %r\n", file);
- if (uflag && (d==nil || d->mtime <= bp->date)) {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- Bterm(bfile);
- free(d);
- continue;
- }
- mesg('r', file);
- skip(&bar, bp->size);
- scanobj(bfile, ap, d->length);
- free(d);
- armove(bfile, ap, bp);
- Bterm(bfile);
- }
- if(fd >= 0)
- close(fd);
- /* copy in remaining files named on command line */
- for (i = 0; i < count; i++) {
- file = files[i];
- if(file == 0)
- continue;
- files[i] = 0;
- bfile = Bopen(file, OREAD);
- if (!bfile) {
- fprint(2, "pack: cannot open %s\n", file);
- errors++;
- } else {
- mesg('a', file);
- d = dirfstat(Bfildes(bfile));
- if (d == nil)
- fprint(2, "can't stat %s\n", file);
- else {
- scanobj(bfile, astart, d->length);
- armove(bfile, astart, newmember());
- free(d);
- }
- Bterm(bfile);
- }
- }
- if(fd < 0 && !cflag)
- install(arname, astart, 0, aend, 1); /* issue 'creating' msg */
- else
- install(arname, astart, 0, aend, 0);
-}
-
-void
-dcmd(char *arname, int count, char **files)
-{
- Armember *bp;
- int fd, i;
-
- if (!count)
- return;
- fd = openar(arname, ORDWR, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- astart = newtempfile(artemp);
- for (i = 0; bp = getdir(&bar); i++) {
- if(match(count, files)) {
- mesg('d', file);
- skip(&bar, bp->size);
- if (strcmp(file, symdef) == 0)
- allobj = 0;
- } else if (i == 0 && strcmp(file, symdef) == 0) {
- skip(&bar, bp->size);
- } else if (gflag && strcmp(file, pkgdef) == 0) {
- skip(&bar, bp->size);
- } else {
- scanobj(&bar, astart, bp->size);
- arcopy(&bar, astart, bp);
- }
- }
- close(fd);
- install(arname, astart, 0, 0, 0);
-}
-
-void
-xcmd(char *arname, int count, char **files)
-{
- int fd, f, mode, i;
- Armember *bp;
- Dir dx;
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- i = 0;
- while (bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
- f = create(file, OWRITE, mode);
- if(f < 0) {
- fprint(2, "pack: %s cannot create\n", file);
- skip(&bar, bp->size);
- } else {
- mesg('x', file);
- arcopy(&bar, 0, bp);
- if (write(f, bp->member, bp->size) < 0)
- wrerr();
- if(oflag && bp->date != 0) {
- nulldir(&dx);
- dx.atime = bp->date;
- dx.mtime = bp->date;
- if(dirwstat(file, &dx) < 0)
- perror(file);
- }
- free(bp->member);
- close(f);
- }
- free(bp);
- if (count && ++i >= count)
- break;
- } else {
- skip(&bar, bp->size);
- free(bp);
- }
- }
- close(fd);
-}
-void
-pcmd(char *arname, int count, char **files)
-{
- int fd;
- Armember *bp;
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- while(bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- if(vflag)
- print("\n<%s>\n\n", file);
- arcopy(&bar, 0, bp);
- if (write(1, bp->member, bp->size) < 0)
- wrerr();
- } else
- skip(&bar, bp->size);
- free(bp);
- }
- close(fd);
-}
-void
-mcmd(char *arname, int count, char **files)
-{
- int fd, i;
- Arfile *ap;
- Armember *bp;
-
- if (count == 0)
- return;
- fd = openar(arname, ORDWR, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- astart = newtempfile(artemp);
- amiddle = newtempfile(movtemp);
- aend = 0;
- ap = astart;
- for (i = 0; bp = getdir(&bar); i++) {
- if (bamatch(file, poname)) {
- aend = newtempfile(tailtemp);
- ap = aend;
- }
- if(match(count, files)) {
- mesg('m', file);
- scanobj(&bar, amiddle, bp->size);
- arcopy(&bar, amiddle, bp);
- } else if (ap == astart && i == 0 && strcmp(file, symdef) == 0) {
- /*
- * pitch the symdef file if it is at the beginning
- * of the archive and we aren't inserting in front
- * of it (ap == astart).
- */
- skip(&bar, bp->size);
- } else if (ap == astart && gflag && strcmp(file, pkgdef) == 0) {
- /*
- * pitch the pkgdef file if we aren't inserting in front
- * of it (ap == astart).
- */
- skip(&bar, bp->size);
- } else {
- scanobj(&bar, ap, bp->size);
- arcopy(&bar, ap, bp);
- }
- }
- close(fd);
- if (poname[0] && aend == 0)
- fprint(2, "pack: %s not found - files moved to end.\n", poname);
- install(arname, astart, amiddle, aend, 0);
-}
-void
-tcmd(char *arname, int count, char **files)
-{
- int fd;
- Armember *bp;
- char name[ARNAMESIZE+1];
-
- fd = openar(arname, OREAD, 0);
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- while(bp = getdir(&bar)) {
- if(count == 0 || match(count, files)) {
- if(vflag)
- longt(bp);
- trim(file, name, ARNAMESIZE);
- Bprint(&bout, "%s\n", name);
- }
- skip(&bar, bp->size);
- free(bp);
- }
- close(fd);
-}
-void
-qcmd(char *arname, int count, char **files)
-{
- int fd, i;
- Armember *bp;
- Biobuf *bfile;
-
- if(aflag || bflag) {
- fprint(2, "pack: abi not allowed with q\n");
- exits("error");
- }
- fd = openar(arname, ORDWR, 1);
- if (fd < 0) {
- if(!cflag)
- fprint(2, "pack: creating %s\n", arname);
- fd = arcreate(arname);
- }
- Binit(&bar, fd, OREAD);
- Bseek(&bar,seek(fd,0,1), 1);
- /* leave note group behind when writing archive; i.e. sidestep interrupts */
- rfork(RFNOTEG);
- Bseek(&bar, 0, 2);
- bp = newmember();
- for(i=0; i<count && files[i]; i++) {
- file = files[i];
- files[i] = 0;
- bfile = Bopen(file, OREAD);
- if(!bfile) {
- fprint(2, "pack: cannot open %s\n", file);
- errors++;
- } else {
- mesg('q', file);
- armove(bfile, 0, bp);
- if (!arwrite(fd, bp))
- wrerr();
- free(bp->member);
- bp->member = 0;
- Bterm(bfile);
- }
- }
- free(bp);
- close(fd);
-}
-
-/*
- * does the object header line p match the last one we saw?
- * update *lastp if it gets more specific.
- */
-int
-matchhdr(char *p, char **lastp)
-{
- int n;
- char *last;
-
- // no information?
- last = *lastp;
- if(last == nil) {
- *lastp = strdup(p);
- return 1;
- }
-
- // identical match?
- if(strcmp(last, p) == 0)
- return 1;
-
- // last has extra fields
- n = strlen(p);
- if(n < strlen(last) && last[n] == ' ')
- return 1;
-
- // p has extra fields - save in last
- n = strlen(last);
- if(n < strlen(p) && p[n] == ' ') {
- free(last);
- *lastp = strdup(p);
- return 1;
- }
-
- return 0;
-}
-
-/*
- * extract the symbol references from an object file
- */
-void
-scanobj(Biobuf *b, Arfile *ap, long size)
-{
- int obj, goobject;
- vlong offset, offset1;
- Dir *d;
- static int lastobj = -1;
- uchar buf[4];
- char *p;
-
- if (!allobj) /* non-object file encountered */
- return;
- offset = Boffset(b);
- obj = objtype(b, 0);
- if (obj < 0) { /* not an object file */
- /* maybe a foreign object file */
- Bseek(b, offset, 0);
- memset(buf, 0, sizeof buf);
- Bread(b, buf, 4);
-
- /* maybe a foreign object file? that's okay */
- if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF
- (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE
- (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian
- (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian
- Bseek(b, offset, 0);
- return;
- }
-
- if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */
- fprint(2, "pack: non-object file %s\n", file);
- errors++;
- allobj = 0;
- }
- d = dirfstat(Bfildes(b));
- if (d != nil && d->length == 0) {
- fprint(2, "pack: zero length file %s\n", file);
- errors++;
- }
- free(d);
- Bseek(b, offset, 0);
- return;
- }
-
- goobject = 1;
- offset1 = Boffset(b);
- Bseek(b, offset, 0);
- p = Brdstr(b, '\n', 1);
-
- // After the go object header comes the Go metadata,
- // followed by ! on a line by itself. If this is not a Go object,
- // the ! comes immediately. Catch that so we can avoid
- // the call to scanpkg below, since scanpkg assumes that the
- // Go metadata is present.
- if(BGETC(b) == '!')
- goobject = 0;
-
- Bseek(b, offset1, 0);
- if(p == nil || strncmp(p, "go object ", 10) != 0) {
- fprint(2, "pack: malformed object file %s\n", file);
- errors++;
- Bseek(b, offset, 0);
- free(p);
- return;
- }
-
- if (!matchhdr(p, &objhdr)) {
- fprint(2, "pack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr);
- errors++;
- allobj = 0;
- free(p);
- return;
- }
- free(p);
-
- // Old check. Should be impossible since objhdrs match, but keep the check anyway.
- if (lastobj >= 0 && obj != lastobj) {
- fprint(2, "pack: inconsistent object file %s\n", file);
- errors++;
- allobj = 0;
- return;
- }
- lastobj = obj;
-
- if (!readar(b, obj, offset+size, 0)) {
- fprint(2, "pack: invalid symbol reference in file %s\n", file);
- errors++;
- allobj = 0;
- Bseek(b, offset, 0);
- return;
- }
- Bseek(b, offset, 0);
- objtraverse(objsym, ap);
- if (gflag && goobject) {
- scanpkg(b, size);
- Bseek(b, offset, 0);
- }
-}
-
-/*
- * does line contain substring (length-limited)
- */
-int
-strstrn(char *line, int len, char *sub)
-{
- int i;
- int sublen;
-
- sublen = strlen(sub);
- for (i = 0; i < len - sublen; i++)
- if (memcmp(line+i, sub, sublen) == 0)
- return 1;
- return 0;
-}
-
-/*
- * package import data
- */
-int safe = 1;
-char* pkgname;
-char* importblock;
-
-void
-getpkgdef(char **datap, int *lenp)
-{
- char *tag, *hdr;
-
- if(pkgname == nil) {
- pkgname = "__emptyarchive__";
- importblock = "";
- }
-
- tag = "";
- if(safe || Sflag)
- tag = "safe";
-
- hdr = "empty archive";
- if(objhdr != nil)
- hdr = objhdr;
-
- *datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock);
- *lenp = strlen(*datap);
-}
-
-/*
- * extract the package definition data from an object file.
- * there can be only one.
- */
-void
-scanpkg(Biobuf *b, long size)
-{
- long n;
- int c;
- long start, end, pkgsize;
- char *data, *line, pkgbuf[1024], *pkg;
- int first;
-
- /*
- * scan until $$
- */
- for (n=0; n<size; ) {
- c = BGETC(b);
- if(c == Beof)
- break;
- n++;
- if(c != '$')
- continue;
- c = BGETC(b);
- if(c == Beof)
- break;
- n++;
- if(c != '$')
- continue;
- goto foundstart;
- }
- // fprint(2, "pack: warning: no package import section in %s\n", file);
- if(b != &bar || !pkgdefsafe)
- safe = 0; // non-Go file (C or assembly)
- return;
-
-foundstart:
- /* found $$; skip rest of line */
- while((c = BGETC(b)) != '\n')
- if(c == Beof)
- goto bad;
-
- /* how big is it? */
- first = 1;
- start = end = 0;
- for (n=0; n<size; n+=Blinelen(b)) {
- line = Brdstr(b, '\n', 0);
- if (line == nil)
- goto bad;
- if (first && strstrn(line, Blinelen(b), "package ")) {
- if (Blinelen(b) > sizeof(pkgbuf)-1)
- goto bad;
- memmove(pkgbuf, line, Blinelen(b));
- pkgbuf[Blinelen(b)] = '\0';
- pkg = pkgbuf;
- while(*pkg == ' ' || *pkg == '\t')
- pkg++;
- if(strncmp(pkg, "package ", 8) != 0)
- goto bad;
- pkg += 8;
- data = pkg;
- while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0')
- pkg++;
- pkgname = armalloc(pkg - data + 1);
- memmove(pkgname, data, pkg - data);
- pkgname[pkg-data] = '\0';
- if(strcmp(pkg, " safe\n") != 0 && (b != &bar || !pkgdefsafe))
- safe = 0;
- start = Boffset(b); // after package statement
- first = 0;
- free(line);
- continue;
- }
- if(line[0] == '$' && line[1] == '$') {
- free(line);
- goto foundend;
- }
- end = Boffset(b); // before closing $$
- free(line);
- }
-bad:
- fprint(2, "pack: bad package import section in %s\n", file);
- errors++;
- return;
-
-foundend:
- if (start == 0)
- return;
- if (end == 0)
- goto bad;
- if(importblock != nil) {
- fprint(2, "pack: multiple Go object files\n");
- errors++;
- return;
- }
- pkgsize = end-start;
- data = armalloc(end - start + 1);
- Bseek(b, start, 0);
- if (Bread(b, data, pkgsize) != pkgsize) {
- fprint(2, "pack: error reading package import section in %s\n", file);
- errors++;
- return;
- }
- data[end-start] = '\0';
- importblock = data;
-}
-
-/*
- * add text and data symbols to the symbol list
- */
-void
-objsym(Sym *s, void *p)
-{
- int n;
- Arsymref *as;
- Arfile *ap;
- char *ofile;
-
- if (s->type != 'T' && s->type != 'D')
- return;
- ap = (Arfile*)p;
- as = armalloc(sizeof(Arsymref));
- as->offset = ap->size;
- as->name = arstrdup(s->name);
- as->file = arstrdup(file);
- if(s->type == 'T' && duplicate(as->name, &ofile)) {
- dupfound = 1;
- fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
- errors++;
- free(as->name);
- free(as);
- return;
- }
- as->type = s->type;
- n = strlen(s->name);
- symdefsize += 4+(n+1)+1;
- as->len = n;
- as->next = ap->sym;
- ap->sym = as;
-}
-
-/*
- * Check the symbol table for duplicate text symbols
- */
-int
-hashstr(char *name)
-{
- uint32 h;
- char *cp;
-
- h = 0;
- for(cp = name; *cp; h += *cp++)
- h *= 1119;
- return h & 0xfffffff;
-}
-
-int
-duplicate(char *name, char **ofile)
-{
- Hashchain *p;
- int h;
-
- h = hashstr(name) % NHASH;
-
- for(p = hash[h]; p; p = p->next)
- if(strcmp(p->name, name) == 0) {
- *ofile = p->file;
- return 1;
- }
- p = armalloc(sizeof(Hashchain));
- p->next = hash[h];
- p->name = name;
- p->file = file;
- hash[h] = p;
- *ofile = nil;
- return 0;
-}
-
-/*
- * open an archive and validate its header
- */
-int
-openar(char *arname, int mode, int errok)
-{
- int fd;
- char mbuf[SARMAG];
-
- fd = open(arname, mode);
- if(fd >= 0){
- if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
- fprint(2, "pack: %s not in archive format\n", arname);
- exits("error");
- }
- }else if(!errok){
- fprint(2, "pack: cannot open %s: %r\n", arname);
- exits("error");
- }
- return fd;
-}
-
-/*
- * create an archive and set its header
- */
-int
-arcreate(char *arname)
-{
- int fd;
-
- fd = create(arname, OWRITE, 0664);
- if(fd < 0){
- fprint(2, "pack: cannot create %s: %r\n", arname);
- exits("error");
- }
- if(write(fd, ARMAG, SARMAG) != SARMAG)
- wrerr();
- return fd;
-}
-
-/*
- * error handling
- */
-void
-wrerr(void)
-{
- perror("pack: write error");
- exits("error");
-}
-
-void
-rderr(void)
-{
- perror("pack: read error");
- exits("error");
-}
-
-void
-phaseerr(int offset)
-{
- fprint(2, "pack: phase error at offset %d\n", offset);
- exits("error");
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: pack [%s][%s][P prefix] archive files ...\n", opt, man);
- exits("error");
-}
-
-/*
- * read the header for the next archive member
- */
-Armember *
-getdir(Biobuf *b)
-{
- Armember *bp;
- char *cp;
- static char name[ARNAMESIZE+1];
-
- bp = newmember();
- if(HEADER_IO(Bread, b, bp->hdr)) {
- free(bp);
- return 0;
- }
- if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
- phaseerr(Boffset(b));
- strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
- cp = name+sizeof(name)-1;
- while(*--cp==' ')
- ;
- cp[1] = '\0';
- file = arstrdup(name);
- bp->date = strtol(bp->hdr.date, 0, 0);
- bp->size = strtol(bp->hdr.size, 0, 0);
- return bp;
-}
-
-/*
- * Copy the file referenced by fd to the temp file
- */
-void
-armove(Biobuf *b, Arfile *ap, Armember *bp)
-{
- char *cp;
- Dir *d;
- vlong n;
-
- d = dirfstat(Bfildes(b));
- if (d == nil) {
- fprint(2, "pack: cannot stat %s\n", file);
- return;
- }
-
- trim(file, bp->hdr.name, sizeof(bp->hdr.name));
- for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
- cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
- *cp = ' ';
- sprint(bp->hdr.date, "%-12ld", 0L); // was d->mtime but removed for idempotent builds
- sprint(bp->hdr.uid, "%-6d", 0);
- sprint(bp->hdr.gid, "%-6d", 0);
- sprint(bp->hdr.mode, "%-8lo", d->mode);
- sprint(bp->hdr.size, "%-10lld", d->length);
- strncpy(bp->hdr.fmag, ARFMAG, 2);
- bp->size = d->length;
- arread(b, bp);
- n = bp->size;
- if (n&1)
- n++;
- if (ap) {
- arinsert(ap, bp);
- ap->size += n+SAR_HDR;
- }
- free(d);
-}
-
-/*
- * Copy the archive member at the current offset into the temp file.
- */
-void
-arcopy(Biobuf *b, Arfile *ap, Armember *bp)
-{
- long n;
-
- arread(b, bp);
- n = bp->size;
- if (n & 01)
- n++;
- if (ap) {
- arinsert(ap, bp);
- ap->size += n+SAR_HDR;
- }
-}
-
-/*
- * Skip an archive member
- */
-void
-skip(Biobuf *bp, vlong len)
-{
- if (len & 01)
- len++;
- Bseek(bp, len, 1);
-}
-
-void
-checksafe(Biobuf *bp, vlong len)
-{
- char *p;
- vlong end;
-
- if (len & 01)
- len++;
- end = Boffset(bp) + len;
-
- p = Brdline(bp, '\n');
- if(p == nil || strncmp(p, "go object ", 10) != 0)
- goto done;
- for(;;) {
- p = Brdline(bp, '\n');
- if(p == nil || Boffset(bp) >= end)
- goto done;
- if(strncmp(p, "$$\n", 3) == 0)
- break;
- }
- p = Brdline(bp, '\n');
- if(p == nil || Boffset(bp) > end)
- goto done;
- if(Blinelen(bp) > 8+6 && strncmp(p, "package ", 8) == 0 && strncmp(p+Blinelen(bp)-6, " safe\n", 6) == 0)
- pkgdefsafe = 1;
-
-done:
- Bseek(bp, end, 0);
-}
-
-/*
- * Stream the three temp files to an archive
- */
-void
-install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
-{
- int fd;
-
- if(allobj && dupfound) {
- fprint(2, "%s not changed\n", arname);
- return;
- }
- /* leave note group behind when copying back; i.e. sidestep interrupts */
- rfork(RFNOTEG);
-
- if(createflag)
- fprint(2, "pack: creating %s\n", arname);
- fd = arcreate(arname);
-
- if(allobj)
- rl(fd);
-
- if (astart) {
- arstream(fd, astart);
- arfree(astart);
- }
- if (amiddle) {
- arstream(fd, amiddle);
- arfree(amiddle);
- }
- if (aend) {
- arstream(fd, aend);
- arfree(aend);
- }
- close(fd);
-}
-
-void
-rl(int fd)
-{
- Biobuf b;
- char *cp;
- struct ar_hdr a;
- long len;
- int headlen;
- char *pkgdefdata;
- int pkgdefsize;
-
- pkgdefdata = nil;
- pkgdefsize = 0;
-
- Binit(&b, fd, OWRITE);
- Bseek(&b,seek(fd,0,1), 0);
-
- len = symdefsize;
- if(len&01)
- len++;
- sprint(a.date, "%-12ld", 0L); // time(0)
- sprint(a.uid, "%-6d", 0);
- sprint(a.gid, "%-6d", 0);
- sprint(a.mode, "%-8lo", 0644L);
- sprint(a.size, "%-10ld", len);
- strncpy(a.fmag, ARFMAG, 2);
- strcpy(a.name, symdef);
- for (cp = strchr(a.name, 0); /* blank pad on right */
- cp < a.name+sizeof(a.name); cp++)
- *cp = ' ';
- if(HEADER_IO(Bwrite, &b, a))
- wrerr();
-
- headlen = Boffset(&b);
- len += headlen;
- if (gflag) {
- getpkgdef(&pkgdefdata, &pkgdefsize);
- len += SAR_HDR + pkgdefsize;
- if (len & 1)
- len++;
- }
- if (astart) {
- wrsym(&b, len, astart->sym);
- len += astart->size;
- }
- if(amiddle) {
- wrsym(&b, len, amiddle->sym);
- len += amiddle->size;
- }
- if(aend)
- wrsym(&b, len, aend->sym);
-
- if(symdefsize&0x01)
- BPUTC(&b, 0);
-
- if (gflag) {
- len = pkgdefsize;
- sprint(a.date, "%-12ld", 0L); // time(0)
- sprint(a.uid, "%-6d", 0);
- sprint(a.gid, "%-6d", 0);
- sprint(a.mode, "%-8lo", 0644L);
- sprint(a.size, "%-10ld", (len + 1) & ~1);
- strncpy(a.fmag, ARFMAG, 2);
- strcpy(a.name, pkgdef);
- for (cp = strchr(a.name, 0); /* blank pad on right */
- cp < a.name+sizeof(a.name); cp++)
- *cp = ' ';
- if(HEADER_IO(Bwrite, &b, a))
- wrerr();
-
- if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize)
- wrerr();
- if(len&0x01)
- BPUTC(&b, 0);
- }
- Bterm(&b);
-}
-
-/*
- * Write the defined symbols to the symdef file
- */
-void
-wrsym(Biobuf *bp, long offset, Arsymref *as)
-{
- int off;
-
- while(as) {
- BPUTC(bp, as->type);
- off = as->offset+offset;
- BPUTLE4(bp, off);
- if (Bwrite(bp, as->name, as->len+1) != as->len+1)
- wrerr();
- as = as->next;
- }
-}
-
-/*
- * Check if the archive member matches an entry on the command line.
- */
-int
-match(int count, char **files)
-{
- int i;
- char name[ARNAMESIZE+1];
-
- for(i=0; i<count; i++) {
- if(files[i] == 0)
- continue;
- trim(files[i], name, ARNAMESIZE);
- if(strncmp(name, file, ARNAMESIZE) == 0) {
- file = files[i];
- files[i] = 0;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * compare the current member to the name of the pivot member
- */
-int
-bamatch(char *file, char *pivot)
-{
- static int state = 0;
-
- switch(state)
- {
- case 0: /* looking for position file */
- if (aflag) {
- if (strncmp(file, pivot, ARNAMESIZE) == 0)
- state = 1;
- } else if (bflag) {
- if (strncmp(file, pivot, ARNAMESIZE) == 0) {
- state = 2; /* found */
- return 1;
- }
- }
- break;
- case 1: /* found - after previous file */
- state = 2;
- return 1;
- case 2: /* already found position file */
- break;
- }
- return 0;
-}
-
-/*
- * output a message, if 'v' option was specified
- */
-void
-mesg(int c, char *file)
-{
-
- if(vflag)
- Bprint(&bout, "%c - %s\n", c, file);
-}
-
-/*
- * isolate file name by stripping leading directories and trailing slashes
- */
-void
-trim(char *s, char *buf, int n)
-{
- char *p, *q;
-
- for(;;) {
- p = strrchr(s, '/');
- q = strrchr(s, '\\');
- if (q > p)
- p = q;
- if (!p) { /* no (back)slash in name */
- strncpy(buf, s, n);
- return;
- }
- if (p[1] != 0) { /* p+1 is first char of file name */
- strncpy(buf, p+1, n);
- return;
- }
- *p = 0; /* strip trailing (back)slash */
- }
-}
-
-/*
- * utilities for printing long form of 't' command
- */
-#define SUID 04000
-#define SGID 02000
-#define ROWN 0400
-#define WOWN 0200
-#define XOWN 0100
-#define RGRP 040
-#define WGRP 020
-#define XGRP 010
-#define ROTH 04
-#define WOTH 02
-#define XOTH 01
-#define STXT 01000
-
-void
-longt(Armember *bp)
-{
- char *cp;
-
- pmode(strtoul(bp->hdr.mode, 0, 8));
- Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
- Bprint(&bout, "%7ld", bp->size);
- cp = ctime(bp->date);
- Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
-}
-
-int m1[] = { 1, ROWN, 'r', '-' };
-int m2[] = { 1, WOWN, 'w', '-' };
-int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
-int m4[] = { 1, RGRP, 'r', '-' };
-int m5[] = { 1, WGRP, 'w', '-' };
-int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
-int m7[] = { 1, ROTH, 'r', '-' };
-int m8[] = { 1, WOTH, 'w', '-' };
-int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
-
-int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
-
-void
-pmode(long mode)
-{
- int **mp;
-
- for(mp = &m[0]; mp < &m[9];)
- select(*mp++, mode);
-}
-
-void
-select(int *ap, long mode)
-{
- int n;
-
- n = *ap++;
- while(--n>=0 && (mode&*ap++)==0)
- ap++;
- BPUTC(&bout, *ap);
-}
-
-/*
- * Temp file I/O subsystem. We attempt to cache all three temp files in
- * core. When we run out of memory we spill to disk.
- * The I/O model assumes that temp files:
- * 1) are only written on the end
- * 2) are only read from the beginning
- * 3) are only read after all writing is complete.
- * The architecture uses one control block per temp file. Each control
- * block anchors a chain of buffers, each containing an archive member.
- */
-Arfile *
-newtempfile(char *name) /* allocate a file control block */
-{
- Arfile *ap;
-
- ap = armalloc(sizeof(Arfile));
- ap->fname = name;
- return ap;
-}
-
-Armember *
-newmember(void) /* allocate a member buffer */
-{
- return armalloc(sizeof(Armember));
-}
-
-void
-arread(Biobuf *b, Armember *bp) /* read an image into a member buffer */
-{
- int i;
- vlong off;
-
- bp->member = armalloc(bp->size);
-
- // If P flag is set, let arread_cutprefix try.
- // If it succeeds, we're done. If not, fall back
- // to a direct copy.
- off = Boffset(b);
- if(Pflag && arread_cutprefix(b, bp))
- return;
- Bseek(b, off, 0);
-
- i = Bread(b, bp->member, bp->size);
- if (i < 0) {
- free(bp->member);
- bp->member = 0;
- rderr();
- }
- if(bp->size&1)
- BGETC(b);
-}
-
-/*
- * insert a member buffer into the member chain
- */
-void
-arinsert(Arfile *ap, Armember *bp)
-{
- bp->next = 0;
- if (!ap->tail)
- ap->head = bp;
- else
- ap->tail->next = bp;
- ap->tail = bp;
-}
-
-/*
- * stream the members in a temp file to the file referenced by 'fd'.
- */
-void
-arstream(int fd, Arfile *ap)
-{
- Armember *bp;
-
- /* dump the in-core buffers */
- for (bp = ap->head; bp; bp = bp->next) {
- if (!arwrite(fd, bp))
- wrerr();
- }
-}
-
-/*
- * write a member to 'fd'.
- */
-int
-arwrite(int fd, Armember *bp)
-{
- int len;
-
- if(HEADER_IO(write, fd, bp->hdr))
- return 0;
- len = bp->size;
- if (len & 01)
- len++;
- if (write(fd, bp->member, len) != len)
- return 0;
- return 1;
-}
-
-void
-arfree(Arfile *ap) /* free a member buffer */
-{
- Armember *bp, *next;
-
- for (bp = ap->head; bp; bp = next) {
- next = bp->next;
- if (bp->member)
- free(bp->member);
- free(bp);
- }
- free(ap);
-}
-
-/*
- * allocate space for a control block or member buffer. if the malloc
- * fails we try to reclaim space by spilling previously allocated
- * member buffers.
- */
-void *
-armalloc(int n)
-{
- char *cp;
-
- // bump so that arwrite can do the same
- if(n&1)
- n++;
-
- cp = malloc(n);
- if (cp) {
- memset(cp, 0, n);
- return cp;
- }
- fprint(2, "pack: out of memory\n");
- exits("malloc");
- return 0;
-}
-
-char *
-arstrdup(char *s)
-{
- char *t;
-
- t = armalloc(strlen(s) + 1);
- strcpy(t, s);
- return t;
-}
-
-
-/*
- * Parts of libmach we're not supposed
- * to look at but need for arread_cutprefix.
- */
-extern int _read5(Biobuf*, Prog*);
-extern int _read6(Biobuf*, Prog*);
-extern int _read8(Biobuf*, Prog*);
-int (*reader[256])(Biobuf*, Prog*) = {
- [ObjArm] = _read5,
- [ObjAmd64] = _read6,
- [Obj386] = _read8,
-};
-
-#define isdelim(c) ((c) == '/' || (c) == '\\')
-
-/*
- * check if p is start of windows full path, like C:\ or c:/.
- * return 1 if so. also set drive parameter to its
- * upper-case drive letter.
- */
-int
-iswinpathstart(char *p, char *drive)
-{
- if('A' <= p[0] || p[0] <= 'Z')
- *drive = p[0];
- else if('a' <= p[0] || p[0] <= 'z')
- *drive = p[0] - ('a' - 'A');
- else
- return 0;
- return p[1] == ':' && isdelim(p[2]);
-}
-
-/*
- * copy b into bp->member but rewrite object
- * during copy to drop prefix from all file names.
- * return 1 if b was recognized as an object file
- * and copied successfully, 0 otherwise.
- */
-int
-arread_cutprefix(Biobuf *b, Armember *bp)
-{
- vlong offset, o, end;
- int n, t;
- int (*rd)(Biobuf*, Prog*);
- char *w, *inprefix, d1, d2;
- Prog p;
-
- offset = Boffset(b);
- end = offset + bp->size;
- t = objtype(b, nil);
- if(t < 0)
- return 0;
- if((rd = reader[t]) == nil)
- return 0;
-
- // copy header
- w = bp->member;
- n = Boffset(b) - offset;
- Bseek(b, -n, 1);
- if(Bread(b, w, n) != n)
- return 0;
- offset += n;
- w += n;
-
- // read object file one pseudo-instruction at a time,
- // eliding the file name instructions that refer to
- // the prefix.
- memset(&p, 0, sizeof p);
- inprefix = nil;
- while(Boffset(b) < end && rd(b, &p)) {
- if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
- // part of a file path.
- // we'll keep continuing (skipping the copy)
- // around the loop until either we get to a
- // name piece that should be kept or we see
- // the whole prefix.
-
- if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') {
- // leading /
- inprefix = prefix+1;
- } else if(inprefix == nil && iswinpathstart(prefix, &d1) && iswinpathstart(p.id + 1, &d2) && d1 == d2 && p.id[4] == '\0') {
- // leading c:\ ...
- inprefix = prefix+3;
- } else if(inprefix != nil) {
- // handle subsequent elements
- n = strlen(p.id+1);
- if(strncmp(p.id+1, inprefix, n) == 0 && (isdelim(inprefix[n]) || inprefix[n] == '\0')) {
- inprefix += n;
- if(isdelim(inprefix[0]))
- inprefix++;
- }
- }
-
- if(inprefix && inprefix[0] == '\0') {
- // reached end of prefix.
- // if we another path element follows,
- // nudge the offset to skip over the prefix we saw.
- // if not, leave offset alone, to emit the whole name.
- // additional name elements will not be skipped
- // because inprefix is now nil and we won't see another
- // leading / in this name.
- inprefix = nil;
- o = Boffset(b);
- if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
- // print("skip %lld-%lld\n", offset, o);
- offset = o;
- }
- }
- } else {
- // didn't find the whole prefix.
- // give up and let it emit the entire name.
- inprefix = nil;
- }
-
- // copy instructions
- if(!inprefix) {
- n = Boffset(b) - offset;
- Bseek(b, -n, 1);
- if(Bread(b, w, n) != n)
- return 0;
- offset += n;
- w += n;
- }
- }
- bp->size = w - (char*)bp->member;
- sprint(bp->hdr.size, "%-10lld", (vlong)bp->size);
- strncpy(bp->hdr.fmag, ARFMAG, 2);
- Bseek(b, end, 0);
- if(Boffset(b)&1)
- BGETC(b);
- return 1;
-}
diff --git a/src/cmd/pack/doc.go b/src/cmd/pack/doc.go
index 67b789731..1529e07e9 100644
--- a/src/cmd/pack/doc.go
+++ b/src/cmd/pack/doc.go
@@ -1,29 +1,37 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build ignore
-
/*
-Pack is a variant of the Plan 9 ar tool. The original is documented at
+Pack is a simple version of the traditional Unix ar tool.
+It implements only the operations needed by Go.
- http://plan9.bell-labs.com/magic/man2html/1/ar
+Usage:
+ go tool pack op file.a [name...]
-It adds a special Go-specific section __.PKGDEF that collects all the
-Go type information from the files in the archive; that section is
-used by the compiler when importing the package during compilation.
+Pack applies the operation to the archive, using the names as arguments to the operation.
-Usage:
- go tool pack [uvnbailogS][mrxtdpq][P prefix] archive files ...
+The operation op is given by one of these letters:
+
+ c append files (from the file system) to a new archive
+ p print files from the archive
+ r append files (from the file system) to the archive
+ t list files from the archive
+ x extract files from the archive
+
+For the p, t, and x commands, listing no names on the command line
+causes the operation to apply to all files in the archive.
-The new option 'g' causes pack to maintain the __.PKGDEF section
-as files are added to the archive.
+In contrast to Unix ar, the r operation always appends to the archive,
+even if a file with the given name already exists in the archive. In this way
+pack's r operation is more like Unix ar's rq operation.
-The new option 'S' forces pack to mark the archive as safe.
+Adding the letter v to an operation, as in pv or rv, enables verbose operation:
+For the c and r commands, names are printed as files are added.
+For the p command, each file is prefixed by the name on a line by itself.
+For the t command, the listing includes additional file metadata.
+For the x command, names are printed as files are extracted.
-The new option 'P' causes pack to remove the given prefix
-from file names in the line number information in object files
-that are already stored in or added to the archive.
*/
package main
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
new file mode 100644
index 000000000..594433712
--- /dev/null
+++ b/src/cmd/pack/pack.go
@@ -0,0 +1,486 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+/*
+The archive format is:
+
+First, on a line by itself
+ !<arch>
+
+Then zero or more file records. Each file record has a fixed-size one-line header
+followed by data bytes followed by an optional padding byte. The header is:
+
+ %-16s%-12d%-6d%-6d%-8o%-10d`
+ name mtime uid gid mode size
+
+(note the trailing backquote). The %-16s here means at most 16 *bytes* of
+the name, and if shorter, space padded on the right.
+*/
+
+const usageMessage = `Usage: pack op file.a [name....]
+Where op is one of cprtx optionally followed by v for verbose output.
+For compatibility with old Go build environments the op string grc is
+accepted as a synonym for c.
+
+For more information, run
+ godoc cmd/pack`
+
+func usage() {
+ fmt.Fprintln(os.Stderr, usageMessage)
+ os.Exit(2)
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("pack: ")
+ // need "pack op archive" at least.
+ if len(os.Args) < 3 {
+ log.Print("not enough arguments")
+ fmt.Fprintln(os.Stderr)
+ usage()
+ }
+ setOp(os.Args[1])
+ var ar *Archive
+ switch op {
+ case 'p':
+ ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+ ar.scan(ar.printContents)
+ case 'r':
+ ar = archive(os.Args[2], os.O_RDWR, os.Args[3:])
+ ar.scan(ar.skipContents)
+ ar.addFiles()
+ case 'c':
+ ar = archive(os.Args[2], os.O_RDWR|os.O_TRUNC, os.Args[3:])
+ ar.addPkgdef()
+ ar.addFiles()
+ case 't':
+ ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+ ar.scan(ar.tableOfContents)
+ case 'x':
+ ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+ ar.scan(ar.extractContents)
+ default:
+ log.Printf("invalid operation %q", os.Args[1])
+ fmt.Fprintln(os.Stderr)
+ usage()
+ }
+ if len(ar.files) > 0 {
+ log.Fatalf("file %q not in archive", ar.files[0])
+ }
+}
+
+// The unusual ancestry means the arguments are not Go-standard.
+// These variables hold the decoded operation specified by the first argument.
+// op holds the operation we are doing (prtx).
+// verbose tells whether the 'v' option was specified.
+var (
+ op rune
+ verbose bool
+)
+
+// setOp parses the operation string (first argument).
+func setOp(arg string) {
+ // Recognize 'go tool pack grc' because that was the
+ // formerly canonical way to build a new archive
+ // from a set of input files. Accepting it keeps old
+ // build systems working with both Go 1.2 and Go 1.3.
+ if arg == "grc" {
+ arg = "c"
+ }
+
+ for _, r := range arg {
+ switch r {
+ case 'c', 'p', 'r', 't', 'x':
+ if op != 0 {
+ // At most one can be set.
+ usage()
+ }
+ op = r
+ case 'v':
+ if verbose {
+ // Can be set only once.
+ usage()
+ }
+ verbose = true
+ default:
+ usage()
+ }
+ }
+}
+
+const (
+ arHeader = "!<arch>\n"
+ entryHeader = "%s%-12d%-6d%-6d%-8o%-10d`\n"
+ // In entryHeader the first entry, the name, is always printed as 16 bytes right-padded.
+ entryLen = 16 + 12 + 6 + 6 + 8 + 10 + 1 + 1
+ timeFormat = "Jan _2 15:04 2006"
+)
+
+// An Archive represents an open archive file. It is always scanned sequentially
+// from start to end, without backing up.
+type Archive struct {
+ fd *os.File // Open file descriptor.
+ files []string // Explicit list of files to be processed.
+ pad int // Padding bytes required at end of current archive file
+ matchAll bool // match all files in archive
+}
+
+// archive opens (or if necessary creates) the named archive.
+func archive(name string, mode int, files []string) *Archive {
+ fd, err := os.OpenFile(name, mode, 0)
+ if err != nil && mode&^os.O_TRUNC == os.O_RDWR && os.IsNotExist(err) {
+ fd, err = create(name)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ mustBeArchive(fd)
+ return &Archive{
+ fd: fd,
+ files: files,
+ matchAll: len(files) == 0,
+ }
+}
+
+// create creates and initializes an archive that does not exist.
+func create(name string) (*os.File, error) {
+ fd, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ return nil, err
+ }
+ fmt.Fprint(fd, arHeader)
+ fd.Seek(0, 0)
+ return fd, nil
+}
+
+// mustBeArchive verifies the header of the file. It assumes the file offset
+// is 0 coming in, and leaves it positioned immediately after the header.
+func mustBeArchive(fd *os.File) {
+ buf := make([]byte, len(arHeader))
+ _, err := io.ReadFull(fd, buf)
+ if err != nil || string(buf) != arHeader {
+ log.Fatal("file is not an archive: bad header")
+ }
+}
+
+// An Entry is the internal representation of the per-file header information of one entry in the archive.
+type Entry struct {
+ name string
+ mtime int64
+ uid int
+ gid int
+ mode os.FileMode
+ size int64
+}
+
+func (e *Entry) String() string {
+ return fmt.Sprintf("%s %6d/%-6d %12d %s %s",
+ (e.mode & 0777).String(),
+ e.uid,
+ e.gid,
+ e.size,
+ time.Unix(e.mtime, 0).Format(timeFormat),
+ e.name)
+}
+
+// readMetadata reads and parses the metadata for the next entry in the archive.
+func (ar *Archive) readMetadata() *Entry {
+ buf := make([]byte, entryLen)
+ _, err := io.ReadFull(ar.fd, buf)
+ if err == io.EOF {
+ // No entries left.
+ return nil
+ }
+ if err != nil || buf[entryLen-2] != '`' || buf[entryLen-1] != '\n' {
+ log.Fatal("file is not an archive: bad entry")
+ }
+ entry := new(Entry)
+ entry.name = strings.TrimRight(string(buf[:16]), " ")
+ if len(entry.name) == 0 {
+ log.Fatal("file is not an archive: bad name")
+ }
+ buf = buf[16:]
+ str := string(buf)
+ get := func(width, base, bitsize int) int64 {
+ v, err := strconv.ParseInt(strings.TrimRight(str[:width], " "), base, bitsize)
+ if err != nil {
+ log.Fatal("file is not an archive: bad number in entry: ", err)
+ }
+ str = str[width:]
+ return v
+ }
+ // %-16s%-12d%-6d%-6d%-8o%-10d`
+ entry.mtime = get(12, 10, 64)
+ entry.uid = int(get(6, 10, 32))
+ entry.gid = int(get(6, 10, 32))
+ entry.mode = os.FileMode(get(8, 8, 32))
+ entry.size = get(10, 10, 64)
+ return entry
+}
+
+// scan scans the archive and executes the specified action on each entry.
+// When action returns, the file offset is at the start of the next entry.
+func (ar *Archive) scan(action func(*Entry)) {
+ for {
+ entry := ar.readMetadata()
+ if entry == nil {
+ break
+ }
+ action(entry)
+ }
+}
+
+// listEntry prints to standard output a line describing the entry.
+func listEntry(ar *Archive, entry *Entry, verbose bool) {
+ if verbose {
+ fmt.Fprintf(stdout, "%s\n", entry)
+ } else {
+ fmt.Fprintf(stdout, "%s\n", entry.name)
+ }
+}
+
+// output copies the entry to the specified writer.
+func (ar *Archive) output(entry *Entry, w io.Writer) {
+ n, err := io.Copy(w, io.LimitReader(ar.fd, entry.size))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if n != entry.size {
+ log.Fatal("short file")
+ }
+ if entry.size&1 == 1 {
+ _, err := ar.fd.Seek(1, 1)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+// skip skips the entry without reading it.
+func (ar *Archive) skip(entry *Entry) {
+ size := entry.size
+ if size&1 == 1 {
+ size++
+ }
+ _, err := ar.fd.Seek(size, 1)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+// match reports whether the entry matches the argument list.
+// If it does, it also drops the file from the to-be-processed list.
+func (ar *Archive) match(entry *Entry) bool {
+ if ar.matchAll {
+ return true
+ }
+ for i, name := range ar.files {
+ if entry.name == name {
+ copy(ar.files[i:], ar.files[i+1:])
+ ar.files = ar.files[:len(ar.files)-1]
+ return true
+ }
+ }
+ return false
+}
+
+// addFiles adds files to the archive. The archive is known to be
+// sane and we are positioned at the end. No attempt is made
+// to check for existing files.
+func (ar *Archive) addFiles() {
+ if len(ar.files) == 0 {
+ usage()
+ }
+ for _, file := range ar.files {
+ if verbose {
+ fmt.Printf("%s\n", file)
+ }
+ fd, err := os.Open(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ ar.addFile(fd)
+ }
+ ar.files = nil
+}
+
+// FileLike abstracts the few methods we need, so we can test without needing real files.
+type FileLike interface {
+ Name() string
+ Stat() (os.FileInfo, error)
+ Read([]byte) (int, error)
+ Close() error
+}
+
+// addFile adds a single file to the archive
+func (ar *Archive) addFile(fd FileLike) {
+ defer fd.Close()
+ // Format the entry.
+ // First, get its info.
+ info, err := fd.Stat()
+ if err != nil {
+ log.Fatal(err)
+ }
+ // mtime, uid, gid are all zero so repeated builds produce identical output.
+ mtime := int64(0)
+ uid := 0
+ gid := 0
+ ar.startFile(info.Name(), mtime, uid, gid, info.Mode(), info.Size())
+ n64, err := io.Copy(ar.fd, fd)
+ if err != nil {
+ log.Fatal("writing file: ", err)
+ }
+ if n64 != info.Size() {
+ log.Fatalf("writing file: wrote %d bytes; file is size %d", n64, info.Size())
+ }
+ ar.endFile()
+}
+
+// startFile writes the archive entry header.
+func (ar *Archive) startFile(name string, mtime int64, uid, gid int, mode os.FileMode, size int64) {
+ n, err := fmt.Fprintf(ar.fd, entryHeader, exactly16Bytes(name), mtime, uid, gid, mode, size)
+ if err != nil || n != entryLen {
+ log.Fatal("writing entry header: ", err)
+ }
+ ar.pad = int(size & 1)
+}
+
+// endFile writes the archive entry tail (a single byte of padding, if the file size was odd).
+func (ar *Archive) endFile() {
+ if ar.pad != 0 {
+ _, err := ar.fd.Write([]byte{0})
+ if err != nil {
+ log.Fatal("writing archive: ", err)
+ }
+ ar.pad = 0
+ }
+}
+
+// addPkgdef adds the __.PKGDEF file to the archive, copied
+// from the first Go object file on the file list, if any.
+// The archive is known to be empty.
+func (ar *Archive) addPkgdef() {
+ for _, file := range ar.files {
+ pkgdef, err := readPkgdef(file)
+ if err != nil {
+ continue
+ }
+ if verbose {
+ fmt.Printf("__.PKGDEF # %s\n", file)
+ }
+ ar.startFile("__.PKGDEF", 0, 0, 0, 0644, int64(len(pkgdef)))
+ _, err = ar.fd.Write(pkgdef)
+ if err != nil {
+ log.Fatal("writing __.PKGDEF: ", err)
+ }
+ ar.endFile()
+ break
+ }
+}
+
+// readPkgdef extracts the __.PKGDEF data from a Go object file.
+func readPkgdef(file string) (data []byte, err error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ // Read from file, collecting header for __.PKGDEF.
+ // The header is from the beginning of the file until a line
+ // containing just "!". The first line must begin with "go object ".
+ rbuf := bufio.NewReader(f)
+ var wbuf bytes.Buffer
+ for {
+ line, err := rbuf.ReadBytes('\n')
+ if err != nil {
+ return nil, err
+ }
+ if wbuf.Len() == 0 && !bytes.HasPrefix(line, []byte("go object ")) {
+ return nil, errors.New("not a Go object file")
+ }
+ if bytes.Equal(line, []byte("!\n")) {
+ break
+ }
+ wbuf.Write(line)
+ }
+ return wbuf.Bytes(), nil
+}
+
+// exactly16Bytes truncates the string if necessary so it is at most 16 bytes long,
+// then pads the result with spaces to be exactly 16 bytes.
+// Fmt uses runes for its width calculation, but we need bytes in the entry header.
+func exactly16Bytes(s string) string {
+ for len(s) > 16 {
+ _, wid := utf8.DecodeLastRuneInString(s)
+ s = s[:len(s)-wid]
+ }
+ const sixteenSpaces = " "
+ s += sixteenSpaces[:16-len(s)]
+ return s
+}
+
+// Finally, the actual commands. Each is an action.
+
+// can be modified for testing.
+var stdout io.Writer = os.Stdout
+
+// printContents implements the 'p' command.
+func (ar *Archive) printContents(entry *Entry) {
+ if ar.match(entry) {
+ if verbose {
+ listEntry(ar, entry, false)
+ }
+ ar.output(entry, stdout)
+ } else {
+ ar.skip(entry)
+ }
+}
+
+// skipContents implements the first part of the 'r' command.
+// It just scans the archive to make sure it's intact.
+func (ar *Archive) skipContents(entry *Entry) {
+ ar.skip(entry)
+}
+
+// tableOfContents implements the 't' command.
+func (ar *Archive) tableOfContents(entry *Entry) {
+ if ar.match(entry) {
+ listEntry(ar, entry, verbose)
+ }
+ ar.skip(entry)
+}
+
+// extractContents implements the 'x' command.
+func (ar *Archive) extractContents(entry *Entry) {
+ if ar.match(entry) {
+ if verbose {
+ listEntry(ar, entry, false)
+ }
+ fd, err := os.OpenFile(entry.name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, entry.mode)
+ if err != nil {
+ log.Fatal(err)
+ }
+ ar.output(entry, fd)
+ fd.Close()
+ } else {
+ ar.skip(entry)
+ }
+}
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
new file mode 100644
index 000000000..486242603
--- /dev/null
+++ b/src/cmd/pack/pack_test.go
@@ -0,0 +1,402 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "testing"
+ "time"
+ "unicode/utf8"
+)
+
+func TestExactly16Bytes(t *testing.T) {
+ var tests = []string{
+ "",
+ "a",
+ "日本語",
+ "1234567890123456",
+ "12345678901234567890",
+ "1234567890123本語4567890",
+ "12345678901234日本語567890",
+ "123456789012345日本語67890",
+ "1234567890123456日本語7890",
+ "1234567890123456日本語7日本語890",
+ }
+ for _, str := range tests {
+ got := exactly16Bytes(str)
+ if len(got) != 16 {
+ t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got))
+ }
+ // Make sure it is full runes.
+ for _, c := range got {
+ if c == utf8.RuneError {
+ t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got)
+ }
+ }
+ }
+}
+
+// tmpDir creates a temporary directory and returns its name.
+func tmpDir(t *testing.T) string {
+ name, err := ioutil.TempDir("", "pack")
+ if err != nil {
+ t.Fatal(err)
+ }
+ return name
+}
+
+// Test that we can create an archive, write to it, and get the same contents back.
+// Tests the rv and then the pv command on a new archive.
+func TestCreate(t *testing.T) {
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ name := filepath.Join(dir, "pack.a")
+ ar := archive(name, os.O_RDWR, nil)
+ // Add an entry by hand.
+ ar.addFile(helloFile.Reset())
+ ar.fd.Close()
+ // Now check it.
+ ar = archive(name, os.O_RDONLY, []string{helloFile.name})
+ var buf bytes.Buffer
+ stdout = &buf
+ verbose = true
+ defer func() {
+ stdout = os.Stdout
+ verbose = false
+ }()
+ ar.scan(ar.printContents)
+ ar.fd.Close()
+ result := buf.String()
+ // Expect verbose output plus file contents.
+ expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents)
+ if result != expect {
+ t.Fatalf("expected %q got %q", expect, result)
+ }
+}
+
+// Test that we can create an archive, put some files in it, and get back a correct listing.
+// Tests the tv command.
+func TestTableOfContents(t *testing.T) {
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ name := filepath.Join(dir, "pack.a")
+ ar := archive(name, os.O_RDWR, nil)
+
+ // Add some entries by hand.
+ ar.addFile(helloFile.Reset())
+ ar.addFile(goodbyeFile.Reset())
+ ar.fd.Close()
+
+ // Now print it.
+ ar = archive(name, os.O_RDONLY, nil)
+ var buf bytes.Buffer
+ stdout = &buf
+ verbose = true
+ defer func() {
+ stdout = os.Stdout
+ verbose = false
+ }()
+ ar.scan(ar.tableOfContents)
+ ar.fd.Close()
+ result := buf.String()
+ // Expect verbose listing.
+ expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry())
+ if result != expect {
+ t.Fatalf("expected %q got %q", expect, result)
+ }
+
+ // Do it again without verbose.
+ verbose = false
+ buf.Reset()
+ ar = archive(name, os.O_RDONLY, nil)
+ ar.scan(ar.tableOfContents)
+ ar.fd.Close()
+ result = buf.String()
+ // Expect non-verbose listing.
+ expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name)
+ if result != expect {
+ t.Fatalf("expected %q got %q", expect, result)
+ }
+
+ // Do it again with file list arguments.
+ verbose = false
+ buf.Reset()
+ ar = archive(name, os.O_RDONLY, []string{helloFile.name})
+ ar.scan(ar.tableOfContents)
+ ar.fd.Close()
+ result = buf.String()
+ // Expect only helloFile.
+ expect = fmt.Sprintf("%s\n", helloFile.name)
+ if result != expect {
+ t.Fatalf("expected %q got %q", expect, result)
+ }
+}
+
+// Test that we can create an archive, put some files in it, and get back a file.
+// Tests the x command.
+func TestExtract(t *testing.T) {
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ name := filepath.Join(dir, "pack.a")
+ ar := archive(name, os.O_RDWR, nil)
+ // Add some entries by hand.
+ ar.addFile(helloFile.Reset())
+ ar.addFile(goodbyeFile.Reset())
+ ar.fd.Close()
+ // Now extract one file. We chdir to the directory of the archive for simplicity.
+ pwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal("os.Getwd: ", err)
+ }
+ err = os.Chdir(dir)
+ if err != nil {
+ t.Fatal("os.Chdir: ", err)
+ }
+ defer func() {
+ err := os.Chdir(pwd)
+ if err != nil {
+ t.Fatal("os.Chdir: ", err)
+ }
+ }()
+ ar = archive(name, os.O_RDONLY, []string{goodbyeFile.name})
+ ar.scan(ar.extractContents)
+ ar.fd.Close()
+ data, err := ioutil.ReadFile(goodbyeFile.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Expect contents of file.
+ result := string(data)
+ expect := goodbyeFile.contents
+ if result != expect {
+ t.Fatalf("expected %q got %q", expect, result)
+ }
+}
+
+// Test that pack-created archives can be understood by the tools.
+func TestHello(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ hello := filepath.Join(dir, "hello.go")
+ prog := `
+ package main
+ func main() {
+ println("hello world")
+ }
+ `
+ err := ioutil.WriteFile(hello, []byte(prog), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ char := findChar(t, dir)
+
+ run := func(args ...string) string {
+ return doRun(t, dir, args...)
+ }
+
+ run("go", "build", "cmd/pack") // writes pack binary to dir
+ run("go", "tool", char+"g", "hello.go")
+ run("./pack", "grc", "hello.a", "hello."+char)
+ run("go", "tool", char+"l", "-o", "a.out", "hello.a")
+ out := run("./a.out")
+ if out != "hello world\n" {
+ t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
+ }
+}
+
+// Test that pack works with very long lines in PKGDEF.
+func TestLargeDefs(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ large := filepath.Join(dir, "large.go")
+ f, err := os.Create(large)
+ if err != nil {
+ t.Fatal(err)
+ }
+ b := bufio.NewWriter(f)
+
+ printf := func(format string, args ...interface{}) {
+ _, err := fmt.Fprintf(b, format, args...)
+ if err != nil {
+ t.Fatalf("Writing to %s: %v", large, err)
+ }
+ }
+
+ printf("package large\n\ntype T struct {\n")
+ for i := 0; i < 10000; i++ {
+ printf("f%d int `tag:\"", i)
+ for j := 0; j < 100; j++ {
+ printf("t%d=%d,", j, j)
+ }
+ printf("\"`\n")
+ }
+ printf("}\n")
+ if err = b.Flush(); err != nil {
+ t.Fatal(err)
+ }
+ if err = f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ main := filepath.Join(dir, "main.go")
+ prog := `
+ package main
+ import "large"
+ var V large.T
+ func main() {
+ println("ok")
+ }
+ `
+ err = ioutil.WriteFile(main, []byte(prog), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ char := findChar(t, dir)
+
+ run := func(args ...string) string {
+ return doRun(t, dir, args...)
+ }
+
+ run("go", "build", "cmd/pack") // writes pack binary to dir
+ run("go", "tool", char+"g", "large.go")
+ run("./pack", "grc", "large.a", "large."+char)
+ run("go", "tool", char+"g", "-I", ".", "main.go")
+ run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char)
+ out := run("./a.out")
+ if out != "ok\n" {
+ t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
+ }
+}
+
+// doRun runs a program in a directory and returns the output.
+func doRun(t *testing.T, dir string, args ...string) string {
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%v: %v\n%s", args, err, string(out))
+ }
+ return string(out)
+}
+
+// findChar returns the architecture character for the go command.
+func findChar(t *testing.T, dir string) string {
+ out := doRun(t, dir, "go", "env")
+ re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fields := re.FindStringSubmatch(out)
+ if fields == nil {
+ t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
+ }
+ return fields[1]
+}
+
+// Fake implementation of files.
+
+var helloFile = &FakeFile{
+ name: "hello",
+ contents: "hello world", // 11 bytes, an odd number.
+ mode: 0644,
+}
+
+var goodbyeFile = &FakeFile{
+ name: "goodbye",
+ contents: "Sayonara, Jim", // 13 bytes, another odd number.
+ mode: 0644,
+}
+
+// FakeFile implements FileLike and also os.FileInfo.
+type FakeFile struct {
+ name string
+ contents string
+ mode os.FileMode
+ offset int
+}
+
+// Reset prepares a FakeFile for reuse.
+func (f *FakeFile) Reset() *FakeFile {
+ f.offset = 0
+ return f
+}
+
+// FileLike methods.
+
+func (f *FakeFile) Name() string {
+ // A bit of a cheat: we only have a basename, so that's also ok for FileInfo.
+ return f.name
+}
+
+func (f *FakeFile) Stat() (os.FileInfo, error) {
+ return f, nil
+}
+
+func (f *FakeFile) Read(p []byte) (int, error) {
+ if f.offset >= len(f.contents) {
+ return 0, io.EOF
+ }
+ n := copy(p, f.contents[f.offset:])
+ f.offset += n
+ return n, nil
+}
+
+func (f *FakeFile) Close() error {
+ return nil
+}
+
+// os.FileInfo methods.
+
+func (f *FakeFile) Size() int64 {
+ return int64(len(f.contents))
+}
+
+func (f *FakeFile) Mode() os.FileMode {
+ return f.mode
+}
+
+func (f *FakeFile) ModTime() time.Time {
+ return time.Time{}
+}
+
+func (f *FakeFile) IsDir() bool {
+ return false
+}
+
+func (f *FakeFile) Sys() interface{} {
+ return nil
+}
+
+// Special helpers.
+
+func (f *FakeFile) Entry() *Entry {
+ return &Entry{
+ name: f.name,
+ mtime: 0, // Defined to be zero.
+ uid: 0, // Ditto.
+ gid: 0, // Ditto.
+ mode: f.mode,
+ size: int64(len(f.contents)),
+ }
+}
diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile
index 480844805..f8c8169bd 100644
--- a/src/cmd/yacc/Makefile
+++ b/src/cmd/yacc/Makefile
@@ -2,9 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-expr: yacc.go expr.y
+TARG=expr$(shell go env GOEXE)
+
+$(TARG): yacc.go expr.y
go run yacc.go -p expr expr.y
- go build -o expr y.go
+ go build -o $(TARG) y.go
clean:
- rm -f y.go y.output expr
+ rm -f y.go y.output $(TARG)
diff --git a/src/cmd/yacc/expr.y b/src/cmd/yacc/expr.y
index 3afffe7ee..77e9259da 100644
--- a/src/cmd/yacc/expr.y
+++ b/src/cmd/yacc/expr.y
@@ -125,7 +125,7 @@ func (x *exprLex) Lex(yylval *exprSymType) int {
case '÷':
return '/'
- case ' ', '\t', '\n':
+ case ' ', '\t', '\n', '\r':
default:
log.Printf("unrecognized character %q", c)
}
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index c53dc3b74..c53403266 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -49,6 +49,8 @@ import (
"bytes"
"flag"
"fmt"
+ "go/format"
+ "io/ioutil"
"os"
"strings"
"unicode"
@@ -3212,6 +3214,7 @@ func exit(status int) {
if ftable != nil {
ftable.Flush()
ftable = nil
+ gofmt()
}
if foutput != nil {
foutput.Flush()
@@ -3224,6 +3227,18 @@ func exit(status int) {
os.Exit(status)
}
+func gofmt() {
+ src, err := ioutil.ReadFile(oflag)
+ if err != nil {
+ return
+ }
+ src, err = format.Source(src)
+ if err != nil {
+ return
+ }
+ ioutil.WriteFile(oflag, src, 0666)
+}
+
var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
var yaccpartext = `
/* parser for yacc output */
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
index ea8ea74e2..af55181b9 100644
--- a/src/lib9/_exits.c
+++ b/src/lib9/_exits.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/_exits.c
http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
index d65edcfbf..6b5a04ead 100644
--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/_p9dir.c
http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
index 3162b0117..5b002df75 100644
--- a/src/lib9/atoi.c
+++ b/src/lib9/atoi.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/ato*.c
http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
diff --git a/src/lib9/await.c b/src/lib9/await.c
index 690a61e5c..dfb155b24 100644
--- a/src/lib9/await.c
+++ b/src/lib9/await.c
@@ -1,3 +1,4 @@
+// +build !plan9
// +build !windows
/*
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
index fee40388f..cb8fce6a5 100644
--- a/src/lib9/cleanname.c
+++ b/src/lib9/cleanname.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Inferno libkern/cleanname.c
http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
diff --git a/src/lib9/create.c b/src/lib9/create.c
index d7023aea0..4ac7f7d61 100644
--- a/src/lib9/create.c
+++ b/src/lib9/create.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/create.c
http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
index 6317b594b..e16ad4a5e 100644
--- a/src/lib9/ctime.c
+++ b/src/lib9/ctime.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !plan9
+
#define NOPLAN9DEFINES
#include <u.h>
#include <libc.h>
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
index 8cc338409..c092a2a07 100644
--- a/src/lib9/dirfstat.c
+++ b/src/lib9/dirfstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/dirfstat.c
http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
index e32ddeaea..4666e2107 100644
--- a/src/lib9/dirfwstat.c
+++ b/src/lib9/dirfwstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/dirfwstat.c
http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
index df2f85bd0..33f0d7cf2 100644
--- a/src/lib9/dirstat.c
+++ b/src/lib9/dirstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/dirstat.c
http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
index 9bf348af6..22e25fff7 100644
--- a/src/lib9/dirwstat.c
+++ b/src/lib9/dirwstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/dirwstat.c
http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
index 9fdfdb8d1..5cac831d6 100644
--- a/src/lib9/dup.c
+++ b/src/lib9/dup.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/dup.c
http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
index f42f2b538..9d919755d 100644
--- a/src/lib9/errstr.c
+++ b/src/lib9/errstr.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/errstr.c
http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
@@ -32,7 +34,6 @@ THE SOFTWARE.
#include <u.h>
#include <errno.h>
-#include <string.h>
#include <libc.h>
enum
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
index f2ad0f9b3..8e5fc5784 100644
--- a/src/lib9/exec.c
+++ b/src/lib9/exec.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/exec.c
http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
index 81d315883..fd4d23daa 100644
--- a/src/lib9/execl.c
+++ b/src/lib9/execl.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/execl.c
http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
index a952b2da2..fc863445f 100644
--- a/src/lib9/exitcode.c
+++ b/src/lib9/exitcode.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/exitcode.c
http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
index 5caef8309..0be7cb9f1 100644
--- a/src/lib9/exits.c
+++ b/src/lib9/exits.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/_exits.c
http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
index c18d9ee5d..f760d47e5 100644
--- a/src/lib9/fmt/dorfmt.c
+++ b/src/lib9/fmt/dorfmt.c
@@ -61,5 +61,4 @@ dorfmt(Fmt *f, const Rune *fmt)
if(fmt == nil)
return -1;
}
- return 0; /* not reached */
}
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
new file mode 100644
index 000000000..a86709398
--- /dev/null
+++ b/src/lib9/fmt/errfmt.c
@@ -0,0 +1,32 @@
+// +build plan9
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+ char buf[ERRMAX];
+
+ rerrstr(buf, sizeof buf);
+ return __fmtcpy(f, buf, utflen(buf), strlen(buf));
+}
diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
index dec6f8480..6fe819221 100644
--- a/src/lib9/fmt/fltfmt.c
+++ b/src/lib9/fmt/fltfmt.c
@@ -154,6 +154,7 @@ xsub1(char *a, int n)
* so that it has a nonzero first digit.
*/
abort();
+ return 0;
}
/*
@@ -180,7 +181,7 @@ xfmtexp(char *p, int e, int ucase)
se[i++] = '0';
while(i > 0)
*p++ = se[--i];
- *p++ = '\0';
+ *p = '\0';
}
/*
@@ -192,7 +193,8 @@ xfmtexp(char *p, int e, int ucase)
static void
xdtoa(double f, char *s, int *exp, int *neg, int *ns)
{
- int d, e2, e, ee, i, ndigit, oerrno;
+ int d, e2, e, ee, i, ndigit;
+ int oerrno;
char c;
char tmp[NSIGNIF+10];
double g;
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
index c32abf115..dde05b7a5 100644
--- a/src/lib9/fmt/fmtfd.c
+++ b/src/lib9/fmt/fmtfd.c
@@ -43,7 +43,7 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size)
f->to = buf;
f->stop = buf + size;
f->flush = __fmtFdFlush;
- f->farg = (void*)(uintptr_t)fd;
+ f->farg = (void*)(uintptr)fd;
f->flags = 0;
f->nfmt = 0;
fmtlocaleinit(f, nil, nil, nil);
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
index 75406b5d1..a0e2636ec 100644
--- a/src/lib9/fmtlock2.c
+++ b/src/lib9/fmtlock2.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/fmtlock2.c
http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
index 9d805b516..2454b6b41 100644
--- a/src/lib9/getenv.c
+++ b/src/lib9/getenv.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/getenv.c
http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
index cbfd9d643..03a8ff1a2 100644
--- a/src/lib9/getwd.c
+++ b/src/lib9/getwd.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/getwd.c
http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
index c44e040d2..733ed70e9 100644
--- a/src/lib9/jmp.c
+++ b/src/lib9/jmp.c
@@ -1,3 +1,4 @@
+// +build !plan9
// +build !windows
/*
diff --git a/src/lib9/main.c b/src/lib9/main.c
index 816494af0..088b09523 100644
--- a/src/lib9/main.c
+++ b/src/lib9/main.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/main.c
http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
@@ -50,8 +52,8 @@ main(int argc, char **argv)
// don't display the crash dialog
DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
- argv0 = argv[0];
#endif
+ argv0 = argv[0];
p9main(argc, argv);
exits("main");
return 99;
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
index fa2277f72..f17b441aa 100644
--- a/src/lib9/nan.c
+++ b/src/lib9/nan.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/nan.c
http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
index c424aed54..7843d3471 100644
--- a/src/lib9/notify.c
+++ b/src/lib9/notify.c
@@ -1,3 +1,4 @@
+// +build !plan9
// +build !windows
/*
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
index aa1a1232e..2157ff313 100644
--- a/src/lib9/nulldir.c
+++ b/src/lib9/nulldir.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Inferno lib9/nulldir.c
http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
diff --git a/src/lib9/open.c b/src/lib9/open.c
index 4ac81ba5f..7f53c8ea6 100644
--- a/src/lib9/open.c
+++ b/src/lib9/open.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/open.c
http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
index 3c80a4fc0..7dfe9e515 100644
--- a/src/lib9/readn.c
+++ b/src/lib9/readn.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Inferno lib9/readn.c
http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
index c4ae90f97..23b3ee671 100644
--- a/src/lib9/rfork.c
+++ b/src/lib9/rfork.c
@@ -1,3 +1,4 @@
+// +build !plan9
// +build !windows
/*
diff --git a/src/lib9/run_plan9.c b/src/lib9/run_plan9.c
index cd85652f7..29932626d 100644
--- a/src/lib9/run_plan9.c
+++ b/src/lib9/run_plan9.c
@@ -2,6 +2,8 @@
// 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 <libc.h>
diff --git a/src/lib9/run_unix.c b/src/lib9/run_unix.c
index 3db33c76e..1acaefed8 100644
--- a/src/lib9/run_unix.c
+++ b/src/lib9/run_unix.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
#include <u.h>
#include <errno.h>
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
index 917003808..0a0706cbe 100644
--- a/src/lib9/seek.c
+++ b/src/lib9/seek.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/seek.c
http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
index 03dc6ea50..4b2b92b43 100644
--- a/src/lib9/strecpy.c
+++ b/src/lib9/strecpy.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Inferno lib9/strecpy.c
http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
index a5af3e1b4..9789061a8 100644
--- a/src/lib9/sysfatal.c
+++ b/src/lib9/sysfatal.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/sysfatal.c
http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
diff --git a/src/lib9/tempdir_plan9.c b/src/lib9/tempdir_plan9.c
index 092d00d16..80d7ddbe4 100644
--- a/src/lib9/tempdir_plan9.c
+++ b/src/lib9/tempdir_plan9.c
@@ -2,6 +2,8 @@
// 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 <libc.h>
diff --git a/src/lib9/tempdir_unix.c b/src/lib9/tempdir_unix.c
index 3ce87751b..269d53823 100644
--- a/src/lib9/tempdir_unix.c
+++ b/src/lib9/tempdir_unix.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
#include <u.h>
#include <dirent.h>
diff --git a/src/lib9/time.c b/src/lib9/time.c
index 7394e9e60..e1b87a774 100644
--- a/src/lib9/time.c
+++ b/src/lib9/time.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Plan 9 from User Space src/lib9/time.c
http://code.swtch.com/plan9port/src/tip/src/lib9/time.c
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
index a9b593567..a095fcda9 100644
--- a/src/lib9/tokenize.c
+++ b/src/lib9/tokenize.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
/*
Inferno lib9/tokenize.c
http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
index 5c9cdf051..fe6f6351a 100644
--- a/src/lib9/utf/Makefile
+++ b/src/lib9/utf/Makefile
@@ -21,10 +21,10 @@ runetypebody-%.h: mkrunetype UnicodeData-%.txt
CLEANFILES+=UnicodeData.txt
-UNICODE_VERSION=6.2.0
+UNICODE_VERSION=6.3.0
test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
clean:
- rm -f UnicodeData.txt mkrunetype \ No newline at end of file
+ rm -f UnicodeData.txt mkrunetype
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
index b3634965f..ed775af08 100644
--- a/src/lib9/utf/runetype.c
+++ b/src/lib9/utf/runetype.c
@@ -35,4 +35,4 @@ rbsearch(Rune c, Rune *t, int n, int ne)
return 0;
}
-#include "runetypebody-6.2.0.h"
+#include "runetypebody-6.3.0.h"
diff --git a/src/lib9/utf/runetypebody-6.2.0.h b/src/lib9/utf/runetypebody-6.3.0.h
index a603af0df..5554dca36 100644
--- a/src/lib9/utf/runetypebody-6.2.0.h
+++ b/src/lib9/utf/runetypebody-6.3.0.h
@@ -1,4 +1,4 @@
-/* generated automatically by mkrunetype.c from UnicodeData-6.2.0.txt */
+/* generated automatically by mkrunetype.c from UnicodeData-6.3.0.txt */
static Rune __isspacer[] = {
0x0009, 0x000d,
@@ -6,7 +6,6 @@ static Rune __isspacer[] = {
0x0085, 0x0085,
0x00a0, 0x00a0,
0x1680, 0x1680,
- 0x180e, 0x180e,
0x2000, 0x200a,
0x2028, 0x2029,
0x202f, 0x202f,
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
index adc6d95fb..4bbdfc643 100644
--- a/src/lib9/utf/utfdef.h
+++ b/src/lib9/utf/utfdef.h
@@ -25,4 +25,3 @@ typedef unsigned int uint;
typedef unsigned long ulong;
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define nil ((void*)0)
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
index 2eca85ef6..854066460 100644
--- a/src/lib9/utf/utfecpy.c
+++ b/src/lib9/utf/utfecpy.c
@@ -11,8 +11,8 @@
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
-#define _BSD_SOURCE 1
-#include <string.h>
+#include <u.h>
+#include <libc.h>
#include "utf.h"
#include "utfdef.h"
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
index 42fcb33ab..9b961856a 100644
--- a/src/lib9/utf/utflen.c
+++ b/src/lib9/utf/utflen.c
@@ -32,5 +32,4 @@ utflen(const char *s)
s += chartorune(&rune, s);
n++;
}
- return 0;
}
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
index 9e28af82a..b1ea93b42 100644
--- a/src/lib9/utf/utfrrune.c
+++ b/src/lib9/utf/utfrrune.c
@@ -11,7 +11,8 @@
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
-#include <string.h>
+#include <u.h>
+#include <libc.h>
#include "utf.h"
#include "utfdef.h"
@@ -42,5 +43,4 @@ utfrrune(const char *s, Rune c)
s1 = s;
s += c1;
}
- return 0;
}
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
index 0136b2821..44675c989 100644
--- a/src/lib9/utf/utfrune.c
+++ b/src/lib9/utf/utfrune.c
@@ -11,7 +11,8 @@
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
-#include <string.h>
+#include <u.h>
+#include <libc.h>
#include "utf.h"
#include "utfdef.h"
@@ -41,5 +42,4 @@ utfrune(const char *s, Rune c)
return (char*)s;
s += n;
}
- return 0;
}
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
index e46ddd923..05335b23e 100644
--- a/src/lib9/utf/utfutf.c
+++ b/src/lib9/utf/utfutf.c
@@ -11,7 +11,8 @@
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
-#include <string.h>
+#include <u.h>
+#include <libc.h>
#include "utf.h"
#include "utfdef.h"
diff --git a/src/libbio/bgetc.c b/src/libbio/bgetc.c
index 3399fb16b..ceb5cb13f 100644
--- a/src/libbio/bgetc.c
+++ b/src/libbio/bgetc.c
@@ -83,7 +83,7 @@ Bgetle4(Biobuf *bp)
l = Bgetle2(bp);
h = Bgetle2(bp);
- return l|((uint32)h<<16);
+ return (int)((uint32)l|((uint32)h<<16));
}
int
diff --git a/src/libbio/bgetrune.c b/src/libbio/bgetrune.c
index 441c07991..b5db39106 100644
--- a/src/libbio/bgetrune.c
+++ b/src/libbio/bgetrune.c
@@ -26,7 +26,6 @@ THE SOFTWARE.
#include <u.h>
#include <libc.h>
#include <bio.h>
-#include <utf.h>
long
Bgetrune(Biobuf *bp)
diff --git a/src/libbio/bputrune.c b/src/libbio/bputrune.c
index 7fe0e6569..f2077958b 100644
--- a/src/libbio/bputrune.c
+++ b/src/libbio/bputrune.c
@@ -26,7 +26,6 @@ THE SOFTWARE.
#include <u.h>
#include <libc.h>
#include <bio.h>
-#include <utf.h>
int
Bputrune(Biobuf *bp, long c)
@@ -37,7 +36,8 @@ Bputrune(Biobuf *bp, long c)
rune = (Rune)c;
if(rune < Runeself) {
- BPUTC(bp, (int)rune);
+ n = BPUTC(bp, (int)rune);
+ USED(n);
return 1;
}
n = runetochar(str, &rune);
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
index eb426ccfc..528958510 100644
--- a/src/libbio/bseek.c
+++ b/src/libbio/bseek.c
@@ -33,7 +33,7 @@ Bseek(Biobuf *bp, vlong offset, int base)
vlong n, d;
int bufsz;
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(PLAN9)
if(sizeof(offset) != sizeof(off_t)) {
fprint(2, "Bseek: libbio compiled with %d-byte offset\n", sizeof(off_t));
abort();
diff --git a/src/libmach/Makefile b/src/liblink/Makefile
index 62aba5dca..2a317462b 100644
--- a/src/libmach/Makefile
+++ b/src/liblink/Makefile
@@ -1,4 +1,4 @@
-# Copyright 2012 The Go Authors. All rights reserved.
+# 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.
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
new file mode 100644
index 000000000..465b645b2
--- /dev/null
+++ b/src/liblink/asm5.c
@@ -0,0 +1,2458 @@
+// Inferno utils/5l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+
+struct Optab
+{
+ char as;
+ uchar a1;
+ char a2;
+ uchar a3;
+ uchar type;
+ char size;
+ char param;
+ char flag;
+ uchar pcrelsiz;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+
+enum
+{
+ LFROM = 1<<0,
+ LTO = 1<<1,
+ LPOOL = 1<<2,
+ LPCREL = 1<<3,
+
+ C_NONE = 0,
+ C_REG,
+ C_REGREG,
+ C_REGREG2,
+ C_SHIFT,
+ C_FREG,
+ C_PSR,
+ C_FCR,
+
+ C_RCON, /* 0xff rotated */
+ C_NCON, /* ~RCON */
+ C_SCON, /* 0xffff */
+ C_LCON,
+ C_LCONADDR,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
+
+ C_RACON,
+ C_LACON,
+
+ C_SBRA,
+ C_LBRA,
+
+ C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
+ C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
+ C_HFAUTO, /* both H and F */
+ C_SAUTO, /* -0xfff to 0xfff */
+ C_LAUTO,
+
+ C_HOREG,
+ C_FOREG,
+ C_HFOREG,
+ C_SOREG,
+ C_ROREG,
+ C_SROREG, /* both nil and R */
+ C_LOREG,
+
+ C_PC,
+ C_SP,
+ C_HREG,
+
+ C_ADDR, /* reference to relocatable address */
+
+ C_GOK,
+};
+
+static Optab optab[] =
+{
+ /* struct Optab:
+ OPCODE, from, prog->reg, to, type,size,param,flag */
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
+
+ { AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 },
+
+ { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 },
+ { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 },
+
+ { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
+ { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
+ { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
+
+ { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
+
+ { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
+ { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+
+ { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
+ { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
+ { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 },
+ { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
+ { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
+
+ { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
+ { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 },
+ { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
+
+ { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
+
+ { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
+ { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
+
+ { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 },
+ { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 },
+ { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
+ { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
+ { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
+
+ { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 },
+ { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
+ { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
+
+ { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 },
+ { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 },
+
+ { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
+ { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
+
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 },
+
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 },
+
+ { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
+
+ { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
+ { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 },
+ { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 },
+
+ { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 },
+ { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 },
+
+ { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 },
+
+ { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
+
+ { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
+ { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
+
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
+
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
+
+ { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 },
+ { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
+ { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
+
+ { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+ { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 },
+
+ { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+ { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+ { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
+
+ { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
+ { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+ { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 },
+
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 },
+
+ { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
+ { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
+
+ { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 },
+ { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
+
+ { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
+ { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
+ { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
+ { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
+
+ { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
+
+ { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 },
+ { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 },
+
+ { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 },
+
+ { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 },
+
+ { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 },
+
+ { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
+ { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
+
+ { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
+ { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 },
+ { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 },
+
+ { ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
+ { ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
+
+static struct {
+ uint32 start;
+ uint32 size;
+ uint32 extra;
+} pool;
+
+static int checkpool(Link*, Prog*, int);
+static int flushpool(Link*, Prog*, int, int);
+static void addpool(Link*, Prog*, Addr*);
+static void asmout(Link*, Prog*, Optab*, int32*);
+static Optab* oplook(Link*, Prog*);
+static int32 oprrr(Link*, int, int);
+static int32 olr(Link*, int32, int, int, int);
+static int32 olhr(Link*, int32, int, int, int);
+static int32 olrr(Link*, int, int, int, int);
+static int32 olhrr(Link*, int, int, int, int);
+static int32 osr(Link*, int, int, int32, int, int);
+static int32 oshr(Link*, int, int32, int, int);
+static int32 ofsr(Link*, int, int, int32, int, int, Prog*);
+static int32 osrr(Link*, int, int, int, int);
+static int32 oshrr(Link*, int, int, int, int);
+static int32 omvl(Link*, Prog*, Addr*, int);
+static int32 immaddr(int32);
+static int aclass(Link*, Addr*);
+static int32 immrot(uint32);
+static int32 immaddr(int32);
+static int32 opbra(Link*, int, int);
+
+static Opcross opcross[8];
+static Oprang oprange[ALAST];
+static char xcmp[C_GOK+1][C_GOK+1];
+static uchar repop[ALAST];
+
+static Prog zprg = {
+ .as = AGOK,
+ .scond = C_SCOND_NONE,
+ .reg = NREG,
+ .from = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .to = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+};
+
+static void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
+
+static int
+scan(Link *ctxt, Prog *op, Prog *p, int c)
+{
+ Prog *q;
+
+ for(q = op->link; q != p && q != nil; q = q->link){
+ q->pc = c;
+ c += oplook(ctxt, q)->size;
+ nocache(q);
+ }
+ return c;
+}
+
+/* size of a case statement including jump table */
+static int32
+casesz(Link *ctxt, Prog *p)
+{
+ int jt = 0;
+ int32 n = 0;
+ Optab *o;
+
+ for( ; p != nil; p = p->link){
+ if(p->as == ABCASE)
+ jt = 1;
+ else if(jt)
+ break;
+ o = oplook(ctxt, p);
+ n += o->size;
+ }
+ return n;
+}
+
+static void buildop(Link*);
+
+void
+span5(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *op;
+ Optab *o;
+ int m, bflag, i, v;
+ int32 c, out[6];
+ uchar *bp;
+
+ p = cursym->text;
+ if(p == nil || p->link == nil) // handle external functions and ELF section symbols
+ return;
+
+ if(oprange[AAND].start == nil)
+ buildop(ctxt);
+
+ ctxt->cursym = cursym;
+
+ ctxt->autosize = p->to.offset + 4;
+ c = 0;
+
+ for(op = p, p = p->link; p != nil; op = p, p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt, p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(ctxt->blitrl){
+ if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
+ p->pc = scan(ctxt, op, p, c);
+ c = p->pc;
+ }
+ }
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(ctxt, p, &p->from);
+ break;
+ case LTO:
+ addpool(ctxt, p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == C_SCOND_NONE)
+ flushpool(ctxt, p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
+ flushpool(ctxt, p, 0, 0);
+ c += m;
+ }
+ if(ctxt->blitrl){
+ if(checkpool(ctxt, op, 0))
+ c = scan(ctxt, op, nil, c);
+ }
+ cursym->size = c;
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ do {
+ if(ctxt->debugvlog)
+ Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ ctxt->curp = p;
+ p->pc = c;
+ o = oplook(ctxt,p);
+/* very large branches
+ if(o->type == 6 && p->pcond) {
+ otxt = p->pcond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = p->pcond;
+ p->pcond = q;
+ q = ctxt->arch->prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = q->link->link;
+ bflag = 1;
+ }
+ }
+ */
+ m = o->size;
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ if(p->as == ATEXT) {
+ ctxt->autosize = p->to.offset + 4;
+ continue;
+ }
+ ctxt->diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ cursym->size = c;
+ } while(bflag);
+
+ /*
+ * lay out the code. all the pc-relative code references,
+ * even cross-function, are resolved now;
+ * only data references need to be relocated.
+ * with more work we could leave cross-function
+ * code references to be relocated too, and then
+ * perhaps we'd be able to parallelize the span loop above.
+ */
+ if(ctxt->gmsym == nil)
+ ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+
+ p = cursym->text;
+ ctxt->autosize = p->to.offset + 4;
+ symgrow(ctxt, cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != nil; p = p->link) {
+ ctxt->pc = p->pc;
+ ctxt->curp = p;
+ o = oplook(ctxt, p);
+ asmout(ctxt, p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ v = out[i];
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 12-bit PC-relative offset,
+ * drop the pool now, and branch round it.
+ * this happens only in extended basic blocks that exceed 4k.
+ */
+static int
+checkpool(Link *ctxt, Prog *p, int sz)
+{
+ if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+ return flushpool(ctxt, p, 1, 0);
+ else if(p->link == nil)
+ return flushpool(ctxt, p, 2, 0);
+ return 0;
+}
+
+static int
+flushpool(Link *ctxt, Prog *p, int skip, int force)
+{
+ Prog *q;
+
+ if(ctxt->blitrl) {
+ if(skip){
+ if(0 && skip==1)print("note: flush literal pool at %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
+ q = ctxt->arch->prg();
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->pcond = p->link;
+ q->link = ctxt->blitrl;
+ q->lineno = p->lineno;
+ ctxt->blitrl = q;
+ }
+ else if(!force && (p->pc+pool.size-pool.start < 2048))
+ return 0;
+ ctxt->elitrl->link = p->link;
+ p->link = ctxt->blitrl;
+ // BUG(minux): how to correctly handle line number for constant pool entries?
+ // for now, we set line number to the last instruction preceding them at least
+ // this won't bloat the .debug_line tables
+ while(ctxt->blitrl) {
+ ctxt->blitrl->lineno = p->lineno;
+ ctxt->blitrl = ctxt->blitrl->link;
+ }
+ ctxt->blitrl = 0; /* BUG: should refer back to values until out-of-range */
+ ctxt->elitrl = 0;
+ pool.size = 0;
+ pool.start = 0;
+ pool.extra = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void
+addpool(Link *ctxt, Prog *p, Addr *a)
+{
+ Prog *q, t;
+ int c;
+
+ c = aclass(ctxt, a);
+
+ t = zprg;
+ t.as = AWORD;
+
+ switch(c) {
+ default:
+ t.to = *a;
+ if(ctxt->flag_shared && t.to.sym != nil)
+ t.pcrel = p;
+ break;
+
+ case C_SROREG:
+ case C_LOREG:
+ case C_ROREG:
+ case C_FOREG:
+ case C_SOREG:
+ case C_HOREG:
+ case C_FAUTO:
+ case C_SAUTO:
+ case C_LAUTO:
+ case C_LACON:
+ t.to.type = D_CONST;
+ t.to.offset = ctxt->instoffset;
+ break;
+ }
+
+ if(t.pcrel == nil) {
+ for(q = ctxt->blitrl; q != nil; q = q->link) /* could hash on t.t0.offset */
+ if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+ p->pcond = q;
+ return;
+ }
+ }
+
+ q = ctxt->arch->prg();
+ *q = t;
+ q->pc = pool.size;
+
+ if(ctxt->blitrl == nil) {
+ ctxt->blitrl = q;
+ pool.start = p->pc;
+ } else
+ ctxt->elitrl->link = q;
+ ctxt->elitrl = q;
+ pool.size += 4;
+
+ p->pcond = q;
+}
+
+static int32
+regoff(Link *ctxt, Addr *a)
+{
+
+ ctxt->instoffset = 0;
+ aclass(ctxt, a);
+ return ctxt->instoffset;
+}
+
+static int32
+immrot(uint32 v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+static int32
+immaddr(int32 v)
+{
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static int
+immfloat(int32 v)
+{
+ return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
+}
+
+static int
+immhalf(int32 v)
+{
+ if(v >= 0 && v <= 0xff)
+ return v|
+ (1<<24)| /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xff && v < 0)
+ return (-v & 0xff)|
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static int
+aclass(Link *ctxt, Addr *a)
+{
+ LSym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_REGREG:
+ return C_REGREG;
+
+ case D_REGREG2:
+ return C_REGREG2;
+
+ case D_SHIFT:
+ return C_SHIFT;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FPCR:
+ return C_FCR;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ t = immaddr(ctxt->instoffset);
+ if(t){
+ if(immhalf(ctxt->instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+ t = immaddr(ctxt->instoffset);
+ if(t){
+ if(immhalf(ctxt->instoffset))
+ return immfloat(t) ? C_HFAUTO : C_HAUTO;
+ if(immfloat(t))
+ return C_FAUTO;
+ return C_SAUTO;
+ }
+ return C_LAUTO;
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ t = immaddr(ctxt->instoffset);
+ if(t) {
+ if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */
+ return immfloat(t) ? C_HFOREG : C_HOREG;
+ if(immfloat(t))
+ return C_FOREG; /* n.b. that it will also satisfy immrot */
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_SROREG;
+ if(immhalf(ctxt->instoffset))
+ return C_HOREG;
+ return C_SOREG;
+ }
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_ROREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_PSR:
+ return C_PSR;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+ }
+ return C_GOK;
+
+ case D_FCONST:
+ if(chipzero5(ctxt, a->u.dval) >= 0)
+ return C_ZFCON;
+ if(chipfloat5(ctxt, a->u.dval) >= 0)
+ return C_SFCON;
+ return C_LFCON;
+
+ case D_CONST:
+ case D_CONST2:
+ switch(a->name) {
+
+ case D_NONE:
+ ctxt->instoffset = a->offset;
+ if(a->reg != NREG)
+ goto aconsize;
+
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_RCON;
+ t = immrot(~ctxt->instoffset);
+ if(t)
+ return C_NCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == nil)
+ break;
+ ctxt->instoffset = 0; // s.b. unused but just in case
+ return C_LCONADDR;
+
+ case D_AUTO:
+ ctxt->instoffset = ctxt->autosize + a->offset;
+ goto aconsize;
+
+ case D_PARAM:
+ ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+ aconsize:
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_RACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+static void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(ctxt, &p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(ctxt, &p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return optab+a1;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ if(0 /*debug['O']*/) {
+ print("oplook %A %d %d %d\n",
+ (int)p->as, a1, a2, a3);
+ print(" %d %d\n", p->from.type, p->to.type);
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ ctxt->diag("illegal combination %P; %d %d %d, %d %d",
+ p, a1, a2, a3, p->from.type, p->to.type);
+ ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name);
+ prasm(p);
+ if(o == 0)
+ o = optab;
+ return o;
+}
+
+static int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_RCON || b == C_NCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_RACON)
+ return 1;
+ break;
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
+ return 1;
+ break;
+
+ case C_HFAUTO:
+ return b == C_HAUTO || b == C_FAUTO;
+ case C_FAUTO:
+ case C_HAUTO:
+ return b == C_HFAUTO;
+ case C_SAUTO:
+ return cmp(C_HFAUTO, b);
+ case C_LAUTO:
+ return cmp(C_SAUTO, b);
+
+ case C_HFOREG:
+ return b == C_HOREG || b == C_FOREG;
+ case C_FOREG:
+ case C_HOREG:
+ return b == C_HFOREG;
+ case C_SROREG:
+ return cmp(C_SOREG, b) || cmp(C_ROREG, b);
+ case C_SOREG:
+ case C_ROREG:
+ return b == C_SROREG || cmp(C_HFOREG, b);
+ case C_LOREG:
+ return cmp(C_SROREG, b);
+
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+
+ case C_HREG:
+ return cmp(C_SP, b) || cmp(C_PC, b);
+
+ }
+ return 0;
+}
+
+static int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+static void
+buildop(Link *ctxt)
+{
+ int i, n, r;
+
+ for(i=0; i<C_GOK; i++)
+ for(n=0; n<C_GOK; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++) {
+ if((optab[n].flag & LPCREL) != 0) {
+ if(ctxt->flag_shared)
+ optab[n].size += optab[n].pcrelsiz;
+ else
+ optab[n].flag &= ~LPCREL;
+ }
+ }
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ ctxt->diag("unknown op in build: %A", r);
+ sysfatal("bad code");
+ case AADD:
+ oprange[AAND] = oprange[r];
+ oprange[AEOR] = oprange[r];
+ oprange[ASUB] = oprange[r];
+ oprange[ARSB] = oprange[r];
+ oprange[AADC] = oprange[r];
+ oprange[ASBC] = oprange[r];
+ oprange[ARSC] = oprange[r];
+ oprange[AORR] = oprange[r];
+ oprange[ABIC] = oprange[r];
+ break;
+ case ACMP:
+ oprange[ATEQ] = oprange[r];
+ oprange[ACMN] = oprange[r];
+ break;
+ case AMVN:
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ oprange[ABCS] = oprange[r];
+ oprange[ABHS] = oprange[r];
+ oprange[ABCC] = oprange[r];
+ oprange[ABLO] = oprange[r];
+ oprange[ABMI] = oprange[r];
+ oprange[ABPL] = oprange[r];
+ oprange[ABVS] = oprange[r];
+ oprange[ABVC] = oprange[r];
+ oprange[ABHI] = oprange[r];
+ oprange[ABLS] = oprange[r];
+ oprange[ABGE] = oprange[r];
+ oprange[ABLT] = oprange[r];
+ oprange[ABGT] = oprange[r];
+ oprange[ABLE] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ break;
+ case AMUL:
+ oprange[AMULU] = oprange[r];
+ break;
+ case ADIV:
+ oprange[AMOD] = oprange[r];
+ oprange[AMODU] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ break;
+ case AMOVW:
+ case AMOVB:
+ case AMOVBS:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHS:
+ case AMOVHU:
+ break;
+ case ASWPW:
+ oprange[ASWPBU] = oprange[r];
+ break;
+ case AB:
+ case ABL:
+ case ABX:
+ case ABXRET:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ case ASWI:
+ case AWORD:
+ case AMOVM:
+ case ARFE:
+ case ATEXT:
+ case AUSEFIELD:
+ case ACASE:
+ case ABCASE:
+ case ATYPE:
+ break;
+ case AADDF:
+ oprange[AADDD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[ASQRTF] = oprange[r];
+ oprange[ASQRTD] = oprange[r];
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ oprange[AABSF] = oprange[r];
+ oprange[AABSD] = oprange[r];
+ break;
+
+ case ACMPF:
+ oprange[ACMPD] = oprange[r];
+ break;
+
+ case AMOVF:
+ oprange[AMOVD] = oprange[r];
+ break;
+
+ case AMOVFW:
+ oprange[AMOVDW] = oprange[r];
+ break;
+
+ case AMOVWF:
+ oprange[AMOVWD] = oprange[r];
+ break;
+
+ case AMULL:
+ oprange[AMULAL] = oprange[r];
+ oprange[AMULLU] = oprange[r];
+ oprange[AMULALU] = oprange[r];
+ break;
+
+ case AMULWT:
+ oprange[AMULWB] = oprange[r];
+ break;
+
+ case AMULAWT:
+ oprange[AMULAWB] = oprange[r];
+ break;
+
+ case AMULA:
+ case ALDREX:
+ case ASTREX:
+ case ALDREXD:
+ case ASTREXD:
+ case ATST:
+ case APLD:
+ case AUNDEF:
+ case ACLZ:
+ case AFUNCDATA:
+ case APCDATA:
+ break;
+ }
+ }
+}
+
+static void
+asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
+{
+ int32 o1, o2, o3, o4, o5, o6, v;
+ int r, rf, rt, rt2;
+ Reloc *rel;
+
+ctxt->printp = p;
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ o6 = 0;
+ ctxt->armsize += o->size;
+if(0 /*debug['P']*/) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
+ switch(o->type) {
+ default:
+ ctxt->diag("unknown asm %d", o->type);
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
+ break;
+
+ case 1: /* op R,[R],R */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else
+ if(r == NREG)
+ r = rt;
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 2: /* movbu $I,[R],R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 3: /* add R<<[IR],[R],R */
+ mov:
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->from.offset;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 4: /* add $I,[R],R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 |= r << 16;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 5: /* bra s */
+ o1 = opbra(ctxt, p->as, p->scond);
+ v = -8;
+ if(p->to.sym != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ v += p->to.offset;
+ rel->add = o1 | ((v >> 2) & 0xffffff);
+ rel->type = R_CALLARM;
+ break;
+ }
+ if(p->pcond != nil)
+ v = (p->pcond->pc - ctxt->pc) - 8;
+ o1 |= (v >> 2) & 0xffffff;
+ break;
+
+ case 6: /* b ,O(R) -> add $O,R,PC */
+ aclass(ctxt, &p->to);
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGPC << 12;
+ break;
+
+ case 7: /* bl (R) -> blx R */
+ aclass(ctxt, &p->to);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p);
+ o1 = oprrr(ctxt, ABL, p->scond);
+ o1 |= p->to.reg;
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 0;
+ rel->type = R_CALLIND;
+ break;
+
+ case 8: /* sll $c,[R],R -> mov (R<<$c),R */
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (ctxt->instoffset&31) << 7;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 9: /* sll R,[R],R -> mov (R<<R),R */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 |= r;
+ o1 |= (p->from.reg << 8) | (1<<4);
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 10: /* swi [$con] */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ if(p->to.type != D_NONE) {
+ aclass(ctxt, &p->to);
+ o1 |= ctxt->instoffset & 0xffffff;
+ }
+ break;
+
+ case 11: /* word */
+ aclass(ctxt, &p->to);
+ o1 = ctxt->instoffset;
+ if(p->to.sym != nil) {
+ // This case happens with words generated
+ // in the PC stream as part of the literal pool.
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+
+ // runtime.tlsgm (aka gmsym) is special.
+ // Its "address" is the offset from the TLS thread pointer
+ // to the thread-local g and m pointers.
+ // Emit a TLS relocation instead of a standard one.
+ if(rel->sym == ctxt->gmsym) {
+ rel->type = R_TLS;
+ if(ctxt->flag_shared)
+ rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
+ rel->xadd = rel->add;
+ rel->xsym = rel->sym;
+ } else if(ctxt->flag_shared) {
+ rel->type = R_PCREL;
+ rel->add += ctxt->pc - p->pcrel->pc - 8;
+ } else
+ rel->type = R_ADDR;
+ o1 = 0;
+ }
+ break;
+
+ case 12: /* movw $lcon, reg */
+ o1 = omvl(ctxt, p, &p->from, p->to.reg);
+ if(o->flag & LPCREL) {
+ o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
+ }
+ break;
+
+ case 13: /* op $lcon, [R], R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = oprrr(ctxt, p->as, p->scond);
+ o2 |= REGTMP;
+ r = p->reg;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = p->to.reg;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 14: /* movb/movbu/movh/movhu R,R */
+ o1 = oprrr(ctxt, ASLL, p->scond);
+
+ if(p->as == AMOVBU || p->as == AMOVHU)
+ o2 = oprrr(ctxt, ASRL, p->scond);
+ else
+ o2 = oprrr(ctxt, ASRA, p->scond);
+
+ r = p->to.reg;
+ o1 |= (p->from.reg)|(r<<12);
+ o2 |= (r)|(r<<12);
+ if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
+ o1 |= (24<<7);
+ o2 |= (24<<7);
+ } else {
+ o1 |= (16<<7);
+ o2 |= (16<<7);
+ }
+ break;
+
+ case 15: /* mul r,[r,]r */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG)
+ r = rt;
+ if(rt == r) {
+ r = rf;
+ rf = rt;
+ }
+ if(0)
+ if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
+ ctxt->diag("bad registers in MUL");
+ prasm(p);
+ }
+ o1 |= (rf<<8) | r | (rt<<16);
+ break;
+
+
+ case 16: /* div r,[r,]r */
+ o1 = 0xf << 28;
+ o2 = 0;
+ break;
+
+ case 17:
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ rt2 = p->to.offset;
+ r = p->reg;
+ o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
+ break;
+
+ case 20: /* mov/movb/movbu R,O(R) */
+ aclass(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond);
+ break;
+
+ case 21: /* mov/movbu O(R),R -> lr */
+ aclass(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
+ if(p->as != AMOVW)
+ o1 |= 1<<22;
+ break;
+
+ case 30: /* mov/movb/movbu R,L(R) */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+ if(p->as != AMOVW)
+ o2 |= 1<<22;
+ break;
+
+ case 31: /* mov/movbu L(R),R -> lr[b] */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
+ o2 |= 1<<22;
+ break;
+
+ case 34: /* mov $lacon,R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+
+ o2 = oprrr(ctxt, AADD, p->scond);
+ o2 |= REGTMP;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 |= r << 16;
+ if(p->to.type != D_NONE)
+ o2 |= p->to.reg << 12;
+ break;
+
+ case 35: /* mov PSR,R */
+ o1 = (2<<23) | (0xf<<16) | (0<<0);
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->from.reg & 1) << 22;
+ o1 |= p->to.reg << 12;
+ break;
+
+ case 36: /* mov R,PSR */
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 37: /* mov $con,PSR */
+ aclass(ctxt, &p->from);
+ o1 = (2<<23) | (0x29f<<12) | (0<<4);
+ if(p->scond & C_FBIT)
+ o1 ^= 0x010 << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= (p->to.reg & 1) << 22;
+ o1 |= p->from.reg << 0;
+ break;
+
+ case 38: /* movm $con,oreg -> stm */
+ o1 = (0x4 << 25);
+ o1 |= p->from.offset & 0xffff;
+ o1 |= p->to.reg << 16;
+ aclass(ctxt, &p->to);
+ goto movm;
+
+ case 39: /* movm oreg,$con -> ldm */
+ o1 = (0x4 << 25) | (1 << 20);
+ o1 |= p->to.offset & 0xffff;
+ o1 |= p->from.reg << 16;
+ aclass(ctxt, &p->from);
+ movm:
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in MOVM; %P", p);
+ o1 |= (p->scond & C_SCOND) << 28;
+ if(p->scond & C_PBIT)
+ o1 |= 1 << 24;
+ if(p->scond & C_UBIT)
+ o1 |= 1 << 23;
+ if(p->scond & C_SBIT)
+ o1 |= 1 << 22;
+ if(p->scond & C_WBIT)
+ o1 |= 1 << 21;
+ break;
+
+ case 40: /* swp oreg,reg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in SWP");
+ o1 = (0x2<<23) | (0x9<<4);
+ if(p->as != ASWPW)
+ o1 |= 1 << 22;
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+
+ case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
+ o1 = 0xe8fd8000;
+ break;
+
+ case 50: /* floating point store */
+ v = regoff(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p);
+ break;
+
+ case 51: /* floating point load */
+ v = regoff(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
+ break;
+
+ case 52: /* floating point store, int32 offset UGLY */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ break;
+
+ case 53: /* floating point load, int32 offset UGLY */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+ o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ break;
+
+ case 54: /* floating point arith */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ rf = p->from.reg;
+ rt = p->to.reg;
+ r = p->reg;
+ if(r == NREG) {
+ r = rt;
+ if(p->as == AMOVF || p->as == AMOVD || p->as == AMOVFD || p->as == AMOVDF ||
+ p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD)
+ r = 0;
+ }
+ o1 |= rf | (r<<16) | (rt<<12);
+ break;
+
+ case 56: /* move to FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
+ break;
+
+ case 57: /* move from FP[CS]R */
+ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
+ o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
+ break;
+ case 58: /* movbu R,R */
+ o1 = oprrr(ctxt, AAND, p->scond);
+ o1 |= immrot(0xff);
+ rt = p->to.reg;
+ r = p->from.reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ break;
+
+ case 59: /* movw/bu R<<I(R),R -> ldr indexed */
+ if(p->from.reg == NREG) {
+ if(p->as != AMOVW)
+ ctxt->diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(1<<4))
+ ctxt->diag("bad shift in LDR");
+ o1 = olrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
+ if(p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 60: /* movb R(R),R -> ldrsb indexed */
+ if(p->from.reg == NREG) {
+ ctxt->diag("byte MOV from shifter operand");
+ goto mov;
+ }
+ if(p->from.offset&(~0xf))
+ ctxt->diag("bad shift in LDRSB");
+ o1 = olhrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
+ o1 ^= (1<<5)|(1<<6);
+ break;
+
+ case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
+ if(p->to.reg == NREG)
+ ctxt->diag("MOV to shifter operand");
+ o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
+ o1 |= 1<<22;
+ break;
+
+ case 62: /* case R -> movw R<<2(PC),PC */
+ if(o->flag & LPCREL) {
+ o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
+ o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond);
+ o2 |= 2<<7;
+ o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
+ } else {
+ o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond);
+ o1 |= 2<<7;
+ }
+ break;
+
+ case 63: /* bcase */
+ if(p->pcond != nil) {
+ rel = addrel(ctxt->cursym);
+ rel->off = ctxt->pc;
+ rel->siz = 4;
+ if(p->to.sym != nil && p->to.sym->type != 0) {
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+ } else {
+ rel->sym = ctxt->cursym;
+ rel->add = p->pcond->pc;
+ }
+ if(o->flag & LPCREL) {
+ rel->type = R_PCREL;
+ rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz;
+ } else
+ rel->type = R_ADDR;
+ o1 = 0;
+ }
+ break;
+
+ /* reloc ops */
+ case 64: /* mov/movb/movbu R,addr */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 65: /* mov/movbu addr,R */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olr(ctxt, 0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
+ o2 |= 1<<22;
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 68: /* floating point store -> ADDR */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ case 69: /* floating point load <- ADDR */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+
+ /* ArmV4 ops: */
+ case 70: /* movh/movhu R,O(R) -> strh */
+ aclass(ctxt, &p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond);
+ break;
+ case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+ aclass(ctxt, &p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o1 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o1 ^= (1<<6);
+ break;
+ case 72: /* movh/movhu R,L(R) -> strh */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+ break;
+ case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o2 ^= (1<<6);
+ break;
+ case 74: /* bx $I */
+ ctxt->diag("ABX $I");
+ break;
+ case 75: /* bx O(R) */
+ aclass(ctxt, &p->to);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("non-zero offset in ABX");
+/*
+ o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+*/
+ // p->to.reg may be REGLINK
+ o1 = oprrr(ctxt, AADD, p->scond);
+ o1 |= immrot(ctxt->instoffset);
+ o1 |= p->to.reg << 16;
+ o1 |= REGTMP << 12;
+ o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
+ break;
+ case 76: /* bx O(R) when returning from fn*/
+ ctxt->diag("ABXRET");
+ break;
+ case 77: /* ldrex oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in LDREX");
+ o1 = (0x19<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 78: /* strex reg,oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in STREX");
+ o1 = (0x18<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 80: /* fmov zfcon,freg */
+ if(p->as == AMOVD) {
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o2 = oprrr(ctxt, ASUBD, p->scond);
+ } else {
+ o1 = 0x0eb00a00; // VMOV imm 32
+ o2 = oprrr(ctxt, ASUBF, p->scond);
+ }
+ v = 0x70; // 1.0
+ r = p->to.reg;
+
+ // movf $1.0, r
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= r << 12;
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+
+ // subf r,r,r
+ o2 |= r | (r<<16) | (r<<12);
+ break;
+ case 81: /* fmov sfcon,freg */
+ o1 = 0x0eb00a00; // VMOV imm 32
+ if(p->as == AMOVD)
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= p->to.reg << 12;
+ v = chipfloat5(ctxt, p->from.u.dval);
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+ break;
+ case 82: /* fcmp freg,freg, */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->reg<<12) | (p->from.reg<<0);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 83: /* fcmp freg,, */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<12) | (1<<16);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 84: /* movfw freg,freg - truncate float-to-fix */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 85: /* movwf freg,freg - fix-to-float */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 86: /* movfw freg,reg - truncate float-to-fix */
+ // macro for movfw freg,FTMP; movw FTMP,reg
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (FREGTMP<<12);
+ o2 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o2 |= (FREGTMP<<16);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 87: /* movwf reg,freg - fix-to-float */
+ // macro for movw reg,FTMP; movwf FTMP,freg
+ o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (FREGTMP<<16);
+ o2 = oprrr(ctxt, p->as, p->scond);
+ o2 |= (FREGTMP<<0);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 88: /* movw reg,freg */
+ o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (p->to.reg<<16);
+ break;
+ case 89: /* movw freg,reg */
+ o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+ o1 |= (p->from.reg<<16);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 90: /* tst reg */
+ o1 = oprrr(ctxt, ACMP+AEND, p->scond);
+ o1 |= p->from.reg<<16;
+ break;
+ case 91: /* ldrexd oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in LDREX");
+ o1 = (0x1b<<20) | (0xf9f);
+ o1 |= p->from.reg << 16;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 92: /* strexd reg,oreg,reg */
+ aclass(ctxt, &p->from);
+ if(ctxt->instoffset != 0)
+ ctxt->diag("offset must be zero in STREX");
+ o1 = (0x1a<<20) | (0xf90);
+ o1 |= p->from.reg << 16;
+ o1 |= p->reg << 0;
+ o1 |= p->to.reg << 12;
+ o1 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(ctxt, p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olhr(ctxt, 0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVB || p->as == AMOVBS)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH || p->as == AMOVHS)
+ o2 ^= (1<<6);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+ case 94: /* movh/movhu R,addr -> strh */
+ o1 = omvl(ctxt, p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond);
+ if(o->flag & LPCREL) {
+ o3 = o2;
+ o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+ }
+ break;
+ case 95: /* PLD off(reg) */
+ o1 = 0xf5d0f000;
+ o1 |= p->from.reg << 16;
+ if(p->from.offset < 0) {
+ o1 &= ~(1 << 23);
+ o1 |= (-p->from.offset) & 0xfff;
+ } else
+ o1 |= p->from.offset & 0xfff;
+ break;
+ case 96: /* UNDEF */
+ // This is supposed to be something that stops execution.
+ // It's not supposed to be reached, ever, but if it is, we'd
+ // like to be able to tell how we got there. Assemble as
+ // 0xf7fabcfd which is guaranteed to raise undefined instruction
+ // exception.
+ o1 = 0xf7fabcfd;
+ break;
+ case 97: /* CLZ Rm, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg;
+ break;
+ case 98: /* MULW{T,B} Rs, Rm, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 16;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ break;
+ case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->to.reg << 12;
+ o1 |= p->from.reg << 8;
+ o1 |= p->reg;
+ o1 |= p->to.offset << 16;
+ break;
+ }
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ out[5] = o6;
+ return;
+
+#ifdef NOTDEF
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
+ lputl(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
+ lputl(o1);
+ lputl(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ break;
+ case 24:
+ if(debug['a'])
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
+ v, o1, o2, o3, o4, o5, o6, p);
+ lputl(o1);
+ lputl(o2);
+ lputl(o3);
+ lputl(o4);
+ lputl(o5);
+ lputl(o6);
+ break;
+ }
+#endif
+}
+
+static int32
+oprrr(Link *ctxt, int a, int sc)
+{
+ int32 o;
+
+ o = (sc & C_SCOND) << 28;
+ if(sc & C_SBIT)
+ o |= 1 << 20;
+ if(sc & (C_PBIT|C_WBIT))
+ ctxt->diag(".nil/.W on dp instruction");
+ switch(a) {
+ case AMULU:
+ case AMUL: return o | (0x0<<21) | (0x9<<4);
+ case AMULA: return o | (0x1<<21) | (0x9<<4);
+ case AMULLU: return o | (0x4<<21) | (0x9<<4);
+ case AMULL: return o | (0x6<<21) | (0x9<<4);
+ case AMULALU: return o | (0x5<<21) | (0x9<<4);
+ case AMULAL: return o | (0x7<<21) | (0x9<<4);
+ case AAND: return o | (0x0<<21);
+ case AEOR: return o | (0x1<<21);
+ case ASUB: return o | (0x2<<21);
+ case ARSB: return o | (0x3<<21);
+ case AADD: return o | (0x4<<21);
+ case AADC: return o | (0x5<<21);
+ case ASBC: return o | (0x6<<21);
+ case ARSC: return o | (0x7<<21);
+ case ATST: return o | (0x8<<21) | (1<<20);
+ case ATEQ: return o | (0x9<<21) | (1<<20);
+ case ACMP: return o | (0xa<<21) | (1<<20);
+ case ACMN: return o | (0xb<<21) | (1<<20);
+ case AORR: return o | (0xc<<21);
+ case AMOVB:
+ case AMOVH:
+ case AMOVW: return o | (0xd<<21);
+ case ABIC: return o | (0xe<<21);
+ case AMVN: return o | (0xf<<21);
+ case ASLL: return o | (0xd<<21) | (0<<5);
+ case ASRL: return o | (0xd<<21) | (1<<5);
+ case ASRA: return o | (0xd<<21) | (2<<5);
+ case ASWI: return o | (0xf<<24);
+
+ case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
+ case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
+ case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
+ case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
+ case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
+ case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
+ case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
+ case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
+ case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
+ case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
+ case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
+ case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
+ case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
+
+ case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
+ case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
+
+ case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (1<<8); // dtof
+ case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (0<<8); // dtof
+
+ case AMOVWF:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<8); // toint, double
+ case AMOVWD:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (1<<8); // toint, double
+
+ case AMOVFW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
+ case AMOVDW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
+
+ case AMOVWF+AEND: // copy WtoF
+ return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
+ case AMOVFW+AEND: // copy FtoW
+ return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
+ case ACMP+AEND: // cmp imm
+ return o | (0x3<<24) | (0x5<<20);
+
+ case ACLZ:
+ // CLZ doesn't support .nil
+ return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
+
+ case AMULWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
+ case AMULWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
+ case AMULAWT:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
+ case AMULAWB:
+ return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
+
+ case ABL: // BLX REG
+ return (o & (0xf<<28)) | (0x12fff3 << 4);
+ }
+ ctxt->diag("bad rrr %d", a);
+ prasm(ctxt->curp);
+ return 0;
+}
+
+static int32
+opbra(Link *ctxt, int a, int sc)
+{
+
+ if(sc & (C_SBIT|C_PBIT|C_WBIT))
+ ctxt->diag(".nil/.nil/.W on bra instruction");
+ sc &= C_SCOND;
+ if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY)
+ return (sc<<28)|(0x5<<25)|(0x1<<24);
+ if(sc != 0xe)
+ ctxt->diag(".COND on bcond instruction");
+ switch(a) {
+ case ABEQ: return (0x0<<28)|(0x5<<25);
+ case ABNE: return (0x1<<28)|(0x5<<25);
+ case ABCS: return (0x2<<28)|(0x5<<25);
+ case ABHS: return (0x2<<28)|(0x5<<25);
+ case ABCC: return (0x3<<28)|(0x5<<25);
+ case ABLO: return (0x3<<28)|(0x5<<25);
+ case ABMI: return (0x4<<28)|(0x5<<25);
+ case ABPL: return (0x5<<28)|(0x5<<25);
+ case ABVS: return (0x6<<28)|(0x5<<25);
+ case ABVC: return (0x7<<28)|(0x5<<25);
+ case ABHI: return (0x8<<28)|(0x5<<25);
+ case ABLS: return (0x9<<28)|(0x5<<25);
+ case ABGE: return (0xa<<28)|(0x5<<25);
+ case ABLT: return (0xb<<28)|(0x5<<25);
+ case ABGT: return (0xc<<28)|(0x5<<25);
+ case ABLE: return (0xd<<28)|(0x5<<25);
+ case AB: return (0xe<<28)|(0x5<<25);
+ }
+ ctxt->diag("bad bra %A", a);
+ prasm(ctxt->curp);
+ return 0;
+}
+
+static int32
+olr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on LDR/STR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(!(sc & C_UBIT))
+ o |= 1 << 23;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<26) | (1<<20);
+ if(v < 0) {
+ if(sc & C_UBIT)
+ ctxt->diag(".U on neg offset");
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<12) || v < 0)
+ ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+ o |= v;
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+static int32
+olhr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on LDRH/STRH instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (1<<23) | (1<<20)|(0xb<<4);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v >= (1<<8) || v < 0)
+ ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+ o |= (v&0xf)|((v>>4)<<8)|(1<<22);
+ o |= b << 16;
+ o |= r << 12;
+ return o;
+}
+
+static int32
+osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olr(ctxt, v, b, r, sc) ^ (1<<20);
+ if(a != AMOVW)
+ o |= 1<<22;
+ return o;
+}
+
+static int32
+oshr(Link *ctxt, int r, int32 v, int b, int sc)
+{
+ int32 o;
+
+ o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
+ return o;
+}
+
+
+static int32
+osrr(Link *ctxt, int r, int i, int b, int sc)
+{
+
+ return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
+}
+
+static int32
+oshrr(Link *ctxt, int r, int i, int b, int sc)
+{
+ return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
+}
+
+static int32
+olrr(Link *ctxt, int i, int b, int r, int sc)
+{
+
+ return olr(ctxt, i, b, r, sc) ^ (1<<25);
+}
+
+static int32
+olhrr(Link *ctxt, int i, int b, int r, int sc)
+{
+ return olhr(ctxt, i, b, r, sc) ^ (1<<22);
+}
+
+static int32
+ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
+{
+ int32 o;
+
+ if(sc & C_SBIT)
+ ctxt->diag(".nil on FLDR/FSTR instruction");
+ o = (sc & C_SCOND) << 28;
+ if(!(sc & C_PBIT))
+ o |= 1 << 24;
+ if(sc & C_WBIT)
+ o |= 1 << 21;
+ o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
+ if(v < 0) {
+ v = -v;
+ o ^= 1 << 23;
+ }
+ if(v & 3)
+ ctxt->diag("odd offset for floating point op: %d\n%P", v, p);
+ else
+ if(v >= (1<<10) || v < 0)
+ ctxt->diag("literal span too large: %d\n%P", v, p);
+ o |= (v>>2) & 0xFF;
+ o |= b << 16;
+ o |= r << 12;
+
+ switch(a) {
+ default:
+ ctxt->diag("bad fst %A", a);
+ case AMOVD:
+ o |= 1 << 8;
+ case AMOVF:
+ break;
+ }
+ return o;
+}
+
+static int32
+omvl(Link *ctxt, Prog *p, Addr *a, int dr)
+{
+ int32 v, o1;
+ if(!p->pcond) {
+ aclass(ctxt, a);
+ v = immrot(~ctxt->instoffset);
+ if(v == 0) {
+ ctxt->diag("missing literal");
+ prasm(p);
+ return 0;
+ }
+ o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND);
+ o1 |= v;
+ o1 |= dr << 12;
+ } else {
+ v = p->pcond->pc - p->pc - 8;
+ o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
+ }
+ return o1;
+}
+
+int
+chipzero5(Link *ctxt, float64 e)
+{
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7 || e != 0)
+ return -1;
+ return 0;
+}
+
+int
+chipfloat5(Link *ctxt, float64 e)
+{
+ int n;
+ ulong h1;
+ int32 l, h;
+ uint64 ei;
+
+ // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+ if(ctxt->goarm < 7)
+ goto no;
+
+ memmove(&ei, &e, 8);
+ l = (int32)ei;
+ h = (int32)(ei>>32);
+
+ if(l != 0 || (h&0xffff) != 0)
+ goto no;
+ h1 = h & 0x7fc00000;
+ if(h1 != 0x40000000 && h1 != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h1 == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", l, h, n);
+ return n;
+
+no:
+ return -1;
+}
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c
new file mode 100644
index 000000000..66afc7a12
--- /dev/null
+++ b/src/liblink/asm6.c
@@ -0,0 +1,3585 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+ MaxAlign = 32, // max data alignment
+
+ // Loop alignment constants:
+ // want to align loop entry to LoopAlign-byte boundary,
+ // and willing to insert at most MaxLoopPad bytes of NOP to do so.
+ // We define a loop entry as the target of a backward jump.
+ //
+ // gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
+ // and it aligns all jump targets, not just backward jump targets.
+ //
+ // As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
+ // is very slight but negative, so the alignment is disabled by
+ // setting MaxLoopPad = 0. The code is here for reference and
+ // for future experiments.
+ //
+ LoopAlign = 16,
+ MaxLoopPad = 0,
+
+ FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef struct Optab Optab;
+typedef struct Movtab Movtab;
+
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[23];
+};
+struct Movtab
+{
+ short as;
+ uchar ft;
+ uchar tt;
+ uchar code;
+ uchar op[4];
+};
+
+enum
+{
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Ys32,
+ Yi32,
+ Yi64,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ytls,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Zlitm_r,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zcallindreg,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zibo_m_xm,
+ Zil_,
+ Zil_rp,
+ Ziq_rp,
+ Zilo_m,
+ Ziqo_m,
+ Zjmp,
+ Zloop,
+ Zo_iw,
+ Zm_o,
+ Zm_r,
+ Zm2_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zm_r_3d,
+ Zm_r_xm_nr,
+ Zr_m_xm_nr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zmb_r,
+ Zaut_r,
+ Zo_m,
+ Zo_m64,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zbyte,
+ Zmax,
+
+ Px = 0,
+ P32 = 0x32, /* 32-bit only */
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escapes: 66 0f */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1: f2 0f */
+ Pf3 = 0xf3, /* xmm escape 2: f3 0f */
+ Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
+ Pw = 0x48, /* Rex.w */
+ Py = 0x80, /* defaults to 64-bit mode */
+
+ Rxf = 1<<9, /* internal flag for Rxr on from */
+ Rxt = 1<<8, /* internal flag for Rxr on to */
+ Rxw = 1<<3, /* =1, 64-bit operand size */
+ Rxr = 1<<2, /* extend modrm reg */
+ Rxx = 1<<1, /* extend sib index */
+ Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
+
+ Maxand = 10, /* in -a output width of the byte codes */
+};
+
+static char ycover[Ymax*Ymax];
+static int reg[D_NONE];
+static int regrex[D_NONE+1];
+static void asmins(Link *ctxt, Prog *p);
+
+static uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar ytext[] =
+{
+ Ymb, Yi64, Zpseudo,1,
+ 0
+};
+static uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,0,
+ Ynone, Yiauto, Zpseudo,0,
+ Ynone, Yml, Zpseudo,0,
+ Ynone, Yrf, Zpseudo,0,
+ Ynone, Yxr, Zpseudo,0,
+ Yiauto, Ynone, Zpseudo,0,
+ Yml, Ynone, Zpseudo,0,
+ Yrf, Ynone, Zpseudo,0,
+ Yxr, Ynone, Zpseudo,1,
+ 0
+};
+static uchar yfuncdata[] =
+{
+ Yi32, Ym, Zpseudo, 0,
+ 0
+};
+static uchar ypcdata[] =
+{
+ Yi32, Yi32, Zpseudo, 0,
+ 0
+};
+static uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yincw[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar yincl[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+static uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+static uchar ymbs[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ybtl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+static uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1,
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Yml, Zr_m_xm, 1, // MMX MOVD
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 2,
+ 0
+};
+static uchar yret[] =
+{
+ Ynone, Ynone, Zo_iw, 1,
+ Yi32, Ynone, Zo_iw, 1,
+ 0
+};
+static uchar ymovq[] =
+{
+ Yrl, Yml, Zr_m, 1, // 0x89
+ Yml, Yrl, Zm_r, 1, // 0x8b
+ Yi0, Yrl, Zclr, 1, // 0x31
+ Ys32, Yrl, Zilo_m, 2, // 32 bit signed 0xc7,(0)
+ Yi64, Yrl, Ziq_rp, 1, // 0xb8 -- 32/64 bit immediate
+ Yi32, Yml, Zilo_m, 2, // 0xc7,(0)
+ Ym, Ymr, Zm_r_xm_nr, 1, // MMX MOVQ (shorter encoding)
+ Ymr, Ym, Zr_m_xm_nr, 1, // MMX MOVQ
+ Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
+ Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
+ Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
+ Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2
+ Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64
+ Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
+ Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
+ Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
+ 0
+};
+static uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+static uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zmb_r, 1,
+ 0
+};
+static uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar yxchg[] =
+{
+ Yax, Yrl, Z_rp, 1,
+ Yrl, Yax, Zrp_, 1,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ Yml, Yrl, Zm_r, 2,
+ 0
+};
+static uchar yimul3[] =
+{
+ Yml, Yrl, Zibm_r, 2,
+ 0
+};
+static uchar ybyte[] =
+{
+ Yi64, Ynone, Zbyte, 1,
+ 0
+};
+static uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+static uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+static uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+static uchar ybswap[] =
+{
+ Ynone, Yrl, Z_rp, 2,
+ 0,
+};
+static uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 0,
+ Yi0, Ybr, Zbr, 0,
+ Yi1, Ybr, Zbr, 1,
+ 0
+};
+static uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+static uchar ycall[] =
+{
+ Ynone, Yml, Zcallindreg, 0,
+ Yrx, Yrx, Zcallindreg, 2,
+ Ynone, Ybr, Zcall, 1,
+ 0
+};
+static uchar yduff[] =
+{
+ Ynone, Yi32, Zcall, 1,
+ 0
+};
+static uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m64, 2,
+ Ynone, Ybr, Zjmp, 1,
+ 0
+};
+
+static uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+static uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+static uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ymm[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+/*
+static uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+*/
+static uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar ymr[] =
+{
+ Ymr, Ymr, Zm_r, 1,
+ 0
+};
+static uchar ymr_ml[] =
+{
+ Ymr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+static uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yps[] =
+{
+ Ymm, Ymr, Zm_r_xm, 1,
+ Yi8, Ymr, Zibo_m_xm, 2,
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yi8, Yxr, Zibo_m_xm, 3,
+ 0
+};
+static uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymfp[] =
+{
+ Ymm, Ymr, Zm_r_3d, 1,
+ 0,
+};
+static uchar ymrxr[] =
+{
+ Ymr, Yxr, Zm_r, 1,
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar ymshuf[] =
+{
+ Ymm, Ymr, Zibm_r, 2,
+ 0
+};
+static uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
+static uchar yxshuf[] =
+{
+ Yxm, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar yextrw[] =
+{
+ Yxr, Yrl, Zibm_r, 2,
+ 0
+};
+static uchar yinsrw[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar yinsr[] =
+{
+ Ymm, Yxr, Zibm_r, 3,
+ 0
+};
+static uchar ypsdq[] =
+{
+ Yi8, Yxr, Zibo_m, 2,
+ 0
+};
+static uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar ycrc32l[] =
+{
+ Yml, Yrl, Zlitm_r, 0,
+};
+static uchar yprefetch[] =
+{
+ Ym, Ynone, Zm_o, 2,
+ 0,
+};
+static uchar yaes[] =
+{
+ Yxm, Yxr, Zlitm_r, 2,
+ 0
+};
+static uchar yaes2[] =
+{
+ Yxm, Yxr, Zibm_r, 2,
+ 0
+};
+
+/*
+ * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
+ * and p->from and p->to as operands (Addr*). The linker scans optab to find
+ * the entry with the given p->as and then looks through the ytable for that
+ * instruction (the second field in the optab struct) for a line whose first
+ * two values match the Ytypes of the p->from and p->to operands. The function
+ * oclass in span.c computes the specific Ytype of an operand and then the set
+ * of more general Ytypes that it satisfies is implied by the ycover table, set
+ * up in instinit. For example, oclass distinguishes the constants 0 and 1
+ * from the more general 8-bit constants, but instinit says
+ *
+ * ycover[Yi0*Ymax + Ys32] = 1;
+ * ycover[Yi1*Ymax + Ys32] = 1;
+ * ycover[Yi8*Ymax + Ys32] = 1;
+ *
+ * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
+ * if that's what an instruction can handle.
+ *
+ * In parallel with the scan through the ytable for the appropriate line, there
+ * is a z pointer that starts out pointing at the strange magic byte list in
+ * the Optab struct. With each step past a non-matching ytable line, z
+ * advances by the 4th entry in the line. When a matching line is found, that
+ * z pointer has the extra data to use in laying down the instruction bytes.
+ * The actual bytes laid down are a function of the 3rd entry in the line (that
+ * is, the Ztype) and the z bytes.
+ *
+ * For example, let's look at AADDL. The optab line says:
+ * { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *
+ * and yaddl says
+ * uchar yaddl[] =
+ * {
+ * Yi8, Yml, Zibo_m, 2,
+ * Yi32, Yax, Zil_, 1,
+ * Yi32, Yml, Zilo_m, 2,
+ * Yrl, Yml, Zr_m, 1,
+ * Yml, Yrl, Zm_r, 1,
+ * 0
+ * };
+ *
+ * so there are 5 possible types of ADDL instruction that can be laid down, and
+ * possible states used to lay them down (Ztype and z pointer, assuming z
+ * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ *
+ * Yi8, Yml -> Zibo_m, z (0x83, 00)
+ * Yi32, Yax -> Zil_, z+2 (0x05)
+ * Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
+ * Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
+ * Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
+ *
+ * The Pconstant in the optab line controls the prefix bytes to emit. That's
+ * relatively straightforward as this program goes.
+ *
+ * The switch on t[2] in doasm implements the various Z cases. Zibo_m, for
+ * example, is an opcode byte (z[0]) then an asmando (which is some kind of
+ * encoded addressing mode for the Yml arg), and then a single immediate byte.
+ * Zilo_m is the same but a long (32-bit) immediate.
+ */
+Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, P32, 0x37 },
+ { AAAD, ynone, P32, 0xd5,0x0a },
+ { AAAM, ynone, P32, 0xd4,0x0a },
+ { AAAS, ynone, P32, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCQ, yxorl, Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Pb, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDQ, yaddl, Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { AANDQ, yxorl, Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, P32, 0x63 },
+ { ABOUNDL, yrl_m, P32, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFQ, yml_rl, Pw, 0x0f,0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRQ, yml_rl, Pw, 0x0f,0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABSWAPL, ybswap, Px, 0x0f,0xc8 },
+ { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 },
+ { ABTCL, ybtl, Pm, 0xba,(07),0xbb },
+ { ABTCQ, ybtl, Pw, 0x0f,0xba,(07),0x0f,0xbb },
+ { ABTCW, ybtl, Pq, 0xba,(07),0xbb },
+ { ABTL, ybtl, Pm, 0xba,(04),0xa3 },
+ { ABTQ, ybtl, Pw, 0x0f,0xba,(04),0x0f,0xa3},
+ { ABTRL, ybtl, Pm, 0xba,(06),0xb3 },
+ { ABTRQ, ybtl, Pw, 0x0f,0xba,(06),0x0f,0xb3 },
+ { ABTRW, ybtl, Pq, 0xba,(06),0xb3 },
+ { ABTSL, ybtl, Pm, 0xba,(05),0xab },
+ { ABTSQ, ybtl, Pw, 0x0f,0xba,(05),0x0f,0xab },
+ { ABTSW, ybtl, Pq, 0xba,(05),0xab },
+ { ABTW, ybtl, Pq, 0xba,(04),0xa3 },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVQCC, yml_rl, Pw, 0x0f,0x43 },
+ { ACMOVQCS, yml_rl, Pw, 0x0f,0x42 },
+ { ACMOVQEQ, yml_rl, Pw, 0x0f,0x44 },
+ { ACMOVQGE, yml_rl, Pw, 0x0f,0x4d },
+ { ACMOVQGT, yml_rl, Pw, 0x0f,0x4f },
+ { ACMOVQHI, yml_rl, Pw, 0x0f,0x47 },
+ { ACMOVQLE, yml_rl, Pw, 0x0f,0x4e },
+ { ACMOVQLS, yml_rl, Pw, 0x0f,0x46 },
+ { ACMOVQLT, yml_rl, Pw, 0x0f,0x4c },
+ { ACMOVQMI, yml_rl, Pw, 0x0f,0x48 },
+ { ACMOVQNE, yml_rl, Pw, 0x0f,0x45 },
+ { ACMOVQOC, yml_rl, Pw, 0x0f,0x41 },
+ { ACMOVQOS, yml_rl, Pw, 0x0f,0x40 },
+ { ACMOVQPC, yml_rl, Pw, 0x0f,0x4b },
+ { ACMOVQPL, yml_rl, Pw, 0x0f,0x49 },
+ { ACMOVQPS, yml_rl, Pw, 0x0f,0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPQ, ycmpl, Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSQ, ynone, Pw, 0xa7 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { API2FW, ymfp, Px, 0x0c },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SQ, yxcvfq, Pw, Pf2,0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSQ2SD, yxcvqf, Pw, Pf2,0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSQ2SS, yxcvqf, Pw, Pf3,0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTSS2SQ, yxcvfq, Pw, Pf3,0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSD2SQ, yxcvfq, Pw, Pf2,0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ACVTTSS2SQ, yxcvfq, Pw, Pf3,0x2c },
+ { ACWD, ynone, Pe, 0x99 },
+ { ACQO, ynone, Pw, 0x99 },
+ { ADAA, ynone, P32, 0x27 },
+ { ADAS, ynone, P32, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0xff,(01) },
+ { ADECQ, yincl, Pw, 0xff,(01) },
+ { ADECW, yincw, Pe, 0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVQ, ydivl, Pw, 0xf7,(06) },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AEMMS, ynone, Pm, 0x77 },
+ { AENTER }, /* botch */
+ { AFXRSTOR, ysvrs, Pm, 0xae,(01),0xae,(01) },
+ { AFXSAVE, ysvrs, Pm, 0xae,(00),0xae,(00) },
+ { AFXRSTOR64, ysvrs, Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
+ { AFXSAVE64, ysvrs, Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVQ, ydivl, Pw, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMUL3Q, yimul3, Pw, 0x6b,(00) },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0xff,(00) },
+ { AINCQ, yincl, Pw, 0xff,(00) },
+ { AINCW, yincw, Pe, 0xff,(00) },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, P32, 0xce },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETQ, ynone, Pw, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZQ, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALDMXCSR, ysvrs, Pm, 0xae,(02),0xae,(02) },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAQ, ym_rl, Pw, 0x8d },
+ { ALEAVEL, ynone, P32, 0xc9 },
+ { ALEAVEQ, ynone, Py, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSQ, ynone, Pw, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMASKMOVQ, ymr, Pm, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBQSX, ymb_rl, Pw, 0x0f,0xbe },
+ { AMOVBQZX, ymb_rl, Pw, 0x0f,0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0 },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVLQSX, yml_rl, Pw, 0x63 },
+ { AMOVLQZX, yml_rl, Px, 0x8b },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVNTQ, ymr_ml, Pm, 0xe7 },
+ { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0 },
+ { AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSQ, ynone, Pw, 0xa5 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00),0 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVWQSX, yml_rl, Pw, 0x0f,0xbf },
+ { AMOVWQZX, yml_rl, Pw, 0x0f,0xb7 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULQ, ydivl, Pw, 0xf7,(04) },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Pb, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGQ, yscond, Pw, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px, 0,0 },
+ { ANOTB, yscond, Pb, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTQ, yscond, Pw, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { AORQ, yxorl, Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { APACKSSLW, ymm, Py, 0x6b,Pe,0x6b },
+ { APACKSSWB, ymm, Py, 0x63,Pe,0x63 },
+ { APACKUSWB, ymm, Py, 0x67,Pe,0x67 },
+ { APADDB, ymm, Py, 0xfc,Pe,0xfc },
+ { APADDL, ymm, Py, 0xfe,Pe,0xfe },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APADDSB, ymm, Py, 0xec,Pe,0xec },
+ { APADDSW, ymm, Py, 0xed,Pe,0xed },
+ { APADDUSB, ymm, Py, 0xdc,Pe,0xdc },
+ { APADDUSW, ymm, Py, 0xdd,Pe,0xdd },
+ { APADDW, ymm, Py, 0xfd,Pe,0xfd },
+ { APAND, ymm, Py, 0xdb,Pe,0xdb },
+ { APANDN, ymm, Py, 0xdf,Pe,0xdf },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APAVGB, ymm, Py, 0xe0,Pe,0xe0 },
+ { APAVGW, ymm, Py, 0xe3,Pe,0xe3 },
+ { APCMPEQB, ymm, Py, 0x74,Pe,0x74 },
+ { APCMPEQL, ymm, Py, 0x76,Pe,0x76 },
+ { APCMPEQW, ymm, Py, 0x75,Pe,0x75 },
+ { APCMPGTB, ymm, Py, 0x64,Pe,0x64 },
+ { APCMPGTL, ymm, Py, 0x66,Pe,0x66 },
+ { APCMPGTW, ymm, Py, 0x65,Pe,0x65 },
+ { APEXTRW, yextrw, Pq, 0xc5,(00) },
+ { APF2IL, ymfp, Px, 0x1d },
+ { APF2IW, ymfp, Px, 0x1c },
+ { API2FL, ymfp, Px, 0x0d },
+ { APFACC, ymfp, Px, 0xae },
+ { APFADD, ymfp, Px, 0x9e },
+ { APFCMPEQ, ymfp, Px, 0xb0 },
+ { APFCMPGE, ymfp, Px, 0x90 },
+ { APFCMPGT, ymfp, Px, 0xa0 },
+ { APFMAX, ymfp, Px, 0xa4 },
+ { APFMIN, ymfp, Px, 0x94 },
+ { APFMUL, ymfp, Px, 0xb4 },
+ { APFNACC, ymfp, Px, 0x8a },
+ { APFPNACC, ymfp, Px, 0x8e },
+ { APFRCP, ymfp, Px, 0x96 },
+ { APFRCPIT1, ymfp, Px, 0xa6 },
+ { APFRCPI2T, ymfp, Px, 0xb6 },
+ { APFRSQIT1, ymfp, Px, 0xa7 },
+ { APFRSQRT, ymfp, Px, 0x97 },
+ { APFSUB, ymfp, Px, 0x9a },
+ { APFSUBR, ymfp, Px, 0xaa },
+ { APINSRW, yinsrw, Pq, 0xc4,(00) },
+ { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) },
+ { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) },
+ { APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APMULHRW, ymfp, Px, 0xb7 },
+ { APMULHUW, ymm, Py, 0xe4,Pe,0xe4 },
+ { APMULHW, ymm, Py, 0xe5,Pe,0xe5 },
+ { APMULLW, ymm, Py, 0xd5,Pe,0xd5 },
+ { APMULULQ, ymm, Py, 0xf4,Pe,0xf4 },
+ { APOPAL, ynone, P32, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, P32, 0x9d },
+ { APOPFQ, ynone, Py, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, P32, 0x58,0x8f,(00) },
+ { APOPQ, ypopl, Py, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APOR, ymm, Py, 0xeb,Pe,0xeb },
+ { APSADBW, yxm, Pq, 0xf6 },
+ { APSHUFHW, yxshuf, Pf3, 0x70,(00) },
+ { APSHUFL, yxshuf, Pq, 0x70,(00) },
+ { APSHUFLW, yxshuf, Pf2, 0x70,(00) },
+ { APSHUFW, ymshuf, Pm, 0x70,(00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
+ { APSLLO, ypsdq, Pq, 0x73,(07) },
+ { APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
+ { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
+ { APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
+ { APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
+ { APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
+ { APSRLO, ypsdq, Pq, 0x73,(03) },
+ { APSRLL, yps, Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
+ { APSRLQ, yps, Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
+ { APSRLW, yps, Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APSWAPL, ymfp, Px, 0xbb },
+ { APUNPCKHBW, ymm, Py, 0x68,Pe,0x68 },
+ { APUNPCKHLQ, ymm, Py, 0x6a,Pe,0x6a },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKHWL, ymm, Py, 0x69,Pe,0x69 },
+ { APUNPCKLBW, ymm, Py, 0x60,Pe,0x60 },
+ { APUNPCKLLQ, ymm, Py, 0x62,Pe,0x62 },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { APUNPCKLWL, ymm, Py, 0x61,Pe,0x61 },
+ { APUSHAL, ynone, P32, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, P32, 0x9c },
+ { APUSHFQ, ynone, Py, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, P32, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHQ, ypushl, Py, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { APXOR, ymm, Py, 0xef,Pe,0xef },
+ { AQUAD, ybyte, Px, 8 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLQ, yshl, Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRQ, yshl, Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { ARETFW, yret, Pe, 0xcb,0xca },
+ { ARETFL, yret, Px, 0xcb,0xca },
+ { ARETFQ, yret, Pw, 0xcb,0xca },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLQ, yshl, Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORQ, yshl, Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASAHF, ynone, Px, 0x86,0xe0,0x50,0x9d }, /* XCHGB AH,AL; PUSH AX; POPFL */
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARQ, yshl, Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBQ, yxorl, Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASQ, ynone, Pw, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLQ, yshl, Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRQ, yshl, Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHUFPD, yxshuf, Pq, 0xc6,(00) },
+ { ASHUFPS, yxshuf, Pm, 0xc6,(00) },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTMXCSR, ysvrs, Pm, 0xae,(03),0xae,(03) },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSQ, ynone, Pw, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBQ, yaddl, Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASWAPGS, ynone, Pm, 0x01,0xf8 },
+ { ASYSCALL, ynone, Px, 0x0f,0x05 }, /* fast syscall */
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTQ, ytestl, Pw, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
+ { AXCHGQ, yxchg, Pw, 0x90,0x90,0x87,0x87 },
+ { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+ { AXORQ, yxorl, Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+
+ { ACMPXCHGB, yrb_mb, Pb, 0x0f,0xb0 },
+ { ACMPXCHGL, yrl_ml, Px, 0x0f,0xb1 },
+ { ACMPXCHGW, yrl_ml, Pe, 0x0f,0xb1 },
+ { ACMPXCHGQ, yrl_ml, Pw, 0x0f,0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { AINVD, ynone, Pm, 0x08 },
+ { AINVLPG, ymbs, Pm, 0x01,(07) },
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { AMOVNTIL, yrl_ml, Pm, 0xc3 },
+ { AMOVNTIQ, yrl_ml, Pw, 0x0f,0xc3 },
+ { ARDMSR, ynone, Pm, 0x32 },
+ { ARDPMC, ynone, Pm, 0x33 },
+ { ARDTSC, ynone, Pm, 0x31 },
+ { ARSM, ynone, Pm, 0xaa },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+ { ASYSRET, ynone, Pm, 0x07 },
+ { AWBINVD, ynone, Pm, 0x09 },
+ { AWRMSR, ynone, Pm, 0x30 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Px, 0x0f,0xc1 },
+ { AXADDQ, yrl_ml, Pw, 0x0f,0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACRC32B, ycrc32l,Px, 0xf2,0x0f,0x38,0xf0,0 },
+ { ACRC32Q, ycrc32l,Pw, 0xf2,0x0f,0x38,0xf1,0 },
+
+ { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
+ { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
+ { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
+ { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
+
+ { AMOVQL, yrl_ml, Px, 0x89 },
+
+ { AUNDEF, ynone, Px, 0x0f, 0x0b },
+
+ { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
+ { AAESENCLAST, yaes, Pq, 0x38,0xdd,(0) },
+ { AAESDEC, yaes, Pq, 0x38,0xde,(0) },
+ { AAESDECLAST, yaes, Pq, 0x38,0xdf,(0) },
+ { AAESIMC, yaes, Pq, 0x38,0xdb,(0) },
+ { AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) },
+
+ { APSHUFD, yaes2, Pq, 0x70,(0) },
+ { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
+
+ { AUSEFIELD, ynop, Px, 0,0 },
+ { ATYPE },
+ { AFUNCDATA, yfuncdata, Px, 0,0 },
+ { APCDATA, ypcdata, Px, 0,0 },
+ { ACHECKNIL },
+ { AVARDEF },
+ { AVARKILL },
+ { ADUFFCOPY, yduff, Px, 0xe8 },
+ { ADUFFZERO, yduff, Px, 0xe8 },
+
+ { AEND },
+ 0
+};
+
+static Optab* opindex[ALAST+1];
+static vlong vaddr(Link*, Addr*, Reloc*);
+
+// single-instruction no-ops of various lengths.
+// constructed by hand and disassembled with gdb to verify.
+// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
+static uchar nop[][16] = {
+ {0x90},
+ {0x66, 0x90},
+ {0x0F, 0x1F, 0x00},
+ {0x0F, 0x1F, 0x40, 0x00},
+ {0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
+ {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ // Native Client rejects the repeated 0x66 prefix.
+ // {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+
+static void
+fillnop(uchar *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = n;
+ if(m > nelem(nop))
+ m = nelem(nop);
+ memmove(p, nop[m-1], m);
+ p += m;
+ n -= m;
+ }
+}
+
+static void instinit(void);
+
+static int32
+naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
+{
+ symgrow(ctxt, s, c+pad);
+ fillnop(s->p+c, pad);
+ return c+pad;
+}
+
+static int
+spadjop(Link *ctxt, Prog *p, int l, int q)
+{
+ if(p->mode != 64 || ctxt->arch->ptrsize == 4)
+ return l;
+ return q;
+}
+
+void
+span6(Link *ctxt, LSym *s)
+{
+ Prog *p, *q;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ ctxt->cursym = s;
+
+ if(s->p != nil)
+ return;
+
+ if(ycover[0] == 0)
+ instinit();
+
+ for(p = ctxt->cursym->text; p != nil; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == nil)
+ p->pcond = p;
+ if((q = p->pcond) != nil)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = spadjop(ctxt, p, AADDL, AADDQ);
+ if(v < 0) {
+ p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ for(p = s->text; p != nil; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != nil && (q->back & 2)) {
+ p->back |= 1; // backward jump
+ q->back |= 4; // loop head
+ }
+
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = spadjop(ctxt, p, AADDL, AADDQ);
+ if(v < 0) {
+ p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != nil; p = p->link) {
+ if(ctxt->headtype == Hnacl && p->isize > 0) {
+ static LSym *deferreturn;
+
+ if(deferreturn == nil)
+ deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+
+ // pad everything to avoid crossing 32-byte boundary
+ if((c>>5) != ((c+p->isize-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+ // pad call deferreturn to start at 32-byte boundary
+ // so that subtracting 5 in jmpdefer will jump back
+ // to that boundary and rerun the call.
+ if(p->as == ACALL && p->to.sym == deferreturn)
+ c = naclpad(ctxt, s, c, -c&31);
+ // pad call to end at 32-byte boundary
+ if(p->as == ACALL)
+ c = naclpad(ctxt, s, c, -(c+p->isize)&31);
+
+ // the linker treats REP and STOSQ as different instructions
+ // but in fact the REP is a prefix on the STOSQ.
+ // make sure REP has room for 2 more bytes, so that
+ // padding will not be inserted before the next instruction.
+ if((p->as == AREP || p->as == AREPN) && (c>>5) != ((c+3-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+
+ // same for LOCK.
+ // various instructions follow; the longest is 4 bytes.
+ // give ourselves 8 bytes so as to avoid surprises.
+ if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+ }
+
+ if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
+ // pad with NOPs
+ v = -c&(LoopAlign-1);
+ if(v <= MaxLoopPad) {
+ symgrow(ctxt, s, c+v);
+ fillnop(s->p+c, v);
+ c += v;
+ }
+ }
+
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != nil; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ if(q->as == AJCXZL)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp = v>>24;
+ }
+ }
+ p->comefrom = nil;
+
+ p->pc = c;
+ asmins(ctxt, p);
+ m = ctxt->andptr-ctxt->and;
+ if(p->isize != m) {
+ p->isize = m;
+ loop++;
+ }
+ symgrow(ctxt, s, p->pc+m);
+ memmove(s->p+p->pc, ctxt->and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ ctxt->diag("span must be looping");
+ sysfatal("loop");
+ }
+ } while(loop);
+
+ if(ctxt->headtype == Hnacl)
+ c = naclpad(ctxt, s, c, -c&31);
+
+ c += -c&(FuncAlign-1);
+ s->size = c;
+
+ if(0 /* debug['a'] > 1 */) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
+ }
+ }
+}
+
+static void
+instinit(void)
+{
+ int c, i;
+
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil)
+ sysfatal("phase error in optab: %d (%A)", i, c);
+ opindex[c] = &optab[i];
+ }
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
+ }
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
+ }
+}
+
+static int
+prefixof(Link *ctxt, Addr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
+ case D_INDIR+D_TLS:
+ // NOTE: Systems listed here should be only systems that
+ // support direct TLS references like 8(TLS) implemented as
+ // direct references from FS or GS. Systems that require
+ // the initial-exec model, where you load the TLS base into
+ // a register and then index from that register, do not reach
+ // this code and should not be listed.
+ switch(ctxt->headtype) {
+ default:
+ sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+ case Hdragonfly:
+ case Hfreebsd:
+ case Hlinux:
+ case Hnetbsd:
+ case Hopenbsd:
+ case Hplan9:
+ case Hsolaris:
+ return 0x64; // FS
+ case Hdarwin:
+ return 0x65; // GS
+ }
+ }
+ switch(a->index) {
+ case D_CS:
+ return 0x2e;
+ case D_DS:
+ return 0x3e;
+ case D_ES:
+ return 0x26;
+ case D_FS:
+ return 0x64;
+ case D_GS:
+ return 0x65;
+ }
+ return 0;
+}
+
+static int
+oclass(Link *ctxt, Addr *a)
+{
+ vlong v;
+ int32 l;
+
+ if(a->type >= D_INDIR || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(ctxt->flag_shared || ctxt->headtype == Hnacl)
+ return Yiauto;
+ else
+ return Yi32; /* TO DO: Yi64 */
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+/*
+ case D_SPB:
+*/
+ case D_BPB:
+ case D_SIB:
+ case D_DIB:
+ case D_R8B:
+ case D_R9B:
+ case D_R10B:
+ case D_R11B:
+ case D_R12B:
+ case D_R13B:
+ case D_R14B:
+ case D_R15B:
+ if(ctxt->asmode != 64)
+ return Yxxx;
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CL:
+ return Ycl;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_R8: /* not really Yrl */
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ return Yxxx;
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_M0+0:
+ case D_M0+1:
+ case D_M0+2:
+ case D_M0+3:
+ case D_M0+4:
+ case D_M0+5:
+ case D_M0+6:
+ case D_M0+7:
+ return Ymr;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ case D_X0+8:
+ case D_X0+9:
+ case D_X0+10:
+ case D_X0+11:
+ case D_X0+12:
+ case D_X0+13:
+ case D_X0+14:
+ case D_X0+15:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+ case D_TLS: return Ytls;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+ case D_CR+8: return Ycr8;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_ADDR:
+ if(a->sym == nil) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ l = v;
+ if((vlong)l == v)
+ return Ys32; /* can sign extend */
+ if((v>>32) == 0)
+ return Yi32; /* unsigned */
+ return Yi64;
+ }
+ return Yi32; /* TO DO: D_ADDR as Yi64 */
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+static void
+asmidx(Link *ctxt, int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_R8:
+ case D_R9:
+ case D_R10:
+ case D_R11:
+ case D_R12:
+ case D_R13:
+ case D_R14:
+ case D_R15:
+ if(ctxt->asmode != 64)
+ goto bad;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *ctxt->andptr++ = i;
+ return;
+bad:
+ ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base);
+ *ctxt->andptr++ = 0;
+ return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ ctxt->diag("bad reloc");
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+}
+
+static void
+put8(Link *ctxt, vlong v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr[4] = v>>32;
+ ctxt->andptr[5] = v>>40;
+ ctxt->andptr[6] = v>>48;
+ ctxt->andptr[7] = v>>56;
+ ctxt->andptr += 8;
+}
+
+/*
+static void
+relput8(Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put8(ctxt, v);
+}
+*/
+
+static vlong
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+ int t;
+ vlong v;
+ LSym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("reloc");
+ }
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
+ if(ctxt->flag_shared || ctxt->headtype == Hnacl) {
+ if(s->type == STLSBSS) {
+ r->xadd = r->add - r->siz;
+ r->type = R_TLS;
+ r->xsym = s;
+ } else
+ r->type = R_PCREL;
+ } else
+ r->type = R_ADDR;
+ break;
+
+ case D_INDIR+D_TLS:
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("reloc");
+ }
+ r->type = R_TLS_LE;
+ r->siz = 4;
+ r->off = -1; // caller must fill in
+ r->add = v;
+ v = 0;
+ break;
+ }
+ return v;
+}
+
+static void
+asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64)
+{
+ int32 v;
+ int t, scale;
+ Reloc rel;
+
+ USED(m64);
+ rex &= (0x40 | Rxr);
+ v = a->offset;
+ t = a->type;
+ rel.siz = 0;
+ if(a->index != D_NONE && a->index != D_TLS) {
+ if(t < D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ if(ctxt->flag_shared || ctxt->headtype == Hnacl)
+ goto bad;
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ } else
+ t -= D_INDIR;
+ ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_X0+15) {
+ if(v)
+ goto bad;
+ *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
+ t -= D_INDIR;
+ if(t == D_TLS)
+ v = vaddr(ctxt, a, &rel);
+
+ ctxt->rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
+ if((ctxt->flag_shared || ctxt->headtype == Hnacl) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
+ *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ return;
+ }
+ if(v >= -128 && v < 128) {
+ *ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(a->index == D_TLS) {
+ memset(&rel, 0, sizeof rel);
+ rel.type = R_TLS_IE;
+ rel.siz = 4;
+ rel.sym = nil;
+ rel.add = v;
+ v = 0;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->andptr[1] = v;
+ ctxt->andptr += 2;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
+ }
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ ctxt->diag("bad rel");
+ goto bad;
+ }
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ }
+
+ put4(ctxt, v);
+ return;
+
+bad:
+ ctxt->diag("asmand: bad address %D", a);
+ return;
+}
+
+static void
+asmand(Link *ctxt, Addr *a, Addr *ra)
+{
+ asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0);
+}
+
+static void
+asmando(Link *ctxt, Addr *a, int o)
+{
+ asmandsz(ctxt, a, o, 0, 0);
+}
+
+static void
+bytereg(Addr *a, char *t)
+{
+ if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
+ a->type = D_AL + (a->type-D_AX);
+ *t = 0;
+ }
+}
+
+#define E 0xff
+static Movtab ymovtab[] =
+{
+/* push */
+ {APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0},
+ {APUSHL, Yss, Ynone, 0, 0x16,E,0,0},
+ {APUSHL, Yds, Ynone, 0, 0x1e,E,0,0},
+ {APUSHL, Yes, Ynone, 0, 0x06,E,0,0},
+ {APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+ {APUSHQ, Yfs, Ynone, 0, 0x0f,0xa0,E,0},
+ {APUSHQ, Ygs, Ynone, 0, 0x0f,0xa8,E,0},
+
+ {APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0},
+ {APUSHW, Yss, Ynone, 0, Pe,0x16,E,0},
+ {APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0},
+ {APUSHW, Yes, Ynone, 0, Pe,0x06,E,0},
+ {APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E},
+ {APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E},
+
+/* pop */
+ {APOPL, Ynone, Yds, 0, 0x1f,E,0,0},
+ {APOPL, Ynone, Yes, 0, 0x07,E,0,0},
+ {APOPL, Ynone, Yss, 0, 0x17,E,0,0},
+ {APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+ {APOPQ, Ynone, Yfs, 0, 0x0f,0xa1,E,0},
+ {APOPQ, Ynone, Ygs, 0, 0x0f,0xa9,E,0},
+
+ {APOPW, Ynone, Yds, 0, Pe,0x1f,E,0},
+ {APOPW, Ynone, Yes, 0, Pe,0x07,E,0},
+ {APOPW, Ynone, Yss, 0, Pe,0x17,E,0},
+ {APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E},
+ {APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E},
+
+/* mov seg */
+ {AMOVW, Yes, Yml, 1, 0x8c,0,0,0},
+ {AMOVW, Ycs, Yml, 1, 0x8c,1,0,0},
+ {AMOVW, Yss, Yml, 1, 0x8c,2,0,0},
+ {AMOVW, Yds, Yml, 1, 0x8c,3,0,0},
+ {AMOVW, Yfs, Yml, 1, 0x8c,4,0,0},
+ {AMOVW, Ygs, Yml, 1, 0x8c,5,0,0},
+
+ {AMOVW, Yml, Yes, 2, 0x8e,0,0,0},
+ {AMOVW, Yml, Ycs, 2, 0x8e,1,0,0},
+ {AMOVW, Yml, Yss, 2, 0x8e,2,0,0},
+ {AMOVW, Yml, Yds, 2, 0x8e,3,0,0},
+ {AMOVW, Yml, Yfs, 2, 0x8e,4,0,0},
+ {AMOVW, Yml, Ygs, 2, 0x8e,5,0,0},
+
+/* mov cr */
+ {AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVL, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+ {AMOVQ, Ycr0, Yml, 3, 0x0f,0x20,0,0},
+ {AMOVQ, Ycr2, Yml, 3, 0x0f,0x20,2,0},
+ {AMOVQ, Ycr3, Yml, 3, 0x0f,0x20,3,0},
+ {AMOVQ, Ycr4, Yml, 3, 0x0f,0x20,4,0},
+ {AMOVQ, Ycr8, Yml, 3, 0x0f,0x20,8,0},
+
+ {AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVL, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+ {AMOVQ, Yml, Ycr0, 4, 0x0f,0x22,0,0},
+ {AMOVQ, Yml, Ycr2, 4, 0x0f,0x22,2,0},
+ {AMOVQ, Yml, Ycr3, 4, 0x0f,0x22,3,0},
+ {AMOVQ, Yml, Ycr4, 4, 0x0f,0x22,4,0},
+ {AMOVQ, Yml, Ycr8, 4, 0x0f,0x22,8,0},
+
+/* mov dr */
+ {AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+ {AMOVQ, Ydr0, Yml, 3, 0x0f,0x21,0,0},
+ {AMOVQ, Ydr6, Yml, 3, 0x0f,0x21,6,0},
+ {AMOVQ, Ydr7, Yml, 3, 0x0f,0x21,7,0},
+
+ {AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+ {AMOVQ, Yml, Ydr0, 4, 0x0f,0x23,0,0},
+ {AMOVQ, Yml, Ydr6, 4, 0x0f,0x23,6,0},
+ {AMOVQ, Yml, Ydr7, 4, 0x0f,0x23,7,0},
+
+/* mov tr */
+ {AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0},
+ {AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0},
+
+ {AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E},
+ {AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E},
+
+/* lgdt, sgdt, lidt, sidt */
+ {AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+ {AMOVQ, Ym, Ygdtr, 4, 0x0f,0x01,2,0},
+ {AMOVQ, Ygdtr, Ym, 3, 0x0f,0x01,0,0},
+ {AMOVQ, Ym, Yidtr, 4, 0x0f,0x01,3,0},
+ {AMOVQ, Yidtr, Ym, 3, 0x0f,0x01,1,0},
+
+/* lldt, sldt */
+ {AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0},
+ {AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0},
+
+/* lmsw, smsw */
+ {AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0},
+ {AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0},
+
+/* ltr, str */
+ {AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0},
+ {AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0},
+
+/* load full pointer */
+ {AMOVL, Yml, Ycol, 5, 0,0,0,0},
+ {AMOVW, Yml, Ycol, 5, Pe,0,0,0},
+
+/* double shift */
+ {ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0},
+ {ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0},
+ {ASHLQ, Ycol, Yml, 6, Pw,0xa4,0xa5,0},
+ {ASHRQ, Ycol, Yml, 6, Pw,0xac,0xad,0},
+ {ASHLW, Ycol, Yml, 6, Pe,0xa4,0xa5,0},
+ {ASHRW, Ycol, Yml, 6, Pe,0xac,0xad,0},
+
+/* load TLS base */
+ {AMOVQ, Ytls, Yrl, 7, 0,0,0,0},
+
+ 0
+};
+
+static int
+isax(Addr *a)
+{
+
+ switch(a->type) {
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ return 1;
+ }
+ if(a->index == D_AX)
+ return 1;
+ return 0;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+ if(0 /*debug['Q']*/)
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from)
+ p->from.type = to;
+ if(p->to.type == from)
+ p->to.type = to;
+
+ if(p->from.index == from)
+ p->from.index = to;
+ if(p->to.index == from)
+ p->to.index = to;
+
+ from += D_INDIR;
+ if(p->from.type == from)
+ p->from.type = to+D_INDIR;
+ if(p->to.type == from)
+ p->to.type = to+D_INDIR;
+
+ if(0 /*debug['Q']*/)
+ print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+ *ctxt->andptr++ = Pm;
+ break;
+ }
+ *ctxt->andptr++ = op;
+ return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ Movtab *mo;
+ int z, op, ft, tt, xo, l, pre;
+ vlong v;
+ Reloc rel, *r;
+ Addr *a;
+
+ ctxt->curp = p; // TODO
+
+ o = opindex[p->as];
+ if(o == nil) {
+ ctxt->diag("asmins: missing op %P", p);
+ return;
+ }
+
+ pre = prefixof(ctxt, &p->from);
+ if(pre)
+ *ctxt->andptr++ = pre;
+ pre = prefixof(ctxt, &p->to);
+ if(pre)
+ *ctxt->andptr++ = pre;
+
+ if(p->ft == 0)
+ p->ft = oclass(ctxt, &p->from);
+ if(p->tt == 0)
+ p->tt = oclass(ctxt, &p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+
+ t = o->ytab;
+ if(t == 0) {
+ ctxt->diag("asmins: noproto %P", p);
+ return;
+ }
+ xo = o->op[0] == 0x0f;
+ for(z=0; *t; z+=t[3]+xo,t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ break;
+ case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pw;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *ctxt->andptr++ = o->prefix;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *ctxt->andptr++ = Pe;
+ break;
+
+ case Pw: /* 64-bit escape */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal 64: %P", p);
+ ctxt->rexflag |= Pw;
+ break;
+
+ case Pb: /* botch */
+ bytereg(&p->from, &p->ft);
+ bytereg(&p->to, &p->tt);
+ break;
+
+ case P32: /* 32 bit but illegal if 64-bit mode */
+ if(p->mode == 64)
+ ctxt->diag("asmins: illegal in 64-bit mode: %P", p);
+ break;
+
+ case Py: /* 64-bit only, no prefix */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
+ break;
+ }
+
+ if(z >= nelem(o->op))
+ sysfatal("asmins bad table %P", p);
+ op = o->op[z];
+ if(op == 0x0f) {
+ *ctxt->andptr++ = op;
+ op = o->op[++z];
+ }
+ switch(t[2]) {
+ default:
+ ctxt->diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zmb_r:
+ bytereg(&p->from, &p->ft);
+ /* fall through */
+ case Zm_r:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ break;
+ case Zm2_r:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_xm_nr:
+ ctxt->rexflag = 0;
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zm_r_3d:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0x0f;
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zibm_r:
+ while ((op = o->op[z++]) != 0)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, &p->to);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *ctxt->andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ ctxt->diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ asmand(ctxt, &p->from, &p->to);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ break;
+
+ case Zm_o:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_xm_nr:
+ ctxt->rexflag = 0;
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, &p->from);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ break;
+
+ case Zo_m64:
+ case_Zo_m64:
+ *ctxt->andptr++ = op;
+ asmandsz(ctxt, &p->to, o->op[z+1], 0, 1);
+ break;
+
+ case Zm_ibo:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+ break;
+
+ case Zibo_m:
+ *ctxt->andptr++ = op;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zibo_m_xm:
+ z = mediaop(ctxt, o, op, t[3], z);
+ asmando(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = vaddr(ctxt, a, nil);
+ break;
+
+ case Zib_rp:
+ ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->to.type];
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zil_rp:
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Zo_iw:
+ *ctxt->andptr++ = op;
+ if(p->from.type != D_NONE){
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ break;
+
+ case Ziq_rp:
+ v = vaddr(ctxt, &p->from, &rel);
+ l = v>>32;
+ if(l == 0 && rel.siz != 8){
+ //p->mark |= 0100;
+ //print("zero: %llux %P\n", v, p);
+ ctxt->rexflag &= ~(0x40|Rxw);
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+ }else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
+ //p->mark |= 0100;
+ //print("sign: %llux %P\n", v, p);
+ *ctxt->andptr ++ = 0xc7;
+ asmando(ctxt, &p->to, 0);
+ put4(ctxt, v);
+ }else{ /* need all 8 */
+ //print("all: %llux %P\n", v, p);
+ ctxt->rexflag |= regrex[p->to.type] & Rxb;
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put8(ctxt, v);
+ }
+ break;
+
+ case Zib_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *ctxt->andptr++ = op;
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(ctxt, &p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(ctxt, &p->from, o->op[z+1]);
+ }
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zil_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Z_rp:
+ ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
+ *ctxt->andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, &p->to);
+ break;
+
+ case Zcall:
+ if(p->to.sym == nil) {
+ ctxt->diag("call without target");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = op;
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->add = p->to.offset;
+ r->type = R_CALL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+
+ case Zcallindreg:
+ r = addrel(ctxt->cursym);
+ r->off = p->pc;
+ r->type = R_CALLIND;
+ r->siz = 0;
+ goto case_Zo_m64;
+
+ case Zbr:
+ case Zjmp:
+ case Zloop:
+ // TODO: jump across functions needs reloc
+ if(p->to.sym != nil) {
+ if(t[2] != Zjmp) {
+ ctxt->diag("branch to ATEXT");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->type = R_PCREL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+ }
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
+
+ // Fill in backward jump now.
+ q = p->pcond;
+ if(q == nil) {
+ ctxt->diag("jmp/branch/loop without target");
+ sysfatal("bad code");
+ }
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
+ if(p->as == AJCXZL)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ if(p->as == AJCXZL)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ if(t[2] == Zbr)
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ }
+ break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+*/
+ break;
+
+ case Zbyte:
+ v = vaddr(ctxt, &p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ *ctxt->andptr++ = v;
+ if(op > 1) {
+ *ctxt->andptr++ = v>>8;
+ if(op > 2) {
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ if(op > 4) {
+ *ctxt->andptr++ = v>>32;
+ *ctxt->andptr++ = v>>40;
+ *ctxt->andptr++ = v>>48;
+ *ctxt->andptr++ = v>>56;
+ }
+ }
+ }
+ break;
+ }
+ return;
+
+domov:
+ for(mo=ymovtab; mo->as; mo++)
+ if(p->as == mo->as)
+ if(ycover[ft+mo->ft])
+ if(ycover[tt+mo->tt]){
+ t = mo->op;
+ goto mfound;
+ }
+bad:
+ if(p->mode != 64){
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->to) || p->to.type == D_NONE) {
+ // We certainly don't want to exchange
+ // with AX if the op is MUL or DIV.
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(ctxt, &p->from, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmando(ctxt, &p->from, reg[D_BX]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if(isax(&p->from)) {
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(ctxt, &p->to, reg[D_BX]);
+ subreg(&pp, z, D_BX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmando(ctxt, &p->to, reg[D_BX]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ }
+ ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(mo->code) {
+ default:
+ ctxt->diag("asmins: unknown mov %d %P", mo->code, p);
+ break;
+
+ case 0: /* lit */
+ for(z=0; t[z]!=E; z++)
+ *ctxt->andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *ctxt->andptr++ = t[0];
+ asmando(ctxt, &p->to, t[1]);
+ break;
+
+ case 2: /* m,r */
+ *ctxt->andptr++ = t[0];
+ asmando(ctxt, &p->from, t[1]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *ctxt->andptr++ = t[0];
+ *ctxt->andptr++ = t[1];
+ asmando(ctxt, &p->to, t[2]);
+ ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
+ break;
+
+ case 4: /* m,r - 2op */
+ *ctxt->andptr++ = t[0];
+ *ctxt->andptr++ = t[1];
+ asmando(ctxt, &p->from, t[2]);
+ ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[0])
+ *ctxt->andptr++ = t[0];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *ctxt->andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *ctxt->andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb5;
+ break;
+ }
+ asmand(ctxt, &p->from, &p->to);
+ break;
+
+ case 6: /* double shift */
+ if(t[0] == Pw){
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal 64: %P", p);
+ ctxt->rexflag |= Pw;
+ t++;
+ }else if(t[0] == Pe){
+ *ctxt->andptr++ = Pe;
+ t++;
+ }
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[0];
+ asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[1];
+ asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+ break;
+ }
+ break;
+
+ case 7: /* mov tls, r */
+ // NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+ // where you load the TLS base register into a register and then index off that
+ // register to access the actual TLS variables. Systems that allow direct TLS access
+ // are handled in prefixof above and should not be listed here.
+ switch(ctxt->headtype) {
+ default:
+ sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
+
+ case Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
+ // TLS base is 0(FS).
+ pp.from = p->from;
+ pp.from.type = D_INDIR+D_NONE;
+ pp.from.offset = 0;
+ pp.from.index = D_NONE;
+ pp.from.scale = 0;
+ ctxt->rexflag |= Pw;
+ *ctxt->andptr++ = 0x64; // FS
+ *ctxt->andptr++ = 0x8B;
+ asmand(ctxt, &pp.from, &p->to);
+ break;
+
+ case Hwindows:
+ // Windows TLS base is always 0x28(GS).
+ pp.from = p->from;
+ pp.from.type = D_INDIR+D_GS;
+ pp.from.offset = 0x28;
+ pp.from.index = D_NONE;
+ pp.from.scale = 0;
+ ctxt->rexflag |= Pw;
+ *ctxt->andptr++ = 0x65; // GS
+ *ctxt->andptr++ = 0x8B;
+ asmand(ctxt, &pp.from, &p->to);
+ break;
+ }
+ break;
+ }
+}
+
+static uchar naclret[] = {
+ 0x5e, // POPL SI
+ // 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+ 0x83, 0xe6, 0xe0, // ANDL $~31, SI
+ 0x4c, 0x01, 0xfe, // ADDQ R15, SI
+ 0xff, 0xe6, // JMP SI
+};
+
+static uchar naclspfix[] = {
+ 0x4c, 0x01, 0xfc, // ADDQ R15, SP
+};
+
+static uchar naclbpfix[] = {
+ 0x4c, 0x01, 0xfd, // ADDQ R15, BP
+};
+
+static uchar naclmovs[] = {
+ 0x89, 0xf6, // MOVL SI, SI
+ 0x49, 0x8d, 0x34, 0x37, // LEAQ (R15)(SI*1), SI
+ 0x89, 0xff, // MOVL DI, DI
+ 0x49, 0x8d, 0x3c, 0x3f, // LEAQ (R15)(DI*1), DI
+};
+
+static uchar naclstos[] = {
+ 0x89, 0xff, // MOVL DI, DI
+ 0x49, 0x8d, 0x3c, 0x3f, // LEAQ (R15)(DI*1), DI
+};
+
+static void
+nacltrunc(Link *ctxt, int reg)
+{
+ if(reg >= D_R8)
+ *ctxt->andptr++ = 0x45;
+ reg = (reg - D_AX) & 7;
+ *ctxt->andptr++ = 0x89;
+ *ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
+}
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+ int n, np, c;
+ uchar *and0;
+ Reloc *r;
+
+ ctxt->andptr = ctxt->and;
+ ctxt->asmode = p->mode;
+
+ if(p->as == AUSEFIELD) {
+ r = addrel(ctxt->cursym);
+ r->off = 0;
+ r->siz = 0;
+ r->sym = p->from.sym;
+ r->type = R_USEFIELD;
+ return;
+ }
+
+ if(ctxt->headtype == Hnacl) {
+ if(p->as == AREP) {
+ ctxt->rep++;
+ return;
+ }
+ if(p->as == AREPN) {
+ ctxt->repn++;
+ return;
+ }
+ if(p->as == ALOCK) {
+ ctxt->lock++;
+ return;
+ }
+ if(p->as != ALEAQ && p->as != ALEAL) {
+ if(p->from.index != D_NONE && p->from.scale > 0)
+ nacltrunc(ctxt, p->from.index);
+ if(p->to.index != D_NONE && p->to.scale > 0)
+ nacltrunc(ctxt, p->to.index);
+ }
+ switch(p->as) {
+ case ARET:
+ memmove(ctxt->andptr, naclret, sizeof naclret);
+ ctxt->andptr += sizeof naclret;
+ return;
+ case ACALL:
+ case AJMP:
+ if(D_AX <= p->to.type && p->to.type <= D_DI) {
+ // ANDL $~31, reg
+ *ctxt->andptr++ = 0x83;
+ *ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+ *ctxt->andptr++ = 0xe0;
+ // ADDQ R15, reg
+ *ctxt->andptr++ = 0x4c;
+ *ctxt->andptr++ = 0x01;
+ *ctxt->andptr++ = 0xf8 | (p->to.type - D_AX);
+ }
+ if(D_R8 <= p->to.type && p->to.type <= D_R15) {
+ // ANDL $~31, reg
+ *ctxt->andptr++ = 0x41;
+ *ctxt->andptr++ = 0x83;
+ *ctxt->andptr++ = 0xe0 | (p->to.type - D_R8);
+ *ctxt->andptr++ = 0xe0;
+ // ADDQ R15, reg
+ *ctxt->andptr++ = 0x4d;
+ *ctxt->andptr++ = 0x01;
+ *ctxt->andptr++ = 0xf8 | (p->to.type - D_R8);
+ }
+ break;
+ case AINT:
+ *ctxt->andptr++ = 0xf4;
+ return;
+ case ASCASB:
+ case ASCASW:
+ case ASCASL:
+ case ASCASQ:
+ case ASTOSB:
+ case ASTOSW:
+ case ASTOSL:
+ case ASTOSQ:
+ memmove(ctxt->andptr, naclstos, sizeof naclstos);
+ ctxt->andptr += sizeof naclstos;
+ break;
+ case AMOVSB:
+ case AMOVSW:
+ case AMOVSL:
+ case AMOVSQ:
+ memmove(ctxt->andptr, naclmovs, sizeof naclmovs);
+ ctxt->andptr += sizeof naclmovs;
+ break;
+ }
+ if(ctxt->rep) {
+ *ctxt->andptr++ = 0xf3;
+ ctxt->rep = 0;
+ }
+ if(ctxt->repn) {
+ *ctxt->andptr++ = 0xf2;
+ ctxt->repn = 0;
+ }
+ if(ctxt->lock) {
+ *ctxt->andptr++ = 0xf0;
+ ctxt->lock = 0;
+ }
+ }
+
+ ctxt->rexflag = 0;
+ and0 = ctxt->andptr;
+ ctxt->asmode = p->mode;
+ doasm(ctxt, p);
+ if(ctxt->rexflag){
+ /*
+ * as befits the whole approach of the architecture,
+ * the rex prefix must appear before the first opcode byte
+ * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
+ * before the 0f opcode escape!), or it might be ignored.
+ * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
+ */
+ if(p->mode != 64)
+ ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p);
+ n = ctxt->andptr - and0;
+ for(np = 0; np < n; np++) {
+ c = and0[np];
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
+ break;
+ }
+ memmove(and0+np+1, and0+np, n-np);
+ and0[np] = 0x40 | ctxt->rexflag;
+ ctxt->andptr++;
+ }
+ n = ctxt->andptr - ctxt->and;
+ for(r=ctxt->cursym->r+ctxt->cursym->nr; r-- > ctxt->cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ if(ctxt->rexflag)
+ r->off++;
+ if(r->type == R_PCREL || r->type == R_CALL)
+ r->add -= p->pc + n - (r->off + r->siz);
+ }
+
+ if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ) {
+ switch(p->to.type) {
+ case D_SP:
+ memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
+ ctxt->andptr += sizeof naclspfix;
+ break;
+ case D_BP:
+ memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
+ ctxt->andptr += sizeof naclbpfix;
+ break;
+ }
+ }
+}
diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c
new file mode 100644
index 000000000..3ab527ce8
--- /dev/null
+++ b/src/liblink/asm8.c
@@ -0,0 +1,2785 @@
+// Inferno utils/8l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Instruction layout.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+ MaxAlign = 32, // max data alignment
+ FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef struct Optab Optab;
+
+struct Optab
+{
+ short as;
+ uchar* ytab;
+ uchar prefix;
+ uchar op[13];
+};
+
+enum
+{
+ Yxxx = 0,
+ Ynone,
+ Yi0,
+ Yi1,
+ Yi8,
+ Yi32,
+ Yiauto,
+ Yal,
+ Ycl,
+ Yax,
+ Ycx,
+ Yrb,
+ Yrl,
+ Yrf,
+ Yf0,
+ Yrx,
+ Ymb,
+ Yml,
+ Ym,
+ Ybr,
+ Ycol,
+ Ytls,
+
+ Ycs, Yss, Yds, Yes, Yfs, Ygs,
+ Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
+ Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
+ Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
+ Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
+ Ymr, Ymm,
+ Yxr, Yxm,
+ Ymax,
+
+ Zxxx = 0,
+
+ Zlit,
+ Zlitm_r,
+ Z_rp,
+ Zbr,
+ Zcall,
+ Zcallcon,
+ Zcallind,
+ Zcallindreg,
+ Zib_,
+ Zib_rp,
+ Zibo_m,
+ Zil_,
+ Zil_rp,
+ Zilo_m,
+ Zjmp,
+ Zjmpcon,
+ Zloop,
+ Zm_o,
+ Zm_r,
+ Zm2_r,
+ Zm_r_xm,
+ Zm_r_i_xm,
+ Zaut_r,
+ Zo_m,
+ Zpseudo,
+ Zr_m,
+ Zr_m_xm,
+ Zr_m_i_xm,
+ Zrp_,
+ Z_ib,
+ Z_il,
+ Zm_ibo,
+ Zm_ilo,
+ Zib_rr,
+ Zil_rr,
+ Zclr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
+ Zbyte,
+ Zmov,
+ Zmax,
+
+ Px = 0,
+ Pe = 0x66, /* operand escape */
+ Pm = 0x0f, /* 2byte opcode escape */
+ Pq = 0xff, /* both escape */
+ Pb = 0xfe, /* byte operands */
+ Pf2 = 0xf2, /* xmm escape 1 */
+ Pf3 = 0xf3, /* xmm escape 2 */
+};
+
+static uchar ycover[Ymax*Ymax];
+static char reg[D_NONE];
+static void asmins(Link *ctxt, Prog *p);
+
+static uchar ynone[] =
+{
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar ytext[] =
+{
+ Ymb, Yi32, Zpseudo,1,
+ 0
+};
+static uchar ynop[] =
+{
+ Ynone, Ynone, Zpseudo,0,
+ Ynone, Yiauto, Zpseudo,0,
+ Ynone, Yml, Zpseudo,0,
+ Ynone, Yrf, Zpseudo,0,
+ Yiauto, Ynone, Zpseudo,0,
+ Ynone, Yxr, Zpseudo,0,
+ Yml, Ynone, Zpseudo,0,
+ Yrf, Ynone, Zpseudo,0,
+ Yxr, Ynone, Zpseudo,1,
+ 0
+};
+static uchar yfuncdata[] =
+{
+ Yi32, Ym, Zpseudo, 0,
+ 0
+};
+static uchar ypcdata[] =
+{
+ Yi32, Yi32, Zpseudo, 0,
+ 0,
+};
+static uchar yxorb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxorl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yaddl[] =
+{
+ Yi8, Yml, Zibo_m, 2,
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yincb[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yincl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Yml, Zo_m, 2,
+ 0
+};
+static uchar ycmpb[] =
+{
+ Yal, Yi32, Z_ib, 1,
+ Ymb, Yi32, Zm_ibo, 2,
+ Ymb, Yrb, Zm_r, 1,
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar ycmpl[] =
+{
+ Yml, Yi8, Zm_ibo, 2,
+ Yax, Yi32, Z_il, 1,
+ Yml, Yi32, Zm_ilo, 2,
+ Yml, Yrl, Zm_r, 1,
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yshb[] =
+{
+ Yi1, Ymb, Zo_m, 2,
+ Yi32, Ymb, Zibo_m, 2,
+ Ycx, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yshl[] =
+{
+ Yi1, Yml, Zo_m, 2,
+ Yi32, Yml, Zibo_m, 2,
+ Ycl, Yml, Zo_m, 2,
+ Ycx, Yml, Zo_m, 2,
+ 0
+};
+static uchar ytestb[] =
+{
+ Yi32, Yal, Zib_, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar ytestl[] =
+{
+ Yi32, Yax, Zil_, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ymovb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ Yi32, Yrb, Zib_rp, 1,
+ Yi32, Ymb, Zibo_m, 2,
+ 0
+};
+static uchar ymovw[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yiauto, Yrl, Zaut_r, 1,
+ 0
+};
+static uchar ymovl[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ Yi0, Yrl, Zclr, 1+2,
+// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
+ Yi32, Yrl, Zil_rp, 1,
+ Yi32, Yml, Zilo_m, 2,
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
+ Yiauto, Yrl, Zaut_r, 1,
+ 0
+};
+static uchar ymovq[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar ym_rl[] =
+{
+ Ym, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrl_m[] =
+{
+ Yrl, Ym, Zr_m, 1,
+ 0
+};
+static uchar ymb_rl[] =
+{
+ Ymb, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yml_rl[] =
+{
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yrb_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ 0
+};
+static uchar yrl_ml[] =
+{
+ Yrl, Yml, Zr_m, 1,
+ 0
+};
+static uchar yml_mb[] =
+{
+ Yrb, Ymb, Zr_m, 1,
+ Ymb, Yrb, Zm_r, 1,
+ 0
+};
+static uchar yxchg[] =
+{
+ Yax, Yrl, Z_rp, 1,
+ Yrl, Yax, Zrp_, 1,
+ Yrl, Yml, Zr_m, 1,
+ Yml, Yrl, Zm_r, 1,
+ 0
+};
+static uchar ydivl[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ydivb[] =
+{
+ Ymb, Ynone, Zm_o, 2,
+ 0
+};
+static uchar yimul[] =
+{
+ Yml, Ynone, Zm_o, 2,
+ Yi8, Yrl, Zib_rr, 1,
+ Yi32, Yrl, Zil_rr, 1,
+ 0
+};
+static uchar ybyte[] =
+{
+ Yi32, Ynone, Zbyte, 1,
+ 0
+};
+static uchar yin[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ Ynone, Ynone, Zlit, 1,
+ 0
+};
+static uchar yint[] =
+{
+ Yi32, Ynone, Zib_, 1,
+ 0
+};
+static uchar ypushl[] =
+{
+ Yrl, Ynone, Zrp_, 1,
+ Ym, Ynone, Zm_o, 2,
+ Yi8, Ynone, Zib_, 1,
+ Yi32, Ynone, Zil_, 1,
+ 0
+};
+static uchar ypopl[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ Ynone, Ym, Zo_m, 2,
+ 0
+};
+static uchar ybswap[] =
+{
+ Ynone, Yrl, Z_rp, 1,
+ 0,
+};
+static uchar yscond[] =
+{
+ Ynone, Ymb, Zo_m, 2,
+ 0
+};
+static uchar yjcond[] =
+{
+ Ynone, Ybr, Zbr, 0,
+ Yi0, Ybr, Zbr, 0,
+ Yi1, Ybr, Zbr, 1,
+ 0
+};
+static uchar yloop[] =
+{
+ Ynone, Ybr, Zloop, 1,
+ 0
+};
+static uchar ycall[] =
+{
+ Ynone, Yml, Zcallindreg, 0,
+ Yrx, Yrx, Zcallindreg, 2,
+ Ynone, Ycol, Zcallind, 2,
+ Ynone, Ybr, Zcall, 0,
+ Ynone, Yi32, Zcallcon, 1,
+ 0
+};
+static uchar yduff[] =
+{
+ Ynone, Yi32, Zcall, 1,
+ 0
+};
+static uchar yjmp[] =
+{
+ Ynone, Yml, Zo_m, 2,
+ Ynone, Ybr, Zjmp, 0,
+ Ynone, Yi32, Zjmpcon, 1,
+ 0
+};
+
+static uchar yfmvd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvdp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfmvf[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfmvx[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfmvp[] =
+{
+ Yf0, Ym, Zo_m, 2,
+ 0
+};
+static uchar yfcmv[] =
+{
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar yfadd[] =
+{
+ Ym, Yf0, Zm_o, 2,
+ Yrf, Yf0, Zm_o, 2,
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfaddp[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ 0
+};
+static uchar yfxch[] =
+{
+ Yf0, Yrf, Zo_m, 2,
+ Yrf, Yf0, Zm_o, 2,
+ 0
+};
+static uchar ycompp[] =
+{
+ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */
+ 0
+};
+static uchar ystsw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ynone, Yax, Zlit, 1,
+ 0
+};
+static uchar ystcw[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ysvrs[] =
+{
+ Ynone, Ym, Zo_m, 2,
+ Ym, Ynone, Zm_o, 2,
+ 0
+};
+static uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxm[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvm1[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Yxm, Ymr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvm2[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ Ymm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxmq[] =
+{
+ Yxm, Yxr, Zm_r_xm, 2,
+ 0
+};
+static uchar yxr[] =
+{
+ Yxr, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxr_ml[] =
+{
+ Yxr, Yml, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcmp[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcmpi[] =
+{
+ Yxm, Yxr, Zm_r_i_xm, 2,
+ 0
+};
+static uchar yxmov[] =
+{
+ Yxm, Yxr, Zm_r_xm, 1,
+ Yxr, Yxm, Zr_m_xm, 1,
+ 0
+};
+static uchar yxcvfl[] =
+{
+ Yxm, Yrl, Zm_r_xm, 1,
+ 0
+};
+static uchar yxcvlf[] =
+{
+ Yml, Yxr, Zm_r_xm, 1,
+ 0
+};
+/*
+static uchar yxcvfq[] =
+{
+ Yxm, Yrl, Zm_r_xm, 2,
+ 0
+};
+static uchar yxcvqf[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
+*/
+static uchar yxrrl[] =
+{
+ Yxr, Yrl, Zm_r, 1,
+ 0
+};
+static uchar yprefetch[] =
+{
+ Ym, Ynone, Zm_o, 2,
+ 0,
+};
+static uchar yaes[] =
+{
+ Yxm, Yxr, Zlitm_r, 2,
+ 0
+};
+static uchar yinsrd[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+static uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
+
+static Optab optab[] =
+/* as, ytab, andproto, opcode */
+{
+ { AXXX },
+ { AAAA, ynone, Px, 0x37 },
+ { AAAD, ynone, Px, 0xd5,0x0a },
+ { AAAM, ynone, Px, 0xd4,0x0a },
+ { AAAS, ynone, Px, 0x3f },
+ { AADCB, yxorb, Pb, 0x14,0x80,(02),0x10,0x10 },
+ { AADCL, yxorl, Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADCW, yxorl, Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+ { AADDB, yxorb, Px, 0x04,0x80,(00),0x00,0x02 },
+ { AADDL, yaddl, Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADDW, yaddl, Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ { AADJSP },
+ { AANDB, yxorb, Pb, 0x24,0x80,(04),0x20,0x22 },
+ { AANDL, yxorl, Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AANDW, yxorl, Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+ { AARPL, yrl_ml, Px, 0x63 },
+ { ABOUNDL, yrl_m, Px, 0x62 },
+ { ABOUNDW, yrl_m, Pe, 0x62 },
+ { ABSFL, yml_rl, Pm, 0xbc },
+ { ABSFW, yml_rl, Pq, 0xbc },
+ { ABSRL, yml_rl, Pm, 0xbd },
+ { ABSRW, yml_rl, Pq, 0xbd },
+ { ABTL, yml_rl, Pm, 0xa3 },
+ { ABTW, yml_rl, Pq, 0xa3 },
+ { ABTCL, yml_rl, Pm, 0xbb },
+ { ABTCW, yml_rl, Pq, 0xbb },
+ { ABTRL, yml_rl, Pm, 0xb3 },
+ { ABTRW, yml_rl, Pq, 0xb3 },
+ { ABTSL, yml_rl, Pm, 0xab },
+ { ABTSW, yml_rl, Pq, 0xab },
+ { ABYTE, ybyte, Px, 1 },
+ { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 },
+ { ACLC, ynone, Px, 0xf8 },
+ { ACLD, ynone, Px, 0xfc },
+ { ACLI, ynone, Px, 0xfa },
+ { ACLTS, ynone, Pm, 0x06 },
+ { ACMC, ynone, Px, 0xf5 },
+ { ACMPB, ycmpb, Pb, 0x3c,0x80,(07),0x38,0x3a },
+ { ACMPL, ycmpl, Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPW, ycmpl, Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+ { ACMPSB, ynone, Pb, 0xa6 },
+ { ACMPSL, ynone, Px, 0xa7 },
+ { ACMPSW, ynone, Pe, 0xa7 },
+ { ADAA, ynone, Px, 0x27 },
+ { ADAS, ynone, Px, 0x2f },
+ { ADATA },
+ { ADECB, yincb, Pb, 0xfe,(01) },
+ { ADECL, yincl, Px, 0x48,0xff,(01) },
+ { ADECW, yincl, Pe, 0x48,0xff,(01) },
+ { ADIVB, ydivb, Pb, 0xf6,(06) },
+ { ADIVL, ydivl, Px, 0xf7,(06) },
+ { ADIVW, ydivl, Pe, 0xf7,(06) },
+ { AENTER }, /* botch */
+ { AGLOBL },
+ { AGOK },
+ { AHISTORY },
+ { AHLT, ynone, Px, 0xf4 },
+ { AIDIVB, ydivb, Pb, 0xf6,(07) },
+ { AIDIVL, ydivl, Px, 0xf7,(07) },
+ { AIDIVW, ydivl, Pe, 0xf7,(07) },
+ { AIMULB, ydivb, Pb, 0xf6,(05) },
+ { AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69 },
+ { AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69 },
+ { AINB, yin, Pb, 0xe4,0xec },
+ { AINL, yin, Px, 0xe5,0xed },
+ { AINW, yin, Pe, 0xe5,0xed },
+ { AINCB, yincb, Pb, 0xfe,(00) },
+ { AINCL, yincl, Px, 0x40,0xff,(00) },
+ { AINCW, yincl, Pe, 0x40,0xff,(00) },
+ { AINSB, ynone, Pb, 0x6c },
+ { AINSL, ynone, Px, 0x6d },
+ { AINSW, ynone, Pe, 0x6d },
+ { AINT, yint, Px, 0xcd },
+ { AINTO, ynone, Px, 0xce },
+ { AIRETL, ynone, Px, 0xcf },
+ { AIRETW, ynone, Pe, 0xcf },
+ { AJCC, yjcond, Px, 0x73,0x83,(00) },
+ { AJCS, yjcond, Px, 0x72,0x82 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZW, yloop, Px, 0xe3 },
+ { AJEQ, yjcond, Px, 0x74,0x84 },
+ { AJGE, yjcond, Px, 0x7d,0x8d },
+ { AJGT, yjcond, Px, 0x7f,0x8f },
+ { AJHI, yjcond, Px, 0x77,0x87 },
+ { AJLE, yjcond, Px, 0x7e,0x8e },
+ { AJLS, yjcond, Px, 0x76,0x86 },
+ { AJLT, yjcond, Px, 0x7c,0x8c },
+ { AJMI, yjcond, Px, 0x78,0x88 },
+ { AJMP, yjmp, Px, 0xff,(04),0xeb,0xe9 },
+ { AJNE, yjcond, Px, 0x75,0x85 },
+ { AJOC, yjcond, Px, 0x71,0x81,(00) },
+ { AJOS, yjcond, Px, 0x70,0x80,(00) },
+ { AJPC, yjcond, Px, 0x7b,0x8b },
+ { AJPL, yjcond, Px, 0x79,0x89 },
+ { AJPS, yjcond, Px, 0x7a,0x8a },
+ { ALAHF, ynone, Px, 0x9f },
+ { ALARL, yml_rl, Pm, 0x02 },
+ { ALARW, yml_rl, Pq, 0x02 },
+ { ALEAL, ym_rl, Px, 0x8d },
+ { ALEAW, ym_rl, Pe, 0x8d },
+ { ALEAVEL, ynone, Px, 0xc9 },
+ { ALEAVEW, ynone, Pe, 0xc9 },
+ { ALOCK, ynone, Px, 0xf0 },
+ { ALODSB, ynone, Pb, 0xac },
+ { ALODSL, ynone, Px, 0xad },
+ { ALODSW, ynone, Pe, 0xad },
+ { ALONG, ybyte, Px, 4 },
+ { ALOOP, yloop, Px, 0xe2 },
+ { ALOOPEQ, yloop, Px, 0xe1 },
+ { ALOOPNE, yloop, Px, 0xe0 },
+ { ALSLL, yml_rl, Pm, 0x03 },
+ { ALSLW, yml_rl, Pq, 0x03 },
+ { AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0 },
+ { AMOVW, ymovw, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0 },
+ { AMOVQ, ymovq, Pf3, 0x7e },
+ { AMOVBLSX, ymb_rl, Pm, 0xbe },
+ { AMOVBLZX, ymb_rl, Pm, 0xb6 },
+ { AMOVBWSX, ymb_rl, Pq, 0xbe },
+ { AMOVBWZX, ymb_rl, Pq, 0xb6 },
+ { AMOVWLSX, yml_rl, Pm, 0xbf },
+ { AMOVWLZX, yml_rl, Pm, 0xb7 },
+ { AMOVSB, ynone, Pb, 0xa4 },
+ { AMOVSL, ynone, Px, 0xa5 },
+ { AMOVSW, ynone, Pe, 0xa5 },
+ { AMULB, ydivb, Pb, 0xf6,(04) },
+ { AMULL, ydivl, Px, 0xf7,(04) },
+ { AMULW, ydivl, Pe, 0xf7,(04) },
+ { ANAME },
+ { ANEGB, yscond, Px, 0xf6,(03) },
+ { ANEGL, yscond, Px, 0xf7,(03) },
+ { ANEGW, yscond, Pe, 0xf7,(03) },
+ { ANOP, ynop, Px,0,0 },
+ { ANOTB, yscond, Px, 0xf6,(02) },
+ { ANOTL, yscond, Px, 0xf7,(02) },
+ { ANOTW, yscond, Pe, 0xf7,(02) },
+ { AORB, yxorb, Pb, 0x0c,0x80,(01),0x08,0x0a },
+ { AORL, yxorl, Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AORW, yxorl, Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+ { AOUTB, yin, Pb, 0xe6,0xee },
+ { AOUTL, yin, Px, 0xe7,0xef },
+ { AOUTW, yin, Pe, 0xe7,0xef },
+ { AOUTSB, ynone, Pb, 0x6e },
+ { AOUTSL, ynone, Px, 0x6f },
+ { AOUTSW, ynone, Pe, 0x6f },
+ { APAUSE, ynone, Px, 0xf3,0x90 },
+ { APOPAL, ynone, Px, 0x61 },
+ { APOPAW, ynone, Pe, 0x61 },
+ { APOPFL, ynone, Px, 0x9d },
+ { APOPFW, ynone, Pe, 0x9d },
+ { APOPL, ypopl, Px, 0x58,0x8f,(00) },
+ { APOPW, ypopl, Pe, 0x58,0x8f,(00) },
+ { APUSHAL, ynone, Px, 0x60 },
+ { APUSHAW, ynone, Pe, 0x60 },
+ { APUSHFL, ynone, Px, 0x9c },
+ { APUSHFW, ynone, Pe, 0x9c },
+ { APUSHL, ypushl, Px, 0x50,0xff,(06),0x6a,0x68 },
+ { APUSHW, ypushl, Pe, 0x50,0xff,(06),0x6a,0x68 },
+ { ARCLB, yshb, Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+ { ARCLL, yshl, Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCLW, yshl, Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+ { ARCRB, yshb, Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+ { ARCRL, yshl, Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { ARCRW, yshl, Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+ { AREP, ynone, Px, 0xf3 },
+ { AREPN, ynone, Px, 0xf2 },
+ { ARET, ynone, Px, 0xc3 },
+ { AROLB, yshb, Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+ { AROLL, yshl, Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { AROLW, yshl, Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+ { ARORB, yshb, Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+ { ARORL, yshl, Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ARORW, yshl, Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+ { ASAHF, ynone, Px, 0x9e },
+ { ASALB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASALL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASALW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASARB, yshb, Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+ { ASARL, yshl, Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASARW, yshl, Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+ { ASBBB, yxorb, Pb, 0x1c,0x80,(03),0x18,0x1a },
+ { ASBBL, yxorl, Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASBBW, yxorl, Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+ { ASCASB, ynone, Pb, 0xae },
+ { ASCASL, ynone, Px, 0xaf },
+ { ASCASW, ynone, Pe, 0xaf },
+ { ASETCC, yscond, Pm, 0x93,(00) },
+ { ASETCS, yscond, Pm, 0x92,(00) },
+ { ASETEQ, yscond, Pm, 0x94,(00) },
+ { ASETGE, yscond, Pm, 0x9d,(00) },
+ { ASETGT, yscond, Pm, 0x9f,(00) },
+ { ASETHI, yscond, Pm, 0x97,(00) },
+ { ASETLE, yscond, Pm, 0x9e,(00) },
+ { ASETLS, yscond, Pm, 0x96,(00) },
+ { ASETLT, yscond, Pm, 0x9c,(00) },
+ { ASETMI, yscond, Pm, 0x98,(00) },
+ { ASETNE, yscond, Pm, 0x95,(00) },
+ { ASETOC, yscond, Pm, 0x91,(00) },
+ { ASETOS, yscond, Pm, 0x90,(00) },
+ { ASETPC, yscond, Pm, 0x96,(00) },
+ { ASETPL, yscond, Pm, 0x99,(00) },
+ { ASETPS, yscond, Pm, 0x9a,(00) },
+ { ACDQ, ynone, Px, 0x99 },
+ { ACWD, ynone, Pe, 0x99 },
+ { ASHLB, yshb, Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+ { ASHLL, yshl, Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHLW, yshl, Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+ { ASHRB, yshb, Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+ { ASHRL, yshl, Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASHRW, yshl, Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+ { ASTC, ynone, Px, 0xf9 },
+ { ASTD, ynone, Px, 0xfd },
+ { ASTI, ynone, Px, 0xfb },
+ { ASTOSB, ynone, Pb, 0xaa },
+ { ASTOSL, ynone, Px, 0xab },
+ { ASTOSW, ynone, Pe, 0xab },
+ { ASUBB, yxorb, Pb, 0x2c,0x80,(05),0x28,0x2a },
+ { ASUBL, yaddl, Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASUBW, yaddl, Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+ { ASYSCALL, ynone, Px, 0xcd,100 },
+ { ATESTB, ytestb, Pb, 0xa8,0xf6,(00),0x84,0x84 },
+ { ATESTL, ytestl, Px, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATESTW, ytestl, Pe, 0xa9,0xf7,(00),0x85,0x85 },
+ { ATEXT, ytext, Px },
+ { AVERR, ydivl, Pm, 0x00,(04) },
+ { AVERW, ydivl, Pm, 0x00,(05) },
+ { AWAIT, ynone, Px, 0x9b },
+ { AWORD, ybyte, Px, 2 },
+ { AXCHGB, yml_mb, Pb, 0x86,0x86 },
+ { AXCHGL, yxchg, Px, 0x90,0x90,0x87,0x87 },
+ { AXCHGW, yxchg, Pe, 0x90,0x90,0x87,0x87 },
+ { AXLAT, ynone, Px, 0xd7 },
+ { AXORB, yxorb, Pb, 0x34,0x80,(06),0x30,0x32 },
+ { AXORL, yxorl, Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+ { AXORW, yxorl, Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+ { AFMOVB, yfmvx, Px, 0xdf,(04) },
+ { AFMOVBP, yfmvp, Px, 0xdf,(06) },
+ { AFMOVD, yfmvd, Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+ { AFMOVDP, yfmvdp, Px, 0xdd,(03),0xdd,(03) },
+ { AFMOVF, yfmvf, Px, 0xd9,(00),0xd9,(02) },
+ { AFMOVFP, yfmvp, Px, 0xd9,(03) },
+ { AFMOVL, yfmvf, Px, 0xdb,(00),0xdb,(02) },
+ { AFMOVLP, yfmvp, Px, 0xdb,(03) },
+ { AFMOVV, yfmvx, Px, 0xdf,(05) },
+ { AFMOVVP, yfmvp, Px, 0xdf,(07) },
+ { AFMOVW, yfmvf, Px, 0xdf,(00),0xdf,(02) },
+ { AFMOVWP, yfmvp, Px, 0xdf,(03) },
+ { AFMOVX, yfmvx, Px, 0xdb,(05) },
+ { AFMOVXP, yfmvp, Px, 0xdb,(07) },
+
+ { AFCOMB },
+ { AFCOMBP },
+ { AFCOMD, yfadd, Px, 0xdc,(02),0xd8,(02),0xdc,(02) }, /* botch */
+ { AFCOMDP, yfadd, Px, 0xdc,(03),0xd8,(03),0xdc,(03) }, /* botch */
+ { AFCOMDPP, ycompp, Px, 0xde,(03) },
+ { AFCOMF, yfmvx, Px, 0xd8,(02) },
+ { AFCOMFP, yfmvx, Px, 0xd8,(03) },
+ { AFCOMI, yfmvx, Px, 0xdb,(06) },
+ { AFCOMIP, yfmvx, Px, 0xdf,(06) },
+ { AFCOML, yfmvx, Px, 0xda,(02) },
+ { AFCOMLP, yfmvx, Px, 0xda,(03) },
+ { AFCOMW, yfmvx, Px, 0xde,(02) },
+ { AFCOMWP, yfmvx, Px, 0xde,(03) },
+
+ { AFUCOM, ycompp, Px, 0xdd,(04) },
+ { AFUCOMI, ycompp, Px, 0xdb,(05) },
+ { AFUCOMIP, ycompp, Px, 0xdf,(05) },
+ { AFUCOMP, ycompp, Px, 0xdd,(05) },
+ { AFUCOMPP, ycompp, Px, 0xda,(13) },
+
+ { AFADDDP, yfaddp, Px, 0xde,(00) },
+ { AFADDW, yfmvx, Px, 0xde,(00) },
+ { AFADDL, yfmvx, Px, 0xda,(00) },
+ { AFADDF, yfmvx, Px, 0xd8,(00) },
+ { AFADDD, yfadd, Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+ { AFMULDP, yfaddp, Px, 0xde,(01) },
+ { AFMULW, yfmvx, Px, 0xde,(01) },
+ { AFMULL, yfmvx, Px, 0xda,(01) },
+ { AFMULF, yfmvx, Px, 0xd8,(01) },
+ { AFMULD, yfadd, Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+ { AFSUBDP, yfaddp, Px, 0xde,(05) },
+ { AFSUBW, yfmvx, Px, 0xde,(04) },
+ { AFSUBL, yfmvx, Px, 0xda,(04) },
+ { AFSUBF, yfmvx, Px, 0xd8,(04) },
+ { AFSUBD, yfadd, Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+ { AFSUBRDP, yfaddp, Px, 0xde,(04) },
+ { AFSUBRW, yfmvx, Px, 0xde,(05) },
+ { AFSUBRL, yfmvx, Px, 0xda,(05) },
+ { AFSUBRF, yfmvx, Px, 0xd8,(05) },
+ { AFSUBRD, yfadd, Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+ { AFDIVDP, yfaddp, Px, 0xde,(07) },
+ { AFDIVW, yfmvx, Px, 0xde,(06) },
+ { AFDIVL, yfmvx, Px, 0xda,(06) },
+ { AFDIVF, yfmvx, Px, 0xd8,(06) },
+ { AFDIVD, yfadd, Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+ { AFDIVRDP, yfaddp, Px, 0xde,(06) },
+ { AFDIVRW, yfmvx, Px, 0xde,(07) },
+ { AFDIVRL, yfmvx, Px, 0xda,(07) },
+ { AFDIVRF, yfmvx, Px, 0xd8,(07) },
+ { AFDIVRD, yfadd, Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+ { AFXCHD, yfxch, Px, 0xd9,(01),0xd9,(01) },
+ { AFFREE },
+ { AFLDCW, ystcw, Px, 0xd9,(05),0xd9,(05) },
+ { AFLDENV, ystcw, Px, 0xd9,(04),0xd9,(04) },
+ { AFRSTOR, ysvrs, Px, 0xdd,(04),0xdd,(04) },
+ { AFSAVE, ysvrs, Px, 0xdd,(06),0xdd,(06) },
+ { AFSTCW, ystcw, Px, 0xd9,(07),0xd9,(07) },
+ { AFSTENV, ystcw, Px, 0xd9,(06),0xd9,(06) },
+ { AFSTSW, ystsw, Px, 0xdd,(07),0xdf,0xe0 },
+ { AF2XM1, ynone, Px, 0xd9, 0xf0 },
+ { AFABS, ynone, Px, 0xd9, 0xe1 },
+ { AFCHS, ynone, Px, 0xd9, 0xe0 },
+ { AFCLEX, ynone, Px, 0xdb, 0xe2 },
+ { AFCOS, ynone, Px, 0xd9, 0xff },
+ { AFDECSTP, ynone, Px, 0xd9, 0xf6 },
+ { AFINCSTP, ynone, Px, 0xd9, 0xf7 },
+ { AFINIT, ynone, Px, 0xdb, 0xe3 },
+ { AFLD1, ynone, Px, 0xd9, 0xe8 },
+ { AFLDL2E, ynone, Px, 0xd9, 0xea },
+ { AFLDL2T, ynone, Px, 0xd9, 0xe9 },
+ { AFLDLG2, ynone, Px, 0xd9, 0xec },
+ { AFLDLN2, ynone, Px, 0xd9, 0xed },
+ { AFLDPI, ynone, Px, 0xd9, 0xeb },
+ { AFLDZ, ynone, Px, 0xd9, 0xee },
+ { AFNOP, ynone, Px, 0xd9, 0xd0 },
+ { AFPATAN, ynone, Px, 0xd9, 0xf3 },
+ { AFPREM, ynone, Px, 0xd9, 0xf8 },
+ { AFPREM1, ynone, Px, 0xd9, 0xf5 },
+ { AFPTAN, ynone, Px, 0xd9, 0xf2 },
+ { AFRNDINT, ynone, Px, 0xd9, 0xfc },
+ { AFSCALE, ynone, Px, 0xd9, 0xfd },
+ { AFSIN, ynone, Px, 0xd9, 0xfe },
+ { AFSINCOS, ynone, Px, 0xd9, 0xfb },
+ { AFSQRT, ynone, Px, 0xd9, 0xfa },
+ { AFTST, ynone, Px, 0xd9, 0xe4 },
+ { AFXAM, ynone, Px, 0xd9, 0xe5 },
+ { AFXTRACT, ynone, Px, 0xd9, 0xf4 },
+ { AFYL2X, ynone, Px, 0xd9, 0xf1 },
+ { AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
+ { AEND },
+ { ADYNT_ },
+ { AINIT_ },
+ { ASIGNAME },
+ { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
+ { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+
+ { ACPUID, ynone, Pm, 0xa2 },
+ { ARDTSC, ynone, Pm, 0x31 },
+
+ { AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
+ { AXADDL, yrl_ml, Pm, 0xc1 },
+ { AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
+
+ { ACMOVLCC, yml_rl, Pm, 0x43 },
+ { ACMOVLCS, yml_rl, Pm, 0x42 },
+ { ACMOVLEQ, yml_rl, Pm, 0x44 },
+ { ACMOVLGE, yml_rl, Pm, 0x4d },
+ { ACMOVLGT, yml_rl, Pm, 0x4f },
+ { ACMOVLHI, yml_rl, Pm, 0x47 },
+ { ACMOVLLE, yml_rl, Pm, 0x4e },
+ { ACMOVLLS, yml_rl, Pm, 0x46 },
+ { ACMOVLLT, yml_rl, Pm, 0x4c },
+ { ACMOVLMI, yml_rl, Pm, 0x48 },
+ { ACMOVLNE, yml_rl, Pm, 0x45 },
+ { ACMOVLOC, yml_rl, Pm, 0x41 },
+ { ACMOVLOS, yml_rl, Pm, 0x40 },
+ { ACMOVLPC, yml_rl, Pm, 0x4b },
+ { ACMOVLPL, yml_rl, Pm, 0x49 },
+ { ACMOVLPS, yml_rl, Pm, 0x4a },
+ { ACMOVWCC, yml_rl, Pq, 0x43 },
+ { ACMOVWCS, yml_rl, Pq, 0x42 },
+ { ACMOVWEQ, yml_rl, Pq, 0x44 },
+ { ACMOVWGE, yml_rl, Pq, 0x4d },
+ { ACMOVWGT, yml_rl, Pq, 0x4f },
+ { ACMOVWHI, yml_rl, Pq, 0x47 },
+ { ACMOVWLE, yml_rl, Pq, 0x4e },
+ { ACMOVWLS, yml_rl, Pq, 0x46 },
+ { ACMOVWLT, yml_rl, Pq, 0x4c },
+ { ACMOVWMI, yml_rl, Pq, 0x48 },
+ { ACMOVWNE, yml_rl, Pq, 0x45 },
+ { ACMOVWOC, yml_rl, Pq, 0x41 },
+ { ACMOVWOS, yml_rl, Pq, 0x40 },
+ { ACMOVWPC, yml_rl, Pq, 0x4b },
+ { ACMOVWPL, yml_rl, Pq, 0x49 },
+ { ACMOVWPS, yml_rl, Pq, 0x4a },
+
+ { AFCMOVCC, yfcmv, Px, 0xdb,(00) },
+ { AFCMOVCS, yfcmv, Px, 0xda,(00) },
+ { AFCMOVEQ, yfcmv, Px, 0xda,(01) },
+ { AFCMOVHI, yfcmv, Px, 0xdb,(02) },
+ { AFCMOVLS, yfcmv, Px, 0xda,(02) },
+ { AFCMOVNE, yfcmv, Px, 0xdb,(01) },
+ { AFCMOVNU, yfcmv, Px, 0xdb,(03) },
+ { AFCMOVUN, yfcmv, Px, 0xda,(03) },
+
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+
+ { AEMMS, ynone, Pm, 0x77 },
+
+ { APREFETCHT0, yprefetch, Pm, 0x18,(01) },
+ { APREFETCHT1, yprefetch, Pm, 0x18,(02) },
+ { APREFETCHT2, yprefetch, Pm, 0x18,(03) },
+ { APREFETCHNTA, yprefetch, Pm, 0x18,(00) },
+
+ { ABSWAPL, ybswap, Pm, 0xc8 },
+
+ { AUNDEF, ynone, Px, 0x0f, 0x0b },
+
+ { AADDPD, yxm, Pq, 0x58 },
+ { AADDPS, yxm, Pm, 0x58 },
+ { AADDSD, yxm, Pf2, 0x58 },
+ { AADDSS, yxm, Pf3, 0x58 },
+ { AANDNPD, yxm, Pq, 0x55 },
+ { AANDNPS, yxm, Pm, 0x55 },
+ { AANDPD, yxm, Pq, 0x54 },
+ { AANDPS, yxm, Pq, 0x54 },
+ { ACMPPD, yxcmpi, Px, Pe,0xc2 },
+ { ACMPPS, yxcmpi, Pm, 0xc2,0 },
+ { ACMPSD, yxcmpi, Px, Pf2,0xc2 },
+ { ACMPSS, yxcmpi, Px, Pf3,0xc2 },
+ { ACOMISD, yxcmp, Pe, 0x2f },
+ { ACOMISS, yxcmp, Pm, 0x2f },
+ { ACVTPL2PD, yxcvm2, Px, Pf3,0xe6,Pe,0x2a },
+ { ACVTPL2PS, yxcvm2, Pm, 0x5b,0,0x2a,0, },
+ { ACVTPD2PL, yxcvm1, Px, Pf2,0xe6,Pe,0x2d },
+ { ACVTPD2PS, yxm, Pe, 0x5a },
+ { ACVTPS2PL, yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+ { ACVTPS2PD, yxm, Pm, 0x5a },
+ { ACVTSD2SL, yxcvfl, Pf2, 0x2d },
+ { ACVTSD2SS, yxm, Pf2, 0x5a },
+ { ACVTSL2SD, yxcvlf, Pf2, 0x2a },
+ { ACVTSL2SS, yxcvlf, Pf3, 0x2a },
+ { ACVTSS2SD, yxm, Pf3, 0x5a },
+ { ACVTSS2SL, yxcvfl, Pf3, 0x2d },
+ { ACVTTPD2PL, yxcvm1, Px, Pe,0xe6,Pe,0x2c },
+ { ACVTTPS2PL, yxcvm1, Px, Pf3,0x5b,Pm,0x2c },
+ { ACVTTSD2SL, yxcvfl, Pf2, 0x2c },
+ { ACVTTSS2SL, yxcvfl, Pf3, 0x2c },
+ { ADIVPD, yxm, Pe, 0x5e },
+ { ADIVPS, yxm, Pm, 0x5e },
+ { ADIVSD, yxm, Pf2, 0x5e },
+ { ADIVSS, yxm, Pf3, 0x5e },
+ { AMASKMOVOU, yxr, Pe, 0xf7 },
+ { AMAXPD, yxm, Pe, 0x5f },
+ { AMAXPS, yxm, Pm, 0x5f },
+ { AMAXSD, yxm, Pf2, 0x5f },
+ { AMAXSS, yxm, Pf3, 0x5f },
+ { AMINPD, yxm, Pe, 0x5d },
+ { AMINPS, yxm, Pm, 0x5d },
+ { AMINSD, yxm, Pf2, 0x5d },
+ { AMINSS, yxm, Pf3, 0x5d },
+ { AMOVAPD, yxmov, Pe, 0x28,0x29 },
+ { AMOVAPS, yxmov, Pm, 0x28,0x29 },
+ { AMOVO, yxmov, Pe, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
+ { AMOVHLPS, yxr, Pm, 0x12 },
+ { AMOVHPD, yxmov, Pe, 0x16,0x17 },
+ { AMOVHPS, yxmov, Pm, 0x16,0x17 },
+ { AMOVLHPS, yxr, Pm, 0x16 },
+ { AMOVLPD, yxmov, Pe, 0x12,0x13 },
+ { AMOVLPS, yxmov, Pm, 0x12,0x13 },
+ { AMOVMSKPD, yxrrl, Pq, 0x50 },
+ { AMOVMSKPS, yxrrl, Pm, 0x50 },
+ { AMOVNTO, yxr_ml, Pe, 0xe7 },
+ { AMOVNTPD, yxr_ml, Pe, 0x2b },
+ { AMOVNTPS, yxr_ml, Pm, 0x2b },
+ { AMOVSD, yxmov, Pf2, 0x10,0x11 },
+ { AMOVSS, yxmov, Pf3, 0x10,0x11 },
+ { AMOVUPD, yxmov, Pe, 0x10,0x11 },
+ { AMOVUPS, yxmov, Pm, 0x10,0x11 },
+ { AMULPD, yxm, Pe, 0x59 },
+ { AMULPS, yxm, Ym, 0x59 },
+ { AMULSD, yxm, Pf2, 0x59 },
+ { AMULSS, yxm, Pf3, 0x59 },
+ { AORPD, yxm, Pq, 0x56 },
+ { AORPS, yxm, Pm, 0x56 },
+ { APADDQ, yxm, Pe, 0xd4 },
+ { APAND, yxm, Pe, 0xdb },
+ { APCMPEQB, yxmq, Pe ,0x74 },
+ { APMAXSW, yxm, Pe, 0xee },
+ { APMAXUB, yxm, Pe, 0xde },
+ { APMINSW, yxm, Pe, 0xea },
+ { APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
+ { APSADBW, yxm, Pq, 0xf6 },
+ { APSUBB, yxm, Pe, 0xf8 },
+ { APSUBL, yxm, Pe, 0xfa },
+ { APSUBQ, yxm, Pe, 0xfb },
+ { APSUBSB, yxm, Pe, 0xe8 },
+ { APSUBSW, yxm, Pe, 0xe9 },
+ { APSUBUSB, yxm, Pe, 0xd8 },
+ { APSUBUSW, yxm, Pe, 0xd9 },
+ { APSUBW, yxm, Pe, 0xf9 },
+ { APUNPCKHQDQ, yxm, Pe, 0x6d },
+ { APUNPCKLQDQ, yxm, Pe, 0x6c },
+ { APXOR, yxm, Pe, 0xef },
+ { ARCPPS, yxm, Pm, 0x53 },
+ { ARCPSS, yxm, Pf3, 0x53 },
+ { ARSQRTPS, yxm, Pm, 0x52 },
+ { ARSQRTSS, yxm, Pf3, 0x52 },
+ { ASQRTPD, yxm, Pe, 0x51 },
+ { ASQRTPS, yxm, Pm, 0x51 },
+ { ASQRTSD, yxm, Pf2, 0x51 },
+ { ASQRTSS, yxm, Pf3, 0x51 },
+ { ASUBPD, yxm, Pe, 0x5c },
+ { ASUBPS, yxm, Pm, 0x5c },
+ { ASUBSD, yxm, Pf2, 0x5c },
+ { ASUBSS, yxm, Pf3, 0x5c },
+ { AUCOMISD, yxcmp, Pe, 0x2e },
+ { AUCOMISS, yxcmp, Pm, 0x2e },
+ { AUNPCKHPD, yxm, Pe, 0x15 },
+ { AUNPCKHPS, yxm, Pm, 0x15 },
+ { AUNPCKLPD, yxm, Pe, 0x14 },
+ { AUNPCKLPS, yxm, Pm, 0x14 },
+ { AXORPD, yxm, Pe, 0x57 },
+ { AXORPS, yxm, Pm, 0x57 },
+
+ { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
+ { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
+
+ { AUSEFIELD, ynop, Px, 0,0 },
+ { ATYPE },
+ { AFUNCDATA, yfuncdata, Px, 0,0 },
+ { APCDATA, ypcdata, Px, 0,0 },
+ { ACHECKNIL },
+ { AVARDEF },
+ { AVARKILL },
+ { ADUFFCOPY, yduff, Px, 0xe8 },
+ { ADUFFZERO, yduff, Px, 0xe8 },
+
+ 0
+};
+
+static int32 vaddr(Link*, Addr*, Reloc*);
+
+// single-instruction no-ops of various lengths.
+// constructed by hand and disassembled with gdb to verify.
+// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
+static uchar nop[][16] = {
+ {0x90},
+ {0x66, 0x90},
+ {0x0F, 0x1F, 0x00},
+ {0x0F, 0x1F, 0x40, 0x00},
+ {0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
+ {0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
+ {0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+ // Native Client rejects the repeated 0x66 prefix.
+ // {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+
+static void
+fillnop(uchar *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = n;
+ if(m > nelem(nop))
+ m = nelem(nop);
+ memmove(p, nop[m-1], m);
+ p += m;
+ n -= m;
+ }
+}
+
+static int32
+naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
+{
+ symgrow(ctxt, s, c+pad);
+ fillnop(s->p+c, pad);
+ return c+pad;
+}
+
+static void instinit(void);
+
+void
+span8(Link *ctxt, LSym *s)
+{
+ Prog *p, *q;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ ctxt->cursym = s;
+
+ if(s->text == nil || s->text->link == nil)
+ return;
+
+ if(ycover[0] == 0)
+ instinit();
+
+ for(p = s->text; p != nil; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == nil)
+ p->pcond = p;
+ if((q = p->pcond) != nil)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ for(p = s->text; p != nil; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != nil && (q->back & 2))
+ p->back |= 1; // backward jump
+
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
+ }
+ }
+
+ n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != nil; p = p->link) {
+ if(ctxt->headtype == Hnacl && p->isize > 0) {
+ static LSym *deferreturn;
+
+ if(deferreturn == nil)
+ deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+
+ // pad everything to avoid crossing 32-byte boundary
+ if((c>>5) != ((c+p->isize-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+ // pad call deferreturn to start at 32-byte boundary
+ // so that subtracting 5 in jmpdefer will jump back
+ // to that boundary and rerun the call.
+ if(p->as == ACALL && p->to.sym == deferreturn)
+ c = naclpad(ctxt, s, c, -c&31);
+ // pad call to end at 32-byte boundary
+ if(p->as == ACALL)
+ c = naclpad(ctxt, s, c, -(c+p->isize)&31);
+
+ // the linker treats REP and STOSQ as different instructions
+ // but in fact the REP is a prefix on the STOSQ.
+ // make sure REP has room for 2 more bytes, so that
+ // padding will not be inserted before the next instruction.
+ if(p->as == AREP && (c>>5) != ((c+3-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+
+ // same for LOCK.
+ // various instructions follow; the longest is 4 bytes.
+ // give ourselves 8 bytes so as to avoid surprises.
+ if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
+ c = naclpad(ctxt, s, c, -c&31);
+ }
+
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != nil; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ if(q->as == AJCXZW)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp = v>>24;
+ }
+ }
+ p->comefrom = nil;
+
+ p->pc = c;
+ asmins(ctxt, p);
+ m = ctxt->andptr-ctxt->and;
+ if(p->isize != m) {
+ p->isize = m;
+ loop++;
+ }
+ symgrow(ctxt, s, p->pc+m);
+ memmove(s->p+p->pc, ctxt->and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ ctxt->diag("span must be looping");
+ sysfatal("bad code");
+ }
+ } while(loop);
+
+ if(ctxt->headtype == Hnacl)
+ c = naclpad(ctxt, s, c, -c&31);
+ c += -c&(FuncAlign-1);
+ s->size = c;
+
+ if(0 /* debug['a'] > 1 */) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
+ }
+ }
+}
+
+static void
+instinit(void)
+{
+ int i;
+
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as)
+ sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_X0 && i <= D_X0+7)
+ reg[i] = (i-D_X0) & 7;
+ }
+}
+
+static int
+prefixof(Link *ctxt, Addr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
+ case D_INDIR+D_TLS:
+ // NOTE: Systems listed here should be only systems that
+ // support direct TLS references like 8(TLS) implemented as
+ // direct references from FS or GS. Systems that require
+ // the initial-exec model, where you load the TLS base into
+ // a register and then index from that register, do not reach
+ // this code and should not be listed.
+ switch(ctxt->headtype) {
+ default:
+ sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+ case Hdarwin:
+ case Hdragonfly:
+ case Hfreebsd:
+ case Hnetbsd:
+ case Hopenbsd:
+ return 0x65; // GS
+ }
+ }
+ return 0;
+}
+
+static int
+oclass(Addr *a)
+{
+ int32 v;
+
+ if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
+ if(a->index != D_NONE && a->scale == 0) {
+ if(a->type == D_ADDR) {
+ switch(a->index) {
+ case D_EXTERN:
+ case D_STATIC:
+ return Yi32;
+ case D_AUTO:
+ case D_PARAM:
+ return Yiauto;
+ }
+ return Yxxx;
+ }
+ //if(a->type == D_INDIR+D_ADDR)
+ // print("*Ycol\n");
+ return Ycol;
+ }
+ return Ym;
+ }
+ switch(a->type)
+ {
+ case D_AL:
+ return Yal;
+
+ case D_AX:
+ return Yax;
+
+ case D_CL:
+ case D_DL:
+ case D_BL:
+ case D_AH:
+ case D_CH:
+ case D_DH:
+ case D_BH:
+ return Yrb;
+
+ case D_CX:
+ return Ycx;
+
+ case D_DX:
+ case D_BX:
+ return Yrx;
+
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ return Yrl;
+
+ case D_F0+0:
+ return Yf0;
+
+ case D_F0+1:
+ case D_F0+2:
+ case D_F0+3:
+ case D_F0+4:
+ case D_F0+5:
+ case D_F0+6:
+ case D_F0+7:
+ return Yrf;
+
+ case D_X0+0:
+ case D_X0+1:
+ case D_X0+2:
+ case D_X0+3:
+ case D_X0+4:
+ case D_X0+5:
+ case D_X0+6:
+ case D_X0+7:
+ return Yxr;
+
+ case D_NONE:
+ return Ynone;
+
+ case D_CS: return Ycs;
+ case D_SS: return Yss;
+ case D_DS: return Yds;
+ case D_ES: return Yes;
+ case D_FS: return Yfs;
+ case D_GS: return Ygs;
+ case D_TLS: return Ytls;
+
+ case D_GDTR: return Ygdtr;
+ case D_IDTR: return Yidtr;
+ case D_LDTR: return Yldtr;
+ case D_MSW: return Ymsw;
+ case D_TASK: return Ytask;
+
+ case D_CR+0: return Ycr0;
+ case D_CR+1: return Ycr1;
+ case D_CR+2: return Ycr2;
+ case D_CR+3: return Ycr3;
+ case D_CR+4: return Ycr4;
+ case D_CR+5: return Ycr5;
+ case D_CR+6: return Ycr6;
+ case D_CR+7: return Ycr7;
+
+ case D_DR+0: return Ydr0;
+ case D_DR+1: return Ydr1;
+ case D_DR+2: return Ydr2;
+ case D_DR+3: return Ydr3;
+ case D_DR+4: return Ydr4;
+ case D_DR+5: return Ydr5;
+ case D_DR+6: return Ydr6;
+ case D_DR+7: return Ydr7;
+
+ case D_TR+0: return Ytr0;
+ case D_TR+1: return Ytr1;
+ case D_TR+2: return Ytr2;
+ case D_TR+3: return Ytr3;
+ case D_TR+4: return Ytr4;
+ case D_TR+5: return Ytr5;
+ case D_TR+6: return Ytr6;
+ case D_TR+7: return Ytr7;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ return Ym;
+
+ case D_CONST:
+ case D_CONST2:
+ case D_ADDR:
+ if(a->sym == nil) {
+ v = a->offset;
+ if(v == 0)
+ return Yi0;
+ if(v == 1)
+ return Yi1;
+ if(v >= -128 && v <= 127)
+ return Yi8;
+ }
+ return Yi32;
+
+ case D_BRANCH:
+ return Ybr;
+ }
+ return Yxxx;
+}
+
+static void
+asmidx(Link *ctxt, int scale, int index, int base)
+{
+ int i;
+
+ switch(index) {
+ default:
+ goto bad;
+
+ case D_NONE:
+ i = 4 << 3;
+ goto bas;
+
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i = reg[index] << 3;
+ break;
+ }
+ switch(scale) {
+ default:
+ goto bad;
+ case 1:
+ break;
+ case 2:
+ i |= (1<<6);
+ break;
+ case 4:
+ i |= (2<<6);
+ break;
+ case 8:
+ i |= (3<<6);
+ break;
+ }
+bas:
+ switch(base) {
+ default:
+ goto bad;
+ case D_NONE: /* must be mod=00 */
+ i |= 5;
+ break;
+ case D_AX:
+ case D_CX:
+ case D_DX:
+ case D_BX:
+ case D_SP:
+ case D_BP:
+ case D_SI:
+ case D_DI:
+ i |= reg[base];
+ break;
+ }
+ *ctxt->andptr++ = i;
+ return;
+bad:
+ ctxt->diag("asmidx: bad address %d,%d,%d", scale, index, base);
+ *ctxt->andptr++ = 0;
+ return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+ ctxt->andptr[0] = v;
+ ctxt->andptr[1] = v>>8;
+ ctxt->andptr[2] = v>>16;
+ ctxt->andptr[3] = v>>24;
+ ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(ctxt, a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ ctxt->diag("bad reloc");
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ put4(ctxt, v);
+}
+
+static int32
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+ int t;
+ int32 v;
+ LSym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
+
+ t = a->type;
+ v = a->offset;
+ if(t == D_ADDR)
+ t = a->index;
+ switch(t) {
+ case D_STATIC:
+ case D_EXTERN:
+ s = a->sym;
+ if(s != nil) {
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("bad code");
+ }
+ r->type = R_ADDR;
+ r->siz = 4;
+ r->off = -1;
+ r->sym = s;
+ r->add = v;
+ v = 0;
+ }
+ break;
+
+ case D_INDIR+D_TLS:
+ if(r == nil) {
+ ctxt->diag("need reloc for %D", a);
+ sysfatal("bad code");
+ }
+ r->type = R_TLS_LE;
+ r->siz = 4;
+ r->off = -1; // caller must fill in
+ r->add = v;
+ v = 0;
+ break;
+ }
+ return v;
+}
+
+static void
+asmand(Link *ctxt, Addr *a, int r)
+{
+ int32 v;
+ int t, scale;
+ Reloc rel;
+
+ v = a->offset;
+ t = a->type;
+ rel.siz = 0;
+ if(a->index != D_NONE && a->index != D_TLS) {
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
+ if(v)
+ goto bad;
+ *ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(ctxt, a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
+ t -= D_INDIR;
+ if(t == D_TLS)
+ v = vaddr(ctxt, a, &rel);
+
+ if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
+ *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ if(t == D_SP) {
+ if(v == 0 && rel.siz == 0) {
+ *ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ *ctxt->andptr++ = v;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(ctxt, scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(a->index == D_TLS) {
+ memset(&rel, 0, sizeof rel);
+ rel.type = R_TLS_IE;
+ rel.siz = 4;
+ rel.sym = nil;
+ rel.add = v;
+ v = 0;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ ctxt->andptr[1] = v;
+ ctxt->andptr += 2;
+ return;
+ }
+ *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
+ }
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ ctxt->diag("bad rel");
+ goto bad;
+ }
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+ }
+
+ put4(ctxt, v);
+ return;
+
+bad:
+ ctxt->diag("asmand: bad address %D", a);
+ return;
+}
+
+#define E 0xff
+static uchar ymovtab[] =
+{
+/* push */
+ APUSHL, Ycs, Ynone, 0, 0x0e,E,0,0,
+ APUSHL, Yss, Ynone, 0, 0x16,E,0,0,
+ APUSHL, Yds, Ynone, 0, 0x1e,E,0,0,
+ APUSHL, Yes, Ynone, 0, 0x06,E,0,0,
+ APUSHL, Yfs, Ynone, 0, 0x0f,0xa0,E,0,
+ APUSHL, Ygs, Ynone, 0, 0x0f,0xa8,E,0,
+
+ APUSHW, Ycs, Ynone, 0, Pe,0x0e,E,0,
+ APUSHW, Yss, Ynone, 0, Pe,0x16,E,0,
+ APUSHW, Yds, Ynone, 0, Pe,0x1e,E,0,
+ APUSHW, Yes, Ynone, 0, Pe,0x06,E,0,
+ APUSHW, Yfs, Ynone, 0, Pe,0x0f,0xa0,E,
+ APUSHW, Ygs, Ynone, 0, Pe,0x0f,0xa8,E,
+
+/* pop */
+ APOPL, Ynone, Yds, 0, 0x1f,E,0,0,
+ APOPL, Ynone, Yes, 0, 0x07,E,0,0,
+ APOPL, Ynone, Yss, 0, 0x17,E,0,0,
+ APOPL, Ynone, Yfs, 0, 0x0f,0xa1,E,0,
+ APOPL, Ynone, Ygs, 0, 0x0f,0xa9,E,0,
+
+ APOPW, Ynone, Yds, 0, Pe,0x1f,E,0,
+ APOPW, Ynone, Yes, 0, Pe,0x07,E,0,
+ APOPW, Ynone, Yss, 0, Pe,0x17,E,0,
+ APOPW, Ynone, Yfs, 0, Pe,0x0f,0xa1,E,
+ APOPW, Ynone, Ygs, 0, Pe,0x0f,0xa9,E,
+
+/* mov seg */
+ AMOVW, Yes, Yml, 1, 0x8c,0,0,0,
+ AMOVW, Ycs, Yml, 1, 0x8c,1,0,0,
+ AMOVW, Yss, Yml, 1, 0x8c,2,0,0,
+ AMOVW, Yds, Yml, 1, 0x8c,3,0,0,
+ AMOVW, Yfs, Yml, 1, 0x8c,4,0,0,
+ AMOVW, Ygs, Yml, 1, 0x8c,5,0,0,
+
+ AMOVW, Yml, Yes, 2, 0x8e,0,0,0,
+ AMOVW, Yml, Ycs, 2, 0x8e,1,0,0,
+ AMOVW, Yml, Yss, 2, 0x8e,2,0,0,
+ AMOVW, Yml, Yds, 2, 0x8e,3,0,0,
+ AMOVW, Yml, Yfs, 2, 0x8e,4,0,0,
+ AMOVW, Yml, Ygs, 2, 0x8e,5,0,0,
+
+/* mov cr */
+ AMOVL, Ycr0, Yml, 3, 0x0f,0x20,0,0,
+ AMOVL, Ycr2, Yml, 3, 0x0f,0x20,2,0,
+ AMOVL, Ycr3, Yml, 3, 0x0f,0x20,3,0,
+ AMOVL, Ycr4, Yml, 3, 0x0f,0x20,4,0,
+
+ AMOVL, Yml, Ycr0, 4, 0x0f,0x22,0,0,
+ AMOVL, Yml, Ycr2, 4, 0x0f,0x22,2,0,
+ AMOVL, Yml, Ycr3, 4, 0x0f,0x22,3,0,
+ AMOVL, Yml, Ycr4, 4, 0x0f,0x22,4,0,
+
+/* mov dr */
+ AMOVL, Ydr0, Yml, 3, 0x0f,0x21,0,0,
+ AMOVL, Ydr6, Yml, 3, 0x0f,0x21,6,0,
+ AMOVL, Ydr7, Yml, 3, 0x0f,0x21,7,0,
+
+ AMOVL, Yml, Ydr0, 4, 0x0f,0x23,0,0,
+ AMOVL, Yml, Ydr6, 4, 0x0f,0x23,6,0,
+ AMOVL, Yml, Ydr7, 4, 0x0f,0x23,7,0,
+
+/* mov tr */
+ AMOVL, Ytr6, Yml, 3, 0x0f,0x24,6,0,
+ AMOVL, Ytr7, Yml, 3, 0x0f,0x24,7,0,
+
+ AMOVL, Yml, Ytr6, 4, 0x0f,0x26,6,E,
+ AMOVL, Yml, Ytr7, 4, 0x0f,0x26,7,E,
+
+/* lgdt, sgdt, lidt, sidt */
+ AMOVL, Ym, Ygdtr, 4, 0x0f,0x01,2,0,
+ AMOVL, Ygdtr, Ym, 3, 0x0f,0x01,0,0,
+ AMOVL, Ym, Yidtr, 4, 0x0f,0x01,3,0,
+ AMOVL, Yidtr, Ym, 3, 0x0f,0x01,1,0,
+
+/* lldt, sldt */
+ AMOVW, Yml, Yldtr, 4, 0x0f,0x00,2,0,
+ AMOVW, Yldtr, Yml, 3, 0x0f,0x00,0,0,
+
+/* lmsw, smsw */
+ AMOVW, Yml, Ymsw, 4, 0x0f,0x01,6,0,
+ AMOVW, Ymsw, Yml, 3, 0x0f,0x01,4,0,
+
+/* ltr, str */
+ AMOVW, Yml, Ytask, 4, 0x0f,0x00,3,0,
+ AMOVW, Ytask, Yml, 3, 0x0f,0x00,1,0,
+
+/* load full pointer */
+ AMOVL, Yml, Ycol, 5, 0,0,0,0,
+ AMOVW, Yml, Ycol, 5, Pe,0,0,0,
+
+/* double shift */
+ ASHLL, Ycol, Yml, 6, 0xa4,0xa5,0,0,
+ ASHRL, Ycol, Yml, 6, 0xac,0xad,0,0,
+
+/* extra imul */
+ AIMULW, Yml, Yrl, 7, Pq,0xaf,0,0,
+ AIMULL, Yml, Yrl, 7, Pm,0xaf,0,0,
+
+/* load TLS base pointer */
+ AMOVL, Ytls, Yrl, 8, 0,0,0,0,
+
+ 0
+};
+
+// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
+// which is not referenced in a->type.
+// If a is empty, it returns BX to account for MULB-like instructions
+// that might use DX and AX.
+static int
+byteswapreg(Link *ctxt, Addr *a)
+{
+ int cana, canb, canc, cand;
+
+ cana = canb = canc = cand = 1;
+
+ switch(a->type) {
+ case D_NONE:
+ cana = cand = 0;
+ break;
+ case D_AX:
+ case D_AL:
+ case D_AH:
+ case D_INDIR+D_AX:
+ cana = 0;
+ break;
+ case D_BX:
+ case D_BL:
+ case D_BH:
+ case D_INDIR+D_BX:
+ canb = 0;
+ break;
+ case D_CX:
+ case D_CL:
+ case D_CH:
+ case D_INDIR+D_CX:
+ canc = 0;
+ break;
+ case D_DX:
+ case D_DL:
+ case D_DH:
+ case D_INDIR+D_DX:
+ cand = 0;
+ break;
+ }
+ switch(a->index) {
+ case D_AX:
+ cana = 0;
+ break;
+ case D_BX:
+ canb = 0;
+ break;
+ case D_CX:
+ canc = 0;
+ break;
+ case D_DX:
+ cand = 0;
+ break;
+ }
+ if(cana)
+ return D_AX;
+ if(canb)
+ return D_BX;
+ if(canc)
+ return D_CX;
+ if(cand)
+ return D_DX;
+
+ ctxt->diag("impossible byte register");
+ sysfatal("bad code");
+ return 0;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+ if(0 /* debug['Q'] */)
+ print("\n%P s/%R/%R/\n", p, from, to);
+
+ if(p->from.type == from) {
+ p->from.type = to;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to;
+ p->tt = 0;
+ }
+
+ if(p->from.index == from) {
+ p->from.index = to;
+ p->ft = 0;
+ }
+ if(p->to.index == from) {
+ p->to.index = to;
+ p->tt = 0;
+ }
+
+ from += D_INDIR;
+ if(p->from.type == from) {
+ p->from.type = to+D_INDIR;
+ p->ft = 0;
+ }
+ if(p->to.type == from) {
+ p->to.type = to+D_INDIR;
+ p->tt = 0;
+ }
+
+ if(0 /* debug['Q'] */)
+ print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+ switch(op){
+ case Pm:
+ case Pe:
+ case Pf2:
+ case Pf3:
+ if(osize != 1){
+ if(op != Pm)
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = Pm;
+ op = o->op[++z];
+ break;
+ }
+ default:
+ if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+ *ctxt->andptr++ = Pm;
+ break;
+ }
+ *ctxt->andptr++ = op;
+ return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+ Optab *o;
+ Prog *q, pp;
+ uchar *t;
+ int z, op, ft, tt, breg;
+ int32 v, pre;
+ Reloc rel, *r;
+ Addr *a;
+
+ ctxt->curp = p; // TODO
+
+ pre = prefixof(ctxt, &p->from);
+ if(pre)
+ *ctxt->andptr++ = pre;
+ pre = prefixof(ctxt, &p->to);
+ if(pre)
+ *ctxt->andptr++ = pre;
+
+ if(p->ft == 0)
+ p->ft = oclass(&p->from);
+ if(p->tt == 0)
+ p->tt = oclass(&p->to);
+
+ ft = p->ft * Ymax;
+ tt = p->tt * Ymax;
+ o = &optab[p->as];
+ t = o->ytab;
+ if(t == 0) {
+ ctxt->diag("asmins: noproto %P", p);
+ return;
+ }
+ for(z=0; *t; z+=t[3],t+=4)
+ if(ycover[ft+t[0]])
+ if(ycover[tt+t[1]])
+ goto found;
+ goto domov;
+
+found:
+ switch(o->prefix) {
+ case Pq: /* 16 bit escape and opcode escape */
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pf2: /* xmm opcode escape */
+ case Pf3:
+ *ctxt->andptr++ = o->prefix;
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pm: /* opcode escape */
+ *ctxt->andptr++ = Pm;
+ break;
+
+ case Pe: /* 16 bit escape */
+ *ctxt->andptr++ = Pe;
+ break;
+
+ case Pb: /* botch */
+ break;
+ }
+
+ op = o->op[z];
+ switch(t[2]) {
+ default:
+ ctxt->diag("asmins: unknown z %d %P", t[2], p);
+ return;
+
+ case Zpseudo:
+ break;
+
+ case Zlit:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ break;
+
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm2_r:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case Zm_r_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zibm_r:
+ while ((op = o->op[z++]) != 0)
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ *ctxt->andptr++ = p->to.offset;
+ break;
+
+ case Zaut_r:
+ *ctxt->andptr++ = 0x8d; /* leal */
+ if(p->from.type != D_ADDR)
+ ctxt->diag("asmins: Zaut sb type ADDR");
+ p->from.type = p->from.index;
+ p->from.index = D_NONE;
+ p->ft = 0;
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ p->from.index = p->from.type;
+ p->from.type = D_ADDR;
+ p->ft = 0;
+ break;
+
+ case Zm_o:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ break;
+
+ case Zr_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ break;
+
+ case Zr_m_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ break;
+
+ case Zr_m_i_xm:
+ mediaop(ctxt, o, op, t[3], z);
+ asmand(ctxt, &p->to, reg[p->from.type]);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+
+ case Zo_m:
+ case_Zo_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ break;
+
+ case Zm_ibo:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+ break;
+
+ case Zibo_m:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_ib:
+ case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ break;
+
+ case Zib_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Zil_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Zib_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ *ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+ break;
+
+ case Z_il:
+ case Zil_:
+ if(t[2] == Zil_)
+ a = &p->from;
+ else
+ a = &p->to;
+ *ctxt->andptr++ = op;
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zm_ilo:
+ case Zilo_m:
+ *ctxt->andptr++ = op;
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmand(ctxt, &p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmand(ctxt, &p->from, o->op[z+1]);
+ }
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, a, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, a);
+ break;
+
+ case Zil_rr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ if(o->prefix == Pe) {
+ v = vaddr(ctxt, &p->from, nil);
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ }
+ else
+ relput4(ctxt, p, &p->from);
+ break;
+
+ case Z_rp:
+ *ctxt->andptr++ = op + reg[p->to.type];
+ break;
+
+ case Zrp_:
+ *ctxt->andptr++ = op + reg[p->from.type];
+ break;
+
+ case Zclr:
+ *ctxt->andptr++ = op;
+ asmand(ctxt, &p->to, reg[p->to.type]);
+ break;
+
+ case Zcall:
+ if(p->to.sym == nil) {
+ ctxt->diag("call without target");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = op;
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = R_CALL;
+ r->siz = 4;
+ r->sym = p->to.sym;
+ r->add = p->to.offset;
+ put4(ctxt, 0);
+ break;
+
+ case Zbr:
+ case Zjmp:
+ case Zloop:
+ if(p->to.sym != nil) {
+ if(t[2] != Zjmp) {
+ ctxt->diag("branch to ATEXT");
+ sysfatal("bad code");
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->sym = p->to.sym;
+ r->type = R_PCREL;
+ r->siz = 4;
+ put4(ctxt, 0);
+ break;
+ }
+
+ // Assumes q is in this function.
+ // Fill in backward jump now.
+ q = p->pcond;
+ if(q == nil) {
+ ctxt->diag("jmp/branch/loop without target");
+ sysfatal("bad code");
+ }
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
+ if(p->as == AJCXZW)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = v;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *ctxt->andptr++ = 0x0f;
+ v--;
+ }
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = v;
+ *ctxt->andptr++ = v>>8;
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ if(p->as == AJCXZW)
+ *ctxt->andptr++ = 0x67;
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ ctxt->diag("loop too far: %P", p);
+ } else {
+ if(t[2] == Zbr)
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = o->op[z+1];
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ *ctxt->andptr++ = 0;
+ }
+ break;
+
+ case Zcallcon:
+ case Zjmpcon:
+ if(t[2] == Zcallcon)
+ *ctxt->andptr++ = op;
+ else
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = R_PCREL;
+ r->siz = 4;
+ r->add = p->to.offset;
+ put4(ctxt, 0);
+ break;
+
+ case Zcallind:
+ *ctxt->andptr++ = op;
+ *ctxt->andptr++ = o->op[z+1];
+ r = addrel(ctxt->cursym);
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ r->type = R_ADDR;
+ r->siz = 4;
+ r->add = p->to.offset;
+ r->sym = p->to.sym;
+ put4(ctxt, 0);
+ break;
+
+ case Zcallindreg:
+ r = addrel(ctxt->cursym);
+ r->off = p->pc;
+ r->type = R_CALLIND;
+ r->siz = 0;
+ goto case_Zo_m;
+
+ case Zbyte:
+ v = vaddr(ctxt, &p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(ctxt->cursym);
+ *r = rel;
+ r->off = p->pc + ctxt->andptr - ctxt->and;
+ }
+ *ctxt->andptr++ = v;
+ if(op > 1) {
+ *ctxt->andptr++ = v>>8;
+ if(op > 2) {
+ *ctxt->andptr++ = v>>16;
+ *ctxt->andptr++ = v>>24;
+ }
+ }
+ break;
+
+ case Zmov:
+ goto domov;
+ }
+ return;
+
+domov:
+ for(t=ymovtab; *t; t+=8)
+ if(p->as == t[0])
+ if(ycover[ft+t[1]])
+ if(ycover[tt+t[2]])
+ goto mfound;
+bad:
+ /*
+ * here, the assembly has failed.
+ * if its a byte instruction that has
+ * unaddressable registers, try to
+ * exchange registers and reissue the
+ * instruction with the operands renamed.
+ */
+ pp = *p;
+ z = p->from.type;
+ if(z >= D_BP && z <= D_DI) {
+ if((breg = byteswapreg(ctxt, &p->to)) != D_AX) {
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(ctxt, &p->from, reg[breg]);
+ subreg(&pp, z, breg);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg lhs,bx */
+ asmand(ctxt, &p->from, reg[breg]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
+ }
+ return;
+ }
+ z = p->to.type;
+ if(z >= D_BP && z <= D_DI) {
+ if((breg = byteswapreg(ctxt, &p->from)) != D_AX) {
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(ctxt, &p->to, reg[breg]);
+ subreg(&pp, z, breg);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x87; /* xchg rhs,bx */
+ asmand(ctxt, &p->to, reg[breg]);
+ } else {
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ subreg(&pp, z, D_AX);
+ doasm(ctxt, &pp);
+ *ctxt->andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
+ }
+ return;
+ }
+ ctxt->diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
+ return;
+
+mfound:
+ switch(t[3]) {
+ default:
+ ctxt->diag("asmins: unknown mov %d %P", t[3], p);
+ break;
+
+ case 0: /* lit */
+ for(z=4; t[z]!=E; z++)
+ *ctxt->andptr++ = t[z];
+ break;
+
+ case 1: /* r,m */
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->to, t[5]);
+ break;
+
+ case 2: /* m,r */
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->from, t[5]);
+ break;
+
+ case 3: /* r,m - 2op */
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->to, t[6]);
+ break;
+
+ case 4: /* m,r - 2op */
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->from, t[6]);
+ break;
+
+ case 5: /* load full pointer, trash heap */
+ if(t[4])
+ *ctxt->andptr++ = t[4];
+ switch(p->to.index) {
+ default:
+ goto bad;
+ case D_DS:
+ *ctxt->andptr++ = 0xc5;
+ break;
+ case D_SS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb2;
+ break;
+ case D_ES:
+ *ctxt->andptr++ = 0xc4;
+ break;
+ case D_FS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb4;
+ break;
+ case D_GS:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = 0xb5;
+ break;
+ }
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case 6: /* double shift */
+ z = p->from.type;
+ switch(z) {
+ default:
+ goto bad;
+ case D_CONST:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[4];
+ asmand(ctxt, &p->to, reg[p->from.index]);
+ *ctxt->andptr++ = p->from.offset;
+ break;
+ case D_CL:
+ case D_CX:
+ *ctxt->andptr++ = 0x0f;
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->to, reg[p->from.index]);
+ break;
+ }
+ break;
+
+ case 7: /* imul rm,r */
+ if(t[4] == Pq) {
+ *ctxt->andptr++ = Pe;
+ *ctxt->andptr++ = Pm;
+ } else
+ *ctxt->andptr++ = t[4];
+ *ctxt->andptr++ = t[5];
+ asmand(ctxt, &p->from, reg[p->to.type]);
+ break;
+
+ case 8: /* mov tls, r */
+ // NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+ // where you load the TLS base register into a register and then index off that
+ // register to access the actual TLS variables. Systems that allow direct TLS access
+ // are handled in prefixof above and should not be listed here.
+ switch(ctxt->headtype) {
+ default:
+ sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
+
+ case Hlinux:
+ case Hnacl:
+ // ELF TLS base is 0(GS).
+ pp.from = p->from;
+ pp.from.type = D_INDIR+D_GS;
+ pp.from.offset = 0;
+ pp.from.index = D_NONE;
+ pp.from.scale = 0;
+ *ctxt->andptr++ = 0x65; // GS
+ *ctxt->andptr++ = 0x8B;
+ asmand(ctxt, &pp.from, reg[p->to.type]);
+ break;
+
+ case Hplan9:
+ if(ctxt->plan9tos == nil)
+ ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
+ memset(&pp.from, 0, sizeof pp.from);
+ pp.from.type = D_EXTERN;
+ pp.from.sym = ctxt->plan9tos;
+ pp.from.offset = 0;
+ pp.from.index = D_NONE;
+ *ctxt->andptr++ = 0x8B;
+ asmand(ctxt, &pp.from, reg[p->to.type]);
+ break;
+
+ case Hwindows:
+ // Windows TLS base is always 0x14(FS).
+ pp.from = p->from;
+ pp.from.type = D_INDIR+D_FS;
+ pp.from.offset = 0x14;
+ pp.from.index = D_NONE;
+ pp.from.scale = 0;
+ *ctxt->andptr++ = 0x64; // FS
+ *ctxt->andptr++ = 0x8B;
+ asmand(ctxt, &pp.from, reg[p->to.type]);
+ break;
+ }
+ break;
+ }
+}
+
+static uchar naclret[] = {
+ 0x5d, // POPL BP
+ // 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+ 0x83, 0xe5, 0xe0, // ANDL $~31, BP
+ 0xff, 0xe5, // JMP BP
+};
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+ Reloc *r;
+
+ ctxt->andptr = ctxt->and;
+
+ if(p->as == AUSEFIELD) {
+ r = addrel(ctxt->cursym);
+ r->off = 0;
+ r->sym = p->from.sym;
+ r->type = R_USEFIELD;
+ r->siz = 0;
+ return;
+ }
+
+ if(ctxt->headtype == Hnacl) {
+ switch(p->as) {
+ case ARET:
+ memmove(ctxt->andptr, naclret, sizeof naclret);
+ ctxt->andptr += sizeof naclret;
+ return;
+ case ACALL:
+ case AJMP:
+ if(D_AX <= p->to.type && p->to.type <= D_DI) {
+ *ctxt->andptr++ = 0x83;
+ *ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+ *ctxt->andptr++ = 0xe0;
+ }
+ break;
+ case AINT:
+ *ctxt->andptr++ = 0xf4;
+ return;
+ }
+ }
+
+ doasm(ctxt, p);
+ if(ctxt->andptr > ctxt->and+sizeof ctxt->and) {
+ print("and[] is too short - %ld byte instruction\n", ctxt->andptr - ctxt->and);
+ sysfatal("bad code");
+ }
+}
diff --git a/src/liblink/data.c b/src/liblink/data.c
new file mode 100644
index 000000000..4504f4171
--- /dev/null
+++ b/src/liblink/data.c
@@ -0,0 +1,370 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+mangle(char *file)
+{
+ sysfatal("%s: mangled input file", file);
+}
+
+void
+symgrow(Link *ctxt, LSym *s, vlong lsiz)
+{
+ int32 siz;
+
+ USED(ctxt);
+
+ siz = (int32)lsiz;
+ if((vlong)siz != lsiz)
+ sysfatal("symgrow size %lld too long", lsiz);
+
+ if(s->np >= siz)
+ return;
+
+ if(s->np > s->maxp) {
+ ctxt->cursym = s;
+ sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
+ }
+
+ if(s->maxp < siz) {
+ if(s->maxp == 0)
+ s->maxp = 8;
+ while(s->maxp < siz)
+ s->maxp <<= 1;
+ s->p = erealloc(s->p, s->maxp);
+ memset(s->p+s->np, 0, s->maxp-s->np);
+ }
+ s->np = siz;
+}
+
+void
+savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
+{
+ int32 off, siz, i, fl;
+ float32 flt;
+ uchar *cast;
+ vlong o;
+ Reloc *r;
+
+ off = p->from.offset;
+ siz = ctxt->arch->datasize(p);
+ if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
+ mangle(pn);
+ symgrow(ctxt, s, off+siz);
+
+ if(p->to.type == ctxt->arch->D_FCONST) {
+ switch(siz) {
+ default:
+ case 4:
+ flt = p->to.u.dval;
+ cast = (uchar*)&flt;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[fnuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&p->to.u.dval;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[fnuxi8[i]];
+ break;
+ }
+ } else if(p->to.type == ctxt->arch->D_SCONST) {
+ for(i=0; i<siz; i++)
+ s->p[off+i] = p->to.u.sval[i];
+ } else if(p->to.type == ctxt->arch->D_CONST) {
+ if(p->to.sym)
+ goto addr;
+ o = p->to.offset;
+ fl = o;
+ cast = (uchar*)&fl;
+ switch(siz) {
+ default:
+ ctxt->diag("bad nuxi %d\n%P", siz, p);
+ break;
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ } else if(p->to.type == ctxt->arch->D_ADDR) {
+ addr:
+ r = addrel(s);
+ r->off = off;
+ r->siz = siz;
+ r->sym = p->to.sym;
+ r->type = R_ADDR;
+ r->add = p->to.offset;
+ } else {
+ ctxt->diag("bad data: %P", p);
+ }
+}
+
+Reloc*
+addrel(LSym *s)
+{
+ if(s->nr >= s->maxr) {
+ if(s->maxr == 0)
+ s->maxr = 4;
+ else
+ s->maxr <<= 1;
+ s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
+ memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
+ }
+ return &s->r[s->nr++];
+}
+
+vlong
+setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid)
+{
+ int32 i, fl;
+ vlong o;
+ uchar *cast;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ if(s->size < off+wid) {
+ s->size = off+wid;
+ symgrow(ctxt, s, s->size);
+ }
+ fl = v;
+ cast = (uchar*)&fl;
+ switch(wid) {
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ o = v;
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ return off+wid;
+}
+
+vlong
+adduintxx(Link *ctxt, LSym *s, uint64 v, int wid)
+{
+ vlong off;
+
+ off = s->size;
+ setuintxx(ctxt, s, off, v, wid);
+ return off;
+}
+
+vlong
+adduint8(Link *ctxt, LSym *s, uint8 v)
+{
+ return adduintxx(ctxt, s, v, 1);
+}
+
+vlong
+adduint16(Link *ctxt, LSym *s, uint16 v)
+{
+ return adduintxx(ctxt, s, v, 2);
+}
+
+vlong
+adduint32(Link *ctxt, LSym *s, uint32 v)
+{
+ return adduintxx(ctxt, s, v, 4);
+}
+
+vlong
+adduint64(Link *ctxt, LSym *s, uint64 v)
+{
+ return adduintxx(ctxt, s, v, 8);
+}
+
+vlong
+setuint8(Link *ctxt, LSym *s, vlong r, uint8 v)
+{
+ return setuintxx(ctxt, s, r, v, 1);
+}
+
+vlong
+setuint16(Link *ctxt, LSym *s, vlong r, uint16 v)
+{
+ return setuintxx(ctxt, s, r, v, 2);
+}
+
+vlong
+setuint32(Link *ctxt, LSym *s, vlong r, uint32 v)
+{
+ return setuintxx(ctxt, s, r, v, 4);
+}
+
+vlong
+setuint64(Link *ctxt, LSym *s, vlong r, uint64 v)
+{
+ return setuintxx(ctxt, s, r, v, 8);
+}
+
+vlong
+addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = R_ADDR;
+ r->add = add;
+ return i + r->siz;
+}
+
+vlong
+addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->add = add;
+ r->type = R_PCREL;
+ r->siz = 4;
+ return i + r->siz;
+}
+
+vlong
+addaddr(Link *ctxt, LSym *s, LSym *t)
+{
+ return addaddrplus(ctxt, s, t, 0);
+}
+
+vlong
+setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add)
+{
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ if(off+ctxt->arch->ptrsize > s->size) {
+ s->size = off + ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ }
+ r = addrel(s);
+ r->sym = t;
+ r->off = off;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = R_ADDR;
+ r->add = add;
+ return off + r->siz;
+}
+
+vlong
+setaddr(Link *ctxt, LSym *s, vlong off, LSym *t)
+{
+ return setaddrplus(ctxt, s, off, t, 0);
+}
+
+vlong
+addsize(Link *ctxt, LSym *s, LSym *t)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += ctxt->arch->ptrsize;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = ctxt->arch->ptrsize;
+ r->type = R_SIZE;
+ return i + r->siz;
+}
+
+vlong
+addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(ctxt, s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = 4;
+ r->type = R_ADDR;
+ r->add = add;
+ return i + r->siz;
+}
diff --git a/src/liblink/go.c b/src/liblink/go.c
new file mode 100644
index 000000000..9f5a423d3
--- /dev/null
+++ b/src/liblink/go.c
@@ -0,0 +1,74 @@
+// 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.
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+// replace all "". with pkg.
+char*
+expandpkg(char *t0, char *pkg)
+{
+ int n;
+ char *p;
+ char *w, *w0, *t;
+
+ n = 0;
+ for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
+ n++;
+
+ if(n == 0)
+ return estrdup(t0);
+
+ w0 = emallocz(strlen(t0) + strlen(pkg)*n);
+ w = w0;
+ for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
+ memmove(w, t, p - t);
+ w += p-t;
+ strcpy(w, pkg);
+ w += strlen(pkg);
+ t = p+2;
+ }
+ strcpy(w, t);
+ return w0;
+}
+
+void*
+emallocz(long n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+char*
+estrdup(char *p)
+{
+ p = strdup(p);
+ if(p == nil)
+ sysfatal("out of memory");
+ return p;
+}
+
+void*
+erealloc(void *p, long n)
+{
+ p = realloc(p, n);
+ if(p == nil)
+ sysfatal("out of memory");
+ return p;
+}
+
+void
+double2ieee(uint64 *ieee, float64 f)
+{
+ memmove(ieee, &f, 8);
+}
diff --git a/src/liblink/ld.c b/src/liblink/ld.c
new file mode 100644
index 000000000..9ea0e9a73
--- /dev/null
+++ b/src/liblink/ld.c
@@ -0,0 +1,258 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+addlib(Link *ctxt, char *src, char *obj, char *pathname)
+{
+ char name[1024], pname[1024], *p;
+ int i;
+
+ if(strlen(pathname) >= sizeof name)
+ sysfatal("addlib pathname too long");
+ strcpy(name, pathname);
+ cleanname(name);
+
+ // runtime.a -> runtime
+ p = nil;
+ if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
+ p = name+strlen(name)-2;
+ *p = '\0';
+ }
+
+ // already loaded?
+ for(i=0; i<ctxt->libraryp; i++)
+ if(strcmp(ctxt->library[i].pkg, name) == 0)
+ return;
+
+ // runtime -> runtime.a for search
+ if(p != nil)
+ *p = '.';
+
+ if((!ctxt->windows && name[0] == '/') || (ctxt->windows && name[1] == ':'))
+ snprint(pname, sizeof pname, "%s", name);
+ else {
+ // try dot, -L "libdir", and then goroot.
+ for(i=0; i<ctxt->nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
+ if(access(pname, AEXIST) >= 0)
+ break;
+ }
+ }
+ cleanname(pname);
+
+ /* runtime.a -> runtime */
+ if(p != nil)
+ *p = '\0';
+
+ if(ctxt->debugvlog > 1 && ctxt->bso)
+ Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
+
+ addlibpath(ctxt, src, obj, pname, name);
+}
+
+/*
+ * add library to library list.
+ * srcref: src file referring to package
+ * objref: object file referring to package
+ * file: object file, e.g., /home/rsc/go/pkg/container/vector.a
+ * pkg: package import path, e.g. container/vector
+ */
+void
+addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg)
+{
+ int i;
+ Library *l;
+
+ for(i=0; i<ctxt->libraryp; i++)
+ if(strcmp(file, ctxt->library[i].file) == 0)
+ return;
+
+ if(ctxt->debugvlog > 1 && ctxt->bso)
+ Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
+ cputime(), srcref, objref, file, pkg);
+
+ if(ctxt->libraryp == ctxt->nlibrary){
+ ctxt->nlibrary = 50 + 2*ctxt->libraryp;
+ ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary);
+ }
+
+ l = &ctxt->library[ctxt->libraryp++];
+ l->objref = estrdup(objref);
+ l->srcref = estrdup(srcref);
+ l->file = estrdup(file);
+ l->pkg = estrdup(pkg);
+}
+
+int
+find1(int32 l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++) {
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ if(c == i) {
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ } else {
+ inuxi8[i] = c+4;
+ inuxi8[i+4] = c;
+ }
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+}
+
+uchar fnuxi8[8];
+uchar fnuxi4[4];
+uchar inuxi1[1];
+uchar inuxi2[2];
+uchar inuxi4[4];
+uchar inuxi8[8];
+
+#define LOG 5
+void
+mkfwd(LSym *sym)
+{
+ Prog *p;
+ int i;
+ int32 dwn[LOG], cnt[LOG];
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1;
+ else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = nil;
+ }
+ i = 0;
+ for(p = sym->text; p != nil && p->link != nil; p = p->link) {
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = nil;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != nil)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+copyp(Link *ctxt, Prog *q)
+{
+ Prog *p;
+
+ p = ctxt->arch->prg();
+ *p = *q;
+ return p;
+}
+
+Prog*
+appendp(Link *ctxt, Prog *q)
+{
+ Prog *p;
+
+ p = ctxt->arch->prg();
+ p->link = q->link;
+ q->link = p;
+ p->lineno = q->lineno;
+ p->mode = q->mode;
+ return p;
+}
+
+vlong
+atolwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
diff --git a/src/liblink/list5.c b/src/liblink/list5.c
new file mode 100644
index 000000000..4a4e8c71f
--- /dev/null
+++ b/src/liblink/list5.c
@@ -0,0 +1,356 @@
+// Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+
+enum
+{
+ STRINGSZ = 1000
+};
+
+static int Aconv(Fmt *fp);
+static int Dconv(Fmt *fp);
+static int Mconv(Fmt *fp);
+static int Pconv(Fmt *fp);
+static int Rconv(Fmt *fp);
+static int RAconv(Fmt *fp);
+static int DSconv(Fmt *fp);
+
+#pragma varargck type "$" char*
+#pragma varargck type "M" Addr*
+#pragma varargck type "@" Addr*
+
+void
+listinit5(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('R', Rconv);
+
+ // for internal use
+ fmtinstall('$', DSconv);
+ fmtinstall('M', Mconv);
+ fmtinstall('@', RAconv);
+}
+
+static char *extra [] = {
+ ".EQ", ".NE", ".CS", ".CC",
+ ".MI", ".PL", ".VS", ".VC",
+ ".HI", ".LS", ".GE", ".LT",
+ ".GT", ".LE", "", ".NV",
+};
+
+static Prog* bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], sc[20];
+ Prog *p;
+ int a, s;
+
+ p = va_arg(fp->args, Prog*);
+ bigP = p;
+ a = p->as;
+ s = p->scond;
+ strcpy(sc, extra[s & C_SCOND]);
+ if(s & C_SBIT)
+ strcat(sc, ".S");
+ if(s & C_PBIT)
+ strcat(sc, ".P");
+ if(s & C_WBIT)
+ strcat(sc, ".W");
+ if(s & C_UBIT) /* ambiguous with FBIT */
+ strcat(sc, ".U");
+ if(a == AMOVM) {
+ if(p->from.type == D_CONST)
+ sprint(str, "%.5lld (%L) %A%s %@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ if(p->to.type == D_CONST)
+ sprint(str, "%.5lld (%L) %A%s %D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ } else
+ if(a == ADATA)
+ sprint(str, "%.5lld (%L) %A %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, "%.5lld (%L) %A %D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, "%.5lld (%L) %A%s %D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, "%.5lld (%L) %A%s %D,R%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+ else
+ sprint(str, "%.5lld (%L) %A%s %D,F%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+ bigP = nil;
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames5[a];
+ return fmtstrcpy(fp, s);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ const char *op;
+ int v;
+
+ a = va_arg(fp->args, Addr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
+ sprint(str, "%M(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%M(R%d)", a, a->reg);
+ else
+ sprint(str, "$%M", a);
+ break;
+
+ case D_CONST2:
+ sprint(str, "$%lld-%d", a->offset, a->offset2);
+ break;
+
+ case D_SHIFT:
+ v = a->offset;
+ op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
+ if(v & (1<<4))
+ sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ else
+ sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ if(a->reg != NREG)
+ sprint(str+strlen(str), "(R%d)", a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%M(R%d)", a, a->reg);
+ else
+ sprint(str, "%M", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_PSR:
+ sprint(str, "PSR");
+ if(a->name != D_NONE || a->sym != nil)
+ sprint(str, "%M(PSR)(REG)", a);
+ break;
+
+ case D_BRANCH:
+ if(a->sym != nil)
+ sprint(str, "%s(SB)", a->sym->name);
+ else if(bigP != nil && bigP->pcond != nil)
+ sprint(str, "%lld", bigP->pcond->pc);
+ else if(a->u.branch != nil)
+ sprint(str, "%lld", a->u.branch->pc);
+ else
+ sprint(str, "%lld(PC)", a->offset/*-pc*/);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17g", a->u.dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%$\"", a->u.sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+static int
+RAconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ int i, v;
+
+ a = va_arg(fp->args, Addr*);
+ sprint(str, "GOK-reglist");
+ switch(a->type) {
+ case D_CONST:
+ case D_CONST2:
+ if(a->reg != NREG)
+ break;
+ if(a->sym != nil)
+ break;
+ v = a->offset;
+ strcpy(str, "");
+ for(i=0; i<NREG; i++) {
+ if(v & (1<<i)) {
+ if(str[0] == 0)
+ strcat(str, "[R");
+ else
+ strcat(str, ",R");
+ sprint(strchr(str, 0), "%d", i);
+ }
+ }
+ strcat(str, "]");
+ }
+ return fmtstrcpy(fp, str);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Rconv(Fmt *fp)
+{
+ int r;
+ char str[STRINGSZ];
+
+ r = va_arg(fp->args, int);
+ sprint(str, "R%d", r);
+ return fmtstrcpy(fp, str);
+}
+
+static int
+Mconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Addr *a;
+ LSym *s;
+
+ a = va_arg(fp->args, Addr*);
+ s = a->sym;
+ if(s == nil) {
+ sprint(str, "%d", (int)a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%lld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6g/list.c b/src/liblink/list6.c
index 9d27a6a09..fe708d877 100644
--- a/src/cmd/6g/list.c
+++ b/src/liblink/list6.c
@@ -1,4 +1,4 @@
-// Derived from Inferno utils/6c/list.c
+// Inferno utils/6c/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
@@ -30,76 +30,125 @@
#include <u.h>
#include <libc.h>
-#include "gg.h"
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+
+//
+// Format conversions
+// %A int Opcodes (instruction mnemonics)
+//
+// %D Addr* Addresses (instruction operands)
+// Flags: "%lD": seperate the high and low words of a constant by "-"
+//
+// %P Prog* Instructions
+//
+// %R int Registers
+//
+// %$ char* String constant addresses (for internal use only)
+
+static int Aconv(Fmt *fp);
+static int Dconv(Fmt *fp);
+static int Pconv(Fmt *fp);
+static int Rconv(Fmt *fp);
+static int DSconv(Fmt *fp);
+
+enum
+{
+ STRINGSZ = 1000
+};
+
+#pragma varargck type "$" char*
-static int sconsize;
void
-listinit(void)
+listinit6(void)
{
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('R', Rconv);
- fmtinstall('A', Aconv); // as
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('R', Rconv); // reg
- fmtinstall('Y', Yconv); // sconst
+ // for internal use
+ fmtinstall('$', DSconv);
}
-int
+static Prog* bigP;
+
+static int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
- char scale[40];
p = va_arg(fp->args, Prog*);
- sconsize = 8;
- scale[0] = '\0';
- if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
- snprint(scale, sizeof scale, "%d,", p->from.scale);
+ bigP = p;
switch(p->as) {
- default:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
-
case ADATA:
- sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
+ sprint(str, "%.5lld (%L) %A %D/%d,%D",
+ p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
+ if(p->from.scale) {
+ sprint(str, "%.5lld (%L) %A %D,%d,%lD",
+ p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ sprint(str, "%.5lld (%L) %A %D,%lD",
+ p->pc, p->lineno, p->as, &p->from, &p->to);
+ break;
+
+ default:
+ sprint(str, "%.5lld (%L) %A %D,%D",
+ p->pc, p->lineno, p->as, &p->from, &p->to);
break;
}
+ bigP = nil;
return fmtstrcpy(fp, str);
}
-int
+static int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames6[i]);
+}
+
+static int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
Addr *a;
int i;
- uint32 d1, d2;
a = va_arg(fp->args, Addr*);
i = a->type;
+
+ if(fp->flags & FmtLong) {
+ if(i == D_CONST)
+ sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
+ else {
+ // ATEXT dst is not constant
+ sprint(str, "!!%D", a);
+ }
+ goto brk;
+ }
+
if(i >= D_INDIR) {
if(a->offset)
- snprint(str, sizeof(str), "%lld(%R)", a->offset, i-D_INDIR);
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
+ sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
-
default:
if(a->offset)
- snprint(str, sizeof(str), "$%lld,%R", a->offset, i);
+ sprint(str, "$%lld,%R", a->offset, i);
else
- snprint(str, sizeof(str), "%R", i);
+ sprint(str, "%R", i);
break;
case D_NONE:
@@ -107,69 +156,70 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- if(a->u.branch == nil)
- snprint(str, sizeof(str), "<nil>");
+ if(a->sym != nil)
+ sprint(str, "%s(SB)", a->sym->name);
+ else if(bigP != nil && bigP->pcond != nil)
+ sprint(str, "%lld", bigP->pcond->pc);
+ else if(a->u.branch != nil)
+ sprint(str, "%lld", a->u.branch->pc);
else
- snprint(str, sizeof(str), "%d", a->u.branch->loc);
+ sprint(str, "%lld(PC)", a->offset);
break;
case D_EXTERN:
- snprint(str, sizeof(str), "%S+%lld(SB)", a->sym, a->offset);
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
break;
case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%lld(SB)", a->sym, a->offset);
+ sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
break;
case D_AUTO:
- snprint(str, sizeof(str), "%S+%lld(SP)", a->sym, a->offset);
+ if(a->sym)
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(SP)", a->offset);
break;
case D_PARAM:
- snprint(str, sizeof(str), "%S+%lld(FP)", a->sym, a->offset);
+ if(a->sym)
+ sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(FP)", a->offset);
break;
case D_CONST:
- if(fp->flags & FmtLong) {
- d1 = a->offset & 0xffffffffLL;
- d2 = (a->offset>>32) & 0xffffffffLL;
- snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
- break;
- }
- snprint(str, sizeof(str), "$%lld", a->offset);
+ sprint(str, "$%lld", a->offset);
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->u.dval);
+ sprint(str, "$(%.17g)", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->u.sval);
+ sprint(str, "$\"%$\"", a->u.sval);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
+ sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
strcat(str, s);
}
conv:
- fmtstrcpy(fp, str);
- if(a->gotype)
- fmtprint(fp, "{%s}", a->gotype->name);
- return 0;
+ return fmtstrcpy(fp, str);
}
-static char* regstr[] =
+char* regstr[] =
{
- "AL", /* [D_AL] */
+ "AL", /* [D_AL] */
"CL",
"DL",
"BL",
@@ -186,7 +236,7 @@ static char* regstr[] =
"R14B",
"R15B",
- "AX", /* [D_AX] */
+ "AX", /* [D_AX] */
"CX",
"DX",
"BX",
@@ -208,7 +258,7 @@ static char* regstr[] =
"DH",
"BH",
- "F0", /* [D_F0] */
+ "F0", /* [D_F0] */
"F1",
"F2",
"F3",
@@ -243,20 +293,20 @@ static char* regstr[] =
"X14",
"X15",
- "CS", /* [D_CS] */
+ "CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
- "CR0", /* [D_CR] */
+ "CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
@@ -273,7 +323,7 @@ static char* regstr[] =
"CR14",
"CR15",
- "DR0", /* [D_DR] */
+ "DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
@@ -282,7 +332,7 @@ static char* regstr[] =
"DR6",
"DR7",
- "TR0", /* [D_TR] */
+ "TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
@@ -291,46 +341,38 @@ static char* regstr[] =
"TR6",
"TR7",
- "NONE", /* [D_NONE] */
+ "TLS", /* [D_TLS] */
+ "NONE", /* [D_NONE] */
};
-int
+static int
Rconv(Fmt *fp)
{
char str[STRINGSZ];
int r;
r = va_arg(fp->args, int);
- if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
- snprint(str, sizeof(str), "BAD_R(%d)", r);
- return fmtstrcpy(fp, str);
- }
- return fmtstrcpy(fp, regstr[r]);
-}
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
+ return fmtstrcpy(fp, str);
}
-
-int
-Yconv(Fmt *fp)
+static int
+DSconv(Fmt *fp)
{
int i, c;
char str[STRINGSZ], *p, *a;
a = va_arg(fp->args, char*);
p = str;
- for(i=0; i<sconsize; i++) {
+ for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
*p++ = c;
continue;
}
diff --git a/src/cmd/8g/list.c b/src/liblink/list8.c
index ec02ba5c5..786692416 100644
--- a/src/cmd/8g/list.c
+++ b/src/liblink/list8.c
@@ -1,4 +1,4 @@
-// Derived from Inferno utils/8c/list.c
+// Inferno utils/8c/list.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
@@ -30,76 +30,112 @@
#include <u.h>
#include <libc.h>
-#include "gg.h"
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+
+static int Aconv(Fmt *fp);
+static int Dconv(Fmt *fp);
+static int Pconv(Fmt *fp);
+static int Rconv(Fmt *fp);
+static int DSconv(Fmt *fp);
+
+enum
+{
+ STRINGSZ = 1000
+};
+
+#pragma varargck type "$" char*
-static int sconsize;
void
-listinit(void)
+listinit8(void)
{
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('R', Rconv);
- fmtinstall('A', Aconv); // as
- fmtinstall('P', Pconv); // Prog*
- fmtinstall('D', Dconv); // Addr*
- fmtinstall('R', Rconv); // reg
- fmtinstall('Y', Yconv); // sconst
+ // for internal use
+ fmtinstall('$', DSconv);
}
-int
+static Prog* bigP;
+
+static int
Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
- char scale[40];
p = va_arg(fp->args, Prog*);
- sconsize = 8;
- scale[0] = '\0';
- if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
- snprint(scale, sizeof scale, "%d,", p->from.scale);
+ bigP = p;
switch(p->as) {
- default:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
- break;
-
case ADATA:
- sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
- p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
+ sprint(str, "%.5lld (%L) %A %D/%d,%D",
+ p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
- p->loc, p->lineno, p->as, &p->from, scale, &p->to);
+ if(p->from.scale) {
+ sprint(str, "%.5lld (%L) %A %D,%d,%lD",
+ p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ sprint(str, "%.5lld (%L) %A %D,%lD",
+ p->pc, p->lineno, p->as, &p->from, &p->to);
+ break;
+
+ default:
+ sprint(str, "%.5lld (%L) %A %D,%D",
+ p->pc, p->lineno, p->as, &p->from, &p->to);
break;
}
+ bigP = nil;
return fmtstrcpy(fp, str);
}
-int
+static int
+Aconv(Fmt *fp)
+{
+ int i;
+
+ i = va_arg(fp->args, int);
+ return fmtstrcpy(fp, anames8[i]);
+}
+
+static int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
Addr *a;
int i;
- uint32 d1, d2;
a = va_arg(fp->args, Addr*);
i = a->type;
+
+ if(fp->flags & FmtLong) {
+ if(i == D_CONST2)
+ sprint(str, "$%lld-%d", a->offset, a->offset2);
+ else {
+ // ATEXT dst is not constant
+ sprint(str, "!!%D", a);
+ }
+ goto brk;
+ }
+
if(i >= D_INDIR) {
if(a->offset)
- snprint(str, sizeof(str), "%d(%R)", a->offset, i-D_INDIR);
+ sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
else
- snprint(str, sizeof(str), "(%R)", i-D_INDIR);
+ sprint(str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
-
default:
if(a->offset)
- snprint(str, sizeof(str), "$%d,%R", a->offset, i);
+ sprint(str, "$%lld,%R", a->offset, i);
else
- snprint(str, sizeof(str), "%R", i);
+ sprint(str, "%R", i);
break;
case D_NONE:
@@ -107,76 +143,86 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- snprint(str, sizeof(str), "%d", a->u.branch->loc);
+ if(a->sym != nil)
+ sprint(str, "%s(SB)", a->sym->name);
+ else if(bigP != nil && bigP->pcond != nil)
+ sprint(str, "%lld", bigP->pcond->pc);
+ else if(a->u.branch != nil)
+ sprint(str, "%lld", a->u.branch->pc);
+ else
+ sprint(str, "%lld(PC)", a->offset);
break;
case D_EXTERN:
- snprint(str, sizeof(str), "%S+%d(SB)", a->sym, a->offset);
+ sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
break;
case D_STATIC:
- snprint(str, sizeof(str), "%S<>+%d(SB)", a->sym, a->offset);
+ sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
break;
case D_AUTO:
- snprint(str, sizeof(str), "%S+%d(SP)", a->sym, a->offset);
+ if(a->sym)
+ sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(SP)", a->offset);
break;
case D_PARAM:
- snprint(str, sizeof(str), "%S+%d(FP)", a->sym, a->offset);
+ if(a->sym)
+ sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(FP)", a->offset);
break;
case D_CONST:
- if(fp->flags & FmtLong) {
- d1 = a->offset;
- d2 = a->offset2;
- snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
- break;
+ sprint(str, "$%lld", a->offset);
+ break;
+
+ case D_CONST2:
+ if(!(fp->flags & FmtLong)) {
+ // D_CONST2 outside of ATEXT should not happen
+ sprint(str, "!!$%lld-%d", a->offset, a->offset2);
}
- snprint(str, sizeof(str), "$%d", a->offset);
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.17e)", a->u.dval);
+ sprint(str, "$(%.17g)", a->u.dval);
break;
case D_SCONST:
- snprint(str, sizeof(str), "$\"%Y\"", a->u.sval);
+ sprint(str, "$\"%$\"", a->u.sval);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
- snprint(str, sizeof(str), "$%D", a);
+ sprint(str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
}
brk:
if(a->index != D_NONE) {
- snprint(s, sizeof(s), "(%R*%d)", (int)a->index, (int)a->scale);
+ sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
strcat(str, s);
}
conv:
- fmtstrcpy(fp, str);
- if(a->gotype)
- fmtprint(fp, "{%s}", a->gotype->name);
- return 0;
+ return fmtstrcpy(fp, str);
}
-static char* regstr[] =
+char* regstr[] =
{
- "AL", /* [D_AL] */
+ "AL", /* [D_AL] */
"CL",
"DL",
"BL",
-
- "AH", /* [D_AH] */
+ "AH",
"CH",
"DH",
"BH",
- "AX", /* [D_AX] */
+ "AX", /* [D_AX] */
"CX",
"DX",
"BX",
@@ -185,7 +231,7 @@ static char* regstr[] =
"SI",
"DI",
- "F0", /* [D_F0] */
+ "F0", /* [D_F0] */
"F1",
"F2",
"F3",
@@ -194,20 +240,20 @@ static char* regstr[] =
"F6",
"F7",
- "CS", /* [D_CS] */
+ "CS", /* [D_CS] */
"SS",
"DS",
"ES",
"FS",
"GS",
- "GDTR", /* [D_GDTR] */
- "IDTR", /* [D_IDTR] */
- "LDTR", /* [D_LDTR] */
- "MSW", /* [D_MSW] */
- "TASK", /* [D_TASK] */
+ "GDTR", /* [D_GDTR] */
+ "IDTR", /* [D_IDTR] */
+ "LDTR", /* [D_LDTR] */
+ "MSW", /* [D_MSW] */
+ "TASK", /* [D_TASK] */
- "CR0", /* [D_CR] */
+ "CR0", /* [D_CR] */
"CR1",
"CR2",
"CR3",
@@ -216,7 +262,7 @@ static char* regstr[] =
"CR6",
"CR7",
- "DR0", /* [D_DR] */
+ "DR0", /* [D_DR] */
"DR1",
"DR2",
"DR3",
@@ -225,7 +271,7 @@ static char* regstr[] =
"DR6",
"DR7",
- "TR0", /* [D_TR] */
+ "TR0", /* [D_TR] */
"TR1",
"TR2",
"TR3",
@@ -234,7 +280,7 @@ static char* regstr[] =
"TR6",
"TR7",
- "X0", /* [D_X0] */
+ "X0", /* [D_X0] */
"X1",
"X2",
"X3",
@@ -243,46 +289,38 @@ static char* regstr[] =
"X6",
"X7",
- "NONE", /* [D_NONE] */
+ "TLS", /* [D_TLS] */
+ "NONE", /* [D_NONE] */
};
-int
+static int
Rconv(Fmt *fp)
{
char str[STRINGSZ];
int r;
r = va_arg(fp->args, int);
- if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
- snprint(str, sizeof(str), "BAD_R(%d)", r);
- return fmtstrcpy(fp, str);
- }
- return fmtstrcpy(fp, regstr[r]);
-}
+ if(r >= D_AL && r <= D_NONE)
+ sprint(str, "%s", regstr[r-D_AL]);
+ else
+ sprint(str, "gok(%d)", r);
-int
-Aconv(Fmt *fp)
-{
- int i;
-
- i = va_arg(fp->args, int);
- return fmtstrcpy(fp, anames[i]);
+ return fmtstrcpy(fp, str);
}
-
-int
-Yconv(Fmt *fp)
+static int
+DSconv(Fmt *fp)
{
int i, c;
char str[STRINGSZ], *p, *a;
a = va_arg(fp->args, char*);
p = str;
- for(i=0; i<sconsize; i++) {
+ for(i=0; i<sizeof(double); i++) {
c = a[i] & 0xff;
- if((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9')) {
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9') {
*p++ = c;
continue;
}
diff --git a/src/liblink/obj.c b/src/liblink/obj.c
new file mode 100644
index 000000000..b8083b0ec
--- /dev/null
+++ b/src/liblink/obj.c
@@ -0,0 +1,296 @@
+// 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.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+enum
+{
+ HISTSZ = 10,
+ NSYM = 50,
+};
+
+int
+linklinefmt(Link *ctxt, Fmt *fp)
+{
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 lno, d;
+ int i, n;
+ Hist *h;
+
+ lno = va_arg(fp->args, int32);
+
+ n = 0;
+ for(h=ctxt->hist; h!=nil; h=h->link) {
+ if(h->offset < 0)
+ continue;
+ if(lno < h->line)
+ break;
+ if(h->name) {
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+
+ if(n > HISTSZ)
+ n = HISTSZ;
+
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec))
+ break;
+ fmtprint(fp, " ");
+ }
+ if(ctxt->debugline || (fp->flags&FmtLong))
+ fmtprint(fp, "%s/", ctxt->pathname);
+ if(a[i].line)
+ fmtprint(fp, "%s:%d[%s:%d]",
+ a[i].line->name, lno-a[i].ldel+1,
+ a[i].incl->name, lno-a[i].idel+1);
+ else
+ fmtprint(fp, "%s:%d",
+ a[i].incl->name, lno-a[i].idel+1);
+ lno = a[i].incl->line - 1; // now print out start of this file
+ }
+ if(n == 0)
+ fmtprint(fp, "<unknown line number>");
+
+ return 0;
+}
+
+// Does s have t as a path prefix?
+// That is, does s == t or does s begin with t followed by a slash?
+// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
+// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
+static int
+haspathprefix(char *s, char *t)
+{
+ int i, cs, ct;
+
+ if(t == nil)
+ return 0;
+ for(i=0; t[i]; i++) {
+ cs = s[i];
+ ct = t[i];
+ if('A' <= cs && cs <= 'Z')
+ cs += 'a' - 'A';
+ if('A' <= ct && ct <= 'Z')
+ ct += 'a' - 'A';
+ if(cs == '\\')
+ cs = '/';
+ if(ct == '\\')
+ ct = '/';
+ if(cs != ct)
+ return 0;
+ }
+ return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
+}
+
+// This is a simplified copy of linklinefmt above.
+// It doesn't allow printing the full stack, and it returns the file name and line number separately.
+// TODO: Unify with linklinefmt somehow.
+void
+linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
+{
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 lno, d, dlno;
+ int n;
+ Hist *h;
+ char buf[1024], buf1[1024], *file;
+
+ lno = line;
+ n = 0;
+ for(h=ctxt->hist; h!=nil; h=h->link) {
+ if(h->offset < 0)
+ continue;
+ if(lno < h->line)
+ break;
+ if(h->name) {
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+
+ if(n > HISTSZ)
+ n = HISTSZ;
+
+ if(n <= 0) {
+ *f = linklookup(ctxt, "??", HistVersion);
+ *l = 0;
+ return;
+ }
+
+ n--;
+ if(a[n].line) {
+ file = a[n].line->name;
+ dlno = a[n].ldel-1;
+ } else {
+ file = a[n].incl->name;
+ dlno = a[n].idel-1;
+ }
+ if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':') || file[0] == '<')
+ snprint(buf, sizeof buf, "%s", file);
+ else
+ snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
+
+ // Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
+ if(haspathprefix(buf, ctxt->trimpath)) {
+ if(strlen(buf) == strlen(ctxt->trimpath))
+ strcpy(buf, "??");
+ else {
+ snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
+ if(buf1[0] == '\0')
+ strcpy(buf1, "??");
+ strcpy(buf, buf1);
+ }
+ } else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
+ snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
+ strcpy(buf, buf1);
+ }
+
+ lno -= dlno;
+ *f = linklookup(ctxt, buf, HistVersion);
+ *l = lno;
+}
+
+void
+linklinehist(Link *ctxt, int lineno, char *f, int offset)
+{
+ Hist *h;
+
+ if(0) // debug['f']
+ if(f) {
+ if(offset)
+ print("%4d: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4d: %s\n", lineno, f);
+ } else
+ print("%4d: <pop>\n", lineno);
+
+ h = malloc(sizeof(Hist));
+ memset(h, 0, sizeof *h);
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = nil;
+ if(ctxt->ehist == nil) {
+ ctxt->hist = h;
+ ctxt->ehist = h;
+ return;
+ }
+ ctxt->ehist->link = h;
+ ctxt->ehist = h;
+}
+
+void
+linkprfile(Link *ctxt, int32 l)
+{
+ int i, n;
+ Hist a[HISTSZ], *h;
+ int32 d;
+
+ n = 0;
+ for(h = ctxt->hist; h != nil; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset == 0) {
+ if(n >= 0 && n < HISTSZ)
+ a[n] = *h;
+ n++;
+ continue;
+ }
+ if(n > 0 && n < HISTSZ)
+ if(a[n-1].offset == 0) {
+ a[n] = *h;
+ n++;
+ } else
+ a[n-1] = *h;
+ continue;
+ }
+ n--;
+ if(n >= 0 && n < HISTSZ) {
+ d = h->line - a[n].line;
+ for(i=0; i<n; i++)
+ a[i].line += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ for(i=0; i<n; i++)
+ print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+linknewplist(Link *ctxt)
+{
+ Plist *pl;
+
+ pl = malloc(sizeof(*pl));
+ memset(pl, 0, sizeof *pl);
+ if(ctxt->plist == nil)
+ ctxt->plist = pl;
+ else
+ ctxt->plast->link = pl;
+ ctxt->plast = pl;
+
+ return pl;
+}
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
new file mode 100644
index 000000000..ccd4c81c7
--- /dev/null
+++ b/src/liblink/obj5.c
@@ -0,0 +1,1068 @@
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+ .as = AGOK,
+ .scond = C_SCOND_NONE,
+ .reg = NREG,
+ .from = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+ .to = {
+ .name = D_NONE,
+ .type = D_NONE,
+ .reg = NREG,
+ },
+};
+
+static int
+symtype(Addr *a)
+{
+ return a->name;
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ABL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->reg;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->reg;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->reg = f;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ char literal[64];
+ LSym *s;
+ LSym *tlsfallback;
+
+ p->from.class = 0;
+ p->to.class = 0;
+
+ // Rewrite B/BL to symbol as D_BRANCH.
+ switch(p->as) {
+ case AB:
+ case ABL:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
+ p->to.type = D_BRANCH;
+ break;
+ }
+
+ // Replace TLS register fetches on older ARM procesors.
+ switch(p->as) {
+ case AMRC:
+ // If the instruction matches MRC 15, 0, <reg>, C13, C0, 3, replace it.
+ if(ctxt->goarm < 7 && (p->to.offset & 0xffff0fff) == 0xee1d0f70) {
+ tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
+
+ // BL runtime.read_tls_fallback(SB)
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = tlsfallback;
+ p->to.offset = 0;
+ } else {
+ // Otherwise, MRC/MCR instructions need no further treatment.
+ p->as = AWORD;
+ }
+ break;
+ }
+
+ // Rewrite float constants to values stored in memory.
+ switch(p->as) {
+ case AMOVF:
+ if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+ (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+ int32 i32;
+ float32 f32;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ sprint(literal, "$f32.%08ux", (uint32)i32);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+
+ case AMOVD:
+ if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+ (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+ int64 i64;
+ memmove(&i64, &p->from.u.dval, 8);
+ sprint(literal, "$f64.%016llux", (uvlong)i64);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ break;
+ }
+
+ if(ctxt->flag_shared) {
+ // Shared libraries use R_ARM_TLS_IE32 instead of
+ // R_ARM_TLS_LE32, replacing the link time constant TLS offset in
+ // runtime.tlsgm with an address to a GOT entry containing the
+ // offset. Rewrite $runtime.tlsgm(SB) to runtime.tlsgm(SB) to
+ // compensate.
+ if(ctxt->gmsym == nil)
+ ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+
+ if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->gmsym)
+ p->from.type = D_OREG;
+ if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->gmsym)
+ p->to.type = D_OREG;
+ }
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+static Prog* stacksplit(Link*, Prog*, int32, int);
+static void initdiv(Link*);
+static void softfloat(Link*, LSym*);
+
+// Prog.mark
+enum
+{
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+};
+
+static void
+linkcase(Prog *casep)
+{
+ Prog *p;
+
+ for(p = casep; p != nil; p = p->link){
+ if(p->as == ABCASE) {
+ for(; p != nil && p->as == ABCASE; p = p->link)
+ p->pcrel = casep;
+ break;
+ }
+ }
+}
+
+static void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *pl, *q, *q1, *q2;
+ int o;
+ int32 autosize, autoffset;
+
+ autosize = 0;
+
+ if(ctxt->symmorestack[0] == nil) {
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+ ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+ }
+
+ q = nil;
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ softfloat(ctxt, cursym);
+
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+ cursym->locals = autoffset;
+ cursym->args = p->to.offset2;
+
+ if(ctxt->debugzerostack) {
+ if(autoffset && !(p->reg&NOSPLIT)) {
+ // MOVW $4(R13), R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW $n(R13), R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = 13;
+ p->from.offset = 4 + autoffset;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW $0, R3
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // L:
+ // MOVW.nil R3, 0(R1) +4
+ // CMP R1, R2
+ // BNE L
+ p = pl = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = 1;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+
+ p = appendp(ctxt, p);
+ p->as = ABNE;
+ p->to.type = D_BRANCH;
+ p->pcond = pl;
+ }
+ }
+
+ /*
+ * find leaf subroutines
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ case ACASE:
+ if(ctxt->flag_shared)
+ linkcase(p);
+ break;
+
+ case ATEXT:
+ p->mark |= LEAF;
+ break;
+
+ case ARET:
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ q = p;
+ if(ctxt->sym_div == nil)
+ initdiv(ctxt);
+ cursym->text->mark &= ~LEAF;
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ if(q1 != nil)
+ q1->mark |= p->mark;
+ continue;
+
+ case ABL:
+ case ABX:
+ case ADUFFZERO:
+ case ADUFFCOPY:
+ cursym->text->mark &= ~LEAF;
+
+ case ABCASE:
+ case AB:
+
+ case ABEQ:
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ q1 = p->pcond;
+ if(q1 != nil) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->pcond = q1;
+ }
+ }
+ break;
+ }
+ q = p;
+ }
+
+ for(p = cursym->text; p != nil; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(cursym->text->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ if(!autosize && !(cursym->text->mark & LEAF)) {
+ if(ctxt->debugvlog) {
+ Bprint(ctxt->bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(ctxt->bso);
+ }
+ cursym->text->mark |= LEAF;
+ }
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ if(!autosize)
+ break;
+ }
+
+ if(!(p->reg & NOSPLIT))
+ p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
+ p->spadj = autosize;
+
+ if(cursym->text->reg & WRAPPER) {
+ // g->panicwrap += autosize;
+ // MOVW panicwrap_offset(g), R3
+ // ADD $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+ break;
+
+ case ARET:
+ nocache(p);
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ p->as = AB;
+ p->from = zprg.from;
+ if(p->to.sym) { // retjmp
+ p->to.type = D_BRANCH;
+ } else {
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ }
+ break;
+ }
+ }
+
+ if(cursym->text->reg & WRAPPER) {
+ int scond;
+
+ // Preserve original RET's cond, to allow RET.EQ
+ // in the implementation of reflect.call.
+ scond = p->scond;
+ p->scond = C_SCOND_NONE;
+
+ // g->panicwrap -= autosize;
+ // MOVW panicwrap_offset(g), R3
+ // SUB $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*ctxt->arch->ptrsize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = ASUB;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(ctxt, p);
+
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+
+ p->scond = scond;
+ }
+
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so no spadj.
+
+ if(p->to.sym) { // retjmp
+ p->to.reg = REGLINK;
+ q2 = appendp(ctxt, p);
+ q2->as = AB;
+ q2->to.type = D_BRANCH;
+ q2->to.sym = p->to.sym;
+ p->to.sym = nil;
+ p = q2;
+ }
+ break;
+
+ case AADD:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+
+ case ASUB:
+ if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = p->from.offset;
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ if(ctxt->debugdivmod)
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->lineno = q1->lineno;
+ p->to.type = D_BRANCH;
+ switch(o) {
+ case ADIV:
+ p->to.sym = ctxt->sym_div;
+ break;
+ case ADIVU:
+ p->to.sym = ctxt->sym_divu;
+ break;
+ case AMOD:
+ p->to.sym = ctxt->sym_mod;
+ break;
+ case AMODU:
+ p->to.sym = ctxt->sym_modu;
+ break;
+ }
+
+ /* MOV REGTMP, b */
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->lineno = q1->lineno;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->lineno = q1->lineno;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ p->spadj = -8;
+
+ /* 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(ctxt, 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;
+ case AMOVW:
+ if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
+ p->spadj = -p->to.offset;
+ if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
+ p->spadj = -p->from.offset;
+ if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
+ p->spadj = -p->from.offset;
+ break;
+ }
+ }
+}
+
+static void
+softfloat(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *next;
+ LSym *symsfloat;
+ int wasfloat;
+
+ if(ctxt->goarm > 5)
+ return;
+
+ symsfloat = linklookup(ctxt, "_sfloat", 0);
+
+ wasfloat = 0;
+ for(p = cursym->text; p != nil; p = p->link)
+ if(p->pcond != nil)
+ p->pcond->mark |= LABEL;
+ for(p = cursym->text; p != nil; p = p->link) {
+ switch(p->as) {
+ case AMOVW:
+ if(p->to.type == D_FREG || p->from.type == D_FREG)
+ goto soft;
+ goto notsoft;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ case AMOVF:
+ case AMOVD:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case ASQRTF:
+ case ASQRTD:
+ case AABSF:
+ case AABSD:
+ goto soft;
+
+ default:
+ goto notsoft;
+
+ soft:
+ if (!wasfloat || (p->mark&LABEL)) {
+ next = ctxt->arch->prg();
+ *next = *p;
+
+ // BL _sfloat(SB)
+ *p = zprg;
+ p->link = next;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symsfloat;
+ p->lineno = next->lineno;
+
+ p = next;
+ wasfloat = 1;
+ }
+ break;
+
+ notsoft:
+ wasfloat = 0;
+ }
+ }
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
+{
+ int32 arg;
+
+ // MOVW g_stackguard(g), R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ if(framesize <= StackSmall) {
+ // small stack: SP < stackguard
+ // CMP stackguard, SP
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = REGSP;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize < stackguard-StackSmall
+ // MOVW $-framesize(SP), R2
+ // CMP stackguard, R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = -framesize;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+ } else {
+ // Such a large stack we need to protect against wraparound
+ // if SP is close to zero.
+ // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ // CMP $StackPreempt, R1
+ // MOVW.NE $StackGuard(SP), R2
+ // SUB.NE R1, R2
+ // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
+ // CMP.NE R3, R2
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_CONST;
+ p->from.offset = (uint32)StackPreempt;
+ p->reg = 1;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = StackGuard;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = ASUB;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = framesize + (StackGuard - StackSmall);
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->reg = 2;
+ p->scond = C_SCOND_NE;
+ }
+
+ // MOVW.LS $framesize, R1
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ p->from.offset = framesize;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LS $args, R2
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ arg = ctxt->cursym->text->to.offset2;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ if(arg&3)
+ ctxt->diag("misaligned argument size in stack split");
+ p->from.offset = arg;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW.LS R14, R3
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted
+ p = appendp(ctxt, p);
+ p->as = ABL;
+ p->scond = C_SCOND_LS;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[noctxt];
+
+ // BLS start
+ p = appendp(ctxt, p);
+ p->as = ABLS;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ return p;
+}
+
+static void
+initdiv(Link *ctxt)
+{
+ if(ctxt->sym_div != nil)
+ return;
+ ctxt->sym_div = linklookup(ctxt, "_div", 0);
+ ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
+ ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
+ ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+relinv(int a)
+{
+ switch(a) {
+ case ABEQ: return ABNE;
+ case ABNE: return ABEQ;
+ case ABCS: return ABCC;
+ case ABHS: return ABLO;
+ case ABCC: return ABCS;
+ case ABLO: return ABHS;
+ case ABMI: return ABPL;
+ case ABPL: return ABMI;
+ case ABVS: return ABVC;
+ case ABVC: return ABVS;
+ case ABHI: return ABLS;
+ case ABLS: return ABHI;
+ case ABGE: return ABLT;
+ case ABLT: return ABGE;
+ case ABGT: return ABLE;
+ case ABLE: return ABGT;
+ }
+ sysfatal("unknown relation: %s", anames5[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == nil)
+ return;
+ a = p->as;
+ if(a == AB) {
+ q = p->pcond;
+ if(q != nil && q->as != ATEXT) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == *last || q == nil)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
+ goto copy;
+ if(q->pcond == nil || (q->pcond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = ctxt->arch->prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("can't happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ (*last)->link = r;
+ *last = r;
+ continue;
+ }
+ (*last)->link = r;
+ *last = r;
+ if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->pcond = p->link;
+ r->link = p->pcond;
+ if(!(r->link->mark&FOLL))
+ xfol(ctxt, r->link, last);
+ if(!(r->pcond->mark&FOLL))
+ print("can't happen 2\n");
+ return;
+ }
+ }
+ a = AB;
+ q = ctxt->arch->prg();
+ q->as = a;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ (*last)->link = p;
+ *last = p;
+ if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){
+ return;
+ }
+ if(p->pcond != nil)
+ if(a != ABL && a != ABX && p->link != nil) {
+ q = brchain(ctxt, p->link);
+ if(a != ATEXT && a != ABCASE)
+ if(q != nil && (q->mark&FOLL)) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ xfol(ctxt, p->link, last);
+ q = brchain(ctxt, p->pcond);
+ if(q == nil)
+ q = p->pcond;
+ if(q->mark&FOLL) {
+ p->pcond = q;
+ return;
+ }
+ p = q;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+LinkArch linkarm = {
+ .name = "arm",
+ .thechar = '5',
+
+ .addstacksplit = addstacksplit,
+ .assemble = span5,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 4,
+ .ptrsize = 4,
+ .regsize = 4,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ABL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = AB,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
new file mode 100644
index 000000000..b1bcd0dc0
--- /dev/null
+++ b/src/liblink/obj6.c
@@ -0,0 +1,1171 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+ .back = 2,
+ .as = AGOK,
+ .from = {
+ .type = D_NONE,
+ .index = D_NONE,
+ },
+ .to = {
+ .type = D_NONE,
+ .index = D_NONE,
+ },
+};
+
+static void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+static int
+symtype(Addr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return t;
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->from.scale = f;
+}
+
+static void nacladdr(Link*, Prog*, Addr*);
+
+static int
+canuselocaltls(Link *ctxt)
+{
+ switch(ctxt->headtype) {
+// case Hlinux:
+ case Hwindows:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ char literal[64];
+ LSym *s;
+ Prog *q;
+
+ // Thread-local storage references use the TLS pseudo-register.
+ // As a register, TLS refers to the thread-local storage base, and it
+ // can only be loaded into another register:
+ //
+ // MOVQ TLS, AX
+ //
+ // An offset from the thread-local storage base is written off(reg)(TLS*1).
+ // Semantically it is off(reg), but the (TLS*1) annotation marks this as
+ // indexing from the loaded TLS base. This emits a relocation so that
+ // if the linker needs to adjust the offset, it can. For example:
+ //
+ // MOVQ TLS, AX
+ // MOVQ 8(AX)(TLS*1), CX // load m into CX
+ //
+ // On systems that support direct access to the TLS memory, this
+ // pair of instructions can be reduced to a direct TLS memory reference:
+ //
+ // MOVQ 8(TLS), CX // load m into CX
+ //
+ // The 2-instruction and 1-instruction forms correspond roughly to
+ // ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
+ //
+ // We applies this rewrite on systems that support the 1-instruction form.
+ // The decision is made using only the operating system (and probably
+ // the -shared flag, eventually), not the link mode. If some link modes
+ // on a particular operating system require the 2-instruction form,
+ // then all builds for that operating system will use the 2-instruction
+ // form, so that the link mode decision can be delayed to link time.
+ //
+ // In this way, all supported systems use identical instructions to
+ // access TLS, and they are rewritten appropriately first here in
+ // liblink and then finally using relocations in the linker.
+
+ if(canuselocaltls(ctxt)) {
+ // Reduce TLS initial exec model to TLS local exec model.
+ // Sequences like
+ // MOVQ TLS, BX
+ // ... off(BX)(TLS*1) ...
+ // become
+ // NOP
+ // ... off(TLS) ...
+ //
+ // TODO(rsc): Remove the Hsolaris special case. It exists only to
+ // guarantee we are producing byte-identical binaries as before this code.
+ // But it should be unnecessary.
+ if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_R15 && ctxt->headtype != Hsolaris)
+ nopout(p);
+ if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_R15) {
+ p->from.type = D_INDIR+D_TLS;
+ p->from.scale = 0;
+ p->from.index = D_NONE;
+ }
+ if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_R15) {
+ p->to.type = D_INDIR+D_TLS;
+ p->to.scale = 0;
+ p->to.index = D_NONE;
+ }
+ } else {
+ // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
+ // The instruction
+ // MOVQ off(TLS), BX
+ // becomes the sequence
+ // MOVQ TLS, BX
+ // MOVQ off(BX)(TLS*1), BX
+ // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+ if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_R15) {
+ q = appendp(ctxt, p);
+ q->as = p->as;
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->from.index = D_TLS;
+ q->from.scale = 2; // TODO: use 1
+ q->to = p->to;
+ p->from.type = D_TLS;
+ p->from.index = D_NONE;
+ p->from.offset = 0;
+ }
+ }
+
+ // TODO: Remove.
+ if(ctxt->headtype == Hwindows || ctxt->headtype == Hplan9) {
+ if(p->from.scale == 1 && p->from.index == D_TLS)
+ p->from.scale = 2;
+ if(p->to.scale == 1 && p->to.index == D_TLS)
+ p->to.scale = 2;
+ }
+
+ if(ctxt->headtype == Hnacl) {
+ nacladdr(ctxt, p, &p->from);
+ nacladdr(ctxt, p, &p->to);
+ }
+
+ // Maintain information about code generation mode.
+ if(ctxt->mode == 0)
+ ctxt->mode = 64;
+ p->mode = ctxt->mode;
+
+ switch(p->as) {
+ case AMODE:
+ if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE) {
+ switch((int)p->from.offset) {
+ case 16:
+ case 32:
+ case 64:
+ ctxt->mode = p->from.offset;
+ break;
+ }
+ }
+ nopout(p);
+ break;
+ }
+
+ // Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+ switch(p->as) {
+ case ACALL:
+ case AJMP:
+ case ARET:
+ if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
+ p->to.type = D_BRANCH;
+ break;
+ }
+
+ // Rewrite float constants to values stored in memory.
+ switch(p->as) {
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(p->from.type == D_FCONST) {
+ int32 i32;
+ float32 f32;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ sprint(literal, "$f32.%08ux", (uint32)i32);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ break;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(p->from.type == D_FCONST) {
+ int64 i64;
+ memmove(&i64, &p->from.u.dval, 8);
+ sprint(literal, "$f64.%016llux", (uvlong)i64);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ break;
+ }
+}
+
+static void
+nacladdr(Link *ctxt, Prog *p, Addr *a)
+{
+ if(p->as == ALEAL || p->as == ALEAQ)
+ return;
+
+ if(a->type == D_BP || a->type == D_INDIR+D_BP) {
+ ctxt->diag("invalid address: %P", p);
+ return;
+ }
+ if(a->type == D_INDIR+D_TLS)
+ a->type = D_INDIR+D_BP;
+ else if(a->type == D_TLS)
+ a->type = D_BP;
+ if(D_INDIR <= a->type && a->type <= D_INDIR+D_INDIR) {
+ switch(a->type) {
+ case D_INDIR+D_BP:
+ case D_INDIR+D_SP:
+ case D_INDIR+D_R15:
+ // all ok
+ break;
+ default:
+ if(a->index != D_NONE)
+ ctxt->diag("invalid address %P", p);
+ a->index = a->type - D_INDIR;
+ if(a->index != D_NONE)
+ a->scale = 1;
+ a->type = D_INDIR+D_R15;
+ break;
+ }
+ }
+}
+
+static char*
+morename[] =
+{
+ "runtime.morestack00",
+ "runtime.morestack00_noctxt",
+ "runtime.morestack10",
+ "runtime.morestack10_noctxt",
+ "runtime.morestack01",
+ "runtime.morestack01_noctxt",
+ "runtime.morestack11",
+ "runtime.morestack11_noctxt",
+
+ "runtime.morestack8",
+ "runtime.morestack8_noctxt",
+ "runtime.morestack16",
+ "runtime.morestack16_noctxt",
+ "runtime.morestack24",
+ "runtime.morestack24_noctxt",
+ "runtime.morestack32",
+ "runtime.morestack32_noctxt",
+ "runtime.morestack40",
+ "runtime.morestack40_noctxt",
+ "runtime.morestack48",
+ "runtime.morestack48_noctxt",
+};
+
+static Prog* load_g_cx(Link*, Prog*);
+static Prog* stacksplit(Link*, Prog*, int32, int32, int, Prog**);
+static void indir_cx(Link*, Addr*);
+
+static void
+parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
+{
+ *textstksiz = arg & 0xffffffffLL;
+ if(*textstksiz & 0x80000000LL)
+ *textstksiz = -(-*textstksiz & 0xffffffffLL);
+
+ *textarg = (arg >> 32) & 0xffffffffLL;
+ if(*textarg & 0x80000000LL)
+ *textarg = 0;
+ *textarg = (*textarg+7) & ~7LL;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q, *q1;
+ int32 autoffset, deltasp;
+ int a, pcsize;
+ uint32 i;
+ vlong textstksiz, textarg;
+
+ if(ctxt->gmsym == nil)
+ ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+ if(ctxt->symmorestack[0] == nil) {
+ if(nelem(morename) > nelem(ctxt->symmorestack))
+ sysfatal("Link.symmorestack needs at least %d elements", nelem(morename));
+ for(i=0; i<nelem(morename); i++)
+ ctxt->symmorestack[i] = linklookup(ctxt, morename[i], 0);
+ }
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ parsetextconst(p->to.offset, &textstksiz, &textarg);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ cursym->args = p->to.offset>>32;
+ cursym->locals = textstksiz;
+
+ if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
+ for(q = p; q != nil; q = q->link) {
+ if(q->as == ACALL)
+ goto noleaf;
+ if((q->as == ADUFFCOPY || q->as == ADUFFZERO) && autoffset >= StackSmall - 8)
+ goto noleaf;
+ }
+ p->from.scale |= NOSPLIT;
+ noleaf:;
+ }
+
+ q = nil;
+ if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+ p = appendp(ctxt, p);
+ p = load_g_cx(ctxt, p); // load g into CX
+ }
+ if(!(cursym->text->from.scale & NOSPLIT))
+ p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+
+ if(autoffset) {
+ if(autoffset%ctxt->arch->regsize != 0)
+ ctxt->diag("unaligned stack size %d", autoffset);
+ p = appendp(ctxt, p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ } else {
+ // zero-byte stack adjustment.
+ // Insert a fake non-zero adjustment so that stkcheck can
+ // recognize the end of the stack-splitting prolog.
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = -ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = ctxt->arch->ptrsize;
+ }
+ if(q != nil)
+ q->pcond = p;
+ deltasp = autoffset;
+
+ if(cursym->text->from.scale & WRAPPER) {
+ // g->panicwrap += autoffset + ctxt->arch->regsize;
+ p = appendp(ctxt, p);
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->regsize;
+ indir_cx(ctxt, &p->to);
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+
+ if(ctxt->debugstack > 1 && autoffset) {
+ // 6l -K -K means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ indir_cx(ctxt, &p->from);
+ p->from.offset = 0;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+
+ if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+ // 6l -Z means zero the stack frame on entry.
+ // This slows down function calls but can help avoid
+ // false positives in garbage collection.
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_SP;
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset/8;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = AREP;
+
+ p = appendp(ctxt, p);
+ p->as = ASTOSQ;
+ }
+
+ for(; p != nil; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ ctxt->diag("unbalanced PUSH/POP");
+
+ if(cursym->text->from.scale & WRAPPER) {
+ p = load_g_cx(ctxt, p);
+ p = appendp(ctxt, p);
+ // g->panicwrap -= autoffset + ctxt->arch->regsize;
+ p->as = ASUBL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->regsize;
+ indir_cx(ctxt, &p->to);
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ }
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
+ }
+}
+
+static void
+indir_cx(Link *ctxt, Addr *a)
+{
+ if(ctxt->headtype == Hnacl) {
+ a->type = D_INDIR + D_R15;
+ a->index = D_CX;
+ a->scale = 1;
+ return;
+ }
+
+ a->type = D_INDIR+D_CX;
+}
+
+// Append code to p to load g into cx.
+// Overwrites p with the first instruction (no first appendp).
+// Overwriting p is unusual but it lets use this in both the
+// prologue (caller must call appendp first) and in the epilogue.
+// Returns last new instruction.
+static Prog*
+load_g_cx(Link *ctxt, Prog *p)
+{
+ Prog *next;
+
+ p->as = AMOVQ;
+ if(ctxt->arch->ptrsize == 4)
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_TLS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+
+ next = p->link;
+ progedit(ctxt, p);
+ while(p->link != next)
+ p = p->link;
+
+ if(p->from.index == D_TLS)
+ p->from.scale = 2;
+
+ return p;
+}
+
+// Append code to p to check for stack split.
+// Appends to (does not overwrite) p.
+// Assumes g is in CX.
+// Returns last new instruction.
+// On return, *jmpok is the instruction that should jump
+// to the stack frame allocation if no split is needed.
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog **jmpok)
+{
+ Prog *q, *q1;
+ uint32 moreconst1, moreconst2, i;
+ int cmp, lea, mov, sub;
+
+ cmp = ACMPQ;
+ lea = ALEAQ;
+ mov = AMOVQ;
+ sub = ASUBQ;
+
+ if(ctxt->headtype == Hnacl) {
+ cmp = ACMPL;
+ lea = ALEAL;
+ mov = AMOVL;
+ sub = ASUBL;
+ }
+
+ if(ctxt->debugstack) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
+
+ p = appendp(ctxt, p);
+ p->as = cmp;
+ indir_cx(ctxt, &p->from);
+ p->from.offset = 8;
+ p->to.type = D_SP;
+
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+
+ q1 = nil;
+ if(framesize <= StackSmall) {
+ // small stack: SP <= stackguard
+ // CMPQ SP, stackguard
+ p = appendp(ctxt, p);
+ p->as = cmp;
+ p->from.type = D_SP;
+ indir_cx(ctxt, &p->to);
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize <= stackguard-StackSmall
+ // LEAQ -xxx(SP), AX
+ // CMPQ AX, stackguard
+ p = appendp(ctxt, p);
+ p->as = lea;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(framesize-StackSmall);
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = cmp;
+ p->from.type = D_AX;
+ indir_cx(ctxt, &p->to);
+ } else {
+ // Such a large stack we need to protect against wraparound.
+ // If SP is close to zero:
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // MOVQ stackguard, CX
+ // CMPQ CX, $StackPreempt
+ // JEQ label-of-call-to-morestack
+ // LEAQ StackGuard(SP), AX
+ // SUBQ CX, AX
+ // CMPQ AX, $(framesize+(StackGuard-StackSmall))
+
+ p = appendp(ctxt, p);
+ p->as = mov;
+ indir_cx(ctxt, &p->from);
+ p->from.offset = 0;
+ p->to.type = D_SI;
+
+ p = appendp(ctxt, p);
+ p->as = cmp;
+ p->from.type = D_SI;
+ p->to.type = D_CONST;
+ p->to.offset = StackPreempt;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = lea;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = StackGuard;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = sub;
+ p->from.type = D_SI;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = cmp;
+ p->from.type = D_AX;
+ p->to.type = D_CONST;
+ p->to.offset = framesize+(StackGuard-StackSmall);
+ }
+
+ // common
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q = p;
+
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
+ moreconst1 = 0;
+ if(StackTop + textarg + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+ moreconst1 = framesize;
+ moreconst2 = textarg;
+ if(moreconst2 == 1) // special marker
+ moreconst2 = 0;
+ if((moreconst2&7) != 0)
+ ctxt->diag("misaligned argument size in stack split");
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(ctxt, p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[0*2+noctxt];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[1*2+noctxt];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[i*2+noctxt];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[2*2+noctxt];
+ } else {
+ // Pass framesize and argsize.
+ p->as = AMOVQ;
+ p->from.type = D_CONST;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[3*2+noctxt];
+ }
+
+ p = appendp(ctxt, p);
+ p->as = AJMP;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ if(q != nil)
+ q->pcond = p->link;
+ if(q1 != nil)
+ q1->pcond = q->link;
+
+ *jmpok = q;
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ case AUNDEF:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+relinv(int a)
+{
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ sysfatal("unknown relation: %s", anames6[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == nil)
+ return;
+ if(p->as == AJMP)
+ if((q = p->pcond) != nil && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == nil)
+ break;
+ if(q == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
+ if(q->pcond == nil || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(ctxt, p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == nil || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(ctxt, q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = ctxt->arch->prg();
+ q->as = AJMP;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ if(p->pcond != nil && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
+ if((q = brchain(ctxt, p->pcond)) != nil)
+ p->pcond = q;
+ if((q = brchain(ctxt, p->link)) != nil)
+ p->link = q;
+ if(p->from.type == D_CONST) {
+ if(p->from.offset == 1) {
+ /*
+ * expect conditional jump to be taken.
+ * rewrite so that's the fall-through case.
+ */
+ p->as = relinv(a);
+ q = p->link;
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ } else {
+ q = p->link;
+ if(q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ }
+ xfol(ctxt, p->link, last);
+ if(p->pcond->mark)
+ return;
+ p = p->pcond;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+LinkArch linkamd64 = {
+ .name = "amd64",
+ .thechar = '6',
+
+ .addstacksplit = addstacksplit,
+ .assemble = span6,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 1,
+ .ptrsize = 8,
+ .regsize = 8,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ACALL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = AJMP,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};
+
+LinkArch linkamd64p32 = {
+ .name = "amd64p32",
+ .thechar = '6',
+
+ .addstacksplit = addstacksplit,
+ .assemble = span6,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 1,
+ .ptrsize = 4,
+ .regsize = 8,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ACALL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = AJMP,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
new file mode 100644
index 000000000..72934c149
--- /dev/null
+++ b/src/liblink/obj8.c
@@ -0,0 +1,859 @@
+// Inferno utils/8l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+ .back = 2,
+ .as = AGOK,
+ .from = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 1,
+ },
+ .to = {
+ .type = D_NONE,
+ .index = D_NONE,
+ .scale = 1,
+ },
+};
+
+static int
+symtype(Addr *a)
+{
+ int t;
+
+ t = a->type;
+ if(t == D_ADDR)
+ t = a->index;
+ return t;
+}
+
+static int
+isdata(Prog *p)
+{
+ return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+ return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+ return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+ return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+ p->from.scale = f;
+}
+
+static int
+canuselocaltls(Link *ctxt)
+{
+ switch(ctxt->headtype) {
+ case Hlinux:
+ case Hnacl:
+ case Hplan9:
+ case Hwindows:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+ char literal[64];
+ LSym *s;
+ Prog *q;
+
+ // See obj6.c for discussion of TLS.
+ if(canuselocaltls(ctxt)) {
+ // Reduce TLS initial exec model to TLS local exec model.
+ // Sequences like
+ // MOVL TLS, BX
+ // ... off(BX)(TLS*1) ...
+ // become
+ // NOP
+ // ... off(TLS) ...
+ if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+ }
+ if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
+ p->from.type = D_INDIR+D_TLS;
+ p->from.scale = 0;
+ p->from.index = D_NONE;
+ }
+ if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
+ p->to.type = D_INDIR+D_TLS;
+ p->to.scale = 0;
+ p->to.index = D_NONE;
+ }
+ } else {
+ // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
+ // The instruction
+ // MOVL off(TLS), BX
+ // becomes the sequence
+ // MOVL TLS, BX
+ // MOVL off(BX)(TLS*1), BX
+ // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+ if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+ q = appendp(ctxt, p);
+ q->as = p->as;
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->from.index = D_TLS;
+ q->from.scale = 2; // TODO: use 1
+ q->to = p->to;
+ p->from.type = D_TLS;
+ p->from.index = D_NONE;
+ p->from.offset = 0;
+ }
+ }
+
+ // TODO: Remove.
+ if(ctxt->headtype == Hplan9) {
+ if(p->from.scale == 1 && p->from.index == D_TLS)
+ p->from.scale = 2;
+ if(p->to.scale == 1 && p->to.index == D_TLS)
+ p->to.scale = 2;
+ }
+
+ // Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+ switch(p->as) {
+ case ACALL:
+ case AJMP:
+ case ARET:
+ if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
+ p->to.type = D_BRANCH;
+ break;
+ }
+
+ // Rewrite float constants to values stored in memory.
+ switch(p->as) {
+ case AFMOVF:
+ case AFADDF:
+ case AFSUBF:
+ case AFSUBRF:
+ case AFMULF:
+ case AFDIVF:
+ case AFDIVRF:
+ case AFCOMF:
+ case AFCOMFP:
+ case AMOVSS:
+ case AADDSS:
+ case ASUBSS:
+ case AMULSS:
+ case ADIVSS:
+ case ACOMISS:
+ case AUCOMISS:
+ if(p->from.type == D_FCONST) {
+ int32 i32;
+ float32 f32;
+ f32 = p->from.u.dval;
+ memmove(&i32, &f32, 4);
+ sprint(literal, "$f32.%08ux", (uint32)i32);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ break;
+
+ case AFMOVD:
+ case AFADDD:
+ case AFSUBD:
+ case AFSUBRD:
+ case AFMULD:
+ case AFDIVD:
+ case AFDIVRD:
+ case AFCOMD:
+ case AFCOMDP:
+ case AMOVSD:
+ case AADDSD:
+ case ASUBSD:
+ case AMULSD:
+ case ADIVSD:
+ case ACOMISD:
+ case AUCOMISD:
+ if(p->from.type == D_FCONST) {
+ int64 i64;
+ memmove(&i64, &p->from.u.dval, 8);
+ sprint(literal, "$f64.%016llux", (uvlong)i64);
+ s = linklookup(ctxt, literal, 0);
+ if(s->type == 0) {
+ s->type = SRODATA;
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = 0;
+ }
+ break;
+ }
+}
+
+static Prog*
+prg(void)
+{
+ Prog *p;
+
+ p = emallocz(sizeof(*p));
+ *p = zprg;
+ return p;
+}
+
+static Prog* load_g_cx(Link*, Prog*);
+static Prog* stacksplit(Link*, Prog*, int32, int, Prog**);
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+ Prog *p, *q;
+ int32 autoffset, deltasp;
+ int a;
+
+ if(ctxt->symmorestack[0] == nil) {
+ ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+ ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+ }
+
+ if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
+ ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
+
+ ctxt->cursym = cursym;
+
+ if(cursym->text == nil || cursym->text->link == nil)
+ return;
+
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ cursym->locals = autoffset;
+ cursym->args = p->to.offset2;
+
+ q = nil;
+
+ if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+ p = appendp(ctxt, p);
+ p = load_g_cx(ctxt, p); // load g into CX
+ }
+ if(!(cursym->text->from.scale & NOSPLIT))
+ p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+
+ if(autoffset) {
+ p = appendp(ctxt, p);
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ } else {
+ // zero-byte stack adjustment.
+ // Insert a fake non-zero adjustment so that stkcheck can
+ // recognize the end of the stack-splitting prolog.
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = -ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p->spadj = ctxt->arch->ptrsize;
+ }
+ if(q != nil)
+ q->pcond = p;
+ deltasp = autoffset;
+
+ if(cursym->text->from.scale & WRAPPER) {
+ // g->panicwrap += autoffset + ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ }
+
+ if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
+ // 8l -Z means zero the stack frame on entry.
+ // This slows down function calls but can help avoid
+ // false positives in garbage collection.
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_SP;
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset/4;
+ p->to.type = D_CX;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = AREP;
+
+ p = appendp(ctxt, p);
+ p->as = ASTOSL;
+ }
+
+ for(; p != nil; p = p->link) {
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ ctxt->diag("unbalanced PUSH/POP");
+
+ if(cursym->text->from.scale & WRAPPER) {
+ p = load_g_cx(ctxt, p);
+ p = appendp(ctxt, p);
+ // g->panicwrap -= autoffset + ctxt->arch->ptrsize;
+ p->as = ASUBL;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset + ctxt->arch->ptrsize;
+ p->to.type = D_INDIR+D_CX;
+ p->to.offset = 2*ctxt->arch->ptrsize;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ }
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(ctxt, p);
+ p->as = ARET;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so undo
+ // the cleanup.
+ p->spadj = +autoffset;
+ }
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
+ }
+}
+
+// Append code to p to load g into cx.
+// Overwrites p with the first instruction (no first appendp).
+// Overwriting p is unusual but it lets use this in both the
+// prologue (caller must call appendp first) and in the epilogue.
+// Returns last new instruction.
+static Prog*
+load_g_cx(Link *ctxt, Prog *p)
+{
+ Prog *next;
+
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_TLS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+
+ next = p->link;
+ progedit(ctxt, p);
+ while(p->link != next)
+ p = p->link;
+
+ if(p->from.index == D_TLS)
+ p->from.scale = 2;
+
+ return p;
+}
+
+// Append code to p to check for stack split.
+// Appends to (does not overwrite) p.
+// Assumes g is in CX.
+// Returns last new instruction.
+// On return, *jmpok is the instruction that should jump
+// to the stack frame allocation if no split is needed.
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
+{
+ Prog *q, *q1;
+ int arg;
+
+ if(ctxt->debugstack) {
+ // 8l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info.
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 4;
+ p->to.type = D_SP;
+
+ p = appendp(ctxt, p);
+ p->as = AJCC;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+ q1 = nil;
+
+ if(framesize <= StackSmall) {
+ // small stack: SP <= stackguard
+ // CMPL SP, stackguard
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize <= stackguard-StackSmall
+ // LEAL -(framesize-StackSmall)(SP), AX
+ // CMPL AX, stackguard
+ p = appendp(ctxt, p);
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(framesize-StackSmall);
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // Such a large stack we need to protect against wraparound
+ // if SP is close to zero.
+ // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ //
+ // Preemption sets stackguard to StackPreempt, a very large value.
+ // That breaks the math above, so we have to check for that explicitly.
+ // MOVL stackguard, CX
+ // CMPL CX, $StackPreempt
+ // JEQ label-of-call-to-morestack
+ // LEAL StackGuard(SP), AX
+ // SUBL stackguard, AX
+ // CMPL AX, $(framesize+(StackGuard-StackSmall))
+ p = appendp(ctxt, p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_SI;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_SI;
+ p->to.type = D_CONST;
+ p->to.offset = (uint32)StackPreempt;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = StackGuard;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ASUBL;
+ p->from.type = D_SI;
+ p->from.offset = 0;
+ p->to.type = D_AX;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_CONST;
+ p->to.offset = framesize+(StackGuard-StackSmall);
+ }
+
+ // common
+ p = appendp(ctxt, p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
+
+ p = appendp(ctxt, p); // save frame size in DI
+ p->as = AMOVL;
+ p->to.type = D_DI;
+ p->from.type = D_CONST;
+
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
+ if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+ p->from.offset = (framesize+7) & ~7LL;
+
+ arg = ctxt->cursym->text->to.offset2;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ if(arg&3)
+ ctxt->diag("misaligned argument size in stack split");
+ p = appendp(ctxt, p); // save arg size in AX
+ p->as = AMOVL;
+ p->to.type = D_AX;
+ p->from.type = D_CONST;
+ p->from.offset = arg;
+
+ p = appendp(ctxt, p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->to.sym = ctxt->symmorestack[noctxt];
+
+ p = appendp(ctxt, p);
+ p->as = AJMP;
+ p->to.type = D_BRANCH;
+ p->pcond = ctxt->cursym->text->link;
+
+ if(q != nil)
+ q->pcond = p->link;
+ if(q1 != nil)
+ q1->pcond = q->link;
+
+ *jmpok = q;
+ return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+ Prog *firstp, *lastp;
+
+ ctxt->cursym = s;
+
+ firstp = ctxt->arch->prg();
+ lastp = firstp;
+ xfol(ctxt, s->text, &lastp);
+ lastp->link = nil;
+ s->text = firstp->link;
+}
+
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETW:
+ case AUNDEF:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+relinv(int a)
+{
+
+ switch(a) {
+ case AJEQ: return AJNE;
+ case AJNE: return AJEQ;
+ case AJLE: return AJGT;
+ case AJLS: return AJHI;
+ case AJLT: return AJGE;
+ case AJMI: return AJPL;
+ case AJGE: return AJLT;
+ case AJPL: return AJMI;
+ case AJGT: return AJLE;
+ case AJHI: return AJLS;
+ case AJCS: return AJCC;
+ case AJCC: return AJCS;
+ case AJPS: return AJPC;
+ case AJPC: return AJPS;
+ case AJOS: return AJOC;
+ case AJOC: return AJOS;
+ }
+ sysfatal("unknown relation: %s", anames8[a]);
+ return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+ Prog *q;
+ int i;
+ enum as a;
+
+loop:
+ if(p == nil)
+ return;
+ if(p->as == AJMP)
+ if((q = p->pcond) != nil && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ if(p->mark) {
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == nil)
+ break;
+ if(q == *last)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
+ if(q->pcond == nil || q->pcond->mark)
+ continue;
+ if(a == ACALL || a == ALOOP)
+ continue;
+ for(;;) {
+ if(p->as == ANOP) {
+ p = p->link;
+ continue;
+ }
+ q = copyp(ctxt, p);
+ p = p->link;
+ q->mark = 1;
+ (*last)->link = q;
+ *last = q;
+ if(q->as != a || q->pcond == nil || q->pcond->mark)
+ continue;
+
+ q->as = relinv(q->as);
+ p = q->pcond;
+ q->pcond = q->link;
+ q->link = p;
+ xfol(ctxt, q->link, last);
+ p = q->link;
+ if(p->mark)
+ return;
+ goto loop;
+ }
+ } /* */
+ q = ctxt->arch->prg();
+ q->as = AJMP;
+ q->lineno = p->lineno;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->pcond = p;
+ p = q;
+ }
+
+ /* emit p */
+ p->mark = 1;
+ (*last)->link = p;
+ *last = p;
+ a = p->as;
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
+ return;
+ if(p->pcond != nil && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
+ if((q = brchain(ctxt, p->pcond)) != nil)
+ p->pcond = q;
+ if((q = brchain(ctxt, p->link)) != nil)
+ p->link = q;
+ if(p->from.type == D_CONST) {
+ if(p->from.offset == 1) {
+ /*
+ * expect conditional jump to be taken.
+ * rewrite so that's the fall-through case.
+ */
+ p->as = relinv(a);
+ q = p->link;
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ } else {
+ q = p->link;
+ if(q->mark)
+ if(a != ALOOP) {
+ p->as = relinv(a);
+ p->link = p->pcond;
+ p->pcond = q;
+ }
+ }
+ xfol(ctxt, p->link, last);
+ if(p->pcond->mark)
+ return;
+ p = p->pcond;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+LinkArch link386 = {
+ .name = "386",
+ .thechar = '8',
+
+ .addstacksplit = addstacksplit,
+ .assemble = span8,
+ .datasize = datasize,
+ .follow = follow,
+ .iscall = iscall,
+ .isdata = isdata,
+ .prg = prg,
+ .progedit = progedit,
+ .settextflag = settextflag,
+ .symtype = symtype,
+ .textflag = textflag,
+
+ .minlc = 1,
+ .ptrsize = 4,
+ .regsize = 4,
+
+ .D_ADDR = D_ADDR,
+ .D_AUTO = D_AUTO,
+ .D_BRANCH = D_BRANCH,
+ .D_CONST = D_CONST,
+ .D_EXTERN = D_EXTERN,
+ .D_FCONST = D_FCONST,
+ .D_NONE = D_NONE,
+ .D_PARAM = D_PARAM,
+ .D_SCONST = D_SCONST,
+ .D_STATIC = D_STATIC,
+
+ .ACALL = ACALL,
+ .ADATA = ADATA,
+ .AEND = AEND,
+ .AFUNCDATA = AFUNCDATA,
+ .AGLOBL = AGLOBL,
+ .AJMP = AJMP,
+ .ANOP = ANOP,
+ .APCDATA = APCDATA,
+ .ARET = ARET,
+ .ATEXT = ATEXT,
+ .ATYPE = ATYPE,
+ .AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c
new file mode 100644
index 000000000..610f87954
--- /dev/null
+++ b/src/liblink/objfile.c
@@ -0,0 +1,746 @@
+// 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.
+
+// Writing and reading of Go object files.
+//
+// Originally, Go object files were Plan 9 object files, but no longer.
+// Now they are more like standard object files, in that each symbol is defined
+// by an associated memory image (bytes) and a list of relocations to apply
+// during linking. We do not (yet?) use a standard file format, however.
+// For now, the format is chosen to be as simple as possible to read and write.
+// It may change for reasons of efficiency, or we may even switch to a
+// standard file format if there are compelling benefits to doing so.
+// See golang.org/s/go13linker for more background.
+//
+// The file format is:
+//
+// - magic header: "\x00\x00go13ld"
+// - byte 1 - version number
+// - sequence of strings giving dependencies (imported packages)
+// - empty string (marks end of sequence)
+// - sequence of defined symbols
+// - byte 0xff (marks end of sequence)
+// - magic footer: "\xff\xffgo13ld"
+//
+// All integers are stored in a zigzag varint format.
+// See golang.org/s/go12symtab for a definition.
+//
+// Data blocks and strings are both stored as an integer
+// followed by that many bytes.
+//
+// A symbol reference is a string name followed by a version.
+// An empty name corresponds to a nil LSym* pointer.
+//
+// Each symbol is laid out as the following fields (taken from LSym*):
+//
+// - byte 0xfe (sanity check for synchronization)
+// - type [int]
+// - name [string]
+// - version [int]
+// - dupok [int]
+// - size [int]
+// - gotype [symbol reference]
+// - p [data block]
+// - nr [int]
+// - r [nr relocations, sorted by off]
+//
+// If type == STEXT, there are a few more fields:
+//
+// - args [int]
+// - locals [int]
+// - nosplit [int]
+// - leaf [int]
+// - nlocal [int]
+// - local [nlocal automatics]
+// - pcln [pcln table]
+//
+// Each relocation has the encoding:
+//
+// - off [int]
+// - siz [int]
+// - type [int]
+// - add [int]
+// - xadd [int]
+// - sym [symbol reference]
+// - xsym [symbol reference]
+//
+// Each local has the encoding:
+//
+// - asym [symbol reference]
+// - offset [int]
+// - type [int]
+// - gotype [symbol reference]
+//
+// The pcln table has the encoding:
+//
+// - pcsp [data block]
+// - pcfile [data block]
+// - pcline [data block]
+// - npcdata [int]
+// - pcdata [npcdata data blocks]
+// - nfuncdata [int]
+// - funcdata [nfuncdata symbol references]
+// - funcdatasym [nfuncdata ints]
+// - nfile [int]
+// - file [nfile symbol references]
+//
+// The file layout and meaning of type integers are architecture-independent.
+//
+// TODO(rsc): The file format is good for a first pass but needs work.
+// - There are SymID in the object file that should really just be strings.
+// - The actual symbol memory images are interlaced with the symbol
+// metadata. They should be separated, to reduce the I/O required to
+// load just the metadata.
+// - The symbol references should be shortened, either with a symbol
+// table or by using a simple backward index to an earlier mentioned symbol.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/ld/textflag.h"
+
+static void writesym(Link*, Biobuf*, LSym*);
+static void wrint(Biobuf*, int64);
+static void wrstring(Biobuf*, char*);
+static void wrpath(Link *, Biobuf*, char*);
+static void wrdata(Biobuf*, void*, int);
+static void wrsym(Biobuf*, LSym*);
+static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
+
+static void readsym(Link*, Biobuf*, char*, char*);
+static int64 rdint(Biobuf*);
+static char *rdstring(Biobuf*);
+static void rddata(Biobuf*, uchar**, int*);
+static LSym *rdsym(Link*, Biobuf*, char*);
+
+// The Go and C compilers, and the assembler, call writeobj to write
+// out a Go object file. The linker does not call this; the linker
+// does not write out object files.
+void
+writeobj(Link *ctxt, Biobuf *b)
+{
+ int flag;
+ Hist *h;
+ LSym *s, *text, *etext, *curtext, *data, *edata;
+ Plist *pl;
+ Prog *p, *plink;
+ Auto *a;
+
+ // Build list of symbols, and assign instructions to lists.
+ // Ignore ctxt->plist boundaries. There are no guarantees there,
+ // and the C compilers and assemblers just use one big list.
+ text = nil;
+ curtext = nil;
+ data = nil;
+ etext = nil;
+ edata = nil;
+ for(pl = ctxt->plist; pl != nil; pl = pl->link) {
+ for(p = pl->firstpc; p != nil; p = plink) {
+ plink = p->link;
+ p->link = nil;
+
+ if(p->as == ctxt->arch->AEND)
+ continue;
+
+ if(p->as == ctxt->arch->ATYPE) {
+ // Assume each TYPE instruction describes
+ // a different local variable or parameter,
+ // so no dedup.
+ // Using only the TYPE instructions means
+ // that we discard location information about local variables
+ // in C and assembly functions; that information is inferred
+ // from ordinary references, because there are no TYPE
+ // instructions there. Without the type information, gdb can't
+ // use the locations, so we don't bother to save them.
+ // If something else could use them, we could arrange to
+ // preserve them.
+ if(curtext == nil)
+ continue;
+ a = emallocz(sizeof *a);
+ a->asym = p->from.sym;
+ a->aoffset = p->from.offset;
+ a->type = ctxt->arch->symtype(&p->from);
+ a->gotype = p->from.gotype;
+ a->link = curtext->autom;
+ curtext->autom = a;
+ continue;
+ }
+
+ if(p->as == ctxt->arch->AGLOBL) {
+ s = p->from.sym;
+ if(s->seenglobl++)
+ print("duplicate %P\n", p);
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(data == nil)
+ data = s;
+ else
+ edata->next = s;
+ s->next = nil;
+ s->size = p->to.offset;
+ if(s->type == 0 || s->type == SXREF)
+ s->type = SBSS;
+
+ if(ctxt->arch->thechar == '5')
+ flag = p->reg;
+ else
+ flag = p->from.scale;
+
+ if(flag & DUPOK)
+ s->dupok = 1;
+ if(flag & RODATA)
+ s->type = SRODATA;
+ else if(flag & NOPTR)
+ s->type = SNOPTRBSS;
+ edata = s;
+ continue;
+ }
+
+ if(p->as == ctxt->arch->ADATA) {
+ savedata(ctxt, p->from.sym, p, "<input>");
+ continue;
+ }
+
+ if(p->as == ctxt->arch->ATEXT) {
+ s = p->from.sym;
+ if(s == nil) {
+ // func _() { }
+ curtext = nil;
+ continue;
+ }
+ if(s->text != nil)
+ sysfatal("duplicate TEXT for %s", s->name);
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(text == nil)
+ text = s;
+ else
+ etext->next = s;
+ etext = s;
+ if(ctxt->arch->thechar == '5')
+ flag = p->reg;
+ else
+ flag = p->from.scale;
+ if(flag & DUPOK)
+ s->dupok = 1;
+ if(flag & NOSPLIT)
+ s->nosplit = 1;
+ s->next = nil;
+ s->type = STEXT;
+ s->text = p;
+ s->etext = p;
+ curtext = s;
+ continue;
+ }
+
+ if(curtext == nil)
+ continue;
+ s = curtext;
+ s->etext->link = p;
+ s->etext = p;
+ }
+ }
+
+ // Turn functions into machine code images.
+ for(s = text; s != nil; s = s->next) {
+ mkfwd(s);
+ linkpatch(ctxt, s);
+ ctxt->arch->follow(ctxt, s);
+ ctxt->arch->addstacksplit(ctxt, s);
+ ctxt->arch->assemble(ctxt, s);
+ linkpcln(ctxt, s);
+ }
+
+ // Emit header.
+ Bputc(b, 0);
+ Bputc(b, 0);
+ Bprint(b, "go13ld");
+ Bputc(b, 1); // version
+
+ // Emit autolib.
+ for(h = ctxt->hist; h != nil; h = h->link)
+ if(h->offset < 0)
+ wrstring(b, h->name);
+ wrstring(b, "");
+
+ // Emit symbols.
+ for(s = text; s != nil; s = s->next)
+ writesym(ctxt, b, s);
+ for(s = data; s != nil; s = s->next)
+ writesym(ctxt, b, s);
+
+ // Emit footer.
+ Bputc(b, 0xff);
+ Bputc(b, 0xff);
+ Bprint(b, "go13ld");
+}
+
+static void
+writesym(Link *ctxt, Biobuf *b, LSym *s)
+{
+ Reloc *r;
+ int i, j, c, n;
+ Pcln *pc;
+ Prog *p;
+ Auto *a;
+ char *name;
+
+ if(ctxt->debugasm) {
+ Bprint(ctxt->bso, "%s ", s->name);
+ if(s->version)
+ Bprint(ctxt->bso, "v=%d ", s->version);
+ if(s->type)
+ Bprint(ctxt->bso, "t=%d ", s->type);
+ if(s->dupok)
+ Bprint(ctxt->bso, "dupok ");
+ if(s->nosplit)
+ Bprint(ctxt->bso, "nosplit ");
+ Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
+ if(s->type == STEXT) {
+ Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
+ if(s->leaf)
+ Bprint(ctxt->bso, " leaf");
+ }
+ Bprint(ctxt->bso, "\n");
+ for(p=s->text; p != nil; p = p->link)
+ Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
+ for(i=0; i<s->np; ) {
+ Bprint(ctxt->bso, "\t%#06ux", i);
+ for(j=i; j<i+16 && j<s->np; j++)
+ Bprint(ctxt->bso, " %02ux", s->p[j]);
+ for(; j<i+16; j++)
+ Bprint(ctxt->bso, " ");
+ Bprint(ctxt->bso, " ");
+ for(j=i; j<i+16 && j<s->np; j++) {
+ c = s->p[j];
+ if(' ' <= c && c <= 0x7e)
+ Bprint(ctxt->bso, "%c", c);
+ else
+ Bprint(ctxt->bso, ".");
+ }
+ Bprint(ctxt->bso, "\n");
+ i += 16;
+ }
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ name = "";
+ if(r->sym != nil)
+ name = r->sym->name;
+ Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
+ }
+ }
+
+ Bputc(b, 0xfe);
+ wrint(b, s->type);
+ wrstring(b, s->name);
+ wrint(b, s->version);
+ wrint(b, s->dupok);
+ wrint(b, s->size);
+ wrsym(b, s->gotype);
+ wrdata(b, s->p, s->np);
+
+ wrint(b, s->nr);
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ wrint(b, r->off);
+ wrint(b, r->siz);
+ wrint(b, r->type);
+ wrint(b, r->add);
+ wrint(b, r->xadd);
+ wrsym(b, r->sym);
+ wrsym(b, r->xsym);
+ }
+
+ if(s->type == STEXT) {
+ wrint(b, s->args);
+ wrint(b, s->locals);
+ wrint(b, s->nosplit);
+ wrint(b, s->leaf);
+ n = 0;
+ for(a = s->autom; a != nil; a = a->link)
+ n++;
+ wrint(b, n);
+ for(a = s->autom; a != nil; a = a->link) {
+ wrsym(b, a->asym);
+ wrint(b, a->aoffset);
+ if(a->type == ctxt->arch->D_AUTO)
+ wrint(b, A_AUTO);
+ else if(a->type == ctxt->arch->D_PARAM)
+ wrint(b, A_PARAM);
+ else
+ sysfatal("%s: invalid local variable type %d", s->name, a->type);
+ wrsym(b, a->gotype);
+ }
+
+ pc = s->pcln;
+ wrdata(b, pc->pcsp.p, pc->pcsp.n);
+ wrdata(b, pc->pcfile.p, pc->pcfile.n);
+ wrdata(b, pc->pcline.p, pc->pcline.n);
+ wrint(b, pc->npcdata);
+ for(i=0; i<pc->npcdata; i++)
+ wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
+ wrint(b, pc->nfuncdata);
+ for(i=0; i<pc->nfuncdata; i++)
+ wrsym(b, pc->funcdata[i]);
+ for(i=0; i<pc->nfuncdata; i++)
+ wrint(b, pc->funcdataoff[i]);
+ wrint(b, pc->nfile);
+ for(i=0; i<pc->nfile; i++)
+ wrpathsym(ctxt, b, pc->file[i]);
+ }
+}
+
+static void
+wrint(Biobuf *b, int64 sval)
+{
+ uint64 uv, v;
+ uchar buf[10], *p;
+
+ uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
+
+ p = buf;
+ for(v = uv; v >= 0x80; v >>= 7)
+ *p++ = v | 0x80;
+ *p++ = v;
+
+ Bwrite(b, buf, p - buf);
+}
+
+static void
+wrstring(Biobuf *b, char *s)
+{
+ wrdata(b, s, strlen(s));
+}
+
+// wrpath writes a path just like a string, but on windows, it
+// translates '\\' to '/' in the process.
+static void
+wrpath(Link *ctxt, Biobuf *b, char *p)
+{
+ int i, n;
+ if (!ctxt->windows || strchr(p, '\\') == nil) {
+ wrstring(b, p);
+ return;
+ } else {
+ n = strlen(p);
+ wrint(b, n);
+ for (i = 0; i < n; i++)
+ Bputc(b, p[i] == '\\' ? '/' : p[i]);
+ }
+}
+
+static void
+wrdata(Biobuf *b, void *v, int n)
+{
+ wrint(b, n);
+ Bwrite(b, v, n);
+}
+
+static void
+wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
+{
+ if(s == nil) {
+ wrint(b, 0);
+ wrint(b, 0);
+ return;
+ }
+ wrpath(ctxt, b, s->name);
+ wrint(b, s->version);
+}
+
+static void
+wrsym(Biobuf *b, LSym *s)
+{
+ if(s == nil) {
+ wrint(b, 0);
+ wrint(b, 0);
+ return;
+ }
+ wrstring(b, s->name);
+ wrint(b, s->version);
+}
+
+static char startmagic[] = "\x00\x00go13ld";
+static char endmagic[] = "\xff\xffgo13ld";
+
+void
+ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int c;
+ uchar buf[8];
+ int64 start;
+ char *lib;
+
+ start = Boffset(f);
+ ctxt->version++;
+ memset(buf, 0, sizeof buf);
+ Bread(f, buf, sizeof buf);
+ if(memcmp(buf, startmagic, sizeof buf) != 0)
+ sysfatal("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ if((c = Bgetc(f)) != 1)
+ sysfatal("%s: invalid file version number %d", pn, c);
+
+ for(;;) {
+ lib = rdstring(f);
+ if(lib[0] == 0)
+ break;
+ addlib(ctxt, pkg, pn, lib);
+ }
+
+ for(;;) {
+ c = Bgetc(f);
+ Bungetc(f);
+ if(c == 0xff)
+ break;
+ readsym(ctxt, f, pkg, pn);
+ }
+
+ memset(buf, 0, sizeof buf);
+ Bread(f, buf, sizeof buf);
+ if(memcmp(buf, endmagic, sizeof buf) != 0)
+ sysfatal("%s: invalid file end", pn);
+
+ if(Boffset(f) != start+len)
+ sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
+}
+
+static void
+readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
+{
+ int i, j, c, t, v, n, size, dupok;
+ static int ndup;
+ char *name;
+ Reloc *r;
+ LSym *s, *dup;
+ Pcln *pc;
+ Auto *a;
+
+ if(Bgetc(f) != 0xfe)
+ sysfatal("readsym out of sync");
+ t = rdint(f);
+ name = expandpkg(rdstring(f), pkg);
+ v = rdint(f);
+ if(v != 0 && v != 1)
+ sysfatal("invalid symbol version %d", v);
+ dupok = rdint(f);
+ size = rdint(f);
+
+ if(v != 0)
+ v = ctxt->version;
+ s = linklookup(ctxt, name, v);
+ dup = nil;
+ if(s->type != 0 && s->type != SXREF) {
+ if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
+ sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
+ if(s->np > 0) {
+ dup = s;
+ s = linknewsym(ctxt, ".dup", ndup++); // scratch
+ }
+ }
+ s->file = pkg;
+ s->dupok = dupok;
+ if(t == SXREF)
+ sysfatal("bad sxref");
+ if(t == 0)
+ sysfatal("missing type for %s in %s", name, pn);
+ s->type = t;
+ if(s->size < size)
+ s->size = size;
+ s->gotype = rdsym(ctxt, f, pkg);
+ rddata(f, &s->p, &s->np);
+ s->maxp = s->np;
+ n = rdint(f);
+ if(n > 0) {
+ s->r = emallocz(n * sizeof s->r[0]);
+ s->nr = n;
+ s->maxr = n;
+ for(i=0; i<n; i++) {
+ r = &s->r[i];
+ r->off = rdint(f);
+ r->siz = rdint(f);
+ r->type = rdint(f);
+ r->add = rdint(f);
+ r->xadd = rdint(f);
+ r->sym = rdsym(ctxt, f, pkg);
+ r->xsym = rdsym(ctxt, f, pkg);
+ }
+ }
+
+ if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
+ // content-addressed garbage collection liveness bitmap symbol.
+ // double check for hash collisions.
+ if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
+ sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
+ }
+
+ if(s->type == STEXT) {
+ s->args = rdint(f);
+ s->locals = rdint(f);
+ s->nosplit = rdint(f);
+ s->leaf = rdint(f);
+ n = rdint(f);
+ for(i=0; i<n; i++) {
+ a = emallocz(sizeof *a);
+ a->asym = rdsym(ctxt, f, pkg);
+ a->aoffset = rdint(f);
+ a->type = rdint(f);
+ a->gotype = rdsym(ctxt, f, pkg);
+ a->link = s->autom;
+ s->autom = a;
+ }
+
+ s->pcln = emallocz(sizeof *s->pcln);
+ pc = s->pcln;
+ rddata(f, &pc->pcsp.p, &pc->pcsp.n);
+ rddata(f, &pc->pcfile.p, &pc->pcfile.n);
+ rddata(f, &pc->pcline.p, &pc->pcline.n);
+ n = rdint(f);
+ pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
+ pc->npcdata = n;
+ for(i=0; i<n; i++)
+ rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
+ n = rdint(f);
+ pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
+ pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
+ pc->nfuncdata = n;
+ for(i=0; i<n; i++)
+ pc->funcdata[i] = rdsym(ctxt, f, pkg);
+ for(i=0; i<n; i++)
+ pc->funcdataoff[i] = rdint(f);
+ n = rdint(f);
+ pc->file = emallocz(n * sizeof pc->file[0]);
+ pc->nfile = n;
+ for(i=0; i<n; i++)
+ pc->file[i] = rdsym(ctxt, f, pkg);
+
+ if(dup == nil) {
+ if(s->onlist)
+ sysfatal("symbol %s listed multiple times", s->name);
+ s->onlist = 1;
+ if(ctxt->etextp)
+ ctxt->etextp->next = s;
+ else
+ ctxt->textp = s;
+ ctxt->etextp = s;
+ }
+ }
+
+ if(ctxt->debugasm) {
+ Bprint(ctxt->bso, "%s ", s->name);
+ if(s->version)
+ Bprint(ctxt->bso, "v=%d ", s->version);
+ if(s->type)
+ Bprint(ctxt->bso, "t=%d ", s->type);
+ if(s->dupok)
+ Bprint(ctxt->bso, "dupok ");
+ if(s->nosplit)
+ Bprint(ctxt->bso, "nosplit ");
+ Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
+ if(s->type == STEXT)
+ Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
+ Bprint(ctxt->bso, "\n");
+ for(i=0; i<s->np; ) {
+ Bprint(ctxt->bso, "\t%#06ux", i);
+ for(j=i; j<i+16 && j<s->np; j++)
+ Bprint(ctxt->bso, " %02ux", s->p[j]);
+ for(; j<i+16; j++)
+ Bprint(ctxt->bso, " ");
+ Bprint(ctxt->bso, " ");
+ for(j=i; j<i+16 && j<s->np; j++) {
+ c = s->p[j];
+ if(' ' <= c && c <= 0x7e)
+ Bprint(ctxt->bso, "%c", c);
+ else
+ Bprint(ctxt->bso, ".");
+ }
+ Bprint(ctxt->bso, "\n");
+ i += 16;
+ }
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
+ }
+ }
+}
+
+static int64
+rdint(Biobuf *f)
+{
+ int c;
+ uint64 uv;
+ int shift;
+
+ uv = 0;
+ for(shift = 0;; shift += 7) {
+ if(shift >= 64)
+ sysfatal("corrupt input");
+ c = Bgetc(f);
+ uv |= (uint64)(c & 0x7F) << shift;
+ if(!(c & 0x80))
+ break;
+ }
+
+ return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
+}
+
+static char*
+rdstring(Biobuf *f)
+{
+ int n;
+ char *p;
+
+ n = rdint(f);
+ p = emallocz(n+1);
+ Bread(f, p, n);
+ return p;
+}
+
+static void
+rddata(Biobuf *f, uchar **pp, int *np)
+{
+ *np = rdint(f);
+ *pp = emallocz(*np);
+ Bread(f, *pp, *np);
+}
+
+static LSym*
+rdsym(Link *ctxt, Biobuf *f, char *pkg)
+{
+ int n, v;
+ char *p;
+ LSym *s;
+
+ n = rdint(f);
+ if(n == 0) {
+ rdint(f);
+ return nil;
+ }
+ p = emallocz(n+1);
+ Bread(f, p, n);
+ v = rdint(f);
+ if(v != 0)
+ v = ctxt->version;
+ s = linklookup(ctxt, expandpkg(p, pkg), v);
+
+ if(v == 0 && s->name[0] == '$' && s->type == 0) {
+ if(strncmp(s->name, "$f32.", 5) == 0) {
+ int32 i32;
+ i32 = strtoul(s->name+5, nil, 16);
+ s->type = SRODATA;
+ adduint32(ctxt, s, i32);
+ s->reachable = 0;
+ } else if(strncmp(s->name, "$f64.", 5) == 0) {
+ int64 i64;
+ i64 = strtoull(s->name+5, nil, 16);
+ s->type = SRODATA;
+ adduint64(ctxt, s, i64);
+ s->reachable = 0;
+ }
+ }
+
+ return s;
+}
diff --git a/src/liblink/pass.c b/src/liblink/pass.c
new file mode 100644
index 000000000..bc8eb4367
--- /dev/null
+++ b/src/liblink/pass.c
@@ -0,0 +1,115 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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.
+
+// Code and data passes.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+Prog*
+brchain(Link *ctxt, Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == nil || p->as != ctxt->arch->AJMP)
+ return p;
+ p = p->pcond;
+ }
+ return nil;
+}
+
+Prog*
+brloop(Link *ctxt, Prog *p)
+{
+ int c;
+ Prog *q;
+
+ c = 0;
+ for(q = p; q != nil; q = q->pcond) {
+ if(q->as != ctxt->arch->AJMP)
+ break;
+ c++;
+ if(c >= 5000)
+ return nil;
+ }
+ return q;
+}
+
+void
+linkpatch(Link *ctxt, LSym *sym)
+{
+ int32 c;
+ Prog *p, *q;
+
+ ctxt->cursym = sym;
+
+ for(p = sym->text; p != nil; p = p->link) {
+ if(ctxt->arch->progedit)
+ ctxt->arch->progedit(ctxt, p);
+ if(p->to.type != ctxt->arch->D_BRANCH)
+ continue;
+ if(p->to.u.branch != nil) {
+ // TODO: Remove to.u.branch in favor of p->pcond.
+ p->pcond = p->to.u.branch;
+ continue;
+ }
+ if(p->to.sym != nil)
+ continue;
+ c = p->to.offset;
+ for(q = sym->text; q != nil;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != nil && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
+ }
+ if(q == nil) {
+ ctxt->diag("branch out of range (%#ux)\n%P [%s]",
+ c, p, p->to.sym ? p->to.sym->name : "<nil>");
+ p->to.type = ctxt->arch->D_NONE;
+ }
+ p->to.u.branch = q;
+ p->pcond = q;
+ }
+
+ for(p = sym->text; p != nil; p = p->link) {
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != nil) {
+ p->pcond = brloop(ctxt, p->pcond);
+ if(p->pcond != nil)
+ if(p->to.type == ctxt->arch->D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
+ }
+}
diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c
new file mode 100644
index 000000000..4b2b85543
--- /dev/null
+++ b/src/liblink/pcln.c
@@ -0,0 +1,365 @@
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static void
+addvarint(Link *ctxt, Pcdata *d, uint32 val)
+{
+ int32 n;
+ uint32 v;
+ uchar *p;
+
+ USED(ctxt);
+
+ n = 0;
+ for(v = val; v >= 0x80; v >>= 7)
+ n++;
+ n++;
+
+ if(d->n + n > d->m) {
+ d->m = (d->n + n)*2;
+ d->p = erealloc(d->p, d->m);
+ }
+
+ p = d->p + d->n;
+ for(v = val; v >= 0x80; v >>= 7)
+ *p++ = v | 0x80;
+ *p = v;
+ d->n += n;
+}
+
+// funcpctab writes to dst a pc-value table mapping the code in func to the values
+// returned by valfunc parameterized by arg. The invocation of valfunc to update the
+// current value is, for each p,
+//
+// val = valfunc(func, val, p, 0, arg);
+// record val as value at p->pc;
+// val = valfunc(func, val, p, 1, arg);
+//
+// where func is the function, val is the current value, p is the instruction being
+// considered, and arg can be used to further parameterize valfunc.
+static void
+funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
+{
+ int dbg, i;
+ int32 oldval, val, started;
+ uint32 delta;
+ vlong pc;
+ Prog *p;
+
+ // To debug a specific function, uncomment second line and change name.
+ dbg = 0;
+ //dbg = strcmp(func->name, "main.main") == 0;
+ //dbg = strcmp(desc, "pctofile") == 0;
+
+ ctxt->debugpcln += dbg;
+
+ dst->n = 0;
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
+
+ val = -1;
+ oldval = val;
+ if(func->text == nil) {
+ ctxt->debugpcln -= dbg;
+ return;
+ }
+
+ pc = func->text->pc;
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
+
+ started = 0;
+ for(p=func->text; p != nil; p = p->link) {
+ // Update val. If it's not changing, keep going.
+ val = valfunc(ctxt, func, val, p, 0, arg);
+ if(val == oldval && started) {
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
+ continue;
+ }
+
+ // If the pc of the next instruction is the same as the
+ // pc of this instruction, this instruction is not a real
+ // instruction. Keep going, so that we only emit a delta
+ // for a true instruction boundary in the program.
+ if(p->link && p->link->pc == p->pc) {
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
+ continue;
+ }
+
+ // The table is a sequence of (value, pc) pairs, where each
+ // pair states that the given value is in effect from the current position
+ // up to the given pc, which becomes the new current position.
+ // To generate the table as we scan over the program instructions,
+ // we emit a "(value" when pc == func->value, and then
+ // each time we observe a change in value we emit ", pc) (value".
+ // When the scan is over, we emit the closing ", pc)".
+ //
+ // The table is delta-encoded. The value deltas are signed and
+ // transmitted in zig-zag form, where a complement bit is placed in bit 0,
+ // and the pc deltas are unsigned. Both kinds of deltas are sent
+ // as variable-length little-endian base-128 integers,
+ // where the 0x80 bit indicates that the integer continues.
+
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
+
+ if(started) {
+ addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
+ pc = p->pc;
+ }
+ delta = val - oldval;
+ if(delta>>31)
+ delta = 1 | ~(delta<<1);
+ else
+ delta <<= 1;
+ addvarint(ctxt, dst, delta);
+ oldval = val;
+ started = 1;
+ val = valfunc(ctxt, func, val, p, 1, arg);
+ }
+
+ if(started) {
+ if(ctxt->debugpcln)
+ Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
+ addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
+ addvarint(ctxt, dst, 0); // terminator
+ }
+
+ if(ctxt->debugpcln) {
+ Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
+ for(i=0; i<dst->n; i++)
+ Bprint(ctxt->bso, " %02ux", dst->p[i]);
+ Bprint(ctxt->bso, "\n");
+ }
+
+ ctxt->debugpcln -= dbg;
+}
+
+// pctofileline computes either the file number (arg == 0)
+// or the line number (arg == 1) to use at p.
+// Because p->lineno applies to p, phase == 0 (before p)
+// takes care of the update.
+static int32
+pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ int32 i, l;
+ LSym *f;
+ Pcln *pcln;
+
+ USED(sym);
+
+ if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
+ return oldval;
+ linkgetline(ctxt, p->lineno, &f, &l);
+ if(f == nil) {
+ // print("getline failed for %s %P\n", ctxt->cursym->name, p);
+ return oldval;
+ }
+ if(arg == nil)
+ return l;
+ pcln = arg;
+
+ if(f == pcln->lastfile)
+ return pcln->lastindex;
+
+ for(i=0; i<pcln->nfile; i++) {
+ if(pcln->file[i] == f) {
+ pcln->lastfile = f;
+ pcln->lastindex = i;
+ return i;
+ }
+ }
+
+ if(pcln->nfile >= pcln->mfile) {
+ pcln->mfile = (pcln->nfile+1)*2;
+ pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
+ }
+ pcln->file[pcln->nfile++] = f;
+ pcln->lastfile = f;
+ pcln->lastindex = i;
+ return i;
+}
+
+// pctospadj computes the sp adjustment in effect.
+// It is oldval plus any adjustment made by p itself.
+// The adjustment by p takes effect only after p, so we
+// apply the change during phase == 1.
+static int32
+pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ USED(arg);
+ USED(sym);
+
+ if(oldval == -1) // starting
+ oldval = 0;
+ if(phase == 0)
+ return oldval;
+ if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
+ ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
+ sysfatal("bad code");
+ }
+ return oldval + p->spadj;
+}
+
+// pctopcdata computes the pcdata value in effect at p.
+// A PCDATA instruction sets the value in effect at future
+// non-PCDATA instructions.
+// Since PCDATA instructions have no width in the final code,
+// it does not matter which phase we use for the update.
+static int32
+pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+ USED(sym);
+
+ if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
+ return oldval;
+ if((int32)p->to.offset != p->to.offset) {
+ ctxt->diag("overflow in PCDATA instruction: %P", p);
+ sysfatal("bad code");
+ }
+ return p->to.offset;
+}
+
+void
+linkpcln(Link *ctxt, LSym *cursym)
+{
+ Prog *p;
+ Pcln *pcln;
+ int i, npcdata, nfuncdata, n;
+ uint32 *havepc, *havefunc;
+
+ ctxt->cursym = cursym;
+
+ pcln = emallocz(sizeof *pcln);
+ cursym->pcln = pcln;
+
+ npcdata = 0;
+ nfuncdata = 0;
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
+ npcdata = p->from.offset+1;
+ if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
+ nfuncdata = p->from.offset+1;
+ }
+
+ pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
+ pcln->npcdata = npcdata;
+ pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
+ pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
+ pcln->nfuncdata = nfuncdata;
+
+ funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
+ funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
+ funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
+
+ // tabulate which pc and func data we have.
+ n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
+ havepc = emallocz(n);
+ havefunc = havepc + (npcdata+31)/32;
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->AFUNCDATA) {
+ if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
+ ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
+ havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
+ }
+ if(p->as == ctxt->arch->APCDATA)
+ havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
+ }
+ // pcdata.
+ for(i=0; i<npcdata; i++) {
+ if(!(havepc[i/32]>>(i%32))&1)
+ continue;
+ funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
+ }
+ free(havepc);
+
+ // funcdata
+ if(nfuncdata > 0) {
+ for(p = cursym->text; p != nil; p = p->link) {
+ if(p->as == ctxt->arch->AFUNCDATA) {
+ i = p->from.offset;
+ pcln->funcdataoff[i] = p->to.offset;
+ if(p->to.type != ctxt->arch->D_CONST) {
+ // TODO: Dedup.
+ //funcdata_bytes += p->to.sym->size;
+ pcln->funcdata[i] = p->to.sym;
+ }
+ }
+ }
+ }
+}
+
+// iteration over encoded pcdata tables.
+
+static uint32
+getvarint(uchar **pp)
+{
+ uchar *p;
+ int shift;
+ uint32 v;
+
+ v = 0;
+ p = *pp;
+ for(shift = 0;; shift += 7) {
+ v |= (uint32)(*p & 0x7F) << shift;
+ if(!(*p++ & 0x80))
+ break;
+ }
+ *pp = p;
+ return v;
+}
+
+void
+pciternext(Pciter *it)
+{
+ uint32 v;
+ int32 dv;
+
+ it->pc = it->nextpc;
+ if(it->done)
+ return;
+ if(it->p >= it->d.p + it->d.n) {
+ it->done = 1;
+ return;
+ }
+
+ // value delta
+ v = getvarint(&it->p);
+ if(v == 0 && !it->start) {
+ it->done = 1;
+ return;
+ }
+ it->start = 0;
+ dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
+ it->value += dv;
+
+ // pc delta
+ v = getvarint(&it->p);
+ it->nextpc = it->pc + v*it->pcscale;
+}
+
+void
+pciterinit(Link *ctxt, Pciter *it, Pcdata *d)
+{
+ it->d = *d;
+ it->p = it->d.p;
+ it->pc = 0;
+ it->nextpc = 0;
+ it->value = -1;
+ it->start = 1;
+ it->done = 0;
+ it->pcscale = ctxt->arch->minlc;
+ pciternext(it);
+}
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
new file mode 100644
index 000000000..cba50e9c7
--- /dev/null
+++ b/src/liblink/sym.c
@@ -0,0 +1,271 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static int
+yy_isalpha(int c)
+{
+ return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+static struct {
+ char *name;
+ int val;
+} headers[] = {
+ "darwin", Hdarwin,
+ "dragonfly", Hdragonfly,
+ "elf", Helf,
+ "freebsd", Hfreebsd,
+ "linux", Hlinux,
+ "nacl", Hnacl,
+ "netbsd", Hnetbsd,
+ "openbsd", Hopenbsd,
+ "plan9", Hplan9,
+ "solaris", Hsolaris,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
+};
+
+int
+headtype(char *name)
+{
+ int i;
+
+ for(i=0; headers[i].name; i++)
+ if(strcmp(name, headers[i].name) == 0)
+ return headers[i].val;
+ return -1;
+}
+
+char*
+headstr(int v)
+{
+ static char buf[20];
+ int i;
+
+ for(i=0; headers[i].name; i++)
+ if(v == headers[i].val)
+ return headers[i].name;
+ snprint(buf, sizeof buf, "%d", v);
+ return buf;
+}
+
+Link*
+linknew(LinkArch *arch)
+{
+ Link *ctxt;
+ char *p;
+ char buf[1024];
+
+ nuxiinit();
+
+ ctxt = emallocz(sizeof *ctxt);
+ ctxt->arch = arch;
+ ctxt->version = HistVersion;
+ ctxt->goroot = getgoroot();
+ ctxt->goroot_final = getenv("GOROOT_FINAL");
+ if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
+ ctxt->goroot_final = nil;
+
+ p = getgoarch();
+ if(strcmp(p, arch->name) != 0)
+ sysfatal("invalid goarch %s (want %s)", p, arch->name);
+
+ if(getwd(buf, sizeof buf) == 0)
+ strcpy(buf, "/???");
+ if(yy_isalpha(buf[0]) && buf[1] == ':') {
+ // On Windows.
+ ctxt->windows = 1;
+
+ // Canonicalize path by converting \ to / (Windows accepts both).
+ for(p=buf; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+ }
+ ctxt->pathname = strdup(buf);
+
+ ctxt->headtype = headtype(getgoos());
+ if(ctxt->headtype < 0)
+ sysfatal("unknown goos %s", getgoos());
+
+ // Record thread-local storage offset.
+ // TODO(rsc): Move tlsoffset back into the linker.
+ switch(ctxt->headtype) {
+ default:
+ sysfatal("unknown thread-local storage offset for %s", headstr(ctxt->headtype));
+ case Hplan9:
+ ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
+ break;
+ case Hwindows:
+ break;
+ case Hlinux:
+ case Hfreebsd:
+ case Hnetbsd:
+ case Hopenbsd:
+ case Hdragonfly:
+ case Hsolaris:
+ /*
+ * ELF uses TLS offset negative from FS.
+ * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+ * Known to low-level assembly in package runtime and runtime/cgo.
+ */
+ ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
+ break;
+
+ case Hnacl:
+ switch(ctxt->arch->thechar) {
+ default:
+ sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
+ case '6':
+ ctxt->tlsoffset = 0;
+ break;
+ case '8':
+ ctxt->tlsoffset = -8;
+ break;
+ }
+ break;
+
+ case Hdarwin:
+ /*
+ * OS X system constants - offset from 0(GS) to our TLS.
+ * Explained in ../../pkg/runtime/cgo/gcc_darwin_*.c.
+ */
+ switch(ctxt->arch->thechar) {
+ default:
+ sysfatal("unknown thread-local storage offset for darwin/%s", ctxt->arch->name);
+ case '6':
+ ctxt->tlsoffset = 0x8a0;
+ break;
+ case '8':
+ ctxt->tlsoffset = 0x468;
+ break;
+ }
+ break;
+ }
+
+ // On arm, record goarm.
+ if(ctxt->arch->thechar == '5') {
+ p = getgoarm();
+ if(p != nil)
+ ctxt->goarm = atoi(p);
+ else
+ ctxt->goarm = 6;
+ }
+
+ return ctxt;
+}
+
+LSym*
+linknewsym(Link *ctxt, char *symb, int v)
+{
+ LSym *s;
+ int l;
+
+ l = strlen(symb) + 1;
+ s = malloc(sizeof(*s));
+ memset(s, 0, sizeof(*s));
+
+ s->dynid = -1;
+ s->plt = -1;
+ s->got = -1;
+ s->name = malloc(l + 1);
+ memmove(s->name, symb, l);
+ s->name[l] = '\0';
+
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ s->sig = 0;
+ s->size = 0;
+ ctxt->nsymbol++;
+
+ s->allsym = ctxt->allsym;
+ ctxt->allsym = s;
+
+ return s;
+}
+
+static LSym*
+_lookup(Link *ctxt, char *symb, int v, int creat)
+{
+ LSym *s;
+ char *p;
+ uint32 h;
+ int c;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ h &= 0xffffff;
+ h %= LINKHASH;
+ for(s = ctxt->hash[h]; s != nil; s = s->hash)
+ if(s->version == v && strcmp(s->name, symb) == 0)
+ return s;
+ if(!creat)
+ return nil;
+
+ s = linknewsym(ctxt, symb, v);
+ s->extname = s->name;
+ s->hash = ctxt->hash[h];
+ ctxt->hash[h] = s;
+
+ return s;
+}
+
+LSym*
+linklookup(Link *ctxt, char *name, int v)
+{
+ return _lookup(ctxt, name, v, 1);
+}
+
+// read-only lookup
+LSym*
+linkrlookup(Link *ctxt, char *name, int v)
+{
+ return _lookup(ctxt, name, v, 0);
+}
+
+int
+linksymfmt(Fmt *f)
+{
+ LSym *s;
+
+ s = va_arg(f->args, LSym*);
+ if(s == nil)
+ return fmtstrcpy(f, "<nil>");
+
+ return fmtstrcpy(f, s->name);
+}
diff --git a/src/libmach/5.c b/src/libmach/5.c
deleted file mode 100644
index 9882c1acd..000000000
--- a/src/libmach/5.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// Inferno libmach/5.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * arm definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_arm.h"
-#include <mach.h>
-
-#define REGOFF(x) (uintptr) (&((struct Ureg *) 0)->x)
-
-#define SP REGOFF(r13)
-#define PC REGOFF(pc)
-
-#define REGSIZE sizeof(struct Ureg)
-
-Reglist armreglist[] =
-{
- {"LINK", REGOFF(link), RINT|RRDONLY, 'X'},
- {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'},
- {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
- {"PC", PC, RINT, 'X'},
- {"SP", SP, RINT, 'X'},
- {"R15", PC, RINT, 'X'},
- {"R14", REGOFF(r14), RINT, 'X'},
- {"R13", REGOFF(r13), RINT, 'X'},
- {"R12", REGOFF(r12), RINT, 'X'},
- {"R11", REGOFF(r11), RINT, 'X'},
- {"R10", REGOFF(r10), RINT, 'X'},
- {"R9", REGOFF(r9), RINT, 'X'},
- {"R8", REGOFF(r8), RINT, 'X'},
- {"R7", REGOFF(r7), RINT, 'X'},
- {"R6", REGOFF(r6), RINT, 'X'},
- {"R5", REGOFF(r5), RINT, 'X'},
- {"R4", REGOFF(r4), RINT, 'X'},
- {"R3", REGOFF(r3), RINT, 'X'},
- {"R2", REGOFF(r2), RINT, 'X'},
- {"R1", REGOFF(r1), RINT, 'X'},
- {"R0", REGOFF(r0), RINT, 'X'},
- { 0 }
-};
-
- /* the machine description */
-Mach marm =
-{
- "arm",
- MARM, /* machine type */
- armreglist, /* register set */
- REGSIZE, /* register set size */
- 0, /* fp register set size */
- "PC", /* name of PC */
- "SP", /* name of SP */
- "R15", /* name of link register */
- "setR12", /* static base register name */
- 0, /* static base register value */
- 0x1000, /* page size */
- 0xC0000000, /* kernel base */
- 0, /* kernel text mask */
- 4, /* quantization of pc */
- 4, /* szaddr */
- 4, /* szreg */
- 4, /* szfloat */
- 8, /* szdouble */
-};
diff --git a/src/libmach/5db.c b/src/libmach/5db.c
deleted file mode 100644
index ae71dd90d..000000000
--- a/src/libmach/5db.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Inferno libmach/5db.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_arm.h"
-#include <mach.h>
-
-static int debug = 0;
-
-#define BITS(a, b) ((1<<(b+1))-(1<<a))
-
-#define LSR(v, s) ((ulong)(v) >> (s))
-#define ASR(v, s) ((long)(v) >> (s))
-#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
-
-
-
-typedef struct Instr Instr;
-struct Instr
-{
- Map *map;
- ulong w;
- ulong addr;
- uchar op; /* super opcode */
-
- uchar cond; /* bits 28-31 */
- uchar store; /* bit 20 */
-
- uchar rd; /* bits 12-15 */
- uchar rn; /* bits 16-19 */
- uchar rs; /* bits 0-11 (shifter operand) */
-
- long imm; /* rotated imm */
- char* curr; /* fill point in buffer */
- char* end; /* end of buffer */
- char* err; /* error message */
-};
-
-typedef struct Opcode Opcode;
-struct Opcode
-{
- char* o;
- void (*fmt)(Opcode*, Instr*);
- ulong (*foll)(Map*, Rgetter, Instr*, ulong);
- char* a;
-};
-
-static void format(char*, Instr*, char*);
-static char FRAMENAME[] = ".frame";
-
-/*
- * Arm-specific debugger interface
- */
-
-extern char *armexcep(Map*, Rgetter);
-static int armfoll(Map*, uvlong, Rgetter, uvlong*);
-static int arminst(Map*, uvlong, char, char*, int);
-static int armdas(Map*, uvlong, char*, int);
-static int arminstlen(Map*, uvlong);
-
-/*
- * Debugger interface
- */
-Machdata armmach =
-{
- {0, 0, 0, 0xD}, /* break point */
- 4, /* break point size */
-
- leswab, /* short to local byte order */
- leswal, /* long to local byte order */
- leswav, /* long to local byte order */
- risctrace, /* C traceback */
- riscframe, /* Frame finder */
- armexcep, /* print exception */
- 0, /* breakpoint fixup */
- 0, /* single precision float printer */
- 0, /* double precision float printer */
- armfoll, /* following addresses */
- arminst, /* print instruction */
- armdas, /* dissembler */
- arminstlen, /* instruction size */
-};
-
-char*
-armexcep(Map *map, Rgetter rget)
-{
- long c;
-
- c = (*rget)(map, "TYPE");
- switch (c&0x1f) {
- case 0x11:
- return "Fiq interrupt";
- case 0x12:
- return "Mirq interrupt";
- case 0x13:
- return "SVC/SWI Exception";
- case 0x17:
- return "Prefetch Abort/Data Abort";
- case 0x18:
- return "Data Abort";
- case 0x1b:
- return "Undefined instruction/Breakpoint";
- case 0x1f:
- return "Sys trap";
- default:
- return "Undefined trap";
- }
-}
-
-static
-char* cond[16] =
-{
- "EQ", "NE", "CS", "CC",
- "MI", "PL", "VS", "VC",
- "HI", "LS", "GE", "LT",
- "GT", "LE", 0, "NV"
-};
-
-static
-char* shtype[4] =
-{
- "<<", ">>", "->", "@>"
-};
-
-static
-char *hb[4] =
-{
- "???", "HU", "B", "H"
-};
-
-static
-char* addsub[2] =
-{
- "-", "+",
-};
-
-int
-armclass(long w)
-{
- int op;
-
- op = (w >> 25) & 0x7;
- switch(op) {
- case 0: /* data processing r,r,r */
- op = ((w >> 4) & 0xf);
- if(op == 0x9) {
- op = 48+16; /* mul */
- if(w & (1<<24)) {
- op += 2;
- if(w & (1<<22))
- op++; /* swap */
- break;
- }
- if(w & (1<<21))
- op++; /* mla */
- break;
- }
- if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */
- {
- op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- }
- op = (w >> 21) & 0xf;
- if(w & (1<<4))
- op += 32;
- else
- if(w & (31<<7))
- op += 16;
- break;
- case 1: /* data processing i,r,r */
- op = (48) + ((w >> 21) & 0xf);
- break;
- case 2: /* load/store byte/word i(r) */
- op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- case 3: /* load/store byte/word (r)(r) */
- op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- case 4: /* block data transfer (r)(r) */
- op = (48+24+4+4) + ((w >> 20) & 0x1);
- break;
- case 5: /* branch / branch link */
- op = (48+24+4+4+2) + ((w >> 24) & 0x1);
- break;
- case 7: /* coprocessor crap */
- op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
- break;
- default:
- op = (48+24+4+4+2+2+4);
- break;
- }
- return op;
-}
-
-static int
-decode(Map *map, ulong pc, Instr *i)
-{
- uint32 w;
-
- if(get4(map, pc, &w) < 0) {
- werrstr("can't read instruction: %r");
- return -1;
- }
- i->w = w;
- i->addr = pc;
- i->cond = (w >> 28) & 0xF;
- i->op = armclass(w);
- i->map = map;
- return 1;
-}
-
-static void
-bprint(Instr *i, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- i->curr = vseprint(i->curr, i->end, fmt, arg);
- va_end(arg);
-}
-
-static int
-plocal(Instr *i)
-{
- char *reg;
- Symbol s;
- char *fn;
- int class;
- int offset;
-
- if(!findsym(i->addr, CTEXT, &s)) {
- if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
- return 0;
- }
- fn = s.name;
- if (!findlocal(&s, FRAMENAME, &s)) {
- if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
- return 0;
- }
- if(s.value > i->imm) {
- class = CAUTO;
- offset = s.value-i->imm;
- reg = "(SP)";
- } else {
- class = CPARAM;
- offset = i->imm-s.value-4;
- reg = "(FP)";
- }
- if(!getauto(&s, offset, class, &s)) {
- if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
- class == CAUTO ? " auto" : "param", offset);
- return 0;
- }
- bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
- return 1;
-}
-
-/*
- * Print value v as name[+offset]
- */
-int
-gsymoff(char *buf, int n, long v, int space)
-{
- Symbol s;
- int r;
- long delta;
-
- r = delta = 0; /* to shut compiler up */
- if (v) {
- r = findsym(v, space, &s);
- if (r)
- delta = v-s.value;
- if (delta < 0)
- delta = -delta;
- }
- if (v == 0 || r == 0 || delta >= 4096)
- return snprint(buf, n, "#%lux", v);
- if (strcmp(s.name, ".string") == 0)
- return snprint(buf, n, "#%lux", v);
- if (!delta)
- return snprint(buf, n, "%s", s.name);
- if (s.type != 't' && s.type != 'T')
- return snprint(buf, n, "%s+%llux", s.name, v-s.value);
- else
- return snprint(buf, n, "#%lux", v);
-}
-
-static void
-armdps(Opcode *o, Instr *i)
-{
- i->store = (i->w >> 20) & 1;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = (i->w >> 0) & 0xf;
- if(i->rn == 15 && i->rs == 0) {
- if(i->op == 8) {
- format("MOVW", i,"CPSR, R%d");
- return;
- } else
- if(i->op == 10) {
- format("MOVW", i,"SPSR, R%d");
- return;
- }
- } else
- if(i->rn == 9 && i->rd == 15) {
- if(i->op == 9) {
- format("MOVW", i, "R%s, CPSR");
- return;
- } else
- if(i->op == 11) {
- format("MOVW", i, "R%s, SPSR");
- return;
- }
- }
- format(o->o, i, o->a);
-}
-
-static void
-armdpi(Opcode *o, Instr *i)
-{
- ulong v;
- int c;
-
- v = (i->w >> 0) & 0xff;
- c = (i->w >> 8) & 0xf;
- while(c) {
- v = (v<<30) | (v>>2);
- c--;
- }
- i->imm = v;
- i->store = (i->w >> 20) & 1;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = i->w&0x0f;
-
- /* RET is encoded as ADD #0,R14,R15 */
- if((i->w & 0x0fffffff) == 0x028ef000){
- format("RET%C", i, "");
- return;
- }
- if((i->w & 0x0ff0ffff) == 0x0280f000){
- format("B%C", i, "0(R%n)");
- return;
- }
- format(o->o, i, o->a);
-}
-
-static void
-armsdti(Opcode *o, Instr *i)
-{
- ulong v;
-
- v = i->w & 0xfff;
- if(!(i->w & (1<<23)))
- v = -v;
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->imm = v;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- /* RET is encoded as LW.P x,R13,R15 */
- if ((i->w & 0x0ffff000) == 0x049df000)
- {
- format("RET%C%p", i, "%I");
- return;
- }
- format(o->o, i, o->a);
-}
-
-/* arm V4 ld/st halfword, signed byte */
-static void
-armhwby(Opcode *o, Instr *i)
-{
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
- if (!(i->w & (1 << 23)))
- i->imm = - i->imm;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = (i->w >> 0) & 0xf;
- format(o->o, i, o->a);
-}
-
-static void
-armsdts(Opcode *o, Instr *i)
-{
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->rs = (i->w >> 0) & 0xf;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- format(o->o, i, o->a);
-}
-
-static void
-armbdt(Opcode *o, Instr *i)
-{
- i->store = (i->w >> 21) & 0x3; /* S & W bits */
- i->rn = (i->w >> 16) & 0xf;
- i->imm = i->w & 0xffff;
- if(i->w == 0xe8fd8000)
- format("RFE", i, "");
- else
- format(o->o, i, o->a);
-}
-
-/*
-static void
-armund(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-
-static void
-armcdt(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-*/
-
-static void
-armunk(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-
-static void
-armb(Opcode *o, Instr *i)
-{
- ulong v;
-
- v = i->w & 0xffffff;
- if(v & 0x800000)
- v |= ~0xffffff;
- i->imm = (v<<2) + i->addr + 8;
- format(o->o, i, o->a);
-}
-
-static void
-armco(Opcode *o, Instr *i) /* coprocessor instructions */
-{
- int op, p, cp;
-
- char buf[1024];
-
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = i->w&0xf;
- cp = (i->w >> 8) & 0xf;
- p = (i->w >> 5) & 0x7;
- if(i->w&(1<<4)) {
- op = (i->w >> 21) & 0x07;
- snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
- } else {
- op = (i->w >> 20) & 0x0f;
- snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
- }
- format(o->o, i, buf);
-}
-
-static int
-armcondpass(Map *map, Rgetter rget, uchar cond)
-{
- ulong psr;
- uchar n;
- uchar z;
- uchar c;
- uchar v;
-
- psr = rget(map, "PSR");
- n = (psr >> 31) & 1;
- z = (psr >> 30) & 1;
- c = (psr >> 29) & 1;
- v = (psr >> 28) & 1;
-
- switch(cond) {
- case 0: return z;
- case 1: return !z;
- case 2: return c;
- case 3: return !c;
- case 4: return n;
- case 5: return !n;
- case 6: return v;
- case 7: return !v;
- case 8: return c && !z;
- case 9: return !c || z;
- case 10: return n == v;
- case 11: return n != v;
- case 12: return !z && (n == v);
- case 13: return z && (n != v);
- case 14: return 1;
- case 15: return 0;
- }
- return 0;
-}
-
-static ulong
-armshiftval(Map *map, Rgetter rget, Instr *i)
-{
- if(i->w & (1 << 25)) { /* immediate */
- ulong imm = i->w & BITS(0, 7);
- ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
- return ROR(imm, s);
- } else {
- char buf[8];
- ulong v;
- ulong s = (i->w & BITS(7,11)) >> 7;
-
- sprint(buf, "R%ld", i->w & 0xf);
- v = rget(map, buf);
-
- switch((i->w & BITS(4, 6)) >> 4) {
- case 0: /* LSLIMM */
- return v << s;
- case 1: /* LSLREG */
- sprint(buf, "R%lud", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) return 0;
- return v << s;
- case 2: /* LSRIMM */
- return LSR(v, s);
- case 3: /* LSRREG */
- sprint(buf, "R%ld", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) return 0;
- return LSR(v, s);
- case 4: /* ASRIMM */
- if(s == 0) {
- if((v & (1U<<31)) == 0)
- return 0;
- return 0xFFFFFFFF;
- }
- return ASR(v, s);
- case 5: /* ASRREG */
- sprint(buf, "R%ld", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) {
- if((v & (1U<<31)) == 0)
- return 0;
- return 0xFFFFFFFF;
- }
- return ASR(v, s);
- case 6: /* RORIMM */
- if(s == 0) {
- ulong c = (rget(map, "PSR") >> 29) & 1;
-
- return (c << 31) | LSR(v, 1);
- }
- return ROR(v, s);
- case 7: /* RORREG */
- sprint(buf, "R%ld", (s>>1)&0xF);
- s = rget(map, buf);
- if(s == 0 || (s & 0xF) == 0)
- return v;
- return ROR(v, s & 0xF);
- }
- }
- return 0;
-}
-
-static int
-nbits(ulong v)
-{
- int n = 0;
- int i;
-
- for(i=0; i < 32 ; i++) {
- if(v & 1) ++n;
- v >>= 1;
- }
-
- return n;
-}
-
-static ulong
-armmaddr(Map *map, Rgetter rget, Instr *i)
-{
- ulong v;
- ulong nb;
- char buf[8];
- ulong rn;
-
- rn = (i->w >> 16) & 0xf;
- sprint(buf,"R%ld", rn);
-
- v = rget(map, buf);
- nb = nbits(i->w & ((1 << 15) - 1));
-
- switch((i->w >> 23) & 3) {
- case 0: return (v - (nb*4)) + 4;
- case 1: return v;
- case 2: return v - (nb*4);
- case 3: return v + 4;
- }
- return 0;
-}
-
-static ulong
-armaddr(Map *map, Rgetter rget, Instr *i)
-{
- char buf[8];
- ulong rn;
-
- sprint(buf, "R%ld", (i->w >> 16) & 0xf);
- rn = rget(map, buf);
-
- if((i->w & (1<<24)) == 0) { /* POSTIDX */
- sprint(buf, "R%ld", rn);
- return rget(map, buf);
- }
-
- if((i->w & (1<<25)) == 0) { /* OFFSET */
- sprint(buf, "R%ld", rn);
- if(i->w & (1U<<23))
- return rget(map, buf) + (i->w & BITS(0,11));
- return rget(map, buf) - (i->w & BITS(0,11));
- } else { /* REGOFF */
- ulong index = 0;
- uchar c;
- uchar rm;
-
- sprint(buf, "R%ld", i->w & 0xf);
- rm = rget(map, buf);
-
- switch((i->w & BITS(5,6)) >> 5) {
- case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
- case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
- case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
- case 3:
- if((i->w & BITS(7,11)) == 0) {
- c = (rget(map, "PSR") >> 29) & 1;
- index = c << 31 | LSR(rm, 1);
- } else {
- index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
- }
- break;
- }
- if(i->w & (1<<23))
- return rn + index;
- return rn - index;
- }
-}
-
-static ulong
-armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- char buf[8];
- int r;
-
- r = (i->w >> 12) & 0xf;
- if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
- return pc+4;
-
- r = (i->w >> 16) & 0xf;
- sprint(buf, "R%d", r);
-
- return rget(map, buf) + armshiftval(map, rget, i);
-}
-
-static ulong
-armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- uint32 v;
- ulong addr;
-
- v = i->w & 1<<15;
- if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
- return pc+4;
-
- addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
- if(get4(map, addr, &v) < 0) {
- werrstr("can't read addr: %r");
- return -1;
- }
- return v;
-}
-
-static ulong
-armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
- return pc+4;
-
- return pc + (((signed long)i->w << 8) >> 6) + 8;
-}
-
-static ulong
-armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- ulong rd;
- uint32 v;
-
- rd = (i->w >> 12) & 0xf;
- if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
- return pc+4;
-
- /* LDR */
- /* BUG: Needs LDH/B, too */
- if(((i->w>>26)&0x3) == 1) {
- if(get4(map, armaddr(map, rget, i), &v) < 0) {
- werrstr("can't read instruction: %r");
- return pc+4;
- }
- return v;
- }
-
- /* MOV */
- return armshiftval(map, rget, i);
-}
-
-static Opcode opcodes[] =
-{
- "AND%C%S", armdps, 0, "R%s,R%n,R%d",
- "EOR%C%S", armdps, 0, "R%s,R%n,R%d",
- "SUB%C%S", armdps, 0, "R%s,R%n,R%d",
- "RSB%C%S", armdps, 0, "R%s,R%n,R%d",
- "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
- "ADC%C%S", armdps, 0, "R%s,R%n,R%d",
- "SBC%C%S", armdps, 0, "R%s,R%n,R%d",
- "RSC%C%S", armdps, 0, "R%s,R%n,R%d",
- "TST%C%S", armdps, 0, "R%s,R%n",
- "TEQ%C%S", armdps, 0, "R%s,R%n",
- "CMP%C%S", armdps, 0, "R%s,R%n",
- "CMN%C%S", armdps, 0, "R%s,R%n",
- "ORR%C%S", armdps, 0, "R%s,R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "R%s,R%d",
- "BIC%C%S", armdps, 0, "R%s,R%n,R%d",
- "MVN%C%S", armdps, 0, "R%s,R%d",
-
-/* 16 */
- "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
- "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "TST%C%S", armdps, 0, "(R%s%h%m),R%n",
- "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
- "CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
- "CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
- "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
- "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
-
-/* 32 */
- "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
- "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
- "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
-
-/* 48 */
- "AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
- "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "TST%C%S", armdpi, 0, "$#%i,R%n",
- "TEQ%C%S", armdpi, 0, "$#%i,R%n",
- "CMP%C%S", armdpi, 0, "$#%i,R%n",
- "CMN%C%S", armdpi, 0, "$#%i,R%n",
- "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
- "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "MVN%C%S", armdpi, 0, "$#%i,R%d",
-
-/* 48+16 */
- "MUL%C%S", armdpi, 0, "R%s,R%M,R%n",
- "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d",
- "SWPW", armdpi, 0, "R%s,(R%n),R%d",
- "SWPB", armdpi, 0, "R%s,(R%n),R%d",
-
-/* 48+16+4 */
- "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)",
- "MOV%u%C%p", armhwby, 0, "R%d,%I",
- "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d",
- "MOV%u%C%p", armhwby, armfmov, "%I,R%d",
-
-/* 48+24 */
- "MOVW%C%p", armsdti, 0, "R%d,%I",
- "MOVB%C%p", armsdti, 0, "R%d,%I",
- "MOVW%C%p", armsdti, armfmov, "%I,R%d",
- "MOVBU%C%p", armsdti, armfmov, "%I,R%d",
-
- "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
- "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
- "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
- "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
-
- "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
- "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
-
- "B%C", armb, armfbranch, "%b",
- "BL%C", armb, armfbranch, "%b",
-
- "CDP%C", armco, 0, "",
- "CDP%C", armco, 0, "",
- "MCR%C", armco, 0, "",
- "MRC%C", armco, 0, "",
-
- "UNK", armunk, 0, "",
-};
-
-static void
-gaddr(Instr *i)
-{
- *i->curr++ = '$';
- i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
-}
-
-static char *mode[] = { 0, "IA", "DB", "IB" };
-static char *pw[] = { "P", "PW", 0, "W" };
-static char *sw[] = { 0, "W", "S", "SW" };
-
-static void
-format(char *mnemonic, Instr *i, char *f)
-{
- int j, k, m, n;
- int g;
- char *fmt;
-
- if(mnemonic)
- format(0, i, mnemonic);
- if(f == 0)
- return;
- if(mnemonic)
- if(i->curr < i->end)
- *i->curr++ = '\t';
- for ( ; *f && i->curr < i->end; f++) {
- if(*f != '%') {
- *i->curr++ = *f;
- continue;
- }
- switch (*++f) {
-
- case 'C': /* .CONDITION */
- if(cond[i->cond])
- bprint(i, ".%s", cond[i->cond]);
- break;
-
- case 'S': /* .STORE */
- if(i->store)
- bprint(i, ".S");
- break;
-
- case 'P': /* P & U bits for block move */
- n = (i->w >>23) & 0x3;
- if (mode[n])
- bprint(i, ".%s", mode[n]);
- break;
-
- case 'p': /* P & W bits for single data xfer*/
- if (pw[i->store])
- bprint(i, ".%s", pw[i->store]);
- break;
-
- case 'a': /* S & W bits for single data xfer*/
- if (sw[i->store])
- bprint(i, ".%s", sw[i->store]);
- break;
-
- case 's':
- bprint(i, "%d", i->rs & 0xf);
- break;
-
- case 'M':
- bprint(i, "%d", (i->w>>8) & 0xf);
- break;
-
- case 'm':
- bprint(i, "%d", (i->w>>7) & 0x1f);
- break;
-
- case 'h':
- bprint(i, shtype[(i->w>>5) & 0x3]);
- break;
-
- case 'u': /* Signed/unsigned Byte/Halfword */
- bprint(i, hb[(i->w>>5) & 0x3]);
- break;
-
- case 'I':
- if (i->rn == 13) {
- if (plocal(i))
- break;
- }
- g = 0;
- fmt = "#%lx(R%d)";
- if (i->rn == 15) {
- /* convert load of offset(PC) to a load immediate */
- uint32 x;
- if (get4(i->map, i->addr+i->imm+8, &x) > 0)
- {
- i->imm = (int32)x;
- g = 1;
- fmt = "";
- }
- }
- if (mach->sb)
- {
- if (i->rd == 11) {
- uint32 nxti;
-
- if (get4(i->map, i->addr+4, &nxti) > 0) {
- if ((nxti & 0x0e0f0fff) == 0x060c000b) {
- i->imm += mach->sb;
- g = 1;
- fmt = "-SB";
- }
- }
- }
- if (i->rn == 12)
- {
- i->imm += mach->sb;
- g = 1;
- fmt = "-SB(SB)";
- }
- }
- if (g)
- {
- gaddr(i);
- bprint(i, fmt, i->rn);
- }
- else
- bprint(i, fmt, i->imm, i->rn);
- break;
- case 'U': /* Add/subtract from base */
- bprint(i, addsub[(i->w >> 23) & 1]);
- break;
-
- case 'n':
- bprint(i, "%d", i->rn);
- break;
-
- case 'd':
- bprint(i, "%d", i->rd);
- break;
-
- case 'i':
- bprint(i, "%lux", i->imm);
- break;
-
- case 'b':
- i->curr += symoff(i->curr, i->end-i->curr,
- i->imm, CTEXT);
- break;
-
- case 'g':
- i->curr += gsymoff(i->curr, i->end-i->curr,
- i->imm, CANY);
- break;
-
- case 'r':
- n = i->imm&0xffff;
- j = 0;
- k = 0;
- while(n) {
- m = j;
- while(n&0x1) {
- j++;
- n >>= 1;
- }
- if(j != m) {
- if(k)
- bprint(i, ",");
- if(j == m+1)
- bprint(i, "R%d", m);
- else
- bprint(i, "R%d-R%d", m, j-1);
- k = 1;
- }
- j++;
- n >>= 1;
- }
- break;
-
- case '\0':
- *i->curr++ = '%';
- return;
-
- default:
- bprint(i, "%%%c", *f);
- break;
- }
- }
- *i->curr = 0;
-}
-
-static int
-printins(Map *map, ulong pc, char *buf, int n)
-{
- Instr i;
-
- i.curr = buf;
- i.end = buf+n-1;
- if(decode(map, pc, &i) < 0)
- return -1;
-
- (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
- return 4;
-}
-
-static int
-arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
-{
- USED(modifier);
- return printins(map, pc, buf, n);
-}
-
-static int
-armdas(Map *map, uvlong pc, char *buf, int n)
-{
- Instr i;
-
- i.curr = buf;
- i.end = buf+n;
- if(decode(map, pc, &i) < 0)
- return -1;
- if(i.end-i.curr > 8)
- i.curr = _hexify(buf, i.w, 7);
- *i.curr = 0;
- return 4;
-}
-
-static int
-arminstlen(Map *map, uvlong pc)
-{
- Instr i;
-
- if(decode(map, pc, &i) < 0)
- return -1;
- return 4;
-}
-
-static int
-armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
-{
- ulong d;
- Instr i;
-
- if(decode(map, pc, &i) < 0)
- return -1;
-
- if(opcodes[i.op].foll) {
- d = (*opcodes[i.op].foll)(map, rget, &i, pc);
- if(d == -1)
- return -1;
- } else
- d = pc+4;
-
- foll[0] = d;
- return 1;
-}
diff --git a/src/libmach/5obj.c b/src/libmach/5obj.c
deleted file mode 100644
index 7fd3459a8..000000000
--- a/src/libmach/5obj.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// Inferno libmach/5obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * 5obj.c - identify and parse an arm object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/5l/5.out.h"
-#include "obj.h"
-
-typedef struct Addr Addr;
-struct Addr
-{
- char type;
- char sym;
- char name;
- char gotype;
-};
-static Addr addr(Biobuf*);
-static char type2char(int);
-static void skip(Biobuf*, int);
-
-int
-_is5(char *s)
-{
- return s[0] == ANAME /* ANAME */
- && s[1] == D_FILE /* type */
- && s[2] == 1 /* sym */
- && s[3] == '<'; /* name of file */
-}
-
-int
-_read5(Biobuf *bp, Prog *p)
-{
- int as, n;
- Addr a;
-
- as = BGETC(bp); /* as */
- if(as < 0)
- return 0;
- p->kind = aNone;
- p->sig = 0;
- if(as == ANAME || as == ASIGNAME){
- if(as == ASIGNAME){
- Bread(bp, &p->sig, 4);
- p->sig = leswal(p->sig);
- }
- p->kind = aName;
- p->type = type2char(BGETC(bp)); /* type */
- p->sym = BGETC(bp); /* sym */
- n = 0;
- for(;;) {
- as = BGETC(bp);
- if(as < 0)
- return 0;
- n++;
- if(as == 0)
- break;
- }
- p->id = malloc(n);
- if(p->id == 0)
- return 0;
- Bseek(bp, -n, 1);
- if(Bread(bp, p->id, n) != n)
- return 0;
- return 1;
- }
- if(as == ATEXT)
- p->kind = aText;
- else if(as == AGLOBL)
- p->kind = aData;
- skip(bp, 6); /* scond(1), reg(1), lineno(4) */
- a = addr(bp);
- addr(bp);
- if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
- p->kind = aNone;
- p->sym = a.sym;
- return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
- Addr a;
- long off;
-
- a.type = BGETC(bp); /* a.type */
- skip(bp,1); /* reg */
- a.sym = BGETC(bp); /* sym index */
- a.name = BGETC(bp); /* sym type */
- a.gotype = BGETC(bp); /* go type */
- switch(a.type){
- default:
- case D_NONE:
- case D_REG:
- case D_FREG:
- case D_PSR:
- case D_FPCR:
- break;
- case D_REGREG:
- case D_REGREG2:
- Bgetc(bp);
- break;
- case D_CONST2:
- Bgetle4(bp); // fall through
- case D_OREG:
- case D_CONST:
- case D_BRANCH:
- case D_SHIFT:
- off = BGETLE4(bp);
- if(off < 0)
- off = -off;
- if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
- _offset(a.sym, off);
- break;
- case D_SCONST:
- skip(bp, NSNAME);
- break;
- case D_FCONST:
- skip(bp, 8);
- break;
- }
- return a;
-}
-
-static char
-type2char(int t)
-{
- switch(t){
- case D_EXTERN: return 'U';
- case D_STATIC: return 'b';
- case D_AUTO: return 'a';
- case D_PARAM: return 'p';
- default: return UNKNOWN;
- }
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
- while (n-- > 0)
- Bgetc(bp);
-}
diff --git a/src/libmach/6.c b/src/libmach/6.c
deleted file mode 100644
index 0f0636303..000000000
--- a/src/libmach/6.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// Inferno libmach/6.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * amd64 definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_amd64.h"
-#include <mach.h>
-
-#define REGOFF(x) offsetof(struct Ureg, x)
-
-#define REGSIZE sizeof(struct Ureg)
-#define FP_CTLS(x) (REGSIZE+2*(x))
-#define FP_CTL(x) (REGSIZE+4*(x))
-#define FP_REG(x) (FP_CTL(8)+16*(x))
-#define XM_REG(x) (FP_CTL(8)+8*16+16*(x))
-
-#define FPREGSIZE 512 /* TO DO? currently only 0x1A0 used */
-
-Reglist amd64reglist[] = {
- {"AX", REGOFF(ax), RINT, 'Y'},
- {"BX", REGOFF(bx), RINT, 'Y'},
- {"CX", REGOFF(cx), RINT, 'Y'},
- {"DX", REGOFF(dx), RINT, 'Y'},
- {"SI", REGOFF(si), RINT, 'Y'},
- {"DI", REGOFF(di), RINT, 'Y'},
- {"BP", REGOFF(bp), RINT, 'Y'},
- {"R8", REGOFF(r8), RINT, 'Y'},
- {"R9", REGOFF(r9), RINT, 'Y'},
- {"R10", REGOFF(r10), RINT, 'Y'},
- {"R11", REGOFF(r11), RINT, 'Y'},
- {"R12", REGOFF(r12), RINT, 'Y'},
- {"R13", REGOFF(r13), RINT, 'Y'},
- {"R14", REGOFF(r14), RINT, 'Y'},
- {"R15", REGOFF(r15), RINT, 'Y'},
- {"DS", REGOFF(ds), RINT, 'x'},
- {"ES", REGOFF(es), RINT, 'x'},
- {"FS", REGOFF(fs), RINT, 'x'},
- {"GS", REGOFF(gs), RINT, 'x'},
- {"TYPE", REGOFF(type), RINT, 'Y'},
- {"TRAP", REGOFF(type), RINT, 'Y'}, /* alias for acid */
- {"ERROR", REGOFF(error), RINT, 'Y'},
- {"IP", REGOFF(ip), RINT, 'Y'},
- {"PC", REGOFF(ip), RINT, 'Y'}, /* alias for acid */
- {"CS", REGOFF(cs), RINT, 'Y'},
- {"FLAGS", REGOFF(flags), RINT, 'Y'},
- {"SP", REGOFF(sp), RINT, 'Y'},
- {"SS", REGOFF(ss), RINT, 'Y'},
-
- {"FCW", FP_CTLS(0), RFLT, 'x'},
- {"FSW", FP_CTLS(1), RFLT, 'x'},
- {"FTW", FP_CTLS(2), RFLT, 'b'},
- {"FOP", FP_CTLS(3), RFLT, 'x'},
- {"RIP", FP_CTL(2), RFLT, 'Y'},
- {"RDP", FP_CTL(4), RFLT, 'Y'},
- {"MXCSR", FP_CTL(6), RFLT, 'X'},
- {"MXCSRMASK", FP_CTL(7), RFLT, 'X'},
- {"M0", FP_REG(0), RFLT, 'F'}, /* assumes double */
- {"M1", FP_REG(1), RFLT, 'F'},
- {"M2", FP_REG(2), RFLT, 'F'},
- {"M3", FP_REG(3), RFLT, 'F'},
- {"M4", FP_REG(4), RFLT, 'F'},
- {"M5", FP_REG(5), RFLT, 'F'},
- {"M6", FP_REG(6), RFLT, 'F'},
- {"M7", FP_REG(7), RFLT, 'F'},
- {"X0", XM_REG(0), RFLT, 'F'}, /* assumes double */
- {"X1", XM_REG(1), RFLT, 'F'},
- {"X2", XM_REG(2), RFLT, 'F'},
- {"X3", XM_REG(3), RFLT, 'F'},
- {"X4", XM_REG(4), RFLT, 'F'},
- {"X5", XM_REG(5), RFLT, 'F'},
- {"X6", XM_REG(6), RFLT, 'F'},
- {"X7", XM_REG(7), RFLT, 'F'},
- {"X8", XM_REG(8), RFLT, 'F'},
- {"X9", XM_REG(9), RFLT, 'F'},
- {"X10", XM_REG(10), RFLT, 'F'},
- {"X11", XM_REG(11), RFLT, 'F'},
- {"X12", XM_REG(12), RFLT, 'F'},
- {"X13", XM_REG(13), RFLT, 'F'},
- {"X14", XM_REG(14), RFLT, 'F'},
- {"X15", XM_REG(15), RFLT, 'F'},
- {"X16", XM_REG(16), RFLT, 'F'},
-/*
- {"F0", FP_REG(7), RFLT, '3'},
- {"F1", FP_REG(6), RFLT, '3'},
- {"F2", FP_REG(5), RFLT, '3'},
- {"F3", FP_REG(4), RFLT, '3'},
- {"F4", FP_REG(3), RFLT, '3'},
- {"F5", FP_REG(2), RFLT, '3'},
- {"F6", FP_REG(1), RFLT, '3'},
- {"F7", FP_REG(0), RFLT, '3'},
-*/
- { 0 }
-};
-
-Mach mamd64=
-{
- "amd64",
- MAMD64, /* machine type */
- amd64reglist, /* register list */
- REGSIZE, /* size of registers in bytes */
- FPREGSIZE, /* size of fp registers in bytes */
- "PC", /* name of PC */
- "SP", /* name of SP */
- 0, /* link register */
- "setSB", /* static base register name (bogus anyways) */
- 0, /* static base register value */
- 0x1000, /* page size */
- 0xFFFFFFFF80110000ULL, /* kernel base */
- 0xFFFF800000000000ULL, /* kernel text mask */
- 0x00007FFFFFFFF000ULL, /* user stack top */
- 1, /* quantization of pc */
- 8, /* szaddr */
- 4, /* szreg */
- 4, /* szfloat */
- 8, /* szdouble */
-};
diff --git a/src/libmach/6obj.c b/src/libmach/6obj.c
deleted file mode 100644
index 1921c9e4c..000000000
--- a/src/libmach/6obj.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno libmach/6obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * 6obj.c - identify and parse an amd64 object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/6l/6.out.h"
-#include "obj.h"
-
-typedef struct Addr Addr;
-struct Addr
-{
- char sym;
- char flags;
- char gotype;
-};
-static Addr addr(Biobuf*);
-static char type2char(int);
-static void skip(Biobuf*, int);
-
-int
-_is6(char *t)
-{
- uchar *s = (uchar*)t;
-
- return s[0] == (ANAME&0xff) /* also = ANAME */
- && s[1] == ((ANAME>>8)&0xff)
- && s[2] == D_FILE /* type */
- && s[3] == 1 /* sym */
- && s[4] == '<'; /* name of file */
-}
-
-int
-_read6(Biobuf *bp, Prog* p)
-{
- int as, n, c;
- Addr a;
-
- as = BGETC(bp); /* as(low) */
- if(as < 0)
- return 0;
- c = BGETC(bp); /* as(high) */
- if(c < 0)
- return 0;
- as |= ((c & 0xff) << 8);
- p->kind = aNone;
- p->sig = 0;
- if(as == ANAME || as == ASIGNAME){
- if(as == ASIGNAME){
- Bread(bp, &p->sig, 4);
- p->sig = leswal(p->sig);
- }
- p->kind = aName;
- p->type = type2char(BGETC(bp)); /* type */
- p->sym = BGETC(bp); /* sym */
- n = 0;
- for(;;) {
- as = BGETC(bp);
- if(as < 0)
- return 0;
- n++;
- if(as == 0)
- break;
- }
- p->id = malloc(n);
- if(p->id == 0)
- return 0;
- Bseek(bp, -n, 1);
- if(Bread(bp, p->id, n) != n)
- return 0;
- return 1;
- }
- if(as == ATEXT)
- p->kind = aText;
- if(as == AGLOBL)
- p->kind = aData;
- skip(bp, 4); /* lineno(4) */
- a = addr(bp);
- addr(bp);
- if(!(a.flags & T_SYM))
- p->kind = aNone;
- p->sym = a.sym;
- return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
- Addr a;
- int t;
- int32 l;
- vlong off;
-
- off = 0;
- a.sym = -1;
- a.flags = BGETC(bp); /* flags */
- a.gotype = 0;
- if(a.flags & T_INDEX)
- skip(bp, 2);
- if(a.flags & T_OFFSET){
- l = BGETLE4(bp);
- off = l;
- if(a.flags & T_64){
- l = BGETLE4(bp);
- off = ((vlong)l << 32) | (off & 0xFFFFFFFF);
- }
- if(off < 0)
- off = -(uvlong)off;
- }
- if(a.flags & T_SYM)
- a.sym = BGETC(bp);
- if(a.flags & T_FCONST)
- skip(bp, 8);
- else
- if(a.flags & T_SCONST)
- skip(bp, NSNAME);
- if(a.flags & T_TYPE) {
- t = BGETC(bp);
- if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
- _offset(a.sym, off);
- }
- if(a.flags & T_GOTYPE)
- a.gotype = BGETC(bp);
- return a;
-}
-
-static char
-type2char(int t)
-{
- switch(t){
- case D_EXTERN: return 'U';
- case D_STATIC: return 'b';
- case D_AUTO: return 'a';
- case D_PARAM: return 'p';
- default: return UNKNOWN;
- }
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
- while (n-- > 0)
- Bgetc(bp);
-}
diff --git a/src/libmach/8.c b/src/libmach/8.c
deleted file mode 100644
index 34248e6f3..000000000
--- a/src/libmach/8.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// Inferno libmach/8.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * 386 definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ureg_x86.h>
-#include <mach.h>
-
-#define REGOFF(x) (uintptr)(&((struct Ureg *) 0)->x)
-
-#define PC REGOFF(pc)
-#define SP REGOFF(sp)
-#define AX REGOFF(ax)
-
-#define REGSIZE sizeof(struct Ureg)
-#define FP_CTL(x) (REGSIZE+4*(x))
-#define FP_REG(x) (FP_CTL(7)+10*(x))
-#define FPREGSIZE (7*4+8*10)
-
-Reglist i386reglist[] = {
- {"DI", REGOFF(di), RINT, 'X'},
- {"SI", REGOFF(si), RINT, 'X'},
- {"BP", REGOFF(bp), RINT, 'X'},
- {"BX", REGOFF(bx), RINT, 'X'},
- {"DX", REGOFF(dx), RINT, 'X'},
- {"CX", REGOFF(cx), RINT, 'X'},
- {"AX", REGOFF(ax), RINT, 'X'},
- {"GS", REGOFF(gs), RINT, 'X'},
- {"FS", REGOFF(fs), RINT, 'X'},
- {"ES", REGOFF(es), RINT, 'X'},
- {"DS", REGOFF(ds), RINT, 'X'},
- {"TRAP", REGOFF(trap), RINT, 'X'},
- {"ECODE", REGOFF(ecode), RINT, 'X'},
- {"PC", PC, RINT, 'X'},
- {"CS", REGOFF(cs), RINT, 'X'},
- {"EFLAGS", REGOFF(flags), RINT, 'X'},
- {"SP", SP, RINT, 'X'},
- {"SS", REGOFF(ss), RINT, 'X'},
-
- {"E0", FP_CTL(0), RFLT, 'X'},
- {"E1", FP_CTL(1), RFLT, 'X'},
- {"E2", FP_CTL(2), RFLT, 'X'},
- {"E3", FP_CTL(3), RFLT, 'X'},
- {"E4", FP_CTL(4), RFLT, 'X'},
- {"E5", FP_CTL(5), RFLT, 'X'},
- {"E6", FP_CTL(6), RFLT, 'X'},
- {"F0", FP_REG(0), RFLT, '3'},
- {"F1", FP_REG(1), RFLT, '3'},
- {"F2", FP_REG(2), RFLT, '3'},
- {"F3", FP_REG(3), RFLT, '3'},
- {"F4", FP_REG(4), RFLT, '3'},
- {"F5", FP_REG(5), RFLT, '3'},
- {"F6", FP_REG(6), RFLT, '3'},
- {"F7", FP_REG(7), RFLT, '3'},
- { 0 }
-};
-
-Mach mi386 =
-{
- "386",
- MI386, /* machine type */
- i386reglist, /* register list */
- REGSIZE, /* size of registers in bytes */
- FPREGSIZE, /* size of fp registers in bytes */
- "PC", /* name of PC */
- "SP", /* name of SP */
- 0, /* link register */
- "setSB", /* static base register name (bogus anyways) */
- 0, /* static base register value */
- 0x1000, /* page size */
- 0x80100000ULL, /* kernel base */
- 0xF0000000ULL, /* kernel text mask */
- 0xFFFFFFFFULL, /* user stack top */
- 1, /* quantization of pc */
- 4, /* szaddr */
- 4, /* szreg */
- 4, /* szfloat */
- 8, /* szdouble */
-};
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
deleted file mode 100644
index cfc9cb99f..000000000
--- a/src/libmach/8db.c
+++ /dev/null
@@ -1,2447 +0,0 @@
-// Inferno libmach/8db.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8db.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg UregAmd64
-#include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg386
-#include <ureg_x86.h>
-#undef Ureg
-
-typedef struct UregAmd64 UregAmd64;
-typedef struct Ureg386 Ureg386;
-
-/*
- * i386-specific debugger interface
- * also amd64 extensions
- */
-
-static char *i386excep(Map*, Rgetter);
-
-static int i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
-static uvlong i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
-static int i386foll(Map*, uvlong, Rgetter, uvlong*);
-static int i386inst(Map*, uvlong, char, char*, int);
-static int i386das(Map*, uvlong, char*, int);
-static int i386instlen(Map*, uvlong);
-
-static char STARTSYM[] = "_main";
-static char GOSTARTSYM[] = "sys·goexit";
-static char PROFSYM[] = "_mainp";
-static char FRAMENAME[] = ".frame";
-static char LESSSTACK[] = "sys·lessstack";
-static char MORESTACK[] = "sys·morestack";
-static char *excname[] =
-{
-[0] = "divide error",
-[1] = "debug exception",
-[4] = "overflow",
-[5] = "bounds check",
-[6] = "invalid opcode",
-[7] = "math coprocessor emulation",
-[8] = "double fault",
-[9] = "math coprocessor overrun",
-[10] = "invalid TSS",
-[11] = "segment not present",
-[12] = "stack exception",
-[13] = "general protection violation",
-[14] = "page fault",
-[16] = "math coprocessor error",
-[17] = "alignment check",
-[18] = "machine check",
-[19] = "floating-point exception",
-[24] = "clock",
-[25] = "keyboard",
-[27] = "modem status",
-[28] = "serial line status",
-[30] = "floppy disk",
-[36] = "mouse",
-[37] = "math coprocessor",
-[38] = "hard disk",
-[64] = "system call",
-};
-
-Machdata i386mach =
-{
- {0xCC, 0, 0, 0}, /* break point: INT 3 */
- 1, /* break point size */
-
- leswab, /* convert short to local byte order */
- leswal, /* convert int32 to local byte order */
- leswav, /* convert vlong to local byte order */
- i386trace, /* C traceback */
- i386frame, /* frame finder */
- i386excep, /* print exception */
- 0, /* breakpoint fixup */
- leieeesftos, /* single precision float printer */
- leieeedftos, /* double precision float printer */
- i386foll, /* following addresses */
- i386inst, /* print instruction */
- i386das, /* dissembler */
- i386instlen, /* instruction size calculation */
-};
-
-static char*
-i386excep(Map *map, Rgetter rget)
-{
- uint32 c;
- uvlong pc;
- static char buf[16];
-
- c = (*rget)(map, "TRAP");
- if(c > 64 || excname[c] == 0) {
- if (c == 3) {
- pc = (*rget)(map, "PC");
- if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
- if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
- return "breakpoint";
- }
- snprint(buf, sizeof(buf), "exception %d", c);
- return buf;
- } else
- return excname[c];
-}
-
-static int
-i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
- int i;
- uvlong osp, pc1;
- Symbol s, f, s1;
- extern Mach mamd64;
- int isamd64;
- uvlong g, m, lessstack, morestack, stktop;
-
- isamd64 = (mach == &mamd64);
-
- // ../pkg/runtime/runtime.h
- // G is
- // byte* stackguard
- // byte* stackbase (= Stktop*)
- // TODO(rsc): Need some way to get at the g for other threads.
- // Probably need to pass it into the trace function.
- g = 0;
- if(isamd64)
- geta(map, offsetof(struct UregAmd64, r15), &g);
- else {
- // TODO(rsc): How to fetch g on 386?
- }
- stktop = 0;
- if(g != 0)
- geta(map, g+1*mach->szaddr, &stktop);
-
- lessstack = 0;
- if(lookup(0, LESSSTACK, &s))
- lessstack = s.value;
- morestack = 0;
- if(lookup(0, MORESTACK, &s))
- morestack = s.value;
-
- USED(link);
- osp = 0;
- i = 0;
-
- for(;;) {
- if(!findsym(pc, CTEXT, &s)) {
- // check for closure return sequence
- uchar buf[8], *p;
- if(get1(map, pc, buf, 8) < 0)
- break;
- // ADDQ $xxx, SP; RET
- p = buf;
- if(mach == &mamd64) {
- if(p[0] != 0x48)
- break;
- p++;
- }
- if(p[0] != 0x81 || p[1] != 0xc4 || p[6] != 0xc3)
- break;
- sp += p[2] | (p[3]<<8) | (p[4]<<16) | (p[5]<<24);
- if(geta(map, sp, &pc) < 0)
- break;
- sp += mach->szaddr;
- continue;
- }
-
- if (osp == sp)
- break;
- osp = sp;
-
- if(strcmp(STARTSYM, s.name) == 0 ||
- strcmp(GOSTARTSYM, s.name) == 0 ||
- strcmp(PROFSYM, s.name) == 0)
- break;
-
- if(s.value == morestack) {
- // This code is old and won't work anymore.
- // But no one uses it anyway.
- // Leave it obviously broken until someone needs it.
- werrstr("morestack not implemented correctly");
- return -1;
- // In the middle of morestack.
- // Caller is m->morepc.
- // Caller's caller is in m->morearg.
- // TODO(rsc): 386
- geta(map, offsetof(struct UregAmd64, r14), &m);
-
- pc = 0;
- sp = 0;
- pc1 = 0;
- s1 = s;
- memset(&s, 0, sizeof s);
- geta(map, m+1*mach->szaddr, &pc1); // m->morepc
- geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
- geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
- findsym(pc1, CTEXT, &s);
- (*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
-
- // caller's caller
- s1 = s;
- findsym(pc, CTEXT, &s);
- (*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
- continue;
- }
-
- if(pc == lessstack) {
- // ../pkg/runtime/runtime.h
- // Stktop is
- // byte* stackguard
- // byte* stackbase
- // Gobuf gobuf
- // byte* sp;
- // byte* pc;
- // G* g;
- if(!isamd64)
- fprint(2, "warning: cannot unwind stack split on 386\n");
- if(stktop == 0)
- break;
- pc = 0;
- sp = 0;
- geta(map, stktop+2*mach->szaddr, &sp);
- geta(map, stktop+3*mach->szaddr, &pc);
- geta(map, stktop+1*mach->szaddr, &stktop);
- (*trace)(map, pc, sp, &s1);
- continue;
- }
-
- s1 = s;
- pc1 = 0;
- if(pc != s.value) { /* not at first instruction */
- if(findlocal(&s, FRAMENAME, &f) == 0)
- break;
- geta(map, sp, &pc1);
- sp += f.value-mach->szaddr;
- }
- if(geta(map, sp, &pc) < 0)
- break;
-
- // If PC is not valid, assume we caught the function
- // before it moved the stack pointer down or perhaps
- // after it moved the stack pointer back up.
- // Try the PC we'd have gotten without the stack
- // pointer adjustment above (pc != s.value).
- // This only matters for the first frame, and it is only
- // a heuristic, but it does help.
- if(!findsym(pc, CTEXT, &s) || strcmp(s.name, "etext") == 0)
- pc = pc1;
-
- if(pc == 0)
- break;
-
- if(pc != lessstack)
- (*trace)(map, pc, sp, &s1);
- sp += mach->szaddr;
-
- if(++i > 1000)
- break;
- }
- return i;
-}
-
-static uvlong
-i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
- Symbol s, f;
-
- USED(link);
- while (findsym(pc, CTEXT, &s)) {
- if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
- break;
-
- if(pc != s.value) { /* not first instruction */
- if(findlocal(&s, FRAMENAME, &f) == 0)
- break;
- sp += f.value-mach->szaddr;
- }
-
- if (s.value == addr)
- return sp;
-
- if (geta(map, sp, &pc) < 0)
- break;
- sp += mach->szaddr;
- }
- return 0;
-}
-
- /* I386/486 - Disassembler and related functions */
-
-/*
- * an instruction
- */
-typedef struct Instr Instr;
-struct Instr
-{
- uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
- uvlong addr; /* address of start of instruction */
- int n; /* number of bytes in instruction */
- char *prefix; /* instr prefix */
- char *segment; /* segment override */
- uchar jumptype; /* set to the operand type for jump/ret/call */
- uchar amd64;
- uchar rex; /* REX prefix (or zero) */
- char osize; /* 'W' or 'L' (or 'Q' on amd64) */
- char asize; /* address size 'W' or 'L' (or 'Q' or amd64) */
- uchar mod; /* bits 6-7 of mod r/m field */
- uchar reg; /* bits 3-5 of mod r/m field */
- char ss; /* bits 6-7 of SIB */
- schar index; /* bits 3-5 of SIB */
- schar base; /* bits 0-2 of SIB */
- char rip; /* RIP-relative in amd64 mode */
- uchar opre; /* f2/f3 could introduce media */
- short seg; /* segment of far address */
- uint32 disp; /* displacement */
- uint32 imm; /* immediate */
- uint32 imm2; /* second immediate operand */
- uvlong imm64; /* big immediate */
- char *curr; /* fill level in output buffer */
- char *end; /* end of output buffer */
- char *err; /* error message */
-};
-
- /* 386 register (ha!) set */
-enum{
- AX=0,
- CX,
- DX,
- BX,
- SP,
- BP,
- SI,
- DI,
-
- /* amd64 */
- /* be careful: some unix system headers #define R8, R9, etc */
- AMD64_R8,
- AMD64_R9,
- AMD64_R10,
- AMD64_R11,
- AMD64_R12,
- AMD64_R13,
- AMD64_R14,
- AMD64_R15
-};
-
- /* amd64 rex extension byte */
-enum{
- REXW = 1<<3, /* =1, 64-bit operand size */
- REXR = 1<<2, /* extend modrm reg */
- REXX = 1<<1, /* extend sib index */
- REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */
-};
-
- /* Operand Format codes */
-/*
-%A - address size register modifier (!asize -> 'E')
-%C - Control register CR0/CR1/CR2
-%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
-%I - second immediate operand
-%O - Operand size register modifier (!osize -> 'E')
-%T - Test register TR6/TR7
-%S - size code ('W' or 'L')
-%W - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
-%d - displacement 16-32 bits
-%e - effective address - Mod R/M value
-%f - floating point register F0-F7 - from Mod R/M register
-%g - segment register
-%i - immediate operand 8-32 bits
-%p - PC-relative - signed displacement in immediate field
-%r - Reg from Mod R/M
-%w - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
-*/
-
-typedef struct Optable Optable;
-struct Optable
-{
- char operand[2];
- void *proto; /* actually either (char*) or (Optable*) */
-};
- /* Operand decoding codes */
-enum {
- Ib = 1, /* 8-bit immediate - (no sign extension)*/
- Ibs, /* 8-bit immediate (sign extended) */
- Jbs, /* 8-bit sign-extended immediate in jump or call */
- Iw, /* 16-bit immediate -> imm */
- Iw2, /* 16-bit immediate -> imm2 */
- Iwd, /* Operand-sized immediate (no sign extension)*/
- Iwdq, /* Operand-sized immediate, possibly 64 bits */
- Awd, /* Address offset */
- Iwds, /* Operand-sized immediate (sign extended) */
- RM, /* Word or int32 R/M field with register (/r) */
- RMB, /* Byte R/M field with register (/r) */
- RMOP, /* Word or int32 R/M field with op code (/digit) */
- RMOPB, /* Byte R/M field with op code (/digit) */
- RMR, /* R/M register only (mod = 11) */
- RMM, /* R/M memory only (mod = 0/1/2) */
- Op_R0, /* Base reg of Mod R/M is literal 0x00 */
- Op_R1, /* Base reg of Mod R/M is literal 0x01 */
- FRMOP, /* Floating point R/M field with opcode */
- FRMEX, /* Extended floating point R/M field with opcode */
- JUMP, /* Jump or Call flag - no operand */
- RET, /* Return flag - no operand */
- OA, /* literal 0x0a byte */
- PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
- AUX, /* Multi-byte op code - Auxiliary table */
- AUXMM, /* multi-byte op code - auxiliary table chosen by prefix */
- PRE, /* Instr Prefix */
- OPRE, /* Instr Prefix or media op extension */
- SEG, /* Segment Prefix */
- OPOVER, /* Operand size override */
- ADDOVER, /* Address size override */
-};
-
-static Optable optab0F00[8]=
-{
-[0x00] = { 0,0, "MOVW LDT,%e" },
-[0x01] = { 0,0, "MOVW TR,%e" },
-[0x02] = { 0,0, "MOVW %e,LDT" },
-[0x03] = { 0,0, "MOVW %e,TR" },
-[0x04] = { 0,0, "VERR %e" },
-[0x05] = { 0,0, "VERW %e" },
-};
-
-static Optable optab0F01[8]=
-{
-[0x00] = { 0,0, "MOVL GDTR,%e" },
-[0x01] = { 0,0, "MOVL IDTR,%e" },
-[0x02] = { 0,0, "MOVL %e,GDTR" },
-[0x03] = { 0,0, "MOVL %e,IDTR" },
-[0x04] = { 0,0, "MOVW MSW,%e" }, /* word */
-[0x06] = { 0,0, "MOVW %e,MSW" }, /* word */
-[0x07] = { 0,0, "INVLPG %e" }, /* or SWAPGS */
-};
-
-static Optable optab0F01F8[1]=
-{
-[0x00] = { 0,0, "SWAPGS" },
-};
-
-/* 0F71 */
-/* 0F72 */
-/* 0F73 */
-
-static Optable optab0FAE[8]=
-{
-[0x00] = { 0,0, "FXSAVE %e" },
-[0x01] = { 0,0, "FXRSTOR %e" },
-[0x02] = { 0,0, "LDMXCSR %e" },
-[0x03] = { 0,0, "STMXCSR %e" },
-[0x05] = { 0,0, "LFENCE" },
-[0x06] = { 0,0, "MFENCE" },
-[0x07] = { 0,0, "SFENCE" },
-};
-
-static Optable optab0F18[4]=
-{
-[0x00] = { 0,0, "PREFETCHNTA %e" },
-[0x01] = { 0,0, "PREFECTCH0 %e" },
-[0x02] = { 0,0, "PREFECTCH1 %e" },
-[0x03] = { 0,0, "PREFECTCH2 %e" },
-};
-
-/* 0F0D */
-
-static Optable optab0FBA[8]=
-{
-[0x04] = { Ib,0, "BT%S %i,%e" },
-[0x05] = { Ib,0, "BTS%S %i,%e" },
-[0x06] = { Ib,0, "BTR%S %i,%e" },
-[0x07] = { Ib,0, "BTC%S %i,%e" },
-};
-
-static Optable optab0F0F[256]=
-{
-[0x0c] = { 0,0, "PI2FW %m,%M" },
-[0x0d] = { 0,0, "PI2L %m,%M" },
-[0x1c] = { 0,0, "PF2IW %m,%M" },
-[0x1d] = { 0,0, "PF2IL %m,%M" },
-[0x8a] = { 0,0, "PFNACC %m,%M" },
-[0x8e] = { 0,0, "PFPNACC %m,%M" },
-[0x90] = { 0,0, "PFCMPGE %m,%M" },
-[0x94] = { 0,0, "PFMIN %m,%M" },
-[0x96] = { 0,0, "PFRCP %m,%M" },
-[0x97] = { 0,0, "PFRSQRT %m,%M" },
-[0x9a] = { 0,0, "PFSUB %m,%M" },
-[0x9e] = { 0,0, "PFADD %m,%M" },
-[0xa0] = { 0,0, "PFCMPGT %m,%M" },
-[0xa4] = { 0,0, "PFMAX %m,%M" },
-[0xa6] = { 0,0, "PFRCPIT1 %m,%M" },
-[0xa7] = { 0,0, "PFRSQIT1 %m,%M" },
-[0xaa] = { 0,0, "PFSUBR %m,%M" },
-[0xae] = { 0,0, "PFACC %m,%M" },
-[0xb0] = { 0,0, "PFCMPEQ %m,%M" },
-[0xb4] = { 0,0, "PFMUL %m,%M" },
-[0xb6] = { 0,0, "PFRCPI2T %m,%M" },
-[0xb7] = { 0,0, "PMULHRW %m,%M" },
-[0xbb] = { 0,0, "PSWAPL %m,%M" },
-};
-
-static Optable optab0FC7[8]=
-{
-[0x01] = { 0,0, "CMPXCHG8B %e" },
-};
-
-static Optable optab660F38[256]=
-{
-[0x00] = { RM,0, "PSHUFB %x,%X" },
-[0xdc] = { RM,0, "AESENC %x,%X" },
-[0xdb] = { RM,0, "AESIMC %x,%X," },
-[0xdd] = { RM,0, "AESENCLAST %x,%X" },
-[0xde] = { RM,0, "AESDEC %x,%X" },
-[0xdf] = { RM,0, "AESDECLAST %x,%X" },
-};
-
-static Optable optab660F3A[256]=
-{
-[0x22] = { RM,Ib, "PINSR%S %i,%e,%X" },
-[0xdf] = { RM,Ib, "AESKEYGENASSIST %i,%x,%X" },
-};
-
-static Optable optab660F71[8]=
-{
-[0x02] = { Ib,0, "PSRLW %i,%X" },
-[0x04] = { Ib,0, "PSRAW %i,%X" },
-[0x06] = { Ib,0, "PSLLW %i,%X" },
-};
-
-static Optable optab660F72[8]=
-{
-[0x02] = { Ib,0, "PSRLL %i,%X" },
-[0x04] = { Ib,0, "PSRAL %i,%X" },
-[0x06] = { Ib,0, "PSLLL %i,%X" },
-};
-
-static Optable optab660F73[8]=
-{
-[0x02] = { Ib,0, "PSRLQ %i,%X" },
-[0x03] = { Ib,0, "PSRLO %i,%X" },
-[0x06] = { Ib,0, "PSLLQ %i,%X" },
-[0x07] = { Ib,0, "PSLLO %i,%X" },
-};
-
-static Optable optab660F[256]=
-{
-[0x2B] = { RM,0, "MOVNTPD %x,%e" },
-[0x2E] = { RM,0, "UCOMISD %x,%X" },
-[0x2F] = { RM,0, "COMISD %x,%X" },
-[0x38] = { AUX,0, optab660F38 },
-[0x3A] = { AUX,0, optab660F3A },
-[0x5A] = { RM,0, "CVTPD2PS %x,%X" },
-[0x5B] = { RM,0, "CVTPS2PL %x,%X" },
-[0x6A] = { RM,0, "PUNPCKHLQ %x,%X" },
-[0x6B] = { RM,0, "PACKSSLW %x,%X" },
-[0x6C] = { RM,0, "PUNPCKLQDQ %x,%X" },
-[0x6D] = { RM,0, "PUNPCKHQDQ %x,%X" },
-[0x6E] = { RM,0, "MOV%S %e,%X" },
-[0x6F] = { RM,0, "MOVO %x,%X" }, /* MOVDQA */
-[0x70] = { RM,Ib, "PSHUFL %i,%x,%X" },
-[0x71] = { RMOP,0, optab660F71 },
-[0x72] = { RMOP,0, optab660F72 },
-[0x73] = { RMOP,0, optab660F73 },
-[0x7E] = { RM,0, "MOV%S %X,%e" },
-[0x7F] = { RM,0, "MOVO %X,%x" },
-[0xC4] = { RM,Ib, "PINSRW %i,%e,%X" },
-[0xC5] = { RMR,Ib, "PEXTRW %i,%X,%e" },
-[0xD4] = { RM,0, "PADDQ %x,%X" },
-[0xD5] = { RM,0, "PMULLW %x,%X" },
-[0xD6] = { RM,0, "MOVQ %X,%x" },
-[0xE6] = { RM,0, "CVTTPD2PL %x,%X" },
-[0xE7] = { RM,0, "MOVNTO %X,%e" },
-[0xF7] = { RM,0, "MASKMOVOU %x,%X" },
-};
-
-static Optable optabF20F38[256]=
-{
-[0xf0] = { RM,0, "CRC32B %e, %r" },
-[0xf1] = { RM,0, "CRC32%S %e, %r" },
-};
-
-static Optable optabF20F[256]=
-{
-[0x10] = { RM,0, "MOVSD %x,%X" },
-[0x11] = { RM,0, "MOVSD %X,%x" },
-[0x2A] = { RM,0, "CVTS%S2SD %e,%X" },
-[0x2C] = { RM,0, "CVTTSD2S%S %x,%r" },
-[0x2D] = { RM,0, "CVTSD2S%S %x,%r" },
-[0x38] = { AUX,0, optabF20F38 },
-[0x5A] = { RM,0, "CVTSD2SS %x,%X" },
-[0x6F] = { RM,0, "MOVOU %x,%X" },
-[0x70] = { RM,Ib, "PSHUFLW %i,%x,%X" },
-[0x7F] = { RM,0, "MOVOU %X,%x" },
-[0xD6] = { RM,0, "MOVQOZX %M,%X" },
-[0xE6] = { RM,0, "CVTPD2PL %x,%X" },
-};
-
-static Optable optabF30F[256]=
-{
-[0x10] = { RM,0, "MOVSS %x,%X" },
-[0x11] = { RM,0, "MOVSS %X,%x" },
-[0x2A] = { RM,0, "CVTS%S2SS %e,%X" },
-[0x2C] = { RM,0, "CVTTSS2S%S %x,%r" },
-[0x2D] = { RM,0, "CVTSS2S%S %x,%r" },
-[0x5A] = { RM,0, "CVTSS2SD %x,%X" },
-[0x5B] = { RM,0, "CVTTPS2PL %x,%X" },
-[0x6F] = { RM,0, "MOVOU %x,%X" },
-[0x70] = { RM,Ib, "PSHUFHW %i,%x,%X" },
-[0x7E] = { RM,0, "MOVQOZX %x,%X" },
-[0x7F] = { RM,0, "MOVOU %X,%x" },
-[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
-[0xE6] = { RM,0, "CVTPL2PD %x,%X" },
-};
-
-static Optable optab0F[256]=
-{
-[0x00] = { RMOP,0, optab0F00 },
-[0x01] = { RMOP,0, optab0F01 },
-[0x02] = { RM,0, "LAR %e,%r" },
-[0x03] = { RM,0, "LSL %e,%r" },
-[0x05] = { 0,0, "SYSCALL" },
-[0x06] = { 0,0, "CLTS" },
-[0x07] = { 0,0, "SYSRET" },
-[0x08] = { 0,0, "INVD" },
-[0x09] = { 0,0, "WBINVD" },
-[0x0B] = { 0,0, "UD2" },
-[0x0F] = { RM,AUX, optab0F0F }, /* 3DNow! */
-[0x10] = { RM,0, "MOVU%s %x,%X" },
-[0x11] = { RM,0, "MOVU%s %X,%x" },
-[0x12] = { RM,0, "MOV[H]L%s %x,%X" }, /* TO DO: H if source is XMM */
-[0x13] = { RM,0, "MOVL%s %X,%e" },
-[0x14] = { RM,0, "UNPCKL%s %x,%X" },
-[0x15] = { RM,0, "UNPCKH%s %x,%X" },
-[0x16] = { RM,0, "MOV[L]H%s %x,%X" }, /* TO DO: L if source is XMM */
-[0x17] = { RM,0, "MOVH%s %X,%x" },
-[0x18] = { RMOP,0, optab0F18 },
-[0x1F] = { RM,0, "NOP%S %e" },
-[0x20] = { RMR,0, "MOVL %C,%e" },
-[0x21] = { RMR,0, "MOVL %D,%e" },
-[0x22] = { RMR,0, "MOVL %e,%C" },
-[0x23] = { RMR,0, "MOVL %e,%D" },
-[0x24] = { RMR,0, "MOVL %T,%e" },
-[0x26] = { RMR,0, "MOVL %e,%T" },
-[0x28] = { RM,0, "MOVA%s %x,%X" },
-[0x29] = { RM,0, "MOVA%s %X,%x" },
-[0x2A] = { RM,0, "CVTPL2%s %m*,%X" },
-[0x2B] = { RM,0, "MOVNT%s %X,%e" },
-[0x2C] = { RM,0, "CVTT%s2PL %x,%M" },
-[0x2D] = { RM,0, "CVT%s2PL %x,%M" },
-[0x2E] = { RM,0, "UCOMISS %x,%X" },
-[0x2F] = { RM,0, "COMISS %x,%X" },
-[0x30] = { 0,0, "WRMSR" },
-[0x31] = { 0,0, "RDTSC" },
-[0x32] = { 0,0, "RDMSR" },
-[0x33] = { 0,0, "RDPMC" },
-[0x42] = { RM,0, "CMOVC %e,%r" }, /* CF */
-[0x43] = { RM,0, "CMOVNC %e,%r" }, /* ¬ CF */
-[0x44] = { RM,0, "CMOVZ %e,%r" }, /* ZF */
-[0x45] = { RM,0, "CMOVNZ %e,%r" }, /* ¬ ZF */
-[0x46] = { RM,0, "CMOVBE %e,%r" }, /* CF ∨ ZF */
-[0x47] = { RM,0, "CMOVA %e,%r" }, /* ¬CF ∧ ¬ZF */
-[0x48] = { RM,0, "CMOVS %e,%r" }, /* SF */
-[0x49] = { RM,0, "CMOVNS %e,%r" }, /* ¬ SF */
-[0x4A] = { RM,0, "CMOVP %e,%r" }, /* PF */
-[0x4B] = { RM,0, "CMOVNP %e,%r" }, /* ¬ PF */
-[0x4C] = { RM,0, "CMOVLT %e,%r" }, /* LT ≡ OF ≠ SF */
-[0x4D] = { RM,0, "CMOVGE %e,%r" }, /* GE ≡ ZF ∨ SF */
-[0x4E] = { RM,0, "CMOVLE %e,%r" }, /* LE ≡ ZF ∨ LT */
-[0x4F] = { RM,0, "CMOVGT %e,%r" }, /* GT ≡ ¬ZF ∧ GE */
-[0x50] = { RM,0, "MOVMSK%s %X,%r" }, /* TO DO: check */
-[0x51] = { RM,0, "SQRT%s %x,%X" },
-[0x52] = { RM,0, "RSQRT%s %x,%X" },
-[0x53] = { RM,0, "RCP%s %x,%X" },
-[0x54] = { RM,0, "AND%s %x,%X" },
-[0x55] = { RM,0, "ANDN%s %x,%X" },
-[0x56] = { RM,0, "OR%s %x,%X" }, /* TO DO: S/D */
-[0x57] = { RM,0, "XOR%s %x,%X" }, /* S/D */
-[0x58] = { RM,0, "ADD%s %x,%X" }, /* S/P S/D */
-[0x59] = { RM,0, "MUL%s %x,%X" },
-[0x5A] = { RM,0, "CVTPS2PD %x,%X" },
-[0x5B] = { RM,0, "CVTPL2PS %x,%X" },
-[0x5C] = { RM,0, "SUB%s %x,%X" },
-[0x5D] = { RM,0, "MIN%s %x,%X" },
-[0x5E] = { RM,0, "DIV%s %x,%X" }, /* TO DO: S/P S/D */
-[0x5F] = { RM,0, "MAX%s %x,%X" },
-[0x60] = { RM,0, "PUNPCKLBW %m,%M" },
-[0x61] = { RM,0, "PUNPCKLWL %m,%M" },
-[0x62] = { RM,0, "PUNPCKLLQ %m,%M" },
-[0x63] = { RM,0, "PACKSSWB %m,%M" },
-[0x64] = { RM,0, "PCMPGTB %m,%M" },
-[0x65] = { RM,0, "PCMPGTW %m,%M" },
-[0x66] = { RM,0, "PCMPGTL %m,%M" },
-[0x67] = { RM,0, "PACKUSWB %m,%M" },
-[0x68] = { RM,0, "PUNPCKHBW %m,%M" },
-[0x69] = { RM,0, "PUNPCKHWL %m,%M" },
-[0x6A] = { RM,0, "PUNPCKHLQ %m,%M" },
-[0x6B] = { RM,0, "PACKSSLW %m,%M" },
-[0x6E] = { RM,0, "MOV%S %e,%M" },
-[0x6F] = { RM,0, "MOVQ %m,%M" },
-[0x70] = { RM,Ib, "PSHUFW %i,%m,%M" },
-[0x74] = { RM,0, "PCMPEQB %m,%M" },
-[0x75] = { RM,0, "PCMPEQW %m,%M" },
-[0x76] = { RM,0, "PCMPEQL %m,%M" },
-[0x77] = { 0,0, "EMMS" },
-[0x7E] = { RM,0, "MOV%S %M,%e" },
-[0x7F] = { RM,0, "MOVQ %M,%m" },
-[0xAE] = { RMOP,0, optab0FAE },
-[0xAA] = { 0,0, "RSM" },
-[0xB0] = { RM,0, "CMPXCHGB %r,%e" },
-[0xB1] = { RM,0, "CMPXCHG%S %r,%e" },
-[0xC0] = { RMB,0, "XADDB %r,%e" },
-[0xC1] = { RM,0, "XADD%S %r,%e" },
-[0xC2] = { RM,Ib, "CMP%s %x,%X,%#i" },
-[0xC3] = { RM,0, "MOVNTI%S %r,%e" },
-[0xC6] = { RM,Ib, "SHUF%s %i,%x,%X" },
-[0xC8] = { 0,0, "BSWAP AX" },
-[0xC9] = { 0,0, "BSWAP CX" },
-[0xCA] = { 0,0, "BSWAP DX" },
-[0xCB] = { 0,0, "BSWAP BX" },
-[0xCC] = { 0,0, "BSWAP SP" },
-[0xCD] = { 0,0, "BSWAP BP" },
-[0xCE] = { 0,0, "BSWAP SI" },
-[0xCF] = { 0,0, "BSWAP DI" },
-[0xD1] = { RM,0, "PSRLW %m,%M" },
-[0xD2] = { RM,0, "PSRLL %m,%M" },
-[0xD3] = { RM,0, "PSRLQ %m,%M" },
-[0xD5] = { RM,0, "PMULLW %m,%M" },
-[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
-[0xD7] = { RM,0, "PMOVMSKB %m,%r" },
-[0xD8] = { RM,0, "PSUBUSB %m,%M" },
-[0xD9] = { RM,0, "PSUBUSW %m,%M" },
-[0xDA] = { RM,0, "PMINUB %m,%M" },
-[0xDB] = { RM,0, "PAND %m,%M" },
-[0xDC] = { RM,0, "PADDUSB %m,%M" },
-[0xDD] = { RM,0, "PADDUSW %m,%M" },
-[0xDE] = { RM,0, "PMAXUB %m,%M" },
-[0xDF] = { RM,0, "PANDN %m,%M" },
-[0xE0] = { RM,0, "PAVGB %m,%M" },
-[0xE1] = { RM,0, "PSRAW %m,%M" },
-[0xE2] = { RM,0, "PSRAL %m,%M" },
-[0xE3] = { RM,0, "PAVGW %m,%M" },
-[0xE4] = { RM,0, "PMULHUW %m,%M" },
-[0xE5] = { RM,0, "PMULHW %m,%M" },
-[0xE7] = { RM,0, "MOVNTQ %M,%e" },
-[0xE8] = { RM,0, "PSUBSB %m,%M" },
-[0xE9] = { RM,0, "PSUBSW %m,%M" },
-[0xEA] = { RM,0, "PMINSW %m,%M" },
-[0xEB] = { RM,0, "POR %m,%M" },
-[0xEC] = { RM,0, "PADDSB %m,%M" },
-[0xED] = { RM,0, "PADDSW %m,%M" },
-[0xEE] = { RM,0, "PMAXSW %m,%M" },
-[0xEF] = { RM,0, "PXOR %m,%M" },
-[0xF1] = { RM,0, "PSLLW %m,%M" },
-[0xF2] = { RM,0, "PSLLL %m,%M" },
-[0xF3] = { RM,0, "PSLLQ %m,%M" },
-[0xF4] = { RM,0, "PMULULQ %m,%M" },
-[0xF5] = { RM,0, "PMADDWL %m,%M" },
-[0xF6] = { RM,0, "PSADBW %m,%M" },
-[0xF7] = { RMR,0, "MASKMOVQ %m,%M" },
-[0xF8] = { RM,0, "PSUBB %m,%M" },
-[0xF9] = { RM,0, "PSUBW %m,%M" },
-[0xFA] = { RM,0, "PSUBL %m,%M" },
-[0xFC] = { RM,0, "PADDB %m,%M" },
-[0xFD] = { RM,0, "PADDW %m,%M" },
-[0xFE] = { RM,0, "PADDL %m,%M" },
-
-[0x80] = { Iwds,0, "JOS %p" },
-[0x81] = { Iwds,0, "JOC %p" },
-[0x82] = { Iwds,0, "JCS %p" },
-[0x83] = { Iwds,0, "JCC %p" },
-[0x84] = { Iwds,0, "JEQ %p" },
-[0x85] = { Iwds,0, "JNE %p" },
-[0x86] = { Iwds,0, "JLS %p" },
-[0x87] = { Iwds,0, "JHI %p" },
-[0x88] = { Iwds,0, "JMI %p" },
-[0x89] = { Iwds,0, "JPL %p" },
-[0x8a] = { Iwds,0, "JPS %p" },
-[0x8b] = { Iwds,0, "JPC %p" },
-[0x8c] = { Iwds,0, "JLT %p" },
-[0x8d] = { Iwds,0, "JGE %p" },
-[0x8e] = { Iwds,0, "JLE %p" },
-[0x8f] = { Iwds,0, "JGT %p" },
-[0x90] = { RMB,0, "SETOS %e" },
-[0x91] = { RMB,0, "SETOC %e" },
-[0x92] = { RMB,0, "SETCS %e" },
-[0x93] = { RMB,0, "SETCC %e" },
-[0x94] = { RMB,0, "SETEQ %e" },
-[0x95] = { RMB,0, "SETNE %e" },
-[0x96] = { RMB,0, "SETLS %e" },
-[0x97] = { RMB,0, "SETHI %e" },
-[0x98] = { RMB,0, "SETMI %e" },
-[0x99] = { RMB,0, "SETPL %e" },
-[0x9a] = { RMB,0, "SETPS %e" },
-[0x9b] = { RMB,0, "SETPC %e" },
-[0x9c] = { RMB,0, "SETLT %e" },
-[0x9d] = { RMB,0, "SETGE %e" },
-[0x9e] = { RMB,0, "SETLE %e" },
-[0x9f] = { RMB,0, "SETGT %e" },
-[0xa0] = { 0,0, "PUSHL FS" },
-[0xa1] = { 0,0, "POPL FS" },
-[0xa2] = { 0,0, "CPUID" },
-[0xa3] = { RM,0, "BT%S %r,%e" },
-[0xa4] = { RM,Ib, "SHLD%S %r,%i,%e" },
-[0xa5] = { RM,0, "SHLD%S %r,CL,%e" },
-[0xa8] = { 0,0, "PUSHL GS" },
-[0xa9] = { 0,0, "POPL GS" },
-[0xab] = { RM,0, "BTS%S %r,%e" },
-[0xac] = { RM,Ib, "SHRD%S %r,%i,%e" },
-[0xad] = { RM,0, "SHRD%S %r,CL,%e" },
-[0xaf] = { RM,0, "IMUL%S %e,%r" },
-[0xb2] = { RMM,0, "LSS %e,%r" },
-[0xb3] = { RM,0, "BTR%S %r,%e" },
-[0xb4] = { RMM,0, "LFS %e,%r" },
-[0xb5] = { RMM,0, "LGS %e,%r" },
-[0xb6] = { RMB,0, "MOVBZX %e,%R" },
-[0xb7] = { RM,0, "MOVWZX %e,%R" },
-[0xba] = { RMOP,0, optab0FBA },
-[0xbb] = { RM,0, "BTC%S %e,%r" },
-[0xbc] = { RM,0, "BSF%S %e,%r" },
-[0xbd] = { RM,0, "BSR%S %e,%r" },
-[0xbe] = { RMB,0, "MOVBSX %e,%R" },
-[0xbf] = { RM,0, "MOVWSX %e,%R" },
-[0xc7] = { RMOP,0, optab0FC7 },
-};
-
-static Optable optab80[8]=
-{
-[0x00] = { Ib,0, "ADDB %i,%e" },
-[0x01] = { Ib,0, "ORB %i,%e" },
-[0x02] = { Ib,0, "ADCB %i,%e" },
-[0x03] = { Ib,0, "SBBB %i,%e" },
-[0x04] = { Ib,0, "ANDB %i,%e" },
-[0x05] = { Ib,0, "SUBB %i,%e" },
-[0x06] = { Ib,0, "XORB %i,%e" },
-[0x07] = { Ib,0, "CMPB %e,%i" },
-};
-
-static Optable optab81[8]=
-{
-[0x00] = { Iwd,0, "ADD%S %i,%e" },
-[0x01] = { Iwd,0, "OR%S %i,%e" },
-[0x02] = { Iwd,0, "ADC%S %i,%e" },
-[0x03] = { Iwd,0, "SBB%S %i,%e" },
-[0x04] = { Iwd,0, "AND%S %i,%e" },
-[0x05] = { Iwd,0, "SUB%S %i,%e" },
-[0x06] = { Iwd,0, "XOR%S %i,%e" },
-[0x07] = { Iwd,0, "CMP%S %e,%i" },
-};
-
-static Optable optab83[8]=
-{
-[0x00] = { Ibs,0, "ADD%S %i,%e" },
-[0x01] = { Ibs,0, "OR%S %i,%e" },
-[0x02] = { Ibs,0, "ADC%S %i,%e" },
-[0x03] = { Ibs,0, "SBB%S %i,%e" },
-[0x04] = { Ibs,0, "AND%S %i,%e" },
-[0x05] = { Ibs,0, "SUB%S %i,%e" },
-[0x06] = { Ibs,0, "XOR%S %i,%e" },
-[0x07] = { Ibs,0, "CMP%S %e,%i" },
-};
-
-static Optable optabC0[8] =
-{
-[0x00] = { Ib,0, "ROLB %i,%e" },
-[0x01] = { Ib,0, "RORB %i,%e" },
-[0x02] = { Ib,0, "RCLB %i,%e" },
-[0x03] = { Ib,0, "RCRB %i,%e" },
-[0x04] = { Ib,0, "SHLB %i,%e" },
-[0x05] = { Ib,0, "SHRB %i,%e" },
-[0x07] = { Ib,0, "SARB %i,%e" },
-};
-
-static Optable optabC1[8] =
-{
-[0x00] = { Ib,0, "ROL%S %i,%e" },
-[0x01] = { Ib,0, "ROR%S %i,%e" },
-[0x02] = { Ib,0, "RCL%S %i,%e" },
-[0x03] = { Ib,0, "RCR%S %i,%e" },
-[0x04] = { Ib,0, "SHL%S %i,%e" },
-[0x05] = { Ib,0, "SHR%S %i,%e" },
-[0x07] = { Ib,0, "SAR%S %i,%e" },
-};
-
-static Optable optabD0[8] =
-{
-[0x00] = { 0,0, "ROLB %e" },
-[0x01] = { 0,0, "RORB %e" },
-[0x02] = { 0,0, "RCLB %e" },
-[0x03] = { 0,0, "RCRB %e" },
-[0x04] = { 0,0, "SHLB %e" },
-[0x05] = { 0,0, "SHRB %e" },
-[0x07] = { 0,0, "SARB %e" },
-};
-
-static Optable optabD1[8] =
-{
-[0x00] = { 0,0, "ROL%S %e" },
-[0x01] = { 0,0, "ROR%S %e" },
-[0x02] = { 0,0, "RCL%S %e" },
-[0x03] = { 0,0, "RCR%S %e" },
-[0x04] = { 0,0, "SHL%S %e" },
-[0x05] = { 0,0, "SHR%S %e" },
-[0x07] = { 0,0, "SAR%S %e" },
-};
-
-static Optable optabD2[8] =
-{
-[0x00] = { 0,0, "ROLB CL,%e" },
-[0x01] = { 0,0, "RORB CL,%e" },
-[0x02] = { 0,0, "RCLB CL,%e" },
-[0x03] = { 0,0, "RCRB CL,%e" },
-[0x04] = { 0,0, "SHLB CL,%e" },
-[0x05] = { 0,0, "SHRB CL,%e" },
-[0x07] = { 0,0, "SARB CL,%e" },
-};
-
-static Optable optabD3[8] =
-{
-[0x00] = { 0,0, "ROL%S CL,%e" },
-[0x01] = { 0,0, "ROR%S CL,%e" },
-[0x02] = { 0,0, "RCL%S CL,%e" },
-[0x03] = { 0,0, "RCR%S CL,%e" },
-[0x04] = { 0,0, "SHL%S CL,%e" },
-[0x05] = { 0,0, "SHR%S CL,%e" },
-[0x07] = { 0,0, "SAR%S CL,%e" },
-};
-
-static Optable optabD8[8+8] =
-{
-[0x00] = { 0,0, "FADDF %e,F0" },
-[0x01] = { 0,0, "FMULF %e,F0" },
-[0x02] = { 0,0, "FCOMF %e,F0" },
-[0x03] = { 0,0, "FCOMFP %e,F0" },
-[0x04] = { 0,0, "FSUBF %e,F0" },
-[0x05] = { 0,0, "FSUBRF %e,F0" },
-[0x06] = { 0,0, "FDIVF %e,F0" },
-[0x07] = { 0,0, "FDIVRF %e,F0" },
-[0x08] = { 0,0, "FADDD %f,F0" },
-[0x09] = { 0,0, "FMULD %f,F0" },
-[0x0a] = { 0,0, "FCOMD %f,F0" },
-[0x0b] = { 0,0, "FCOMPD %f,F0" },
-[0x0c] = { 0,0, "FSUBD %f,F0" },
-[0x0d] = { 0,0, "FSUBRD %f,F0" },
-[0x0e] = { 0,0, "FDIVD %f,F0" },
-[0x0f] = { 0,0, "FDIVRD %f,F0" },
-};
-/*
- * optabD9 and optabDB use the following encoding:
- * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
- * else instruction = optabDx[(modrm&0x3f)+8];
- *
- * the instructions for MOD == 3, follow the 8 instructions
- * for the other MOD values stored at the front of the table.
- */
-static Optable optabD9[64+8] =
-{
-[0x00] = { 0,0, "FMOVF %e,F0" },
-[0x02] = { 0,0, "FMOVF F0,%e" },
-[0x03] = { 0,0, "FMOVFP F0,%e" },
-[0x04] = { 0,0, "FLDENV%S %e" },
-[0x05] = { 0,0, "FLDCW %e" },
-[0x06] = { 0,0, "FSTENV%S %e" },
-[0x07] = { 0,0, "FSTCW %e" },
-[0x08] = { 0,0, "FMOVD F0,F0" }, /* Mod R/M = 11xx xxxx*/
-[0x09] = { 0,0, "FMOVD F1,F0" },
-[0x0a] = { 0,0, "FMOVD F2,F0" },
-[0x0b] = { 0,0, "FMOVD F3,F0" },
-[0x0c] = { 0,0, "FMOVD F4,F0" },
-[0x0d] = { 0,0, "FMOVD F5,F0" },
-[0x0e] = { 0,0, "FMOVD F6,F0" },
-[0x0f] = { 0,0, "FMOVD F7,F0" },
-[0x10] = { 0,0, "FXCHD F0,F0" },
-[0x11] = { 0,0, "FXCHD F1,F0" },
-[0x12] = { 0,0, "FXCHD F2,F0" },
-[0x13] = { 0,0, "FXCHD F3,F0" },
-[0x14] = { 0,0, "FXCHD F4,F0" },
-[0x15] = { 0,0, "FXCHD F5,F0" },
-[0x16] = { 0,0, "FXCHD F6,F0" },
-[0x17] = { 0,0, "FXCHD F7,F0" },
-[0x18] = { 0,0, "FNOP" },
-[0x28] = { 0,0, "FCHS" },
-[0x29] = { 0,0, "FABS" },
-[0x2c] = { 0,0, "FTST" },
-[0x2d] = { 0,0, "FXAM" },
-[0x30] = { 0,0, "FLD1" },
-[0x31] = { 0,0, "FLDL2T" },
-[0x32] = { 0,0, "FLDL2E" },
-[0x33] = { 0,0, "FLDPI" },
-[0x34] = { 0,0, "FLDLG2" },
-[0x35] = { 0,0, "FLDLN2" },
-[0x36] = { 0,0, "FLDZ" },
-[0x38] = { 0,0, "F2XM1" },
-[0x39] = { 0,0, "FYL2X" },
-[0x3a] = { 0,0, "FPTAN" },
-[0x3b] = { 0,0, "FPATAN" },
-[0x3c] = { 0,0, "FXTRACT" },
-[0x3d] = { 0,0, "FPREM1" },
-[0x3e] = { 0,0, "FDECSTP" },
-[0x3f] = { 0,0, "FNCSTP" },
-[0x40] = { 0,0, "FPREM" },
-[0x41] = { 0,0, "FYL2XP1" },
-[0x42] = { 0,0, "FSQRT" },
-[0x43] = { 0,0, "FSINCOS" },
-[0x44] = { 0,0, "FRNDINT" },
-[0x45] = { 0,0, "FSCALE" },
-[0x46] = { 0,0, "FSIN" },
-[0x47] = { 0,0, "FCOS" },
-};
-
-static Optable optabDA[8+8] =
-{
-[0x00] = { 0,0, "FADDL %e,F0" },
-[0x01] = { 0,0, "FMULL %e,F0" },
-[0x02] = { 0,0, "FCOML %e,F0" },
-[0x03] = { 0,0, "FCOMLP %e,F0" },
-[0x04] = { 0,0, "FSUBL %e,F0" },
-[0x05] = { 0,0, "FSUBRL %e,F0" },
-[0x06] = { 0,0, "FDIVL %e,F0" },
-[0x07] = { 0,0, "FDIVRL %e,F0" },
-[0x08] = { 0,0, "FCMOVCS %f,F0" },
-[0x09] = { 0,0, "FCMOVEQ %f,F0" },
-[0x0a] = { 0,0, "FCMOVLS %f,F0" },
-[0x0b] = { 0,0, "FCMOVUN %f,F0" },
-[0x0d] = { Op_R1,0, "FUCOMPP" },
-};
-
-static Optable optabDB[8+64] =
-{
-[0x00] = { 0,0, "FMOVL %e,F0" },
-[0x02] = { 0,0, "FMOVL F0,%e" },
-[0x03] = { 0,0, "FMOVLP F0,%e" },
-[0x05] = { 0,0, "FMOVX %e,F0" },
-[0x07] = { 0,0, "FMOVXP F0,%e" },
-[0x08] = { 0,0, "FCMOVCC F0,F0" }, /* Mod R/M = 11xx xxxx*/
-[0x09] = { 0,0, "FCMOVCC F1,F0" },
-[0x0a] = { 0,0, "FCMOVCC F2,F0" },
-[0x0b] = { 0,0, "FCMOVCC F3,F0" },
-[0x0c] = { 0,0, "FCMOVCC F4,F0" },
-[0x0d] = { 0,0, "FCMOVCC F5,F0" },
-[0x0e] = { 0,0, "FCMOVCC F6,F0" },
-[0x0f] = { 0,0, "FCMOVCC F7,F0" },
-[0x10] = { 0,0, "FCMOVNE F0,F0" },
-[0x11] = { 0,0, "FCMOVNE F1,F0" },
-[0x12] = { 0,0, "FCMOVNE F2,F0" },
-[0x13] = { 0,0, "FCMOVNE F3,F0" },
-[0x14] = { 0,0, "FCMOVNE F4,F0" },
-[0x15] = { 0,0, "FCMOVNE F5,F0" },
-[0x16] = { 0,0, "FCMOVNE F6,F0" },
-[0x17] = { 0,0, "FCMOVNE F7,F0" },
-[0x18] = { 0,0, "FCMOVHI F0,F0" },
-[0x19] = { 0,0, "FCMOVHI F1,F0" },
-[0x1a] = { 0,0, "FCMOVHI F2,F0" },
-[0x1b] = { 0,0, "FCMOVHI F3,F0" },
-[0x1c] = { 0,0, "FCMOVHI F4,F0" },
-[0x1d] = { 0,0, "FCMOVHI F5,F0" },
-[0x1e] = { 0,0, "FCMOVHI F6,F0" },
-[0x1f] = { 0,0, "FCMOVHI F7,F0" },
-[0x20] = { 0,0, "FCMOVNU F0,F0" },
-[0x21] = { 0,0, "FCMOVNU F1,F0" },
-[0x22] = { 0,0, "FCMOVNU F2,F0" },
-[0x23] = { 0,0, "FCMOVNU F3,F0" },
-[0x24] = { 0,0, "FCMOVNU F4,F0" },
-[0x25] = { 0,0, "FCMOVNU F5,F0" },
-[0x26] = { 0,0, "FCMOVNU F6,F0" },
-[0x27] = { 0,0, "FCMOVNU F7,F0" },
-[0x2a] = { 0,0, "FCLEX" },
-[0x2b] = { 0,0, "FINIT" },
-[0x30] = { 0,0, "FUCOMI F0,F0" },
-[0x31] = { 0,0, "FUCOMI F1,F0" },
-[0x32] = { 0,0, "FUCOMI F2,F0" },
-[0x33] = { 0,0, "FUCOMI F3,F0" },
-[0x34] = { 0,0, "FUCOMI F4,F0" },
-[0x35] = { 0,0, "FUCOMI F5,F0" },
-[0x36] = { 0,0, "FUCOMI F6,F0" },
-[0x37] = { 0,0, "FUCOMI F7,F0" },
-[0x38] = { 0,0, "FCOMI F0,F0" },
-[0x39] = { 0,0, "FCOMI F1,F0" },
-[0x3a] = { 0,0, "FCOMI F2,F0" },
-[0x3b] = { 0,0, "FCOMI F3,F0" },
-[0x3c] = { 0,0, "FCOMI F4,F0" },
-[0x3d] = { 0,0, "FCOMI F5,F0" },
-[0x3e] = { 0,0, "FCOMI F6,F0" },
-[0x3f] = { 0,0, "FCOMI F7,F0" },
-};
-
-static Optable optabDC[8+8] =
-{
-[0x00] = { 0,0, "FADDD %e,F0" },
-[0x01] = { 0,0, "FMULD %e,F0" },
-[0x02] = { 0,0, "FCOMD %e,F0" },
-[0x03] = { 0,0, "FCOMDP %e,F0" },
-[0x04] = { 0,0, "FSUBD %e,F0" },
-[0x05] = { 0,0, "FSUBRD %e,F0" },
-[0x06] = { 0,0, "FDIVD %e,F0" },
-[0x07] = { 0,0, "FDIVRD %e,F0" },
-[0x08] = { 0,0, "FADDD F0,%f" },
-[0x09] = { 0,0, "FMULD F0,%f" },
-[0x0c] = { 0,0, "FSUBRD F0,%f" },
-[0x0d] = { 0,0, "FSUBD F0,%f" },
-[0x0e] = { 0,0, "FDIVRD F0,%f" },
-[0x0f] = { 0,0, "FDIVD F0,%f" },
-};
-
-static Optable optabDD[8+8] =
-{
-[0x00] = { 0,0, "FMOVD %e,F0" },
-[0x02] = { 0,0, "FMOVD F0,%e" },
-[0x03] = { 0,0, "FMOVDP F0,%e" },
-[0x04] = { 0,0, "FRSTOR%S %e" },
-[0x06] = { 0,0, "FSAVE%S %e" },
-[0x07] = { 0,0, "FSTSW %e" },
-[0x08] = { 0,0, "FFREED %f" },
-[0x0a] = { 0,0, "FMOVD %f,F0" },
-[0x0b] = { 0,0, "FMOVDP %f,F0" },
-[0x0c] = { 0,0, "FUCOMD %f,F0" },
-[0x0d] = { 0,0, "FUCOMDP %f,F0" },
-};
-
-static Optable optabDE[8+8] =
-{
-[0x00] = { 0,0, "FADDW %e,F0" },
-[0x01] = { 0,0, "FMULW %e,F0" },
-[0x02] = { 0,0, "FCOMW %e,F0" },
-[0x03] = { 0,0, "FCOMWP %e,F0" },
-[0x04] = { 0,0, "FSUBW %e,F0" },
-[0x05] = { 0,0, "FSUBRW %e,F0" },
-[0x06] = { 0,0, "FDIVW %e,F0" },
-[0x07] = { 0,0, "FDIVRW %e,F0" },
-[0x08] = { 0,0, "FADDDP F0,%f" },
-[0x09] = { 0,0, "FMULDP F0,%f" },
-[0x0b] = { Op_R1,0, "FCOMPDP" },
-[0x0c] = { 0,0, "FSUBRDP F0,%f" },
-[0x0d] = { 0,0, "FSUBDP F0,%f" },
-[0x0e] = { 0,0, "FDIVRDP F0,%f" },
-[0x0f] = { 0,0, "FDIVDP F0,%f" },
-};
-
-static Optable optabDF[8+8] =
-{
-[0x00] = { 0,0, "FMOVW %e,F0" },
-[0x02] = { 0,0, "FMOVW F0,%e" },
-[0x03] = { 0,0, "FMOVWP F0,%e" },
-[0x04] = { 0,0, "FBLD %e" },
-[0x05] = { 0,0, "FMOVL %e,F0" },
-[0x06] = { 0,0, "FBSTP %e" },
-[0x07] = { 0,0, "FMOVLP F0,%e" },
-[0x0c] = { Op_R0,0, "FSTSW %OAX" },
-[0x0d] = { 0,0, "FUCOMIP F0,%f" },
-[0x0e] = { 0,0, "FCOMIP F0,%f" },
-};
-
-static Optable optabF6[8] =
-{
-[0x00] = { Ib,0, "TESTB %i,%e" },
-[0x02] = { 0,0, "NOTB %e" },
-[0x03] = { 0,0, "NEGB %e" },
-[0x04] = { 0,0, "MULB AL,%e" },
-[0x05] = { 0,0, "IMULB AL,%e" },
-[0x06] = { 0,0, "DIVB AL,%e" },
-[0x07] = { 0,0, "IDIVB AL,%e" },
-};
-
-static Optable optabF7[8] =
-{
-[0x00] = { Iwd,0, "TEST%S %i,%e" },
-[0x02] = { 0,0, "NOT%S %e" },
-[0x03] = { 0,0, "NEG%S %e" },
-[0x04] = { 0,0, "MUL%S %OAX,%e" },
-[0x05] = { 0,0, "IMUL%S %OAX,%e" },
-[0x06] = { 0,0, "DIV%S %OAX,%e" },
-[0x07] = { 0,0, "IDIV%S %OAX,%e" },
-};
-
-static Optable optabFE[8] =
-{
-[0x00] = { 0,0, "INCB %e" },
-[0x01] = { 0,0, "DECB %e" },
-};
-
-static Optable optabFF[8] =
-{
-[0x00] = { 0,0, "INC%S %e" },
-[0x01] = { 0,0, "DEC%S %e" },
-[0x02] = { JUMP,0, "CALL* %e" },
-[0x03] = { JUMP,0, "CALLF* %e" },
-[0x04] = { JUMP,0, "JMP* %e" },
-[0x05] = { JUMP,0, "JMPF* %e" },
-[0x06] = { 0,0, "PUSHL %e" },
-};
-
-static Optable optable[256+2] =
-{
-[0x00] = { RMB,0, "ADDB %r,%e" },
-[0x01] = { RM,0, "ADD%S %r,%e" },
-[0x02] = { RMB,0, "ADDB %e,%r" },
-[0x03] = { RM,0, "ADD%S %e,%r" },
-[0x04] = { Ib,0, "ADDB %i,AL" },
-[0x05] = { Iwd,0, "ADD%S %i,%OAX" },
-[0x06] = { 0,0, "PUSHL ES" },
-[0x07] = { 0,0, "POPL ES" },
-[0x08] = { RMB,0, "ORB %r,%e" },
-[0x09] = { RM,0, "OR%S %r,%e" },
-[0x0a] = { RMB,0, "ORB %e,%r" },
-[0x0b] = { RM,0, "OR%S %e,%r" },
-[0x0c] = { Ib,0, "ORB %i,AL" },
-[0x0d] = { Iwd,0, "OR%S %i,%OAX" },
-[0x0e] = { 0,0, "PUSHL CS" },
-[0x0f] = { AUXMM,0, optab0F },
-[0x10] = { RMB,0, "ADCB %r,%e" },
-[0x11] = { RM,0, "ADC%S %r,%e" },
-[0x12] = { RMB,0, "ADCB %e,%r" },
-[0x13] = { RM,0, "ADC%S %e,%r" },
-[0x14] = { Ib,0, "ADCB %i,AL" },
-[0x15] = { Iwd,0, "ADC%S %i,%OAX" },
-[0x16] = { 0,0, "PUSHL SS" },
-[0x17] = { 0,0, "POPL SS" },
-[0x18] = { RMB,0, "SBBB %r,%e" },
-[0x19] = { RM,0, "SBB%S %r,%e" },
-[0x1a] = { RMB,0, "SBBB %e,%r" },
-[0x1b] = { RM,0, "SBB%S %e,%r" },
-[0x1c] = { Ib,0, "SBBB %i,AL" },
-[0x1d] = { Iwd,0, "SBB%S %i,%OAX" },
-[0x1e] = { 0,0, "PUSHL DS" },
-[0x1f] = { 0,0, "POPL DS" },
-[0x20] = { RMB,0, "ANDB %r,%e" },
-[0x21] = { RM,0, "AND%S %r,%e" },
-[0x22] = { RMB,0, "ANDB %e,%r" },
-[0x23] = { RM,0, "AND%S %e,%r" },
-[0x24] = { Ib,0, "ANDB %i,AL" },
-[0x25] = { Iwd,0, "AND%S %i,%OAX" },
-[0x26] = { SEG,0, "ES:" },
-[0x27] = { 0,0, "DAA" },
-[0x28] = { RMB,0, "SUBB %r,%e" },
-[0x29] = { RM,0, "SUB%S %r,%e" },
-[0x2a] = { RMB,0, "SUBB %e,%r" },
-[0x2b] = { RM,0, "SUB%S %e,%r" },
-[0x2c] = { Ib,0, "SUBB %i,AL" },
-[0x2d] = { Iwd,0, "SUB%S %i,%OAX" },
-[0x2e] = { SEG,0, "CS:" },
-[0x2f] = { 0,0, "DAS" },
-[0x30] = { RMB,0, "XORB %r,%e" },
-[0x31] = { RM,0, "XOR%S %r,%e" },
-[0x32] = { RMB,0, "XORB %e,%r" },
-[0x33] = { RM,0, "XOR%S %e,%r" },
-[0x34] = { Ib,0, "XORB %i,AL" },
-[0x35] = { Iwd,0, "XOR%S %i,%OAX" },
-[0x36] = { SEG,0, "SS:" },
-[0x37] = { 0,0, "AAA" },
-[0x38] = { RMB,0, "CMPB %r,%e" },
-[0x39] = { RM,0, "CMP%S %r,%e" },
-[0x3a] = { RMB,0, "CMPB %e,%r" },
-[0x3b] = { RM,0, "CMP%S %e,%r" },
-[0x3c] = { Ib,0, "CMPB %i,AL" },
-[0x3d] = { Iwd,0, "CMP%S %i,%OAX" },
-[0x3e] = { SEG,0, "DS:" },
-[0x3f] = { 0,0, "AAS" },
-[0x40] = { 0,0, "INC%S %OAX" },
-[0x41] = { 0,0, "INC%S %OCX" },
-[0x42] = { 0,0, "INC%S %ODX" },
-[0x43] = { 0,0, "INC%S %OBX" },
-[0x44] = { 0,0, "INC%S %OSP" },
-[0x45] = { 0,0, "INC%S %OBP" },
-[0x46] = { 0,0, "INC%S %OSI" },
-[0x47] = { 0,0, "INC%S %ODI" },
-[0x48] = { 0,0, "DEC%S %OAX" },
-[0x49] = { 0,0, "DEC%S %OCX" },
-[0x4a] = { 0,0, "DEC%S %ODX" },
-[0x4b] = { 0,0, "DEC%S %OBX" },
-[0x4c] = { 0,0, "DEC%S %OSP" },
-[0x4d] = { 0,0, "DEC%S %OBP" },
-[0x4e] = { 0,0, "DEC%S %OSI" },
-[0x4f] = { 0,0, "DEC%S %ODI" },
-[0x50] = { 0,0, "PUSH%S %OAX" },
-[0x51] = { 0,0, "PUSH%S %OCX" },
-[0x52] = { 0,0, "PUSH%S %ODX" },
-[0x53] = { 0,0, "PUSH%S %OBX" },
-[0x54] = { 0,0, "PUSH%S %OSP" },
-[0x55] = { 0,0, "PUSH%S %OBP" },
-[0x56] = { 0,0, "PUSH%S %OSI" },
-[0x57] = { 0,0, "PUSH%S %ODI" },
-[0x58] = { 0,0, "POP%S %OAX" },
-[0x59] = { 0,0, "POP%S %OCX" },
-[0x5a] = { 0,0, "POP%S %ODX" },
-[0x5b] = { 0,0, "POP%S %OBX" },
-[0x5c] = { 0,0, "POP%S %OSP" },
-[0x5d] = { 0,0, "POP%S %OBP" },
-[0x5e] = { 0,0, "POP%S %OSI" },
-[0x5f] = { 0,0, "POP%S %ODI" },
-[0x60] = { 0,0, "PUSHA%S" },
-[0x61] = { 0,0, "POPA%S" },
-[0x62] = { RMM,0, "BOUND %e,%r" },
-[0x63] = { RM,0, "ARPL %r,%e" },
-[0x64] = { SEG,0, "FS:" },
-[0x65] = { SEG,0, "GS:" },
-[0x66] = { OPOVER,0, "" },
-[0x67] = { ADDOVER,0, "" },
-[0x68] = { Iwd,0, "PUSH%S %i" },
-[0x69] = { RM,Iwd, "IMUL%S %e,%i,%r" },
-[0x6a] = { Ib,0, "PUSH%S %i" },
-[0x6b] = { RM,Ibs, "IMUL%S %e,%i,%r" },
-[0x6c] = { 0,0, "INSB DX,(%ODI)" },
-[0x6d] = { 0,0, "INS%S DX,(%ODI)" },
-[0x6e] = { 0,0, "OUTSB (%ASI),DX" },
-[0x6f] = { 0,0, "OUTS%S (%ASI),DX" },
-[0x70] = { Jbs,0, "JOS %p" },
-[0x71] = { Jbs,0, "JOC %p" },
-[0x72] = { Jbs,0, "JCS %p" },
-[0x73] = { Jbs,0, "JCC %p" },
-[0x74] = { Jbs,0, "JEQ %p" },
-[0x75] = { Jbs,0, "JNE %p" },
-[0x76] = { Jbs,0, "JLS %p" },
-[0x77] = { Jbs,0, "JHI %p" },
-[0x78] = { Jbs,0, "JMI %p" },
-[0x79] = { Jbs,0, "JPL %p" },
-[0x7a] = { Jbs,0, "JPS %p" },
-[0x7b] = { Jbs,0, "JPC %p" },
-[0x7c] = { Jbs,0, "JLT %p" },
-[0x7d] = { Jbs,0, "JGE %p" },
-[0x7e] = { Jbs,0, "JLE %p" },
-[0x7f] = { Jbs,0, "JGT %p" },
-[0x80] = { RMOPB,0, optab80 },
-[0x81] = { RMOP,0, optab81 },
-[0x83] = { RMOP,0, optab83 },
-[0x84] = { RMB,0, "TESTB %r,%e" },
-[0x85] = { RM,0, "TEST%S %r,%e" },
-[0x86] = { RMB,0, "XCHGB %r,%e" },
-[0x87] = { RM,0, "XCHG%S %r,%e" },
-[0x88] = { RMB,0, "MOVB %r,%e" },
-[0x89] = { RM,0, "MOV%S %r,%e" },
-[0x8a] = { RMB,0, "MOVB %e,%r" },
-[0x8b] = { RM,0, "MOV%S %e,%r" },
-[0x8c] = { RM,0, "MOVW %g,%e" },
-[0x8d] = { RM,0, "LEA%S %e,%r" },
-[0x8e] = { RM,0, "MOVW %e,%g" },
-[0x8f] = { RM,0, "POP%S %e" },
-[0x90] = { 0,0, "NOP" },
-[0x91] = { 0,0, "XCHG %OCX,%OAX" },
-[0x92] = { 0,0, "XCHG %ODX,%OAX" },
-[0x93] = { 0,0, "XCHG %OBX,%OAX" },
-[0x94] = { 0,0, "XCHG %OSP,%OAX" },
-[0x95] = { 0,0, "XCHG %OBP,%OAX" },
-[0x96] = { 0,0, "XCHG %OSI,%OAX" },
-[0x97] = { 0,0, "XCHG %ODI,%OAX" },
-[0x98] = { 0,0, "%W" }, /* miserable CBW or CWDE */
-[0x99] = { 0,0, "%w" }, /* idiotic CWD or CDQ */
-[0x9a] = { PTR,0, "CALL%S %d" },
-[0x9b] = { 0,0, "WAIT" },
-[0x9c] = { 0,0, "PUSHF" },
-[0x9d] = { 0,0, "POPF" },
-[0x9e] = { 0,0, "SAHF" },
-[0x9f] = { 0,0, "LAHF" },
-[0xa0] = { Awd,0, "MOVB %i,AL" },
-[0xa1] = { Awd,0, "MOV%S %i,%OAX" },
-[0xa2] = { Awd,0, "MOVB AL,%i" },
-[0xa3] = { Awd,0, "MOV%S %OAX,%i" },
-[0xa4] = { 0,0, "MOVSB (%ASI),(%ADI)" },
-[0xa5] = { 0,0, "MOVS%S (%ASI),(%ADI)" },
-[0xa6] = { 0,0, "CMPSB (%ASI),(%ADI)" },
-[0xa7] = { 0,0, "CMPS%S (%ASI),(%ADI)" },
-[0xa8] = { Ib,0, "TESTB %i,AL" },
-[0xa9] = { Iwd,0, "TEST%S %i,%OAX" },
-[0xaa] = { 0,0, "STOSB AL,(%ADI)" },
-[0xab] = { 0,0, "STOS%S %OAX,(%ADI)" },
-[0xac] = { 0,0, "LODSB (%ASI),AL" },
-[0xad] = { 0,0, "LODS%S (%ASI),%OAX" },
-[0xae] = { 0,0, "SCASB (%ADI),AL" },
-[0xaf] = { 0,0, "SCAS%S (%ADI),%OAX" },
-[0xb0] = { Ib,0, "MOVB %i,AL" },
-[0xb1] = { Ib,0, "MOVB %i,CL" },
-[0xb2] = { Ib,0, "MOVB %i,DL" },
-[0xb3] = { Ib,0, "MOVB %i,BL" },
-[0xb4] = { Ib,0, "MOVB %i,AH" },
-[0xb5] = { Ib,0, "MOVB %i,CH" },
-[0xb6] = { Ib,0, "MOVB %i,DH" },
-[0xb7] = { Ib,0, "MOVB %i,BH" },
-[0xb8] = { Iwdq,0, "MOV%S %i,%OAX" },
-[0xb9] = { Iwdq,0, "MOV%S %i,%OCX" },
-[0xba] = { Iwdq,0, "MOV%S %i,%ODX" },
-[0xbb] = { Iwdq,0, "MOV%S %i,%OBX" },
-[0xbc] = { Iwdq,0, "MOV%S %i,%OSP" },
-[0xbd] = { Iwdq,0, "MOV%S %i,%OBP" },
-[0xbe] = { Iwdq,0, "MOV%S %i,%OSI" },
-[0xbf] = { Iwdq,0, "MOV%S %i,%ODI" },
-[0xc0] = { RMOPB,0, optabC0 },
-[0xc1] = { RMOP,0, optabC1 },
-[0xc2] = { Iw,0, "RET %i" },
-[0xc3] = { RET,0, "RET" },
-[0xc4] = { RM,0, "LES %e,%r" },
-[0xc5] = { RM,0, "LDS %e,%r" },
-[0xc6] = { RMB,Ib, "MOVB %i,%e" },
-[0xc7] = { RM,Iwd, "MOV%S %i,%e" },
-[0xc8] = { Iw2,Ib, "ENTER %i,%I" }, /* loony ENTER */
-[0xc9] = { RET,0, "LEAVE" }, /* bizarre LEAVE */
-[0xca] = { Iw,0, "RETF %i" },
-[0xcb] = { RET,0, "RETF" },
-[0xcc] = { 0,0, "INT 3" },
-[0xcd] = { Ib,0, "INTB %i" },
-[0xce] = { 0,0, "INTO" },
-[0xcf] = { 0,0, "IRET" },
-[0xd0] = { RMOPB,0, optabD0 },
-[0xd1] = { RMOP,0, optabD1 },
-[0xd2] = { RMOPB,0, optabD2 },
-[0xd3] = { RMOP,0, optabD3 },
-[0xd4] = { OA,0, "AAM" },
-[0xd5] = { OA,0, "AAD" },
-[0xd7] = { 0,0, "XLAT" },
-[0xd8] = { FRMOP,0, optabD8 },
-[0xd9] = { FRMEX,0, optabD9 },
-[0xda] = { FRMOP,0, optabDA },
-[0xdb] = { FRMEX,0, optabDB },
-[0xdc] = { FRMOP,0, optabDC },
-[0xdd] = { FRMOP,0, optabDD },
-[0xde] = { FRMOP,0, optabDE },
-[0xdf] = { FRMOP,0, optabDF },
-[0xe0] = { Jbs,0, "LOOPNE %p" },
-[0xe1] = { Jbs,0, "LOOPE %p" },
-[0xe2] = { Jbs,0, "LOOP %p" },
-[0xe3] = { Jbs,0, "JCXZ %p" },
-[0xe4] = { Ib,0, "INB %i,AL" },
-[0xe5] = { Ib,0, "IN%S %i,%OAX" },
-[0xe6] = { Ib,0, "OUTB AL,%i" },
-[0xe7] = { Ib,0, "OUT%S %OAX,%i" },
-[0xe8] = { Iwds,0, "CALL %p" },
-[0xe9] = { Iwds,0, "JMP %p" },
-[0xea] = { PTR,0, "JMP %d" },
-[0xeb] = { Jbs,0, "JMP %p" },
-[0xec] = { 0,0, "INB DX,AL" },
-[0xed] = { 0,0, "IN%S DX,%OAX" },
-[0xee] = { 0,0, "OUTB AL,DX" },
-[0xef] = { 0,0, "OUT%S %OAX,DX" },
-[0xf0] = { PRE,0, "LOCK" },
-[0xf2] = { OPRE,0, "REPNE" },
-[0xf3] = { OPRE,0, "REP" },
-[0xf4] = { 0,0, "HLT" },
-[0xf5] = { 0,0, "CMC" },
-[0xf6] = { RMOPB,0, optabF6 },
-[0xf7] = { RMOP,0, optabF7 },
-[0xf8] = { 0,0, "CLC" },
-[0xf9] = { 0,0, "STC" },
-[0xfa] = { 0,0, "CLI" },
-[0xfb] = { 0,0, "STI" },
-[0xfc] = { 0,0, "CLD" },
-[0xfd] = { 0,0, "STD" },
-[0xfe] = { RMOPB,0, optabFE },
-[0xff] = { RMOP,0, optabFF },
-[0x100] = { RM,0, "MOVLQSX %e,%r" },
-[0x101] = { RM,0, "MOVLQZX %e,%r" },
-};
-
-/*
- * get a byte of the instruction
- */
-static int
-igetc(Map *map, Instr *ip, uchar *c)
-{
- if(ip->n+1 > sizeof(ip->mem)){
- werrstr("instruction too long");
- return -1;
- }
- if (get1(map, ip->addr+ip->n, c, 1) < 0) {
- werrstr("can't read instruction: %r");
- return -1;
- }
- ip->mem[ip->n++] = *c;
- return 1;
-}
-
-/*
- * get two bytes of the instruction
- */
-static int
-igets(Map *map, Instr *ip, ushort *sp)
-{
- uchar c;
- ushort s;
-
- if (igetc(map, ip, &c) < 0)
- return -1;
- s = c;
- if (igetc(map, ip, &c) < 0)
- return -1;
- s |= (c<<8);
- *sp = s;
- return 1;
-}
-
-/*
- * get 4 bytes of the instruction
- */
-static int
-igetl(Map *map, Instr *ip, uint32 *lp)
-{
- ushort s;
- int32 l;
-
- if (igets(map, ip, &s) < 0)
- return -1;
- l = s;
- if (igets(map, ip, &s) < 0)
- return -1;
- l |= (s<<16);
- *lp = l;
- return 1;
-}
-
-/*
- * get 8 bytes of the instruction
- *
-static int
-igetq(Map *map, Instr *ip, vlong *qp)
-{
- uint32 l;
- uvlong q;
-
- if (igetl(map, ip, &l) < 0)
- return -1;
- q = l;
- if (igetl(map, ip, &l) < 0)
- return -1;
- q |= ((uvlong)l<<32);
- *qp = q;
- return 1;
-}
- */
-
-static int
-getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
-{
- uchar c;
- ushort s;
-
- if (mod > 2)
- return 1;
- if (mod == 1) {
- if (igetc(map, ip, &c) < 0)
- return -1;
- if (c&0x80)
- ip->disp = c|0xffffff00;
- else
- ip->disp = c&0xff;
- } else if (mod == 2 || rm == code) {
- if (ip->asize == 'E') {
- if (igetl(map, ip, &ip->disp) < 0)
- return -1;
- if (mod == 0)
- ip->rip = pcrel;
- } else {
- if (igets(map, ip, &s) < 0)
- return -1;
- if (s&0x8000)
- ip->disp = s|0xffff0000;
- else
- ip->disp = s;
- }
- if (mod == 0)
- ip->base = -1;
- }
- return 1;
-}
-
-static int
-modrm(Map *map, Instr *ip, uchar c)
-{
- uchar rm, mod;
-
- mod = (c>>6)&3;
- rm = c&7;
- ip->mod = mod;
- ip->base = rm;
- ip->reg = (c>>3)&7;
- ip->rip = 0;
- if (mod == 3) /* register */
- return 1;
- if (ip->asize == 0) { /* 16-bit mode */
- switch(rm) {
- case 0:
- ip->base = BX; ip->index = SI;
- break;
- case 1:
- ip->base = BX; ip->index = DI;
- break;
- case 2:
- ip->base = BP; ip->index = SI;
- break;
- case 3:
- ip->base = BP; ip->index = DI;
- break;
- case 4:
- ip->base = SI;
- break;
- case 5:
- ip->base = DI;
- break;
- case 6:
- ip->base = BP;
- break;
- case 7:
- ip->base = BX;
- break;
- default:
- break;
- }
- return getdisp(map, ip, mod, rm, 6, 0);
- }
- if (rm == 4) { /* scummy sib byte */
- if (igetc(map, ip, &c) < 0)
- return -1;
- ip->ss = (c>>6)&0x03;
- ip->index = (c>>3)&0x07;
- if (ip->index == 4)
- ip->index = -1;
- ip->base = c&0x07;
- return getdisp(map, ip, mod, ip->base, 5, 0);
- }
- return getdisp(map, ip, mod, rm, 5, ip->amd64);
-}
-
-static Optable *
-mkinstr(Map *map, Instr *ip, uvlong pc)
-{
- int i, n, norex;
- uchar c;
- ushort s;
- Optable *op, *obase;
- char buf[128];
-
- memset(ip, 0, sizeof(*ip));
- norex = 1;
- ip->base = -1;
- ip->index = -1;
- if(asstype == AI8086)
- ip->osize = 'W';
- else {
- ip->osize = 'L';
- ip->asize = 'E';
- ip->amd64 = asstype != AI386;
- norex = 0;
- }
- ip->addr = pc;
- if (igetc(map, ip, &c) < 0)
- return 0;
- obase = optable;
-newop:
- if(ip->amd64 && !norex){
- if(c >= 0x40 && c <= 0x4f) {
- ip->rex = c;
- if(igetc(map, ip, &c) < 0)
- return 0;
- }
- if(c == 0x63){
- if(ip->rex&REXW)
- op = &obase[0x100]; /* MOVLQSX */
- else
- op = &obase[0x101]; /* MOVLQZX */
- goto hack;
- }
- }
- op = &obase[c];
-hack:
- if (op->proto == 0) {
-badop:
- n = snprint(buf, sizeof(buf), "opcode: ??");
- for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
- _hexify(buf+n, ip->mem[i], 1);
- strcpy(buf+n, "??");
- werrstr(buf);
- return 0;
- }
- for(i = 0; i < 2 && op->operand[i]; i++) {
- switch(op->operand[i]) {
- case Ib: /* 8-bit immediate - (no sign extension)*/
- if (igetc(map, ip, &c) < 0)
- return 0;
- ip->imm = c&0xff;
- ip->imm64 = ip->imm;
- break;
- case Jbs: /* 8-bit jump immediate (sign extended) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (c&0x80)
- ip->imm = c|0xffffff00;
- else
- ip->imm = c&0xff;
- ip->imm64 = (int32)ip->imm;
- ip->jumptype = Jbs;
- break;
- case Ibs: /* 8-bit immediate (sign extended) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (c&0x80)
- if (ip->osize == 'L')
- ip->imm = c|0xffffff00;
- else
- ip->imm = c|0xff00;
- else
- ip->imm = c&0xff;
- ip->imm64 = (int32)ip->imm;
- break;
- case Iw: /* 16-bit immediate -> imm */
- if (igets(map, ip, &s) < 0)
- return 0;
- ip->imm = s&0xffff;
- ip->imm64 = ip->imm;
- ip->jumptype = Iw;
- break;
- case Iw2: /* 16-bit immediate -> in imm2*/
- if (igets(map, ip, &s) < 0)
- return 0;
- ip->imm2 = s&0xffff;
- break;
- case Iwd: /* Operand-sized immediate (no sign extension unless 64 bits)*/
- if (ip->osize == 'L') {
- if (igetl(map, ip, &ip->imm) < 0)
- return 0;
- ip->imm64 = ip->imm;
- if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
- ip->imm64 |= (vlong)~0 << 32;
- } else {
- if (igets(map, ip, &s)< 0)
- return 0;
- ip->imm = s&0xffff;
- ip->imm64 = ip->imm;
- }
- break;
- case Iwdq: /* Operand-sized immediate, possibly big */
- if (ip->osize == 'L') {
- if (igetl(map, ip, &ip->imm) < 0)
- return 0;
- ip->imm64 = ip->imm;
- if (ip->rex & REXW) {
- uint32 l;
- if (igetl(map, ip, &l) < 0)
- return 0;
- ip->imm64 |= (uvlong)l << 32;
- }
- } else {
- if (igets(map, ip, &s)< 0)
- return 0;
- ip->imm = s&0xffff;
- }
- break;
- case Awd: /* Address-sized immediate (no sign extension)*/
- if (ip->asize == 'E') {
- if (igetl(map, ip, &ip->imm) < 0)
- return 0;
- /* TO DO: REX */
- } else {
- if (igets(map, ip, &s)< 0)
- return 0;
- ip->imm = s&0xffff;
- }
- break;
- case Iwds: /* Operand-sized immediate (sign extended) */
- if (ip->osize == 'L') {
- if (igetl(map, ip, &ip->imm) < 0)
- return 0;
- } else {
- if (igets(map, ip, &s)< 0)
- return 0;
- if (s&0x8000)
- ip->imm = s|0xffff0000;
- else
- ip->imm = s&0xffff;
- }
- ip->jumptype = Iwds;
- break;
- case OA: /* literal 0x0a byte */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (c != 0x0a)
- goto badop;
- break;
- case Op_R0: /* base register must be R0 */
- if (ip->base != 0)
- goto badop;
- break;
- case Op_R1: /* base register must be R1 */
- if (ip->base != 1)
- goto badop;
- break;
- case RMB: /* R/M field with byte register (/r)*/
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- ip->osize = 'B';
- break;
- case RM: /* R/M field with register (/r) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- break;
- case RMOPB: /* R/M field with op code (/digit) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- c = ip->reg; /* secondary op code */
- obase = (Optable*)op->proto;
- ip->osize = 'B';
- goto newop;
- case RMOP: /* R/M field with op code (/digit) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- obase = (Optable*)op->proto;
- if(ip->amd64 && obase == optab0F01 && c == 0xF8)
- return optab0F01F8;
- c = ip->reg;
- goto newop;
- case FRMOP: /* FP R/M field with op code (/digit) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- if ((c&0xc0) == 0xc0)
- c = ip->reg+8; /* 16 entry table */
- else
- c = ip->reg;
- obase = (Optable*)op->proto;
- goto newop;
- case FRMEX: /* Extended FP R/M field with op code (/digit) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (modrm(map, ip, c) < 0)
- return 0;
- if ((c&0xc0) == 0xc0)
- c = (c&0x3f)+8; /* 64-entry table */
- else
- c = ip->reg;
- obase = (Optable*)op->proto;
- goto newop;
- case RMR: /* R/M register only (mod = 11) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if ((c&0xc0) != 0xc0) {
- werrstr("invalid R/M register: %x", c);
- return 0;
- }
- if (modrm(map, ip, c) < 0)
- return 0;
- break;
- case RMM: /* R/M register only (mod = 11) */
- if (igetc(map, ip, &c) < 0)
- return 0;
- if ((c&0xc0) == 0xc0) {
- werrstr("invalid R/M memory mode: %x", c);
- return 0;
- }
- if (modrm(map, ip, c) < 0)
- return 0;
- break;
- case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
- if (ip->osize == 'L') {
- if (igetl(map, ip, &ip->disp) < 0)
- return 0;
- } else {
- if (igets(map, ip, &s)< 0)
- return 0;
- ip->disp = s&0xffff;
- }
- if (igets(map, ip, (ushort*)&ip->seg) < 0)
- return 0;
- ip->jumptype = PTR;
- break;
- case AUXMM: /* Multi-byte op code; prefix determines table selection */
- if (igetc(map, ip, &c) < 0)
- return 0;
- obase = (Optable*)op->proto;
- switch (ip->opre) {
- case 0x66:
- op = optab660F;
- break;
- case 0xF2:
- op = optabF20F;
- ip->prefix = 0; /* discard REPNE */
- break;
- case 0xF3:
- op = optabF30F;
- ip->prefix = 0; /* discard REP */
- break;
- default:
- op = nil;
- break;
- }
- if(op != nil && op[c].proto != nil)
- obase = op;
- /* otherwise the optab entry captures it */
- goto newop;
- case AUX: /* Multi-byte op code - Auxiliary table */
- obase = (Optable*)op->proto;
- if (igetc(map, ip, &c) < 0)
- return 0;
- goto newop;
- case OPRE: /* Instr Prefix or media op */
- ip->opre = c;
- /* fall through */
- case PRE: /* Instr Prefix */
- ip->prefix = (char*)op->proto;
- if (igetc(map, ip, &c) < 0)
- return 0;
- goto newop;
- case SEG: /* Segment Prefix */
- ip->segment = (char*)op->proto;
- if (igetc(map, ip, &c) < 0)
- return 0;
- goto newop;
- case OPOVER: /* Operand size override */
- ip->opre = c;
- ip->osize = 'W';
- if (igetc(map, ip, &c) < 0)
- return 0;
- if (c == 0x0F)
- ip->osize = 'L';
- else if (ip->amd64 && (c&0xF0) == 0x40)
- ip->osize = 'Q';
- goto newop;
- case ADDOVER: /* Address size override */
- ip->asize = 0;
- if (igetc(map, ip, &c) < 0)
- return 0;
- goto newop;
- case JUMP: /* mark instruction as JUMP or RET */
- case RET:
- ip->jumptype = op->operand[i];
- break;
- default:
- werrstr("bad operand type %d", op->operand[i]);
- return 0;
- }
- }
- return op;
-}
-
-#pragma varargck argpos bprint 2
-
-static void
-bprint(Instr *ip, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
- va_end(arg);
-}
-
-/*
- * if we want to call 16 bit regs AX,BX,CX,...
- * and 32 bit regs EAX,EBX,ECX,... then
- * change the defs of ANAME and ONAME to:
- * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
- * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
- */
-#define ANAME(ip) ""
-#define ONAME(ip) ""
-
-static char *reg[] = {
-[AX] = "AX",
-[CX] = "CX",
-[DX] = "DX",
-[BX] = "BX",
-[SP] = "SP",
-[BP] = "BP",
-[SI] = "SI",
-[DI] = "DI",
-
- /* amd64 */
-[AMD64_R8] = "R8",
-[AMD64_R9] = "R9",
-[AMD64_R10] = "R10",
-[AMD64_R11] = "R11",
-[AMD64_R12] = "R12",
-[AMD64_R13] = "R13",
-[AMD64_R14] = "R14",
-[AMD64_R15] = "R15",
-};
-
-static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
-static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
- "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
-static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
-
-static void
-plocal(Instr *ip)
-{
- int ret;
- int32 offset;
- Symbol s;
- char *reg;
-
- offset = ip->disp;
- if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
- bprint(ip, "%ux(SP)", offset);
- return;
- }
-
- if (s.value > ip->disp) {
- ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
- reg = "(SP)";
- } else {
- offset -= s.value;
- ret = getauto(&s, offset, CPARAM, &s);
- reg = "(FP)";
- }
- if (ret)
- bprint(ip, "%s+", s.name);
- else
- offset = ip->disp;
- bprint(ip, "%ux%s", offset, reg);
-}
-
-static int
-isjmp(Instr *ip)
-{
- switch(ip->jumptype){
- case Iwds:
- case Jbs:
- case JUMP:
- return 1;
- default:
- return 0;
- }
-}
-
-/*
- * This is too smart for its own good, but it really is nice
- * to have accurate translations when debugging, and it
- * helps us identify which code is different in binaries that
- * are changed on sources.
- */
-static int
-issymref(Instr *ip, Symbol *s, int32 w, int32 val)
-{
- Symbol next, tmp;
- int32 isstring, size;
-
- if (isjmp(ip))
- return 1;
- if (s->class==CTEXT && w==0)
- return 1;
- if (s->class==CDATA) {
- /* use first bss symbol (or "end") rather than edata */
- if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
- if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
- || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
- *s = tmp;
- }
- if (w == 0)
- return 1;
- for (next=*s; next.value==s->value; next=tmp)
- if (!globalsym(&tmp, next.index+1))
- break;
- size = next.value - s->value;
- if (w >= size)
- return 0;
- if (w > size-w)
- w = size-w;
- /* huge distances are usually wrong except in .string */
- isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
- if (w > 8192 && !isstring)
- return 0;
- /* medium distances are tricky - look for constants */
- /* near powers of two */
- if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-immediate(Instr *ip, vlong val)
-{
- Symbol s;
- int32 w;
-
- if (findsym(val, CANY, &s)) { /* TO DO */
- w = val - s.value;
- if (w < 0)
- w = -w;
- if (issymref(ip, &s, w, val)) {
- if (w)
- bprint(ip, "%s+%#ux(SB)", s.name, w);
- else
- bprint(ip, "%s(SB)", s.name);
- return;
- }
-/*
- if (s.class==CDATA && globalsym(&s, s.index+1)) {
- w = s.value - val;
- if (w < 0)
- w = -w;
- if (w < 4096) {
- bprint(ip, "%s-%#lux(SB)", s.name, w);
- return;
- }
- }
-*/
- }
- if((ip->rex & REXW) == 0)
- bprint(ip, "%lux", (long)val);
- else
- bprint(ip, "%llux", val);
-}
-
-static void
-pea(Instr *ip)
-{
- int base;
-
- base = ip->base;
- if(base >= 0 && (ip->rex & REXB))
- base += 8;
-
- if (ip->mod == 3) {
- if (ip->osize == 'B')
- bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
- else
- bprint(ip, "%s%s", ANAME(ip), reg[base]);
- return;
- }
-
- if (ip->segment)
- bprint(ip, ip->segment);
- if (ip->asize == 'E' && base == SP)
- plocal(ip);
- else {
- if (ip->base < 0)
- immediate(ip, ip->disp);
- else {
- bprint(ip, "%ux", ip->disp);
- if(ip->rip)
- bprint(ip, "(RIP)");
- bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
- }
- }
- if (ip->index >= 0)
- bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
-}
-
-static void
-prinstr(Instr *ip, char *fmt)
-{
- int sharp;
- vlong v;
-
- if (ip->prefix)
- bprint(ip, "%s ", ip->prefix);
- for (; *fmt && ip->curr < ip->end; fmt++) {
- if (*fmt != '%'){
- *ip->curr++ = *fmt;
- continue;
- }
- sharp = 0;
- if(*++fmt == '#') {
- sharp = 1;
- ++fmt;
- }
- switch(*fmt){
- case '%':
- *ip->curr++ = '%';
- break;
- case 'A':
- bprint(ip, "%s", ANAME(ip));
- break;
- case 'C':
- bprint(ip, "CR%d", ip->reg);
- break;
- case 'D':
- if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
- bprint(ip, "DR%d",ip->reg);
- else
- bprint(ip, "???");
- break;
- case 'I':
- bprint(ip, "$");
- immediate(ip, ip->imm2);
- break;
- case 'O':
- bprint(ip,"%s", ONAME(ip));
- break;
- case 'i':
- if(!sharp)
- bprint(ip, "$");
- v = ip->imm;
- if(ip->rex & REXW)
- v = ip->imm64;
- immediate(ip, v);
- break;
- case 'R':
- bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
- break;
- case 'S':
- if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
- bprint(ip, "Q");
- else
- bprint(ip, "%c", ip->osize);
- break;
- case 's':
- if(ip->opre == 0 || ip->opre == 0x66)
- bprint(ip, "P");
- else
- bprint(ip, "S");
- if(ip->opre == 0xf2 || ip->opre == 0x66)
- bprint(ip, "D");
- else
- bprint(ip, "S");
- break;
- case 'T':
- if (ip->reg == 6 || ip->reg == 7)
- bprint(ip, "TR%d",ip->reg);
- else
- bprint(ip, "???");
- break;
- case 'W':
- if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
- bprint(ip, "CDQE");
- else if (ip->osize == 'L')
- bprint(ip,"CWDE");
- else
- bprint(ip, "CBW");
- break;
- case 'd':
- bprint(ip,"%ux:%ux", ip->seg, ip->disp);
- break;
- case 'm':
- if (ip->mod == 3 && ip->osize != 'B') {
- if(fmt[1] != '*'){
- if(ip->opre != 0) {
- bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
- break;
- }
- } else
- fmt++;
- bprint(ip, "M%d", ip->base);
- break;
- }
- pea(ip);
- break;
- case 'e':
- pea(ip);
- break;
- case 'f':
- bprint(ip, "F%d", ip->base);
- break;
- case 'g':
- if (ip->reg < 6)
- bprint(ip,"%s",sreg[ip->reg]);
- else
- bprint(ip,"???");
- break;
- case 'p':
- /*
- * signed immediate in the uint32 ip->imm.
- */
- v = (int32)ip->imm;
- immediate(ip, v+ip->addr+ip->n);
- break;
- case 'r':
- if (ip->osize == 'B')
- bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
- else
- bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
- break;
- case 'w':
- if (ip->osize == 'Q' || ip->rex & REXW)
- bprint(ip, "CQO");
- else if (ip->osize == 'L')
- bprint(ip,"CDQ");
- else
- bprint(ip, "CWD");
- break;
- case 'M':
- if(ip->opre != 0)
- bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
- else
- bprint(ip, "M%d", ip->reg);
- break;
- case 'x':
- if (ip->mod == 3 && ip->osize != 'B') {
- bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
- break;
- }
- pea(ip);
- break;
- case 'X':
- bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
- break;
- default:
- bprint(ip, "%%%c", *fmt);
- break;
- }
- }
- *ip->curr = 0; /* there's always room for 1 byte */
-}
-
-static int
-i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
-{
- Instr instr;
- Optable *op;
-
- USED(modifier);
- op = mkinstr(map, &instr, pc);
- if (op == 0) {
- errstr(buf, n);
- return -1;
- }
- instr.curr = buf;
- instr.end = buf+n-1;
- prinstr(&instr, op->proto);
- return instr.n;
-}
-
-static int
-i386das(Map *map, uvlong pc, char *buf, int n)
-{
- Instr instr;
- int i;
-
- if (mkinstr(map, &instr, pc) == 0) {
- errstr(buf, n);
- return -1;
- }
- for(i = 0; i < instr.n && n > 2; i++) {
- _hexify(buf, instr.mem[i], 1);
- buf += 2;
- n -= 2;
- }
- *buf = 0;
- return instr.n;
-}
-
-static int
-i386instlen(Map *map, uvlong pc)
-{
- Instr i;
-
- if (mkinstr(map, &i, pc))
- return i.n;
- return -1;
-}
-
-static int
-i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
-{
- Instr i;
- Optable *op;
- ushort s;
- uvlong l, addr;
- vlong v;
- int n;
-
- op = mkinstr(map, &i, pc);
- if (!op)
- return -1;
-
- n = 0;
-
- switch(i.jumptype) {
- case RET: /* RETURN or LEAVE */
- case Iw: /* RETURN */
- if (strcmp(op->proto, "LEAVE") == 0) {
- if (geta(map, (*rget)(map, "BP"), &l) < 0)
- return -1;
- } else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
- return -1;
- foll[0] = l;
- return 1;
- case Iwds: /* pc relative JUMP or CALL*/
- case Jbs: /* pc relative JUMP or CALL */
- v = (int32)i.imm;
- foll[0] = pc+v+i.n;
- n = 1;
- break;
- case PTR: /* seg:displacement JUMP or CALL */
- foll[0] = (i.seg<<4)+i.disp;
- return 1;
- case JUMP: /* JUMP or CALL EA */
-
- if(i.mod == 3) {
- foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
- return 1;
- }
- /* calculate the effective address */
- addr = i.disp;
- if (i.base >= 0) {
- if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
- return -1;
- addr += l;
- }
- if (i.index >= 0) {
- if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
- return -1;
- addr += l*(1<<i.ss);
- }
- /* now retrieve a seg:disp value at that address */
- if (get2(map, addr, &s) < 0) /* seg */
- return -1;
- foll[0] = s<<4;
- addr += 2;
- if (i.asize == 'L') {
- if (geta(map, addr, &l) < 0) /* disp32 */
- return -1;
- foll[0] += l;
- } else { /* disp16 */
- if (get2(map, addr, &s) < 0)
- return -1;
- foll[0] += s;
- }
- return 1;
- default:
- break;
- }
- if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
- return 1;
- foll[n++] = pc+i.n;
- return n;
-}
diff --git a/src/libmach/8obj.c b/src/libmach/8obj.c
deleted file mode 100644
index c44d92c55..000000000
--- a/src/libmach/8obj.c
+++ /dev/null
@@ -1,170 +0,0 @@
-// Inferno libmach/8obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * 8obj.c - identify and parse a 386 object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/8l/8.out.h"
-#include "obj.h"
-
-typedef struct Addr Addr;
-struct Addr
-{
- char sym;
- char flags;
- char gotype;
-};
-static Addr addr(Biobuf*);
-static char type2char(int);
-static void skip(Biobuf*, int);
-
-int
-_is8(char *t)
-{
- uchar *s = (uchar*)t;
-
- return s[0] == (ANAME&0xff) /* also = ANAME */
- && s[1] == ((ANAME>>8)&0xff)
- && s[2] == D_FILE /* type */
- && s[3] == 1 /* sym */
- && s[4] == '<'; /* name of file */
-}
-
-int
-_read8(Biobuf *bp, Prog* p)
-{
- int as, n, c;
- Addr a;
-
- as = BGETC(bp); /* as(low) */
- if(as < 0)
- return 0;
- c = BGETC(bp); /* as(high) */
- if(c < 0)
- return 0;
- as |= ((c & 0xff) << 8);
- p->kind = aNone;
- p->sig = 0;
- if(as == ANAME || as == ASIGNAME){
- if(as == ASIGNAME){
- Bread(bp, &p->sig, 4);
- p->sig = leswal(p->sig);
- }
- p->kind = aName;
- p->type = type2char(BGETC(bp)); /* type */
- p->sym = BGETC(bp); /* sym */
- n = 0;
- for(;;) {
- as = BGETC(bp);
- if(as < 0)
- return 0;
- n++;
- if(as == 0)
- break;
- }
- p->id = malloc(n);
- if(p->id == 0)
- return 0;
- Bseek(bp, -n, 1);
- if(Bread(bp, p->id, n) != n)
- return 0;
- return 1;
- }
- if(as == ATEXT)
- p->kind = aText;
- if(as == AGLOBL)
- p->kind = aData;
- skip(bp, 4); /* lineno(4) */
- a = addr(bp);
- addr(bp);
- if(!(a.flags & T_SYM))
- p->kind = aNone;
- p->sym = a.sym;
- return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
- Addr a;
- int t;
- long off;
-
- off = 0;
- a.gotype = 0;
- a.sym = -1;
- a.flags = BGETC(bp); /* flags */
- if(a.flags & T_INDEX)
- skip(bp, 2);
- if(a.flags & T_OFFSET){
- off = BGETLE4(bp);
- if(off < 0)
- off = -off;
- }
- if(a.flags & T_OFFSET2){
- Bgetle4(bp);
- }
- if(a.flags & T_SYM)
- a.sym = BGETC(bp);
- if(a.flags & T_FCONST)
- skip(bp, 8);
- else
- if(a.flags & T_SCONST)
- skip(bp, NSNAME);
- if(a.flags & T_TYPE) {
- t = BGETC(bp);
- if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
- _offset(a.sym, off);
- }
- if(a.flags & T_GOTYPE)
- a.gotype = BGETC(bp);
- return a;
-}
-
-static char
-type2char(int t)
-{
- switch(t){
- case D_EXTERN: return 'U';
- case D_STATIC: return 'b';
- case D_AUTO: return 'a';
- case D_PARAM: return 'p';
- default: return UNKNOWN;
- }
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
- while (n-- > 0)
- Bgetc(bp);
-}
diff --git a/src/libmach/access.c b/src/libmach/access.c
deleted file mode 100644
index 0ee75d148..000000000
--- a/src/libmach/access.c
+++ /dev/null
@@ -1,241 +0,0 @@
-// Inferno libmach/access.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/access.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * functions to read and write an executable or file image
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-static int mget(Map*, uvlong, void*, int);
-static int mput(Map*, uvlong, void*, int);
-static Seg* reloc(Map*, uvlong, vlong*);
-
-/*
- * routines to get/put various types
- */
-int
-geta(Map *map, uvlong addr, uvlong *x)
-{
- uint32 l;
- uvlong vl;
-
- if (mach->szaddr == 8){
- if (get8(map, addr, &vl) < 0)
- return -1;
- *x = vl;
- return 1;
- }
-
- if (get4(map, addr, &l) < 0)
- return -1;
- *x = l;
-
- return 1;
-}
-
-int
-get8(Map *map, uvlong addr, uvlong *x)
-{
- if (!map) {
- werrstr("get8: invalid map");
- return -1;
- }
-
- if (map->nsegs == 1 && map->seg[0].fd < 0) {
- *x = addr;
- return 1;
- }
- if (mget(map, addr, x, 8) < 0)
- return -1;
- *x = machdata->swav(*x);
- return 1;
-}
-
-int
-get4(Map *map, uvlong addr, uint32 *x)
-{
- if (!map) {
- werrstr("get4: invalid map");
- return -1;
- }
-
- if (map->nsegs == 1 && map->seg[0].fd < 0) {
- *x = addr;
- return 1;
- }
- if (mget(map, addr, x, 4) < 0)
- return -1;
- *x = machdata->swal(*x);
- return 1;
-}
-
-int
-get2(Map *map, uvlong addr, ushort *x)
-{
- if (!map) {
- werrstr("get2: invalid map");
- return -1;
- }
-
- if (map->nsegs == 1 && map->seg[0].fd < 0) {
- *x = addr;
- return 1;
- }
- if (mget(map, addr, x, 2) < 0)
- return -1;
- *x = machdata->swab(*x);
- return 1;
-}
-
-int
-get1(Map *map, uvlong addr, uchar *x, int size)
-{
- uchar *cp;
-
- if (!map) {
- werrstr("get1: invalid map");
- return -1;
- }
-
- if (map->nsegs == 1 && map->seg[0].fd < 0) {
- cp = (uchar*)&addr;
- while (cp < (uchar*)(&addr+1) && size-- > 0)
- *x++ = *cp++;
- while (size-- > 0)
- *x++ = 0;
- } else
- return mget(map, addr, x, size);
- return 1;
-}
-
-int
-puta(Map *map, uvlong addr, uvlong v)
-{
- if (mach->szaddr == 8)
- return put8(map, addr, v);
-
- return put4(map, addr, v);
-}
-
-int
-put8(Map *map, uvlong addr, uvlong v)
-{
- if (!map) {
- werrstr("put8: invalid map");
- return -1;
- }
- v = machdata->swav(v);
- return mput(map, addr, &v, 8);
-}
-
-int
-put4(Map *map, uvlong addr, uint32 v)
-{
- if (!map) {
- werrstr("put4: invalid map");
- return -1;
- }
- v = machdata->swal(v);
- return mput(map, addr, &v, 4);
-}
-
-int
-put2(Map *map, uvlong addr, ushort v)
-{
- if (!map) {
- werrstr("put2: invalid map");
- return -1;
- }
- v = machdata->swab(v);
- return mput(map, addr, &v, 2);
-}
-
-int
-put1(Map *map, uvlong addr, uchar *v, int size)
-{
- if (!map) {
- werrstr("put1: invalid map");
- return -1;
- }
- return mput(map, addr, v, size);
-}
-
-static int
-mget(Map *map, uvlong addr, void *buf, int size)
-{
- uvlong off;
- Seg *s;
-
- s = reloc(map, addr, (vlong*)&off);
- if (!s)
- return -1;
- if (s->rw == nil) {
- werrstr("unreadable map");
- return -1;
- }
- return s->rw(map, s, off, buf, size, 1);
-}
-
-static int
-mput(Map *map, uvlong addr, void *buf, int size)
-{
- vlong off;
- Seg *s;
-
- s = reloc(map, addr, &off);
- if (!s)
- return -1;
- if (s->rw == nil) {
- werrstr("unwritable map");
- return -1;
- }
- return s->rw(map, s, off, buf, size, 0);
-}
-
-/*
- * convert address to file offset; returns nonzero if ok
- */
-static Seg*
-reloc(Map *map, uvlong addr, vlong *offp)
-{
- int i;
-
- for (i = 0; i < map->nsegs; i++) {
- if (map->seg[i].inuse)
- if (map->seg[i].b <= addr && addr < map->seg[i].e) {
- *offp = addr + map->seg[i].f - map->seg[i].b;
- return &map->seg[i];
- }
- }
- werrstr("can't translate address %llux", addr);
- return 0;
-}
diff --git a/src/libmach/darwin.c b/src/libmach/darwin.c
deleted file mode 100644
index 807dfa0d8..000000000
--- a/src/libmach/darwin.c
+++ /dev/null
@@ -1,897 +0,0 @@
-// 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.
-
-#define __DARWIN_UNIX03 0
-
-#include <u.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <mach/mach.h>
-#include <mach/mach_traps.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg Ureg32
-#include <ureg_x86.h>
-#undef Ureg
-#define Ureg Ureg64
-#include <ureg_amd64.h>
-#undef Ureg
-#undef waitpid /* want Unix waitpid, not Plan 9 */
-
-typedef struct Ureg32 Ureg32;
-typedef struct Ureg64 Ureg64;
-
-extern mach_port_t mach_reply_port(void); // should be in system headers, is not
-
-// Mach-error wrapper.
-// Takes a mach return code and converts it into 0 / -1,
-// setting errstr when it returns -1.
-
-static struct {
- int code;
- char *name;
-} macherr[] = {
- KERN_INVALID_ADDRESS, "invalid address",
- KERN_PROTECTION_FAILURE, "protection failure",
- KERN_NO_SPACE, "no space",
- KERN_INVALID_ARGUMENT, "invalid argument",
- KERN_FAILURE, "failure",
- KERN_RESOURCE_SHORTAGE, "resource shortage",
- KERN_NOT_RECEIVER, "not receiver",
- KERN_NO_ACCESS, "no access",
- KERN_MEMORY_FAILURE, "memory failure",
- KERN_MEMORY_ERROR, "memory error",
- KERN_ALREADY_IN_SET, "already in set",
- KERN_NOT_IN_SET, "not in set",
- KERN_NAME_EXISTS, "name exists",
- KERN_ABORTED, "aborted",
- KERN_INVALID_NAME, "invalid name",
- KERN_INVALID_TASK, "invalid task",
- KERN_INVALID_RIGHT, "invalid right",
- KERN_INVALID_VALUE, "invalid value",
- KERN_UREFS_OVERFLOW, "urefs overflow",
- KERN_INVALID_CAPABILITY, "invalid capability",
- KERN_RIGHT_EXISTS, "right exists",
- KERN_INVALID_HOST, "invalid host",
- KERN_MEMORY_PRESENT, "memory present",
- KERN_MEMORY_DATA_MOVED, "memory data moved",
- KERN_MEMORY_RESTART_COPY, "memory restart copy",
- KERN_INVALID_PROCESSOR_SET, "invalid processor set",
- KERN_POLICY_LIMIT, "policy limit",
- KERN_INVALID_POLICY, "invalid policy",
- KERN_INVALID_OBJECT, "invalid object",
- KERN_ALREADY_WAITING, "already waiting",
- KERN_DEFAULT_SET, "default set",
- KERN_EXCEPTION_PROTECTED, "exception protected",
- KERN_INVALID_LEDGER, "invalid ledger",
- KERN_INVALID_MEMORY_CONTROL, "invalid memory control",
- KERN_INVALID_SECURITY, "invalid security",
- KERN_NOT_DEPRESSED, "not depressed",
- KERN_TERMINATED, "terminated",
- KERN_LOCK_SET_DESTROYED, "lock set destroyed",
- KERN_LOCK_UNSTABLE, "lock unstable",
- KERN_LOCK_OWNED, "lock owned",
- KERN_LOCK_OWNED_SELF, "lock owned self",
- KERN_SEMAPHORE_DESTROYED, "semaphore destroyed",
- KERN_RPC_SERVER_TERMINATED, "rpc server terminated",
- KERN_RPC_TERMINATE_ORPHAN, "rpc terminate orphan",
- KERN_RPC_CONTINUE_ORPHAN, "rpc continue orphan",
- KERN_NOT_SUPPORTED, "not supported",
- KERN_NODE_DOWN, "node down",
- KERN_NOT_WAITING, "not waiting",
- KERN_OPERATION_TIMED_OUT, "operation timed out",
- KERN_RETURN_MAX, "return max",
-
- MACH_SEND_IN_PROGRESS, "send in progress",
- MACH_SEND_INVALID_DATA, "send invalid data",
- MACH_SEND_INVALID_DEST, "send invalid dest",
- MACH_SEND_TIMED_OUT, "send timed out",
- MACH_SEND_INTERRUPTED, "send interrupted",
- MACH_SEND_MSG_TOO_SMALL, "send msg too small",
- MACH_SEND_INVALID_REPLY, "send invalid reply",
- MACH_SEND_INVALID_RIGHT, "send invalid right",
- MACH_SEND_INVALID_NOTIFY, "send invalid notify",
- MACH_SEND_INVALID_MEMORY, "send invalid memory",
- MACH_SEND_NO_BUFFER, "send no buffer",
- MACH_SEND_TOO_LARGE, "send too large",
- MACH_SEND_INVALID_TYPE, "send invalid type",
- MACH_SEND_INVALID_HEADER, "send invalid header",
- MACH_SEND_INVALID_TRAILER, "send invalid trailer",
- MACH_SEND_INVALID_RT_OOL_SIZE, "send invalid rt ool size",
- MACH_RCV_IN_PROGRESS, "rcv in progress",
- MACH_RCV_INVALID_NAME, "rcv invalid name",
- MACH_RCV_TIMED_OUT, "rcv timed out",
- MACH_RCV_TOO_LARGE, "rcv too large",
- MACH_RCV_INTERRUPTED, "rcv interrupted",
- MACH_RCV_PORT_CHANGED, "rcv port changed",
- MACH_RCV_INVALID_NOTIFY, "rcv invalid notify",
- MACH_RCV_INVALID_DATA, "rcv invalid data",
- MACH_RCV_PORT_DIED, "rcv port died",
- MACH_RCV_IN_SET, "rcv in set",
- MACH_RCV_HEADER_ERROR, "rcv header error",
- MACH_RCV_BODY_ERROR, "rcv body error",
- MACH_RCV_INVALID_TYPE, "rcv invalid type",
- MACH_RCV_SCATTER_SMALL, "rcv scatter small",
- MACH_RCV_INVALID_TRAILER, "rcv invalid trailer",
- MACH_RCV_IN_PROGRESS_TIMED, "rcv in progress timed",
-
- MIG_TYPE_ERROR, "mig type error",
- MIG_REPLY_MISMATCH, "mig reply mismatch",
- MIG_REMOTE_ERROR, "mig remote error",
- MIG_BAD_ID, "mig bad id",
- MIG_BAD_ARGUMENTS, "mig bad arguments",
- MIG_NO_REPLY, "mig no reply",
- MIG_EXCEPTION, "mig exception",
- MIG_ARRAY_TOO_LARGE, "mig array too large",
- MIG_SERVER_DIED, "server died",
- MIG_TRAILER_ERROR, "trailer has an unknown format",
-};
-
-static int
-me(kern_return_t r)
-{
- int i;
-
- if(r == 0)
- return 0;
-
- for(i=0; i<nelem(macherr); i++){
- if(r == macherr[i].code){
- werrstr("mach: %s", macherr[i].name);
- return -1;
- }
- }
- werrstr("mach error %#x", r);
- return -1;
-}
-
-// Plan 9 and Linux do not distinguish between
-// process ids and thread ids, so the interface here doesn't either.
-// Unfortunately, Mach has three kinds of identifiers: process ids,
-// handles to tasks (processes), and handles to threads within a
-// process. All of them are small integers.
-//
-// To accommodate Mach, we employ a clumsy hack: in this interface,
-// if you pass in a positive number, that's a process id.
-// If you pass in a negative number, that identifies a thread that
-// has been previously returned by procthreadpids (it indexes
-// into the Thread table below).
-
-// Table of threads we have handles for.
-typedef struct Thread Thread;
-struct Thread
-{
- int pid;
- mach_port_t task;
- mach_port_t thread;
- int stopped;
- int exc;
- int code[10];
- Map *map;
-};
-static Thread thr[1000];
-static int nthr;
-static pthread_mutex_t mu;
-static pthread_cond_t cond;
-static void* excthread(void*);
-static void* waitthread(void*);
-static mach_port_t excport;
-
-enum {
- ExcMask = EXC_MASK_BAD_ACCESS |
- EXC_MASK_BAD_INSTRUCTION |
- EXC_MASK_ARITHMETIC |
- EXC_MASK_BREAKPOINT |
- EXC_MASK_SOFTWARE
-};
-
-// Add process pid to the thread table.
-// If it's already there, don't re-add it (unless force != 0).
-static Thread*
-addpid(int pid, int force)
-{
- int i, j;
- mach_port_t task;
- mach_port_t *thread;
- uint nthread;
- Thread *ret;
- static int first = 1;
-
- if(first){
- // Allocate a port for exception messages and
- // send all thread exceptions to that port.
- // The excthread reads that port and signals
- // us if we are waiting on that thread.
- pthread_t p;
- int err;
-
- excport = mach_reply_port();
- pthread_mutex_init(&mu, nil);
- pthread_cond_init(&cond, nil);
- err = pthread_create(&p, nil, excthread, nil);
- if (err != 0) {
- fprint(2, "pthread_create failed: %s\n", strerror(err));
- abort();
- }
- err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
- if (err != 0) {
- fprint(2, "pthread_create failed: %s\n", strerror(err));
- abort();
- }
- first = 0;
- }
-
- if(!force){
- for(i=0; i<nthr; i++)
- if(thr[i].pid == pid)
- return &thr[i];
- }
- if(me(task_for_pid(mach_task_self(), pid, &task)) < 0)
- return nil;
- if(me(task_threads(task, &thread, &nthread)) < 0)
- return nil;
- mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
- if(me(task_set_exception_ports(task, ExcMask,
- excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
- fprint(2, "warning: cannot set excport: %r\n");
- }
- ret = nil;
- for(j=0; j<nthread; j++){
- if(force){
- // If we're forcing a refresh, don't re-add existing threads.
- for(i=0; i<nthr; i++)
- if(thr[i].pid == pid && thr[i].thread == thread[j]){
- if(ret == nil)
- ret = &thr[i];
- goto skip;
- }
- }
- if(nthr >= nelem(thr))
- return nil;
- // TODO: We probably should save the old thread exception
- // ports for each bit and then put them back when we exit.
- // Probably the BSD signal handlers have put stuff there.
- mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
- if(me(thread_set_exception_ports(thread[j], ExcMask,
- excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
- fprint(2, "warning: cannot set excport: %r\n");
- }
- thr[nthr].pid = pid;
- thr[nthr].task = task;
- thr[nthr].thread = thread[j];
- if(ret == nil)
- ret = &thr[nthr];
- nthr++;
- skip:;
- }
- return ret;
-}
-
-static Thread*
-idtotable(int id)
-{
- if(id >= 0)
- return addpid(id, 1);
-
- id = -(id+1);
- if(id >= nthr)
- return nil;
- return &thr[id];
-}
-
-/*
-static int
-idtopid(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->pid;
-}
-*/
-
-static mach_port_t
-idtotask(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->task;
-}
-
-static mach_port_t
-idtothread(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->thread;
-}
-
-static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-
-Map*
-attachproc(int id, Fhdr *fp)
-{
- Thread *t;
- Map *map;
-
- if((t = idtotable(id)) == nil)
- return nil;
- if(t->map)
- return t->map;
- map = newmap(0, 4);
- if(!map)
- return nil;
- map->pid = -((t-thr) + 1);
- if(mach->regsize)
- setmap(map, -1, 0, mach->regsize, 0, "regs", machregrw);
- setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", machsegrw);
- setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", machsegrw);
- t->map = map;
- return map;
-}
-
-// Return list of ids for threads in id.
-int
-procthreadpids(int id, int *out, int nout)
-{
- Thread *t;
- int i, n, pid;
-
- t = idtotable(id);
- if(t == nil)
- return -1;
- pid = t->pid;
- addpid(pid, 1); // force refresh of thread list
- n = 0;
- for(i=0; i<nthr; i++) {
- if(thr[i].pid == pid) {
- if(n < nout)
- out[n] = -(i+1);
- n++;
- }
- }
- return n;
-}
-
-// Detach from proc.
-// TODO(rsc): Perhaps should unsuspend any threads and clean-up the table.
-void
-detachproc(Map *m)
-{
- free(m);
-}
-
-// Should return array of pending signals (notes)
-// but don't know how to do that on OS X.
-int
-procnotes(int pid, char ***pnotes)
-{
- USED(pid);
- *pnotes = 0;
- return 0;
-}
-
-// There must be a way to do this. Gdb can do it.
-// But I don't see, in the Apple gdb sources, how.
-char*
-proctextfile(int pid)
-{
- USED(pid);
- return nil;
-}
-
-// Read/write from a Mach data segment.
-static int
-machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- mach_port_t task;
- int r;
-
- USED(seg);
-
- task = idtotask(map->pid);
- if(task == -1)
- return -1;
-
- if(isr){
- vm_size_t nn;
- nn = n;
- if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) {
- fprint(2, "vm_read_overwrite %#llux %d to %p: %r\n", addr, n, v);
- return -1;
- }
- return nn;
- }else{
- r = vm_write(task, addr, (uintptr)v, n);
- if(r == KERN_INVALID_ADDRESS){
- // Happens when writing to text segment.
- // Change protections.
- if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){
- fprint(2, "vm_protect: %s\n", r);
- return -1;
- }
- r = vm_write(task, addr, (uintptr)v, n);
- }
- if(r != 0){
- me(r);
- return -1;
- }
- return n;
- }
-}
-
-// Convert Ureg offset to x86_thread_state32_t offset.
-static int
-go2darwin32(uvlong addr)
-{
- switch(addr){
- case offsetof(Ureg32, ax):
- return offsetof(x86_thread_state32_t, eax);
- case offsetof(Ureg32, bx):
- return offsetof(x86_thread_state32_t, ebx);
- case offsetof(Ureg32, cx):
- return offsetof(x86_thread_state32_t, ecx);
- case offsetof(Ureg32, dx):
- return offsetof(x86_thread_state32_t, edx);
- case offsetof(Ureg32, si):
- return offsetof(x86_thread_state32_t, esi);
- case offsetof(Ureg32, di):
- return offsetof(x86_thread_state32_t, edi);
- case offsetof(Ureg32, bp):
- return offsetof(x86_thread_state32_t, ebp);
- case offsetof(Ureg32, fs):
- return offsetof(x86_thread_state32_t, fs);
- case offsetof(Ureg32, gs):
- return offsetof(x86_thread_state32_t, gs);
- case offsetof(Ureg32, pc):
- return offsetof(x86_thread_state32_t, eip);
- case offsetof(Ureg32, cs):
- return offsetof(x86_thread_state32_t, cs);
- case offsetof(Ureg32, flags):
- return offsetof(x86_thread_state32_t, eflags);
- case offsetof(Ureg32, sp):
- return offsetof(x86_thread_state32_t, esp);
- }
- return -1;
-}
-
-// Convert Ureg offset to x86_thread_state64_t offset.
-static int
-go2darwin64(uvlong addr)
-{
- switch(addr){
- case offsetof(Ureg64, ax):
- return offsetof(x86_thread_state64_t, rax);
- case offsetof(Ureg64, bx):
- return offsetof(x86_thread_state64_t, rbx);
- case offsetof(Ureg64, cx):
- return offsetof(x86_thread_state64_t, rcx);
- case offsetof(Ureg64, dx):
- return offsetof(x86_thread_state64_t, rdx);
- case offsetof(Ureg64, si):
- return offsetof(x86_thread_state64_t, rsi);
- case offsetof(Ureg64, di):
- return offsetof(x86_thread_state64_t, rdi);
- case offsetof(Ureg64, bp):
- return offsetof(x86_thread_state64_t, rbp);
- case offsetof(Ureg64, r8):
- return offsetof(x86_thread_state64_t, r8);
- case offsetof(Ureg64, r9):
- return offsetof(x86_thread_state64_t, r9);
- case offsetof(Ureg64, r10):
- return offsetof(x86_thread_state64_t, r10);
- case offsetof(Ureg64, r11):
- return offsetof(x86_thread_state64_t, r11);
- case offsetof(Ureg64, r12):
- return offsetof(x86_thread_state64_t, r12);
- case offsetof(Ureg64, r13):
- return offsetof(x86_thread_state64_t, r13);
- case offsetof(Ureg64, r14):
- return offsetof(x86_thread_state64_t, r14);
- case offsetof(Ureg64, r15):
- return offsetof(x86_thread_state64_t, r15);
- case offsetof(Ureg64, fs):
- return offsetof(x86_thread_state64_t, fs);
- case offsetof(Ureg64, gs):
- return offsetof(x86_thread_state64_t, gs);
- case offsetof(Ureg64, ip):
- return offsetof(x86_thread_state64_t, rip);
- case offsetof(Ureg64, cs):
- return offsetof(x86_thread_state64_t, cs);
- case offsetof(Ureg64, flags):
- return offsetof(x86_thread_state64_t, rflags);
- case offsetof(Ureg64, sp):
- return offsetof(x86_thread_state64_t, rsp);
- }
- return -1;
-}
-
-extern Mach mi386;
-
-// Read/write from fake register segment.
-static int
-machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- uint nn, count, state;
- mach_port_t thread;
- int reg;
- char buf[100];
- union {
- x86_thread_state64_t reg64;
- x86_thread_state32_t reg32;
- uchar p[1];
- } u;
- uchar *p;
-
- USED(seg);
-
- if(n > 8){
- werrstr("asked for %d-byte register", n);
- return -1;
- }
-
- thread = idtothread(map->pid);
- if(thread == -1){
- werrstr("no such id");
- return -1;
- }
-
- if(mach == &mi386) {
- count = x86_THREAD_STATE32_COUNT;
- state = x86_THREAD_STATE32;
- if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
- } else {
- count = x86_THREAD_STATE64_COUNT;
- state = x86_THREAD_STATE64;
- if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
- }
-
- if(!isr && me(thread_suspend(thread)) < 0){
- werrstr("thread suspend %#x: %r", thread);
- return -1;
- }
- nn = count;
- if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){
- if(!isr)
- thread_resume(thread);
- rerrstr(buf, sizeof buf);
- if(strstr(buf, "send invalid dest") != nil)
- werrstr("process exited");
- else
- werrstr("thread_get_state: %r");
- return -1;
- }
-
- p = u.p+reg;
- if(isr)
- memmove(v, p, n);
- else{
- memmove(p, v, n);
- nn = count;
- if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){
- thread_resume(thread);
- werrstr("thread_set_state: %r");
- return -1;
- }
-
- if(me(thread_resume(thread)) < 0){
- werrstr("thread_resume: %r");
- return -1;
- }
- }
- return 0;
-}
-
-enum
-{
- FLAGS_TF = 0x100 // x86 single-step processor flag
-};
-
-// Is thread t suspended?
-static int
-threadstopped(Thread *t)
-{
- struct thread_basic_info info;
- uint size;
-
- size = sizeof info;
- if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &size)) < 0){
- fprint(2, "threadstopped thread_info %#x: %r\n");
- return 1;
- }
- return info.suspend_count > 0;
-}
-
-// If thread t is suspended, start it up again.
-// If singlestep is set, only let it execute one instruction.
-static int
-threadstart(Thread *t, int singlestep)
-{
- int i;
- uint n;
- struct thread_basic_info info;
-
- if(!threadstopped(t))
- return 0;
-
- // Set or clear the processor single-step flag, as appropriate.
- if(mach == &mi386) {
- x86_thread_state32_t regs;
- n = x86_THREAD_STATE32_COUNT;
- if(me(thread_get_state(t->thread, x86_THREAD_STATE32,
- (thread_state_t)&regs,
- &n)) < 0)
- return -1;
- if(singlestep)
- regs.eflags |= FLAGS_TF;
- else
- regs.eflags &= ~FLAGS_TF;
- if(me(thread_set_state(t->thread, x86_THREAD_STATE32,
- (thread_state_t)&regs,
- x86_THREAD_STATE32_COUNT)) < 0)
- return -1;
- } else {
- x86_thread_state64_t regs;
- n = x86_THREAD_STATE64_COUNT;
- if(me(thread_get_state(t->thread, x86_THREAD_STATE64,
- (thread_state_t)&regs,
- &n)) < 0)
- return -1;
- if(singlestep)
- regs.rflags |= FLAGS_TF;
- else
- regs.rflags &= ~FLAGS_TF;
- if(me(thread_set_state(t->thread, x86_THREAD_STATE64,
- (thread_state_t)&regs,
- x86_THREAD_STATE64_COUNT)) < 0)
- return -1;
- }
-
- // Run.
- n = sizeof info;
- if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &n)) < 0)
- return -1;
- for(i=0; i<info.suspend_count; i++)
- if(me(thread_resume(t->thread)) < 0)
- return -1;
- return 0;
-}
-
-// Stop thread t.
-static int
-threadstop(Thread *t)
-{
- if(threadstopped(t))
- return 0;
- if(me(thread_suspend(t->thread)) < 0)
- return -1;
- return 0;
-}
-
-// Callback for exc_server below. Called when a thread we are
-// watching has an exception like hitting a breakpoint.
-kern_return_t
-catch_exception_raise(mach_port_t eport, mach_port_t thread,
- mach_port_t task, exception_type_t exception,
- exception_data_t code, mach_msg_type_number_t ncode)
-{
- Thread *t;
- int i;
-
- USED(eport);
- USED(task);
-
- t = nil;
- for(i=0; i<nthr; i++){
- if(thr[i].thread == thread){
- t = &thr[i];
- goto havet;
- }
- }
- if(nthr > 0)
- addpid(thr[0].pid, 1);
- for(i=0; i<nthr; i++){
- if(thr[i].thread == thread){
- t = &thr[i];
- goto havet;
- }
- }
- fprint(2, "did not find thread in catch_exception_raise\n");
- return KERN_SUCCESS; // let thread continue
-
-havet:
- t->exc = exception;
- if(ncode > nelem(t->code))
- ncode = nelem(t->code);
- memmove(t->code, code, ncode*sizeof t->code[0]);
-
- // Suspend thread, so that we can look at it & restart it later.
- if(me(thread_suspend(thread)) < 0)
- fprint(2, "catch_exception_raise thread_suspend: %r\n");
-
- // Synchronize with waitstop below.
- pthread_mutex_lock(&mu);
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mu);
-
- return KERN_SUCCESS;
-}
-
-// Exception watching thread, started in addpid above.
-static void*
-excthread(void *v)
-{
- USED(v);
- extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
- mach_msg_server(exc_server, 2048, excport, 0);
- return 0;
-}
-
-// Wait for pid to exit.
-static int exited;
-static void*
-waitthread(void *v)
-{
- int pid, status;
-
- pid = (int)(uintptr)v;
- waitpid(pid, &status, 0);
- exited = 1;
- // Synchronize with waitstop below.
- pthread_mutex_lock(&mu);
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mu);
- return nil;
-}
-
-// Wait for thread t to stop.
-static int
-waitstop(Thread *t)
-{
- pthread_mutex_lock(&mu);
- while(!exited && !threadstopped(t))
- pthread_cond_wait(&cond, &mu);
- pthread_mutex_unlock(&mu);
- return 0;
-}
-
-int
-ctlproc(int id, char *msg)
-{
- Thread *t;
- int status;
-
- // Hang/attached dance is for debugging newly exec'ed programs.
- // After fork, the child does ctlproc("hang") before exec,
- // and the parent does ctlproc("attached") and then waitstop.
- // Using these requires the BSD ptrace interface, unlike everything
- // else we do, which uses only the Mach interface. Our goal here
- // is to do as little as possible using ptrace and then flip over to Mach.
-
- if(strcmp(msg, "hang") == 0)
- return ptrace(PT_TRACE_ME, 0, 0, 0);
-
- if(strcmp(msg, "attached") == 0){
- // The pid "id" has done a ctlproc "hang" and then
- // exec, so we should find it stoppped just before exec
- // of the new program.
- #undef waitpid
- if(waitpid(id, &status, WUNTRACED) < 0){
- fprint(2, "ctlproc attached waitpid: %r\n");
- return -1;
- }
- if(WIFEXITED(status) || !WIFSTOPPED(status)){
- fprint(2, "ctlproc attached: bad process state\n");
- return -1;
- }
-
- // Find Mach thread for pid and suspend it.
- t = addpid(id, 1);
- if(t == nil) {
- fprint(2, "ctlproc attached: addpid: %r\n");
- return -1;
- }
- if(me(thread_suspend(t->thread)) < 0){
- fprint(2, "ctlproc attached: thread_suspend: %r\n");
- return -1;
- }
-
- // Let ptrace tell the process to keep going:
- // then ptrace is out of the way and we're back in Mach land.
- if(ptrace(PT_CONTINUE, id, (caddr_t)1, 0) < 0) {
- fprint(2, "ctlproc attached: ptrace continue: %r\n");
- return -1;
- }
-
- return 0;
- }
-
- // All the other control messages require a Thread structure.
- if((t = idtotable(id)) == nil){
- werrstr("no such thread");
- return -1;
- }
-
- if(strcmp(msg, "kill") == 0)
- return ptrace(PT_KILL, t->pid, 0, 0);
-
- if(strcmp(msg, "start") == 0)
- return threadstart(t, 0);
-
- if(strcmp(msg, "stop") == 0)
- return threadstop(t);
-
- if(strcmp(msg, "startstop") == 0){
- if(threadstart(t, 0) < 0)
- return -1;
- return waitstop(t);
- }
-
- if(strcmp(msg, "step") == 0){
- if(threadstart(t, 1) < 0)
- return -1;
- return waitstop(t);
- }
-
- if(strcmp(msg, "waitstop") == 0)
- return waitstop(t);
-
- // sysstop not available on OS X
-
- werrstr("unknown control message");
- return -1;
-}
-
-char*
-procstatus(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return "gone!";
-
- if(threadstopped(t))
- return "Stopped";
-
- return "Running";
-}
-
diff --git a/src/libmach/dragonfly.c b/src/libmach/dragonfly.c
deleted file mode 100644
index 43dd005e9..000000000
--- a/src/libmach/dragonfly.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented in DragonFly");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented in DragonFly");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented in DragonFly");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented in DragonFly");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented in DragonFly");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented in DragonFly");
- return -1;
-}
diff --git a/src/libmach/elf.h b/src/libmach/elf.h
deleted file mode 100644
index 8dbc983f0..000000000
--- a/src/libmach/elf.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Inferno libmach/elf.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/elf.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * Definitions needed for accessing ELF headers.
- * 32-bit and 64-bit structs differ.
- */
-typedef struct {
- uchar ident[16]; /* ident bytes */
- ushort type; /* file type */
- ushort machine; /* target machine */
- int version; /* file version */
- uint32 elfentry; /* start address */
- uint32 phoff; /* phdr file offset */
- uint32 shoff; /* shdr file offset */
- int flags; /* file flags */
- ushort ehsize; /* sizeof ehdr */
- ushort phentsize; /* sizeof phdr */
- ushort phnum; /* number phdrs */
- ushort shentsize; /* sizeof shdr */
- ushort shnum; /* number shdrs */
- ushort shstrndx; /* shdr string index */
-} Ehdr32;
-
-typedef struct {
- uchar ident[16]; /* ident bytes */
- ushort type; /* file type */
- ushort machine; /* target machine */
- int version; /* file version */
- uvlong elfentry; /* start address */
- uvlong phoff; /* phdr file offset */
- uvlong shoff; /* shdr file offset */
- int flags; /* file flags */
- ushort ehsize; /* sizeof ehdr */
- ushort phentsize; /* sizeof phdr */
- ushort phnum; /* number phdrs */
- ushort shentsize; /* sizeof shdr */
- ushort shnum; /* number shdrs */
- ushort shstrndx; /* shdr string index */
-} Ehdr64;
-
-typedef struct {
- int type; /* entry type */
- uint32 offset; /* file offset */
- uint32 vaddr; /* virtual address */
- uint32 paddr; /* physical address */
- int filesz; /* file size */
- uint32 memsz; /* memory size */
- int flags; /* entry flags */
- int align; /* memory/file alignment */
-} Phdr32;
-
-typedef struct {
- int type; /* entry type */
- int flags; /* entry flags */
- uvlong offset; /* file offset */
- uvlong vaddr; /* virtual address */
- uvlong paddr; /* physical address */
- uvlong filesz; /* file size */
- uvlong memsz; /* memory size */
- uvlong align; /* memory/file alignment */
-} Phdr64;
-
-typedef struct {
- uint32 name; /* section name */
- uint32 type; /* SHT_... */
- uint32 flags; /* SHF_... */
- uint32 addr; /* virtual address */
- uint32 offset; /* file offset */
- uint32 size; /* section size */
- uint32 link; /* misc info */
- uint32 info; /* misc info */
- uint32 addralign; /* memory alignment */
- uint32 entsize; /* entry size if table */
-} Shdr32;
-
-typedef struct {
- uint32 name; /* section name */
- uint32 type; /* SHT_... */
- uvlong flags; /* SHF_... */
- uvlong addr; /* virtual address */
- uvlong offset; /* file offset */
- uvlong size; /* section size */
- uint32 link; /* misc info */
- uint32 info; /* misc info */
- uvlong addralign; /* memory alignment */
- uvlong entsize; /* entry size if table */
-} Shdr64;
-
-enum {
- /* Ehdr codes */
- MAG0 = 0, /* ident[] indexes */
- MAG1 = 1,
- MAG2 = 2,
- MAG3 = 3,
- CLASS = 4,
- DATA = 5,
- VERSION = 6,
-
- ELFCLASSNONE = 0, /* ident[CLASS] */
- ELFCLASS32 = 1,
- ELFCLASS64 = 2,
- ELFCLASSNUM = 3,
-
- ELFDATANONE = 0, /* ident[DATA] */
- ELFDATA2LSB = 1,
- ELFDATA2MSB = 2,
- ELFDATANUM = 3,
-
- NOETYPE = 0, /* type */
- REL = 1,
- EXEC = 2,
- DYN = 3,
- CORE = 4,
-
- NONE = 0, /* machine */
- M32 = 1, /* AT&T WE 32100 */
- SPARC = 2, /* Sun SPARC */
- I386 = 3, /* Intel 80386 */
- M68K = 4, /* Motorola 68000 */
- M88K = 5, /* Motorola 88000 */
- I486 = 6, /* Intel 80486 */
- I860 = 7, /* Intel i860 */
- MIPS = 8, /* Mips R2000 */
- S370 = 9, /* Amdhal */
- SPARC64 = 18, /* Sun SPARC v9 */
- POWER = 20, /* PowerPC */
- ARM = 40, /* ARM */
- AMD64 = 62, /* Amd64 */
-
- NO_VERSION = 0, /* version, ident[VERSION] */
- CURRENT = 1,
-
- /* Phdr Codes */
- NOPTYPE = 0, /* type */
- LOAD = 1,
- DYNAMIC = 2,
- INTERP = 3,
- NOTE = 4,
- SHLIB = 5,
- PHDR = 6,
-
- R = 0x4, /* flags */
- W = 0x2,
- X = 0x1,
-
- /* Shdr Codes */
- Progbits = 1, /* section types */
- Strtab = 3,
- Nobits = 8,
-
- Swrite = 1, /* section attributes */
- Salloc = 2,
- Sexec = 4,
-};
-
-#define ELF_MAG ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
diff --git a/src/libmach/executable.c b/src/libmach/executable.c
deleted file mode 100644
index eae14441a..000000000
--- a/src/libmach/executable.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-// Inferno libmach/executable.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <bootexec.h>
-#include <mach.h>
-#include "elf.h"
-#include "macho.h"
-
-/*
- * All a.out header types. The dummy entry allows canonical
- * processing of the union as a sequence of int32s
- */
-
-typedef struct {
- union{
- /*struct { */
- Exec exechdr; /* a.out.h */
- /* uvlong hdr[1];*/
- /*};*/
- Ehdr32 elfhdr32; /* elf.h */
- Ehdr64 elfhdr64; /* elf.h */
- struct mipsexec mips; /* bootexec.h */
- struct mips4kexec mipsk4; /* bootexec.h */
- struct sparcexec sparc; /* bootexec.h */
- struct nextexec next; /* bootexec.h */
- Machhdr machhdr; /* macho.h */
- } e;
- int32 dummy; /* padding to ensure extra int32 */
-} ExecHdr;
-
-static int nextboot(int, Fhdr*, ExecHdr*);
-static int sparcboot(int, Fhdr*, ExecHdr*);
-static int mipsboot(int, Fhdr*, ExecHdr*);
-static int mips4kboot(int, Fhdr*, ExecHdr*);
-static int common(int, Fhdr*, ExecHdr*);
-static int commonllp64(int, Fhdr*, ExecHdr*);
-static int adotout(int, Fhdr*, ExecHdr*);
-static int elfdotout(int, Fhdr*, ExecHdr*);
-static int machdotout(int, Fhdr*, ExecHdr*);
-static int armdotout(int, Fhdr*, ExecHdr*);
-static int pedotout(int, Fhdr*, ExecHdr*);
-static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
-static void setdata(Fhdr*, uvlong, int32, vlong, int32);
-static void settext(Fhdr*, uvlong, uvlong, int32, vlong);
-static void hswal(void*, int, uint32(*)(uint32));
-static uvlong _round(uvlong, uint32);
-
-/*
- * definition of per-executable file type structures
- */
-
-typedef struct Exectable{
- int32 magic; /* big-endian magic number of file */
- char *name; /* executable identifier */
- char *dlmname; /* dynamically loadable module identifier */
- uchar type; /* Internal code */
- uchar _magic; /* _MAGIC() magic */
- Mach *mach; /* Per-machine data */
- int32 hsize; /* header size */
- uint32 (*swal)(uint32); /* beswal or leswal */
- int (*hparse)(int, Fhdr*, ExecHdr*);
-} ExecTable;
-
-extern Mach mmips;
-extern Mach mmips2le;
-extern Mach mmips2be;
-extern Mach msparc;
-extern Mach msparc64;
-extern Mach m68020;
-extern Mach mi386;
-extern Mach mamd64;
-extern Mach marm;
-extern Mach mpower;
-extern Mach mpower64;
-extern Mach malpha;
-
-/* BUG: FIX THESE WHEN NEEDED */
-Mach mmips;
-Mach mmips2le;
-Mach mmips2be;
-Mach msparc;
-Mach msparc64;
-Mach m68020;
-Mach mpower;
-Mach mpower64;
-Mach malpha;
-
-ExecTable exectab[] =
-{
- { V_MAGIC, /* Mips v.out */
- "mips plan 9 executable BE",
- "mips plan 9 dlm BE",
- FMIPS,
- 1,
- &mmips,
- sizeof(Exec),
- beswal,
- adotout },
- { P_MAGIC, /* Mips 0.out (r3k le) */
- "mips plan 9 executable LE",
- "mips plan 9 dlm LE",
- FMIPSLE,
- 1,
- &mmips,
- sizeof(Exec),
- beswal,
- adotout },
- { M_MAGIC, /* Mips 4.out */
- "mips 4k plan 9 executable BE",
- "mips 4k plan 9 dlm BE",
- FMIPS2BE,
- 1,
- &mmips2be,
- sizeof(Exec),
- beswal,
- adotout },
- { N_MAGIC, /* Mips 0.out */
- "mips 4k plan 9 executable LE",
- "mips 4k plan 9 dlm LE",
- FMIPS2LE,
- 1,
- &mmips2le,
- sizeof(Exec),
- beswal,
- adotout },
- { 0x160<<16, /* Mips boot image */
- "mips plan 9 boot image",
- nil,
- FMIPSB,
- 0,
- &mmips,
- sizeof(struct mipsexec),
- beswal,
- mipsboot },
- { (0x160<<16)|3, /* Mips boot image */
- "mips 4k plan 9 boot image",
- nil,
- FMIPSB,
- 0,
- &mmips2be,
- sizeof(struct mips4kexec),
- beswal,
- mips4kboot },
- { K_MAGIC, /* Sparc k.out */
- "sparc plan 9 executable",
- "sparc plan 9 dlm",
- FSPARC,
- 1,
- &msparc,
- sizeof(Exec),
- beswal,
- adotout },
- { 0x01030107, /* Sparc boot image */
- "sparc plan 9 boot image",
- nil,
- FSPARCB,
- 0,
- &msparc,
- sizeof(struct sparcexec),
- beswal,
- sparcboot },
- { U_MAGIC, /* Sparc64 u.out */
- "sparc64 plan 9 executable",
- "sparc64 plan 9 dlm",
- FSPARC64,
- 1,
- &msparc64,
- sizeof(Exec),
- beswal,
- adotout },
- { A_MAGIC, /* 68020 2.out & boot image */
- "68020 plan 9 executable",
- "68020 plan 9 dlm",
- F68020,
- 1,
- &m68020,
- sizeof(Exec),
- beswal,
- common },
- { 0xFEEDFACE, /* Next boot image */
- "next plan 9 boot image",
- nil,
- FNEXTB,
- 0,
- &m68020,
- sizeof(struct nextexec),
- beswal,
- nextboot },
- { I_MAGIC, /* I386 8.out & boot image */
- "386 plan 9 executable",
- "386 plan 9 dlm",
- FI386,
- 1,
- &mi386,
- sizeof(Exec),
- beswal,
- common },
- { S_MAGIC, /* amd64 6.out & boot image */
- "amd64 plan 9 executable",
- "amd64 plan 9 dlm",
- FAMD64,
- 1,
- &mamd64,
- sizeof(Exec)+8,
- nil,
- commonllp64 },
- { Q_MAGIC, /* PowerPC q.out & boot image */
- "power plan 9 executable",
- "power plan 9 dlm",
- FPOWER,
- 1,
- &mpower,
- sizeof(Exec),
- beswal,
- common },
- { T_MAGIC, /* power64 9.out & boot image */
- "power64 plan 9 executable",
- "power64 plan 9 dlm",
- FPOWER64,
- 1,
- &mpower64,
- sizeof(Exec)+8,
- nil,
- commonllp64 },
- { ELF_MAG, /* any elf32 or elf64 */
- "elf executable",
- nil,
- FNONE,
- 0,
- &mi386,
- sizeof(Ehdr64),
- nil,
- elfdotout },
- { MACH64_MAG, /* 64-bit MACH (apple mac) */
- "mach executable",
- nil,
- FAMD64,
- 0,
- &mamd64,
- sizeof(Machhdr),
- nil,
- machdotout },
- { MACH32_MAG, /* 32-bit MACH (apple mac) */
- "mach executable",
- nil,
- FI386,
- 0,
- &mi386,
- sizeof(Machhdr),
- nil,
- machdotout },
- { E_MAGIC, /* Arm 5.out and boot image */
- "arm plan 9 executable",
- "arm plan 9 dlm",
- FARM,
- 1,
- &marm,
- sizeof(Exec),
- beswal,
- common },
- { (143<<16)|0413, /* (Free|Net)BSD Arm */
- "arm *bsd executable",
- nil,
- FARM,
- 0,
- &marm,
- sizeof(Exec),
- leswal,
- armdotout },
- { L_MAGIC, /* alpha 7.out */
- "alpha plan 9 executable",
- "alpha plan 9 dlm",
- FALPHA,
- 1,
- &malpha,
- sizeof(Exec),
- beswal,
- common },
- { 0x0700e0c3, /* alpha boot image */
- "alpha plan 9 boot image",
- nil,
- FALPHA,
- 0,
- &malpha,
- sizeof(Exec),
- beswal,
- common },
- { 0x4d5a9000, /* see dosstub[] in pe.c */
- "windows PE executable",
- nil,
- FWINPE,
- 0,
- &mi386,
- sizeof(Exec), /* TODO */
- nil,
- pedotout },
- { 0 },
-};
-
-Mach *mach = &mi386; /* Global current machine table */
-
-static ExecTable*
-couldbe4k(ExecTable *mp)
-{
- Dir *d;
- ExecTable *f;
-
- if((d=dirstat("/proc/1/regs")) == nil)
- return mp;
- if(d->length < 32*8){ /* R3000 */
- free(d);
- return mp;
- }
- free(d);
- for (f = exectab; f->magic; f++)
- if(f->magic == M_MAGIC) {
- f->name = "mips plan 9 executable on mips2 kernel";
- return f;
- }
- return mp;
-}
-
-int
-crackhdr(int fd, Fhdr *fp)
-{
- ExecTable *mp;
- ExecHdr d;
- int nb, ret;
- uint32 magic;
-
- fp->type = FNONE;
- nb = read(fd, (char *)&d.e, sizeof(d.e));
- if (nb <= 0)
- return 0;
-
- ret = 0;
- magic = beswal(d.e.exechdr.magic); /* big-endian */
- for (mp = exectab; mp->magic; mp++) {
- if (nb < mp->hsize)
- continue;
-
- /*
- * The magic number has morphed into something
- * with fields (the straw was DYN_MAGIC) so now
- * a flag is needed in Fhdr to distinguish _MAGIC()
- * magic numbers from foreign magic numbers.
- *
- * This code is creaking a bit and if it has to
- * be modified/extended much more it's probably
- * time to step back and redo it all.
- */
- if(mp->_magic){
- if(mp->magic != (magic & ~DYN_MAGIC))
- continue;
-
- if(mp->magic == V_MAGIC)
- mp = couldbe4k(mp);
-
- if ((magic & DYN_MAGIC) && mp->dlmname != nil)
- fp->name = mp->dlmname;
- else
- fp->name = mp->name;
- }
- else{
- if(mp->magic != magic)
- continue;
- fp->name = mp->name;
- }
- fp->type = mp->type;
- fp->hdrsz = mp->hsize; /* will be zero on bootables */
- fp->_magic = mp->_magic;
- fp->magic = magic;
-
- mach = mp->mach;
- if(mp->swal != nil)
- hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
- ret = mp->hparse(fd, fp, &d);
- seek(fd, mp->hsize, 0); /* seek to end of header */
- break;
- }
- if(mp->magic == 0)
- werrstr("unknown header type");
- return ret;
-}
-
-/*
- * Convert header to canonical form
- */
-static void
-hswal(void *v, int n, uint32 (*swap)(uint32))
-{
- uint32 *ulp;
-
- for(ulp = v; n--; ulp++)
- *ulp = (*swap)(*ulp);
-}
-
-/*
- * Crack a normal a.out-type header
- */
-static int
-adotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- int32 pgsize;
-
- USED(fd);
- pgsize = mach->pgsize;
- settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
- hp->e.exechdr.text, sizeof(Exec));
- setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
- hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
- setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
- return 1;
-}
-
-static void
-commonboot(Fhdr *fp)
-{
- if (!(fp->entry & mach->ktmask))
- return;
-
- switch(fp->type) { /* boot image */
- case F68020:
- fp->type = F68020B;
- fp->name = "68020 plan 9 boot image";
- break;
- case FI386:
- fp->type = FI386B;
- fp->txtaddr = (u32int)fp->entry;
- fp->name = "386 plan 9 boot image";
- fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
- break;
- case FARM:
- fp->type = FARMB;
- fp->txtaddr = (u32int)fp->entry;
- fp->name = "ARM plan 9 boot image";
- fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
- return;
- case FALPHA:
- fp->type = FALPHAB;
- fp->txtaddr = (u32int)fp->entry;
- fp->name = "alpha plan 9 boot image";
- fp->dataddr = fp->txtaddr+fp->txtsz;
- break;
- case FPOWER:
- fp->type = FPOWERB;
- fp->txtaddr = (u32int)fp->entry;
- fp->name = "power plan 9 boot image";
- fp->dataddr = fp->txtaddr+fp->txtsz;
- break;
- case FAMD64:
- fp->type = FAMD64B;
- fp->txtaddr = fp->entry;
- fp->name = "amd64 plan 9 boot image";
- fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
- break;
- default:
- return;
- }
- fp->hdrsz = 0; /* header stripped */
-}
-
-/*
- * _MAGIC() style headers and
- * alpha plan9-style bootable images for axp "headerless" boot
- *
- */
-static int
-common(int fd, Fhdr *fp, ExecHdr *hp)
-{
- adotout(fd, fp, hp);
- if(hp->e.exechdr.magic & DYN_MAGIC) {
- fp->txtaddr = 0;
- fp->dataddr = fp->txtsz;
- return 1;
- }
- commonboot(fp);
- return 1;
-}
-
-static int
-commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
-{
- int32 pgsize;
- uvlong entry;
-
- USED(unused);
-
- hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
- if(!(hp->e.exechdr.magic & HDR_MAGIC))
- return 0;
-
- /*
- * There can be more magic here if the
- * header ever needs more expansion.
- * For now just catch use of any of the
- * unused bits.
- */
- if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
- return 0;
- union {
- char *p;
- uvlong *v;
- } u;
- u.p = (char*)&hp->e.exechdr;
- entry = beswav(*u.v);
-
- pgsize = mach->pgsize;
- settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
- setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
- hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
- setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
- if(hp->e.exechdr.magic & DYN_MAGIC) {
- fp->txtaddr = 0;
- fp->dataddr = fp->txtsz;
- return 1;
- }
- commonboot(fp);
- return 1;
-}
-
-/*
- * mips bootable image.
- */
-static int
-mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
- USED(fd);
- USED(fp);
- USED(hp);
-
-abort();
-#ifdef unused
- USED(fd);
- fp->type = FMIPSB;
- switch(hp->e.exechdr.amagic) {
- default:
- case 0407: /* some kind of mips */
- settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
- hp->e.tsize, sizeof(struct mipsexec)+4);
- setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
- fp->txtoff+hp->e.tsize, hp->e.bsize);
- break;
- case 0413: /* some kind of mips */
- settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
- hp->e.tsize, 0);
- setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
- hp->e.tsize, hp->e.bsize);
- break;
- }
- setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
- fp->hdrsz = 0; /* header stripped */
-#endif
- return 1;
-}
-
-/*
- * mips4k bootable image.
- */
-static int
-mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
- USED(fd);
- USED(fp);
- USED(hp);
-
-abort();
-#ifdef unused
- USED(fd);
- fp->type = FMIPSB;
- switch(hp->e.h.amagic) {
- default:
- case 0407: /* some kind of mips */
- settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
- hp->e.h.tsize, sizeof(struct mips4kexec));
- setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
- fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
- break;
- case 0413: /* some kind of mips */
- settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
- hp->e.h.tsize, 0);
- setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
- hp->e.h.tsize, hp->e.h.bsize);
- break;
- }
- setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
- fp->hdrsz = 0; /* header stripped */
-#endif
- return 1;
-}
-
-/*
- * sparc bootable image
- */
-static int
-sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
- USED(fd);
- USED(fp);
- USED(hp);
-
-abort();
-#ifdef unused
- USED(fd);
- fp->type = FSPARCB;
- settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
- sizeof(struct sparcexec));
- setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
- fp->txtoff+hp->e.stext, hp->e.sbss);
- setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
- fp->hdrsz = 0; /* header stripped */
-#endif
- return 1;
-}
-
-/*
- * next bootable image
- */
-static int
-nextboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
- USED(fd);
- USED(fp);
- USED(hp);
-
-abort();
-#ifdef unused
- USED(fd);
- fp->type = FNEXTB;
- settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
- hp->e.texts.size, hp->e.texts.offset);
- setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
- hp->e.datas.offset, hp->e.bsss.size);
- setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
- hp->e.symc.symoff);
- fp->hdrsz = 0; /* header stripped */
-#endif
- return 1;
-}
-
-/*
- * Elf32 and Elf64 binaries.
- */
-static int
-elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uvlong (*swav)(uvlong);
- uint32 (*swal)(uint32);
- ushort (*swab)(ushort);
- Ehdr64 *ep;
- Phdr64 *ph, *pph;
- Shdr64 *sh;
- int i, it, id, is, phsz, shsz;
-
- /* bitswap the header according to the DATA format */
- ep = &hp->e.elfhdr64;
- if(ep->ident[CLASS] != ELFCLASS64) {
- werrstr("bad ELF class - not 32 bit or 64 bit");
- return 0;
- }
- if(ep->ident[DATA] == ELFDATA2LSB) {
- swab = leswab;
- swal = leswal;
- swav = leswav;
- } else if(ep->ident[DATA] == ELFDATA2MSB) {
- swab = beswab;
- swal = beswal;
- swav = beswav;
- } else {
- werrstr("bad ELF encoding - not big or little endian");
- return 0;
- }
-
- ep->type = swab(ep->type);
- ep->machine = swab(ep->machine);
- ep->version = swal(ep->version);
- ep->elfentry = swal(ep->elfentry);
- ep->phoff = swav(ep->phoff);
- ep->shoff = swav(ep->shoff);
- ep->flags = swav(ep->flags);
- ep->ehsize = swab(ep->ehsize);
- ep->phentsize = swab(ep->phentsize);
- ep->phnum = swab(ep->phnum);
- ep->shentsize = swab(ep->shentsize);
- ep->shnum = swab(ep->shnum);
- ep->shstrndx = swab(ep->shstrndx);
- if(ep->type != EXEC || ep->version != CURRENT)
- return 0;
-
- /* we could definitely support a lot more machines here */
- fp->magic = ELF_MAG;
- fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
- switch(ep->machine) {
- case AMD64:
- mach = &mamd64;
- fp->type = FAMD64;
- break;
- default:
- return 0;
- }
-
- if(ep->phentsize != sizeof(Phdr64)) {
- werrstr("bad ELF header size");
- return 0;
- }
- phsz = sizeof(Phdr64)*ep->phnum;
- ph = malloc(phsz);
- if(!ph)
- return 0;
- seek(fd, ep->phoff, 0);
- if(read(fd, ph, phsz) < 0) {
- free(ph);
- return 0;
- }
- hswal(ph, phsz/sizeof(uint32), swal);
-
- shsz = sizeof(Shdr64)*ep->shnum;
- sh = malloc(shsz);
- if(sh) {
- seek(fd, ep->shoff, 0);
- if(read(fd, sh, shsz) < 0) {
- free(sh);
- sh = 0;
- } else
- hswal(sh, shsz/sizeof(uint32), swal);
- }
-
- /* find text, data and symbols and install them */
- it = id = is = -1;
- for(i = 0; i < ep->phnum; i++) {
- if(ph[i].type == LOAD
- && (ph[i].flags & (R|X)) == (R|X) && it == -1)
- it = i;
- else if(ph[i].type == LOAD
- && (ph[i].flags & (R|W)) == (R|W) && id == -1)
- id = i;
- else if(ph[i].type == NOPTYPE && is == -1)
- is = i;
- }
- if(it == -1 || id == -1) {
- /*
- * The SPARC64 boot image is something of an ELF hack.
- * Text+Data+BSS are represented by ph[0]. Symbols
- * are represented by ph[1]:
- *
- * filesz, memsz, vaddr, paddr, off
- * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
- * ph[1] : symsz, lcsz, 0, 0, symoff
- */
- if(ep->machine == SPARC64 && ep->phnum == 2) {
- uint32 txtaddr, txtsz, dataddr, bsssz;
-
- txtaddr = ph[0].vaddr | 0x80000000;
- txtsz = ph[0].filesz - ph[0].paddr;
- dataddr = txtaddr + txtsz;
- bsssz = ph[0].memsz - ph[0].filesz;
- settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
- setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
- setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
- free(ph);
- return 1;
- }
-
- werrstr("No TEXT or DATA sections");
- free(ph);
- free(sh);
- return 0;
- }
-
- settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
- pph = ph + id;
- setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
- if(is != -1)
- setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
- else if(sh != 0){
- char *buf;
- uvlong symsize = 0;
- uvlong symoff = 0;
- uvlong pclnsz = 0;
- uvlong pclnoff = 0;
-
- /* load shstrtab names */
- buf = malloc(sh[ep->shstrndx].size);
- if (buf == 0)
- goto done;
- memset(buf, 0, sh[ep->shstrndx].size);
- seek(fd, sh[ep->shstrndx].offset, 0);
- i = read(fd, buf, sh[ep->shstrndx].size);
- USED(i); // shut up ubuntu gcc
-
- for(i = 0; i < ep->shnum; i++) {
- if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
- symsize = sh[i].size;
- symoff = sh[i].offset;
- }
- if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- pclnsz = sh[i].size;
- pclnoff = sh[i].offset;
- }
- }
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
- free(buf);
- }
-done:
- free(ph);
- free(sh);
- return 1;
-}
-
-static int
-elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-
- uint32 (*swal)(uint32);
- ushort (*swab)(ushort);
- Ehdr32 *ep;
- Phdr32 *ph;
- int i, it, id, is, phsz, shsz;
- Shdr32 *sh;
-
- /* bitswap the header according to the DATA format */
- ep = &hp->e.elfhdr32;
- if(ep->ident[CLASS] != ELFCLASS32) {
- return elf64dotout(fd, fp, hp);
- }
- if(ep->ident[DATA] == ELFDATA2LSB) {
- swab = leswab;
- swal = leswal;
- } else if(ep->ident[DATA] == ELFDATA2MSB) {
- swab = beswab;
- swal = beswal;
- } else {
- werrstr("bad ELF encoding - not big or little endian");
- return 0;
- }
-
- ep->type = swab(ep->type);
- ep->machine = swab(ep->machine);
- ep->version = swal(ep->version);
- ep->elfentry = swal(ep->elfentry);
- ep->phoff = swal(ep->phoff);
- ep->shoff = swal(ep->shoff);
- ep->flags = swal(ep->flags);
- ep->ehsize = swab(ep->ehsize);
- ep->phentsize = swab(ep->phentsize);
- ep->phnum = swab(ep->phnum);
- ep->shentsize = swab(ep->shentsize);
- ep->shnum = swab(ep->shnum);
- ep->shstrndx = swab(ep->shstrndx);
- if(ep->type != EXEC || ep->version != CURRENT)
- return 0;
-
- /* we could definitely support a lot more machines here */
- fp->magic = ELF_MAG;
- fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
- switch(ep->machine) {
- case I386:
- mach = &mi386;
- fp->type = FI386;
- break;
- case MIPS:
- mach = &mmips;
- fp->type = FMIPS;
- break;
- case SPARC64:
- mach = &msparc64;
- fp->type = FSPARC64;
- break;
- case POWER:
- mach = &mpower;
- fp->type = FPOWER;
- break;
- case ARM:
- mach = &marm;
- fp->type = FARM;
- break;
- default:
- return 0;
- }
-
- if(ep->phentsize != sizeof(Phdr32)) {
- werrstr("bad ELF header size");
- return 0;
- }
- phsz = sizeof(Phdr32)*ep->phnum;
- ph = malloc(phsz);
- if(!ph)
- return 0;
- seek(fd, ep->phoff, 0);
- if(read(fd, ph, phsz) < 0) {
- free(ph);
- return 0;
- }
- hswal(ph, phsz/sizeof(uint32), swal);
-
- shsz = sizeof(Shdr32)*ep->shnum;
- sh = malloc(shsz);
- if(sh) {
- seek(fd, ep->shoff, 0);
- if(read(fd, sh, shsz) < 0) {
- free(sh);
- sh = 0;
- } else
- hswal(sh, shsz/sizeof(uint32), swal);
- }
-
- /* find text, data and symbols and install them */
- it = id = is = -1;
- for(i = 0; i < ep->phnum; i++) {
- if(ph[i].type == LOAD
- && (ph[i].flags & (R|X)) == (R|X) && it == -1)
- it = i;
- else if(ph[i].type == LOAD
- && (ph[i].flags & (R|W)) == (R|W) && id == -1)
- id = i;
- else if(ph[i].type == NOPTYPE && is == -1)
- is = i;
- }
- if(it == -1 || id == -1) {
- /*
- * The SPARC64 boot image is something of an ELF hack.
- * Text+Data+BSS are represented by ph[0]. Symbols
- * are represented by ph[1]:
- *
- * filesz, memsz, vaddr, paddr, off
- * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
- * ph[1] : symsz, lcsz, 0, 0, symoff
- */
- if(ep->machine == SPARC64 && ep->phnum == 2) {
- uint32 txtaddr, txtsz, dataddr, bsssz;
-
- txtaddr = ph[0].vaddr | 0x80000000;
- txtsz = ph[0].filesz - ph[0].paddr;
- dataddr = txtaddr + txtsz;
- bsssz = ph[0].memsz - ph[0].filesz;
- settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
- setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
- setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
- free(ph);
- return 1;
- }
-
- werrstr("No TEXT or DATA sections");
- free(sh);
- free(ph);
- return 0;
- }
-
- settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
- setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
- if(is != -1)
- setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
- else if(sh != 0){
- char *buf;
- uvlong symsize = 0;
- uvlong symoff = 0;
- uvlong pclnsize = 0;
- uvlong pclnoff = 0;
-
- /* load shstrtab names */
- buf = malloc(sh[ep->shstrndx].size);
- if (buf == 0)
- goto done;
- memset(buf, 0, sh[ep->shstrndx].size);
- seek(fd, sh[ep->shstrndx].offset, 0);
- i = read(fd, buf, sh[ep->shstrndx].size);
- USED(i); // shut up ubuntu gcc
-
- for(i = 0; i < ep->shnum; i++) {
- if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
- symsize = sh[i].size;
- symoff = sh[i].offset;
- }
- if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- pclnsize = sh[i].size;
- pclnoff = sh[i].offset;
- }
- }
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
- free(buf);
- }
-done:
- free(sh);
- free(ph);
- return 1;
-}
-
-static int
-machdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uvlong (*swav)(uvlong);
- uint32 (*swal)(uint32);
- Machhdr *mp;
- MachCmd **cmd;
- MachSymSeg *symtab;
- MachSymSeg *pclntab;
- MachSeg64 *seg;
- MachSect64 *sect;
- MachSeg32 *seg32;
- MachSect32 *sect32;
- uvlong textsize, datasize, bsssize;
- uchar *cmdbuf;
- uchar *cmdp;
- int i, j, hdrsize;
- uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize;
-
- mp = &hp->e.machhdr;
- if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
- werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
- return 0;
- }
-
- swal = leswal;
- swav = leswav;
-
- mp->magic = swal(mp->magic);
- mp->cputype = swal(mp->cputype);
- mp->cpusubtype = swal(mp->cpusubtype);
- mp->filetype = swal(mp->filetype);
- mp->ncmds = swal(mp->ncmds);
- mp->sizeofcmds = swal(mp->sizeofcmds);
- mp->flags = swal(mp->flags);
- mp->reserved = swal(mp->reserved);
-
- switch(mp->magic) {
- case 0xFEEDFACE: // 32-bit mach
- if (mp->cputype != MACH_CPU_TYPE_X86) {
- werrstr("bad MACH cpu type - not 386");
- return 0;
- }
- if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
- werrstr("bad MACH cpu subtype - not 386");
- return 0;
- }
- if (mp->filetype != MACH_EXECUTABLE_TYPE) {
- werrstr("bad MACH executable type");
- return 0;
- }
- mach = &mi386;
- fp->type = FI386;
- hdrsize = 28;
- break;
-
- case 0xFEEDFACF: // 64-bit mach
- if (mp->cputype != MACH_CPU_TYPE_X86_64) {
- werrstr("bad MACH cpu type - not amd64");
- return 0;
- }
-
- if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86 && mp->cpusubtype != MACH_CPU_SUBTYPE_X86_64) {
- werrstr("bad MACH cpu subtype - not amd64");
- return 0;
- }
- mach = &mamd64;
- fp->type = FAMD64;
- hdrsize = 32;
- break;
-
- default:
- werrstr("not mach %#ux", mp->magic);
- return 0;
- }
-
- cmdbuf = malloc(mp->sizeofcmds);
- if(!cmdbuf) {
- werrstr("out of memory");
- return 0;
- }
- seek(fd, hdrsize, 0);
- if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
- free(cmdbuf);
- return 0;
- }
- cmd = malloc(mp->ncmds * sizeof(MachCmd*));
- if(!cmd) {
- free(cmdbuf);
- werrstr("out of memory");
- return 0;
- }
- cmdp = cmdbuf;
- textva = 0;
- textoff = 0;
- dataoff = 0;
- datava = 0;
- symtab = 0;
- pclntab = 0;
- textsize = 0;
- datasize = 0;
- bsssize = 0;
- symoff = 0;
- symsize = 0;
- pclnoff = 0;
- pclnsize = 0;
- for (i = 0; i < mp->ncmds; i++) {
- MachCmd *c;
-
- cmd[i] = (MachCmd*)cmdp;
- c = cmd[i];
- c->type = swal(c->type);
- c->size = swal(c->size);
- switch(c->type) {
- case MACH_SEGMENT_32:
- if(mp->magic != 0xFEEDFACE) {
- werrstr("segment 32 in mach 64");
- goto bad;
- }
- seg32 = (MachSeg32*)c;
- seg32->vmaddr = swav(seg32->vmaddr);
- seg32->vmsize = swav(seg32->vmsize);
- seg32->fileoff = swav(seg32->fileoff);
- seg32->filesize = swav(seg32->filesize);
- seg32->maxprot = swal(seg32->maxprot);
- seg32->initprot = swal(seg32->initprot);
- seg32->nsects = swal(seg32->nsects);
- seg32->flags = swal(seg32->flags);
- if (strcmp(seg32->segname, "__TEXT") == 0) {
- textva = seg32->vmaddr;
- textoff = seg32->fileoff;
- textsize = seg32->vmsize;
- sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
- for(j = 0; j < seg32->nsects; j++, sect32++) {
- if (strcmp(sect32->sectname, "__gosymtab") == 0) {
- symoff = swal(sect32->offset);
- symsize = swal(sect32->size);
- }
- if (strcmp(sect32->sectname, "__gopclntab") == 0) {
- pclnoff = swal(sect32->offset);
- pclnsize = swal(sect32->size);
- }
- }
- }
- if (strcmp(seg32->segname, "__DATA") == 0) {
- datava = seg32->vmaddr;
- dataoff = seg32->fileoff;
- datasize = seg32->filesize;
- bsssize = seg32->vmsize - seg32->filesize;
- }
- break;
-
- case MACH_SEGMENT_64:
- if(mp->magic != 0xFEEDFACF) {
- werrstr("segment 32 in mach 64");
- goto bad;
- }
- seg = (MachSeg64*)c;
- seg->vmaddr = swav(seg->vmaddr);
- seg->vmsize = swav(seg->vmsize);
- seg->fileoff = swav(seg->fileoff);
- seg->filesize = swav(seg->filesize);
- seg->maxprot = swal(seg->maxprot);
- seg->initprot = swal(seg->initprot);
- seg->nsects = swal(seg->nsects);
- seg->flags = swal(seg->flags);
- if (strcmp(seg->segname, "__TEXT") == 0) {
- textva = seg->vmaddr;
- textoff = seg->fileoff;
- textsize = seg->vmsize;
- sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
- for(j = 0; j < seg->nsects; j++, sect++) {
- if (strcmp(sect->sectname, "__gosymtab") == 0) {
- symoff = swal(sect->offset);
- symsize = swal(sect->size);
- }
- if (strcmp(sect->sectname, "__gopclntab") == 0) {
- pclnoff = swal(sect->offset);
- pclnsize = swal(sect->size);
- }
- }
- }
- if (strcmp(seg->segname, "__DATA") == 0) {
- datava = seg->vmaddr;
- dataoff = seg->fileoff;
- datasize = seg->filesize;
- bsssize = seg->vmsize - seg->filesize;
- }
- break;
- case MACH_UNIXTHREAD:
- break;
- case MACH_SYMSEG:
- if (symtab == 0) {
- symtab = (MachSymSeg*)c;
- symoff = swal(symtab->fileoff);
- symsize = swal(symtab->filesize);
- } else if (pclntab == 0) {
- pclntab = (MachSymSeg*)c;
- pclnoff = swal(pclntab->fileoff);
- pclnsize = swal(pclntab->filesize);
- }
- break;
- }
- cmdp += c->size;
- }
- if (textva == 0 || datava == 0) {
- free(cmd);
- free(cmdbuf);
- return 0;
- }
- /* compute entry by taking address after header - weird - BUG? */
- settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
- setdata(fp, datava, datasize, dataoff, bsssize);
- if(symoff > 0)
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
- free(cmd);
- free(cmdbuf);
- return 1;
-bad:
- free(cmd);
- free(cmdbuf);
- return 0;
-}
-
-/*
- * (Free|Net)BSD ARM header.
- */
-static int
-armdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uvlong kbase;
-
- USED(fd);
- settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
- setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
- setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
- kbase = 0xF0000000;
- if ((fp->entry & kbase) == kbase) { /* Boot image */
- fp->txtaddr = kbase+sizeof(Exec);
- fp->name = "ARM *BSD boot image";
- fp->hdrsz = 0; /* header stripped */
- fp->dataddr = kbase+fp->txtsz;
- }
- return 1;
-}
-
-/*
- * Structures needed to parse PE image.
- */
-typedef struct {
- uint16 Machine;
- uint16 NumberOfSections;
- uint32 TimeDateStamp;
- uint32 PointerToSymbolTable;
- uint32 NumberOfSymbols;
- uint16 SizeOfOptionalHeader;
- uint16 Characteristics;
-} IMAGE_FILE_HEADER;
-
-typedef struct {
- uint8 Name[8];
- uint32 VirtualSize;
- uint32 VirtualAddress;
- uint32 SizeOfRawData;
- uint32 PointerToRawData;
- uint32 PointerToRelocations;
- uint32 PointerToLineNumbers;
- uint16 NumberOfRelocations;
- uint16 NumberOfLineNumbers;
- uint32 Characteristics;
-} IMAGE_SECTION_HEADER;
-
-typedef struct {
- uint32 VirtualAddress;
- uint32 Size;
-} IMAGE_DATA_DIRECTORY;
-
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint32 BaseOfData;
- uint32 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint32 SizeOfStackReserve;
- uint32 SizeOfStackCommit;
- uint32 SizeOfHeapReserve;
- uint32 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} IMAGE_OPTIONAL_HEADER;
-
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint64 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint64 SizeOfStackReserve;
- uint64 SizeOfStackCommit;
- uint64 SizeOfHeapReserve;
- uint64 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} PE64_IMAGE_OPTIONAL_HEADER;
-
-static int
-match8(void *buf, char *cmp)
-{
- return strncmp((char*)buf, cmp, 8) == 0;
-}
-
-/*
- * Read from Windows PE/COFF .exe file image.
- */
-static int
-pedotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uint32 start, magic;
- uint32 symtab, esymtab, pclntab, epclntab;
- IMAGE_FILE_HEADER fh;
- IMAGE_SECTION_HEADER sh;
- IMAGE_OPTIONAL_HEADER oh;
- PE64_IMAGE_OPTIONAL_HEADER oh64;
- uint8 sym[18];
- uint32 *valp, ib, entry;
- int i, ohoffset;
-
- USED(hp);
- seek(fd, 0x3c, 0);
- if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
- werrstr("crippled PE MSDOS header");
- return 0;
- }
- start = leswal(start);
-
- seek(fd, start, 0);
- if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
- werrstr("no PE magic number found");
- return 0;
- }
- if (beswal(magic) != 0x50450000) { /* "PE\0\0" */
- werrstr("incorrect PE magic number");
- return 0;
- }
-
- if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
- werrstr("crippled PE File Header");
- return 0;
- }
- if (fh.PointerToSymbolTable == 0) {
- werrstr("zero pointer to COFF symbol table");
- return 0;
- }
-
- ohoffset = seek(fd, 0, 1);
- if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
- werrstr("crippled PE Optional Header");
- return 0;
- }
-
- switch(oh.Magic) {
- case 0x10b: // PE32
- fp->type = FI386;
- ib = leswal(oh.ImageBase);
- entry = leswal(oh.AddressOfEntryPoint);
- break;
- case 0x20b: // PE32+
- fp->type = FAMD64;
- seek(fd, ohoffset, 0);
- if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) {
- werrstr("crippled PE32+ Optional Header");
- return 0;
- }
- ib = leswal(oh64.ImageBase);
- entry = leswal(oh64.AddressOfEntryPoint);
- break;
- default:
- werrstr("invalid PE Optional Header magic number");
- return 0;
- }
-
- fp->txtaddr = 0;
- fp->dataddr = 0;
- for (i=0; i<leswab(fh.NumberOfSections); i++) {
- if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
- werrstr("could not read Section Header %d", i+1);
- return 0;
- }
- if (match8(sh.Name, ".text"))
- settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
- if (match8(sh.Name, ".data"))
- setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
- }
- if (fp->txtaddr==0 || fp->dataddr==0) {
- werrstr("no .text or .data");
- return 0;
- }
-
- seek(fd, leswal(fh.PointerToSymbolTable), 0);
- symtab = esymtab = pclntab = epclntab = 0;
- for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
- if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
- werrstr("crippled COFF symbol %d", i);
- return 0;
- }
- valp = (uint32 *)&sym[8];
- if (match8(sym, "symtab"))
- symtab = leswal(*valp);
- if (match8(sym, "esymtab"))
- esymtab = leswal(*valp);
- if (match8(sym, "pclntab"))
- pclntab = leswal(*valp);
- if (match8(sym, "epclntab"))
- epclntab = leswal(*valp);
- }
- if (symtab==0 || esymtab==0 || pclntab==0 || epclntab==0) {
- werrstr("no symtab or esymtab or pclntab or epclntab in COFF symbol table");
- return 0;
- }
- setsym(fp, symtab, esymtab-symtab, 0, 0, pclntab, epclntab-pclntab);
-
- return 1;
-}
-
-static void
-settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
-{
- fp->txtaddr = a;
- fp->entry = e;
- fp->txtsz = s;
- fp->txtoff = off;
-}
-
-static void
-setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
-{
- fp->dataddr = a;
- fp->datsz = s;
- fp->datoff = off;
- fp->bsssz = bss;
-}
-
-static void
-setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
-{
- fp->symoff = symoff;
- fp->symsz = symsz;
-
- if(sppcoff == 0)
- sppcoff = symoff+symsz;
- fp->sppcoff = symoff;
- fp->sppcsz = sppcsz;
-
- if(lnpcoff == 0)
- lnpcoff = sppcoff + sppcsz;
- fp->lnpcoff = lnpcoff;
- fp->lnpcsz = lnpcsz;
-}
-
-static uvlong
-_round(uvlong a, uint32 b)
-{
- uvlong w;
-
- w = (a/b)*b;
- if (a!=w)
- w += b;
- return(w);
-}
diff --git a/src/libmach/fakeobj.c b/src/libmach/fakeobj.c
deleted file mode 100644
index a4a897cfe..000000000
--- a/src/libmach/fakeobj.c
+++ /dev/null
@@ -1,29 +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.
-
-/*
- * obj.c
- * routines universal to all object files
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ar.h>
-#include <mach.h>
-#include "obj.h"
-
-int _is2(char* x) { USED(x); return 0; }
-int _is7(char* x) { USED(x); return 0; }
-int _is9(char* x) { USED(x); return 0; }
-int _isk(char* x) { USED(x); return 0; }
-int _isq(char* x) { USED(x); return 0; }
-int _isv(char* x) { USED(x); return 0; }
-int _isu(char* x) { USED(x); return 0; }
-int _read2(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read7(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read9(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readk(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readq(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readv(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readu(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
diff --git a/src/libmach/freebsd.c b/src/libmach/freebsd.c
deleted file mode 100644
index c4e5efddf..000000000
--- a/src/libmach/freebsd.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented in FreeBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented in FreeBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented in FreeBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented in FreeBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented in FreeBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented in FreeBSD");
- return -1;
-}
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
deleted file mode 100644
index 2c143266a..000000000
--- a/src/libmach/linux.c
+++ /dev/null
@@ -1,1014 +0,0 @@
-// Derived from Plan 9 from User Space src/libmach/Linux.c
-// http://code.swtch.com/plan9port/src/tip/src/libmach/Linux.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// Portions Copyright © 2001-2007 Russ Cox.
-// 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 <u.h>
-#include <sys/syscall.h> /* for tkill */
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg Ureg32
-#include <ureg_x86.h>
-#undef Ureg
-#define Ureg Ureg64
-#include <ureg_amd64.h>
-#undef Ureg
-#undef waitpid
-
-// The old glibc used with crosstool compilers on thresher
-// doesn't know these numbers, but the Linux kernel
-// had them as far back as 2.6.0.
-#ifndef WSTOPPED
-#define WSTOPPED 2
-#define WCONTINUED 8
-#define WIFCONTINUED(x) ((x) == 0xffff)
-#endif
-#ifndef PTRACE_SETOPTIONS
-#define PTRACE_SETOPTIONS 0x4200
-#define PTRACE_GETEVENTMSG 0x4201
-#define PTRACE_O_TRACEFORK 0x2
-#define PTRACE_O_TRACEVFORK 0x4
-#define PTRACE_O_TRACECLONE 0x8
-#define PTRACE_O_TRACEEXEC 0x10
-#define PTRACE_O_TRACEVFORKDONE 0x20
-#define PTRACE_O_TRACEEXIT 0x40
-#define PTRACE_EVENT_FORK 0x1
-#define PTRACE_EVENT_VFORK 0x2
-#define PTRACE_EVENT_CLONE 0x3
-#define PTRACE_EVENT_EXEC 0x4
-#define PTRACE_EVENT_VFORK_DONE 0x5
-#define PTRACE_EVENT_EXIT 0x6
-#endif
-
-typedef struct Ureg64 Ureg64;
-
-static Maprw ptracesegrw;
-static Maprw ptraceregrw;
-
-// /usr/include/asm-x86_64/user.h
-struct user_regs_struct {
- unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
- unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
- unsigned long rip,cs,eflags;
- unsigned long rsp,ss;
- unsigned long fs_base, gs_base;
- unsigned long ds,es,fs,gs;
-};
-
-// Linux gets very upset if a debugger forgets the reported state
-// of a debugged process, so we keep everything we know about
-// a debugged process in the LinuxThread structure.
-//
-// We can poll for state changes by calling waitpid and interpreting
-// the integer status code that comes back. Wait1 does this.
-//
-// If the process is already running, it is an error to PTRACE_CONT it.
-//
-// If the process is already stopped, it is an error to stop it again.
-//
-// If the process is stopped because of a signal, the debugger must
-// relay the signal to the PTRACE_CONT call, or else the signal is
-// dropped.
-//
-// If the process exits, the debugger should detach so that the real
-// parent can reap the zombie.
-//
-// On first attach, the debugger should set a handful of flags in order
-// to catch future events like fork, clone, exec, etc.
-
-// One for every attached thread.
-typedef struct LinuxThread LinuxThread;
-struct LinuxThread
-{
- int pid;
- int tid;
- int state;
- int signal;
- int child;
- int exitcode;
-};
-
-static int trace = 0;
-
-static LinuxThread **thr;
-static int nthr;
-static int mthr;
-
-static int realpid(int pid);
-
-enum
-{
- Unknown,
- Detached,
- Attached,
- AttachStop,
- Stopped,
- Running,
- Forking,
- Vforking,
- VforkDone,
- Cloning,
- Execing,
- Exiting,
- Exited,
- Killed,
-
- NSTATE,
-};
-
-static char* statestr[NSTATE] = {
- "Unknown",
- "Detached",
- "Attached",
- "AttachStop",
- "Stopped",
- "Running",
- "Forking",
- "Vforking",
- "VforkDone",
- "Cloning",
- "Execing",
- "Exiting",
- "Exited",
- "Killed"
-};
-
-static LinuxThread*
-attachthread(int pid, int tid, int *new, int newstate)
-{
- int i, n, status;
- LinuxThread **p, *t;
- uintptr flags;
-
- if(new)
- *new = 0;
-
- for(i=0; i<nthr; i++)
- if((pid == 0 || thr[i]->pid == pid) && thr[i]->tid == tid) {
- t = thr[i];
- goto fixup;
- }
-
- if(!new)
- return nil;
-
- if(nthr >= mthr) {
- n = mthr;
- if(n == 0)
- n = 64;
- else
- n *= 2;
- p = realloc(thr, n*sizeof thr[0]);
- if(p == nil)
- return nil;
- thr = p;
- mthr = n;
- }
-
- t = malloc(sizeof *t);
- if(t == nil)
- return nil;
- memset(t, 0, sizeof *t);
-
- thr[nthr++] = t;
- if(pid == 0 && nthr > 0)
- pid = thr[0]->pid;
- t->pid = pid;
- t->tid = tid;
- t->state = newstate;
- if(trace)
- fprint(2, "new thread %d %d\n", t->pid, t->tid);
- if(new)
- *new = 1;
-
-fixup:
- if(t->state == Detached) {
- if(ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- fprint(2, "ptrace ATTACH %d: %r\n", tid);
- return nil;
- }
- t->state = Attached;
- }
-
- if(t->state == Attached) {
- // wait for stop, so we can set options
- if(waitpid(tid, &status, __WALL|WUNTRACED|WSTOPPED) < 0)
- return nil;
- if(!WIFSTOPPED(status)) {
- fprint(2, "waitpid %d: status=%#x not stopped\n", tid);
- return nil;
- }
- t->state = AttachStop;
- }
-
- if(t->state == AttachStop) {
- // set options so we'll find out about new threads
- flags = PTRACE_O_TRACEFORK |
- PTRACE_O_TRACEVFORK |
- PTRACE_O_TRACECLONE |
- PTRACE_O_TRACEEXEC |
- PTRACE_O_TRACEVFORKDONE;
- if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0) {
- fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid);
- return nil;
- }
- t->state = Stopped;
- }
-
- return t;
-}
-
-static LinuxThread*
-findthread(int tid)
-{
- return attachthread(0, tid, nil, 0);
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- int i, n;
- LinuxThread *t;
-
- n = 0;
- for(i=0; i<nthr; i++) {
- t = thr[i];
- if(t->pid == pid) {
- switch(t->state) {
- case Exited:
- case Detached:
- case Killed:
- break;
-
- default:
- if(n < np)
- p[n] = t->tid;
- n++;
- break;
- }
- }
- }
- return n;
-}
-
-// Execute a single wait and update the corresponding thread.
-static int
-wait1(int nohang)
-{
- int tid, new, status, event;
- ulong data;
- LinuxThread *t;
- enum
- {
- NormalStop = 0x137f
- };
-
- if(nohang != 0)
- nohang = WNOHANG;
-
- status = 0;
- tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
-
- if(tid < 0)
- return -1;
- if(tid == 0)
- return 0;
-
- if(trace > 0 && status != NormalStop)
- fprint(2, "TID %d: %#x\n", tid, status);
-
- t = findthread(tid);
- if(t == nil) {
- // Sometimes the kernel tells us about new threads
- // before we see the parent clone.
- t = attachthread(0, tid, &new, Stopped);
- if(t == nil) {
- fprint(2, "failed to attach to new thread %d\n", tid);
- return -1;
- }
- }
-
- if(WIFSTOPPED(status)) {
- t->state = Stopped;
- t->signal = WSTOPSIG(status);
- if(trace)
- fprint(2, "tid %d: stopped %#x%s\n", tid, status,
- status != NormalStop ? " ***" : "");
- if(t->signal == SIGTRAP && (event = status>>16) != 0) { // ptrace event
- switch(event) {
- case PTRACE_EVENT_FORK:
- t->state = Forking;
- goto child;
-
- case PTRACE_EVENT_VFORK:
- t->state = Vforking;
- goto child;
-
- case PTRACE_EVENT_CLONE:
- t->state = Cloning;
- goto child;
-
- child:
- if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
- fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
- break;
- }
- t->child = data;
- attachthread(t->pid, t->child, &new, Running);
- break;
-
- case PTRACE_EVENT_EXEC:
- t->state = Execing;
- break;
-
- case PTRACE_EVENT_VFORK_DONE:
- t->state = VforkDone;
- break;
-
- case PTRACE_EVENT_EXIT:
- // We won't see this unless we set PTRACE_O_TRACEEXIT.
- // The debuggers assume that a read or write on a Map
- // will fail for a thread that has exited. This event
- // breaks that assumption. It's not a big deal: we
- // only lose the ability to see the register state at
- // the time of exit.
- if(trace)
- fprint(2, "tid %d: exiting %#x\n", tid, status);
- t->state = Exiting;
- if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
- fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
- break;
- }
- t->exitcode = data;
- break;
- }
- }
- }
- if(WIFCONTINUED(status)) {
- if(trace)
- fprint(2, "tid %d: continued %#x\n", tid, status);
- t->state = Running;
- }
- if(WIFEXITED(status)) {
- if(trace)
- fprint(2, "tid %d: exited %#x\n", tid, status);
- t->state = Exited;
- t->exitcode = WEXITSTATUS(status);
- t->signal = -1;
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- if(trace)
- fprint(2, "tid %d: detach exited\n", tid);
- }
- if(WIFSIGNALED(status)) {
- if(trace)
- fprint(2, "tid %d: signaled %#x\n", tid, status);
- t->state = Exited;
- t->signal = WTERMSIG(status);
- t->exitcode = -1;
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- if(trace)
- fprint(2, "tid %d: detach signaled\n", tid);
- }
- return 1;
-}
-
-static int
-waitstop(LinuxThread *t)
-{
- while(t->state == Running)
- if(wait1(0) < 0)
- return -1;
- return 0;
-}
-
-// Attach to and stop all threads in process pid.
-// Must stop everyone in order to make sure we set
-// the "tell me about new threads" option in every
-// task.
-int
-attachallthreads(int pid)
-{
- int tid, foundnew, new;
- char buf[100];
- DIR *d;
- struct dirent *de;
- LinuxThread *t;
-
- if(pid == 0) {
- fprint(2, "attachallthreads(0)\n");
- return -1;
- }
-
- pid = realpid(pid);
-
- snprint(buf, sizeof buf, "/proc/%d/task", pid);
- if((d = opendir(buf)) == nil) {
- fprint(2, "opendir %s: %r\n", buf);
- return -1;
- }
-
- // Loop in case new threads are being created right now.
- // We stop every thread as we find it, so eventually
- // this has to stop (or the system runs out of procs).
- do {
- foundnew = 0;
- while((de = readdir(d)) != nil) {
- tid = atoi(de->d_name);
- if(tid == 0)
- continue;
- t = attachthread(pid, tid, &new, Detached);
- foundnew |= new;
- if(t)
- waitstop(t);
- }
- rewinddir(d);
- } while(foundnew);
- closedir(d);
-
- return 0;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- Map *map;
-
- if(pid == 0) {
- fprint(2, "attachproc(0)\n");
- return nil;
- }
-
- if(findthread(pid) == nil && attachallthreads(pid) < 0)
- return nil;
-
- map = newmap(0, 4);
- if (!map)
- return 0;
- map->pid = pid;
- if(mach->regsize)
- setmap(map, -1, 0, mach->regsize, 0, "regs", ptraceregrw);
-// if(mach->fpregsize)
-// setmap(map, -1, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs", ptraceregrw);
- setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", ptracesegrw);
- setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", ptracesegrw);
- return map;
-}
-
-void
-detachproc(Map *m)
-{
- LinuxThread *t;
-
- t = findthread(m->pid);
- if(t != nil) {
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- t->state = Detached;
- if(trace)
- fprint(2, "tid %d: detachproc\n", t->tid);
- // TODO(rsc): Reclaim thread structs somehow?
- }
- free(m);
-}
-
-/* /proc/pid/stat contains
- pid
- command in parens
- 0. state
- 1. ppid
- 2. pgrp
- 3. session
- 4. tty_nr
- 5. tpgid
- 6. flags (math=4, traced=10)
- 7. minflt
- 8. cminflt
- 9. majflt
- 10. cmajflt
- 11. utime
- 12. stime
- 13. cutime
- 14. cstime
- 15. priority
- 16. nice
- 17. 0
- 18. itrealvalue
- 19. starttime
- 20. vsize
- 21. rss
- 22. rlim
- 23. startcode
- 24. endcode
- 25. startstack
- 26. kstkesp
- 27. kstkeip
- 28. pending signal bitmap
- 29. blocked signal bitmap
- 30. ignored signal bitmap
- 31. caught signal bitmap
- 32. wchan
- 33. nswap
- 34. cnswap
- 35. exit_signal
- 36. processor
-*/
-
-static int
-readstat(int pid, char *buf, int nbuf, char **f, int nf)
-{
- int fd, n;
- char *p;
-
- snprint(buf, nbuf, "/proc/%d/stat", pid);
- if((fd = open(buf, OREAD)) < 0){
- fprint(2, "open %s: %r\n", buf);
- return -1;
- }
- n = read(fd, buf, nbuf-1);
- close(fd);
- if(n <= 0){
- fprint(2, "read %s: %r\n", buf);
- return -1;
- }
- buf[n] = 0;
-
- /* command name is in parens, no parens afterward */
- p = strrchr(buf, ')');
- if(p == nil || *++p != ' '){
- fprint(2, "bad format in /proc/%d/stat\n", pid);
- return -1;
- }
- ++p;
-
- nf = tokenize(p, f, nf);
- if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
- strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
- strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
-
- return nf;
-}
-
-static char*
-readstatus(int pid, char *buf, int nbuf, char *key)
-{
- int fd, n;
- char *p;
-
- snprint(buf, nbuf, "/proc/%d/status", pid);
- if((fd = open(buf, OREAD)) < 0){
- fprint(2, "open %s: %r\n", buf);
- return nil;
- }
- n = read(fd, buf, nbuf-1);
- close(fd);
- if(n <= 0){
- fprint(2, "read %s: %r\n", buf);
- return nil;
- }
- buf[n] = 0;
- p = strstr(buf, key);
- if(p)
- return p+strlen(key);
- return nil;
-}
-
-int
-procnotes(int pid, char ***pnotes)
-{
- char buf[1024], *f[40];
- int i, n, nf;
- char *s, **notes;
- ulong sigs;
- extern char *_p9sigstr(int, char*);
-
- *pnotes = nil;
- nf = readstat(pid, buf, sizeof buf, f, nelem(f));
- if(nf <= 28)
- return -1;
-
- sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
- if(sigs == 0){
- *pnotes = nil;
- return 0;
- }
-
- notes = malloc(32*sizeof(char*));
- if(notes == nil)
- return -1;
- memset(notes, 0, 32*sizeof(char*));
- n = 0;
- for(i=0; i<32; i++){
- if((sigs&(1<<i)) == 0)
- continue;
- if((s = _p9sigstr(i, nil)) == nil)
- continue;
- notes[n++] = s;
- }
- *pnotes = notes;
- return n;
-}
-
-static int
-realpid(int pid)
-{
- char buf[1024], *p;
-
- p = readstatus(pid, buf, sizeof buf, "\nTgid:");
- if(p == nil)
- return pid;
- return atoi(p);
-}
-
-int
-ctlproc(int pid, char *msg)
-{
- int new;
- LinuxThread *t;
- uintptr data;
-
- while(wait1(1) > 0)
- ;
-
- if(strcmp(msg, "attached") == 0){
- t = attachthread(pid, pid, &new, Attached);
- if(t == nil)
- return -1;
- return 0;
- }
-
- if(strcmp(msg, "hang") == 0){
- if(pid == getpid())
- return ptrace(PTRACE_TRACEME, 0, 0, 0);
- werrstr("can only hang self");
- return -1;
- }
-
- t = findthread(pid);
- if(t == nil) {
- werrstr("not attached to pid %d", pid);
- return -1;
- }
- if(t->state == Exited) {
- werrstr("pid %d has exited", pid);
- return -1;
- }
- if(t->state == Killed) {
- werrstr("pid %d has been killed", pid);
- return -1;
- }
-
- if(strcmp(msg, "kill") == 0) {
- if(ptrace(PTRACE_KILL, pid, 0, 0) < 0)
- return -1;
- t->state = Killed;
- return 0;
- }
- if(strcmp(msg, "startstop") == 0){
- if(ctlproc(pid, "start") < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "sysstop") == 0){
- if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
- return -1;
- t->state = Running;
- return waitstop(t);
- }
- if(strcmp(msg, "stop") == 0){
- if(trace > 1)
- fprint(2, "tid %d: tkill stop\n", pid);
- if(t->state == Stopped)
- return 0;
- if(syscall(__NR_tkill, pid, SIGSTOP) < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "step") == 0){
- if(t->state == Running) {
- werrstr("cannot single-step unstopped %d", pid);
- return -1;
- }
- if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "start") == 0) {
- if(t->state == Running)
- return 0;
- data = 0;
- if(t->state == Stopped && t->signal != SIGSTOP && t->signal != SIGTRAP)
- data = t->signal;
- if(trace && data)
- fprint(2, "tid %d: continue %lud\n", pid, (ulong)data);
- if(ptrace(PTRACE_CONT, pid, 0, (void*)data) < 0)
- return -1;
- t->state = Running;
- return 0;
- }
- if(strcmp(msg, "waitstop") == 0) {
- return waitstop(t);
- }
- werrstr("unknown control message '%s'", msg);
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- static char buf[1024], pbuf[128];
-
- snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
- if(readlink(pbuf, buf, sizeof buf) >= 0)
- return strdup(buf);
- if(access(pbuf, AEXIST) >= 0)
- return strdup(pbuf);
- return nil;
-}
-
-
-static int
-ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
-{
- int i;
- uintptr u, a;
- uchar buf[sizeof(uintptr)];
-
- for(i=0; i<n; i+=sizeof(uintptr)){
- // Tread carefully here. On recent versions of glibc,
- // ptrace is a variadic function which means the third
- // argument will be pushed onto the stack as a uvlong.
- // This is fine on amd64 but will not work for 386.
- // We must convert addr to a uintptr.
- a = addr+i;
- if(isr){
- errno = 0;
- u = ptrace(type, pid, a, 0);
- if(errno)
- goto ptraceerr;
- if(n-i >= sizeof(uintptr))
- memmove((char*)v+i, &u, sizeof(uintptr));
- else{
- memmove(buf, &u, sizeof u);
- memmove((char*)v+i, buf, n-i);
- }
- }else{
- if(n-i >= sizeof(uintptr))
- u = *(uintptr*)((char*)v+i);
- else{
- errno = 0;
- u = ptrace(xtype, pid, a, 0);
- if(errno)
- return -1;
- memmove(buf, &u, sizeof u);
- memmove(buf, (char*)v+i, n-i);
- memmove(&u, buf, sizeof u);
- }
- if(ptrace(type, pid, a, u) < 0)
- goto ptraceerr;
- }
- }
- return 0;
-
-ptraceerr:
- werrstr("ptrace %s addr=%#llux pid=%d: %r", isr ? "read" : "write", addr, pid);
- return -1;
-}
-
-static int
-ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- USED(seg);
-
- return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
- isr, map->pid, addr, v, n);
-}
-
-// If the debugger is compiled as an x86-64 program,
-// then all the ptrace register read/writes are done on
-// a 64-bit register set. If the target program
-// is a 32-bit program, the debugger is expected to
-// read the bottom half of the relevant registers
-// out of the 64-bit set.
-
-// Linux 32-bit is
-// BX CX DX SI DI BP AX DS ES FS GS OrigAX IP CS EFLAGS SP SS
-
-// Linux 64-bit is
-// R15 R14 R13 R12 BP BX R11 R10 R9 R8 AX CX DX SI DI OrigAX IP CS EFLAGS SP SS FSBase GSBase DS ES FS GS
-
-// Go 32-bit is
-// DI SI BP NSP BX DX CX AX GS FS ES DS TRAP ECODE PC CS EFLAGS SP SS
-
-uint go32tolinux32tab[] = {
- 4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16
-};
-static int
-go32tolinux32(uvlong addr)
-{
- int r;
-
- if(addr%4 || addr/4 >= nelem(go32tolinux32tab))
- return -1;
- r = go32tolinux32tab[addr/4];
- if(r < 0)
- return -1;
- return r*4;
-}
-
-uint go32tolinux64tab[] = {
- 14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20
-};
-static int
-go32tolinux64(uvlong addr)
-{
- int r;
-
- if(addr%4 || addr/4 >= nelem(go32tolinux64tab))
- return -1;
- r = go32tolinux64tab[addr/4];
- if(r < 0)
- return -1;
- return r*8;
-}
-
-extern Mach mi386;
-extern Mach mamd64;
-
-static int
-go2linux(uvlong addr)
-{
- if(sizeof(void*) == 4) {
- if(mach == &mi386)
- return go32tolinux32(addr);
- werrstr("unsupported architecture");
- return -1;
- }
-
- if(mach == &mi386)
- return go32tolinux64(addr);
- if(mach != &mamd64) {
- werrstr("unsupported architecture");
- return -1;
- }
-
- switch(addr){
- case offsetof(Ureg64, ax):
- return offsetof(struct user_regs_struct, rax);
- case offsetof(Ureg64, bx):
- return offsetof(struct user_regs_struct, rbx);
- case offsetof(Ureg64, cx):
- return offsetof(struct user_regs_struct, rcx);
- case offsetof(Ureg64, dx):
- return offsetof(struct user_regs_struct, rdx);
- case offsetof(Ureg64, si):
- return offsetof(struct user_regs_struct, rsi);
- case offsetof(Ureg64, di):
- return offsetof(struct user_regs_struct, rdi);
- case offsetof(Ureg64, bp):
- return offsetof(struct user_regs_struct, rbp);
- case offsetof(Ureg64, r8):
- return offsetof(struct user_regs_struct, r8);
- case offsetof(Ureg64, r9):
- return offsetof(struct user_regs_struct, r9);
- case offsetof(Ureg64, r10):
- return offsetof(struct user_regs_struct, r10);
- case offsetof(Ureg64, r11):
- return offsetof(struct user_regs_struct, r11);
- case offsetof(Ureg64, r12):
- return offsetof(struct user_regs_struct, r12);
- case offsetof(Ureg64, r13):
- return offsetof(struct user_regs_struct, r13);
- case offsetof(Ureg64, r14):
- return offsetof(struct user_regs_struct, r14);
- case offsetof(Ureg64, r15):
- return offsetof(struct user_regs_struct, r15);
- case offsetof(Ureg64, ds):
- return offsetof(struct user_regs_struct, ds);
- case offsetof(Ureg64, es):
- return offsetof(struct user_regs_struct, es);
- case offsetof(Ureg64, fs):
- return offsetof(struct user_regs_struct, fs);
- case offsetof(Ureg64, gs):
- return offsetof(struct user_regs_struct, gs);
- case offsetof(Ureg64, ip):
- return offsetof(struct user_regs_struct, rip);
- case offsetof(Ureg64, cs):
- return offsetof(struct user_regs_struct, cs);
- case offsetof(Ureg64, flags):
- return offsetof(struct user_regs_struct, eflags);
- case offsetof(Ureg64, sp):
- return offsetof(struct user_regs_struct, rsp);
- case offsetof(Ureg64, ss):
- return offsetof(struct user_regs_struct, ss);
- }
- return -1;
-}
-
-static int
-ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- int laddr;
- uvlong u;
-
- USED(seg);
-
- if((laddr = go2linux(addr)) < 0){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
-
- if(isr){
- errno = 0;
- u = ptrace(PTRACE_PEEKUSER, map->pid, laddr, 0);
- if(errno)
- goto ptraceerr;
- switch(n){
- case 1:
- *(uint8*)v = u;
- break;
- case 2:
- *(uint16*)v = u;
- break;
- case 4:
- *(uint32*)v = u;
- break;
- case 8:
- *(uint64*)v = u;
- break;
- default:
- werrstr("bad register size");
- return -1;
- }
- }else{
- switch(n){
- case 1:
- u = *(uint8*)v;
- break;
- case 2:
- u = *(uint16*)v;
- break;
- case 4:
- u = *(uint32*)v;
- break;
- case 8:
- u = *(uint64*)v;
- break;
- default:
- werrstr("bad register size");
- return -1;
- }
- if(ptrace(PTRACE_POKEUSER, map->pid, laddr, (void*)(uintptr)u) < 0)
- goto ptraceerr;
- }
- return 0;
-
-ptraceerr:
- werrstr("ptrace %s register laddr=%d pid=%d n=%d: %r", isr ? "read" : "write", laddr, map->pid, n);
- return -1;
-}
-
-char*
-procstatus(int pid)
-{
- LinuxThread *t;
-
- t = findthread(pid);
- if(t == nil)
- return "???";
-
- return statestr[t->state];
-}
diff --git a/src/libmach/machdata.c b/src/libmach/machdata.c
deleted file mode 100644
index 66c19f953..000000000
--- a/src/libmach/machdata.c
+++ /dev/null
@@ -1,477 +0,0 @@
-// Inferno libmach/machdata.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * Debugger utilities shared by at least two architectures
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-#define STARTSYM "_main"
-#define PROFSYM "_mainp"
-#define FRAMENAME ".frame"
-
-extern Machdata mipsmach;
-
-int asstype = AMIPS; /* disassembler type */
-Machdata *machdata; /* machine-dependent functions */
-
-int
-localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
-{
- Symbol s;
- uvlong fp, pc, sp, link;
-
- if (!lookup(fn, 0, &s)) {
- werrstr("function not found");
- return -1;
- }
- pc = rget(map, mach->pc);
- sp = rget(map, mach->sp);
- if(mach->link)
- link = rget(map, mach->link);
- else
- link = 0;
- fp = machdata->findframe(map, s.value, pc, sp, link);
- if (fp == 0) {
- werrstr("stack frame not found");
- return -1;
- }
-
- if (!var || !var[0]) {
- *r = fp;
- return 1;
- }
-
- if (findlocal(&s, var, &s) == 0) {
- werrstr("local variable not found");
- return -1;
- }
-
- switch (s.class) {
- case CAUTO:
- *r = fp - s.value;
- break;
- case CPARAM: /* assume address size is stack width */
- *r = fp + s.value + mach->szaddr;
- break;
- default:
- werrstr("local variable not found: %d", s.class);
- return -1;
- }
- return 1;
-}
-
-/*
- * Print value v as s.name[+offset] if possible, or just v.
- */
-int
-symoff(char *buf, int n, uvlong v, int space)
-{
- Symbol s;
- int r;
- int32 delta;
-
- r = delta = 0; /* to shut compiler up */
- if (v) {
- r = findsym(v, space, &s);
- if (r)
- delta = v-s.value;
- if (delta < 0)
- delta = -delta;
- }
- if (v == 0 || r == 0)
- return snprint(buf, n, "%llux", v);
- if (s.type != 't' && s.type != 'T' && delta >= 4096)
- return snprint(buf, n, "%llux", v);
- else if (delta)
- return snprint(buf, n, "%s+%#ux", s.name, delta);
- else
- return snprint(buf, n, "%s", s.name);
-}
-
-/*
- * Format floating point registers
- *
- * Register codes in format field:
- * 'X' - print as 32-bit hexadecimal value
- * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
- * 'f' - 32-bit ieee float
- * '8' - big endian 80-bit ieee extended float
- * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
- */
-int
-fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
-{
- char reg[12];
- uint32 r;
-
- switch(rp->rformat)
- {
- case 'X':
- if (get4(map, rp->roffs, &r) < 0)
- return -1;
- snprint(buf, n, "%ux", r);
- break;
- case 'F': /* first reg of double reg pair */
- if (modif == 'F')
- if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
- if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
- return -1;
- machdata->dftos(buf, n, reg);
- if (rp->rformat == 'F')
- return 1;
- return 2;
- }
- /* treat it like 'f' */
- if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
- return -1;
- machdata->sftos(buf, n, reg);
- break;
- case 'f': /* 32 bit float */
- if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
- return -1;
- machdata->sftos(buf, n, reg);
- break;
- case '3': /* little endian ieee 80 with hole in bytes 8&9 */
- if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
- return -1;
- memmove(reg+10, reg+8, 2); /* open hole */
- memset(reg+8, 0, 2); /* fill it */
- leieee80ftos(buf, n, reg);
- break;
- case '8': /* big-endian ieee 80 */
- if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
- return -1;
- beieee80ftos(buf, n, reg);
- break;
- default: /* unknown */
- break;
- }
- return 1;
-}
-
-char *
-_hexify(char *buf, uint32 p, int zeros)
-{
- uint32 d;
-
- d = p/16;
- if(d)
- buf = _hexify(buf, d, zeros-1);
- else
- while(zeros--)
- *buf++ = '0';
- *buf++ = "0123456789abcdef"[p&0x0f];
- return buf;
-}
-
-/*
- * These routines assume that if the number is representable
- * in IEEE floating point, it will be representable in the native
- * double format. Naive but workable, probably.
- */
-int
-ieeedftos(char *buf, int n, uint32 h, uint32 l)
-{
- double fr;
- int exp;
-
- if (n <= 0)
- return 0;
-
-
- if(h & (1L<<31)){
- *buf++ = '-';
- h &= ~(1L<<31);
- }else
- *buf++ = ' ';
- n--;
- if(l == 0 && h == 0)
- return snprint(buf, n, "0.");
- exp = (h>>20) & ((1L<<11)-1L);
- if(exp == 0)
- return snprint(buf, n, "DeN(%.8ux%.8ux)", h, l);
- if(exp == ((1L<<11)-1L)){
- if(l==0 && (h&((1L<<20)-1L)) == 0)
- return snprint(buf, n, "Inf");
- else
- return snprint(buf, n, "NaN(%.8ux%.8ux)", h&((1<<20)-1), l);
- }
- exp -= (1L<<10) - 2L;
- fr = l & ((1L<<16)-1L);
- fr /= 1L<<16;
- fr += (l>>16) & ((1L<<16)-1L);
- fr /= 1L<<16;
- fr += (h & (1L<<20)-1L) | (1L<<20);
- fr /= 1L<<21;
- fr = ldexp(fr, exp);
- return snprint(buf, n, "%.18g", fr);
-}
-
-int
-ieeesftos(char *buf, int n, uint32 h)
-{
- double fr;
- int exp;
-
- if (n <= 0)
- return 0;
-
- if(h & (1L<<31)){
- *buf++ = '-';
- h &= ~(1L<<31);
- }else
- *buf++ = ' ';
- n--;
- if(h == 0)
- return snprint(buf, n, "0.");
- exp = (h>>23) & ((1L<<8)-1L);
- if(exp == 0)
- return snprint(buf, n, "DeN(%.8ux)", h);
- if(exp == ((1L<<8)-1L)){
- if((h&((1L<<23)-1L)) == 0)
- return snprint(buf, n, "Inf");
- else
- return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
- }
- exp -= (1L<<7) - 2L;
- fr = (h & ((1L<<23)-1L)) | (1L<<23);
- fr /= 1L<<24;
- fr = ldexp(fr, exp);
- return snprint(buf, n, "%.9g", fr);
-}
-
-int
-beieeesftos(char *buf, int n, void *s)
-{
- return ieeesftos(buf, n, beswal(*(uint32*)s));
-}
-
-int
-beieeedftos(char *buf, int n, void *s)
-{
- return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1]));
-}
-
-int
-leieeesftos(char *buf, int n, void *s)
-{
- return ieeesftos(buf, n, leswal(*(uint32*)s));
-}
-
-int
-leieeedftos(char *buf, int n, void *s)
-{
- return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)s));
-}
-
-/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
-int
-beieee80ftos(char *buf, int n, void *s)
-{
- uchar *reg = (uchar*)s;
- int i;
- uint32 x;
- uchar ieee[8+8]; /* room for slop */
- uchar *p, *q;
-
- memset(ieee, 0, sizeof(ieee));
- /* sign */
- if(reg[0] & 0x80)
- ieee[0] |= 0x80;
-
- /* exponent */
- x = ((reg[0]&0x7F)<<8) | reg[1];
- if(x == 0) /* number is ±0 */
- goto done;
- if(x == 0x7FFF){
- if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
- x = 2047;
- }else{ /* NaN */
- x = 2047;
- ieee[7] = 0x1; /* make sure */
- }
- ieee[0] |= x>>4;
- ieee[1] |= (x&0xF)<<4;
- goto done;
- }
- x -= 0x3FFF; /* exponent bias */
- x += 1023;
- if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
- return snprint(buf, n, "not in range");
- ieee[0] |= x>>4;
- ieee[1] |= (x&0xF)<<4;
-
- /* mantissa */
- p = reg+4;
- q = ieee+1;
- for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
- x = (p[0]&0x7F) << 1;
- if(p[1] & 0x80)
- x |= 1;
- q[0] |= x>>4;
- q[1] |= (x&0xF)<<4;
- }
- done:
- return beieeedftos(buf, n, (void*)ieee);
-}
-
-int
-leieee80ftos(char *buf, int n, void *s)
-{
- int i;
- char *cp;
- char b[12];
-
- cp = (char*) s;
- for(i=0; i<12; i++)
- b[11-i] = *cp++;
- return beieee80ftos(buf, n, b);
-}
-
-int
-cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
- Symbol s;
- int found, i;
- uvlong opc, moved;
-
- USED(link);
- i = 0;
- opc = 0;
- while(pc && opc != pc) {
- moved = pc2sp(pc);
- if (moved == ~0)
- break;
- found = findsym(pc, CTEXT, &s);
- if (!found)
- break;
- if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
- break;
-
- sp += moved;
- opc = pc;
- if (geta(map, sp, &pc) < 0)
- break;
- (*trace)(map, pc, sp, &s);
- sp += mach->szaddr; /*assumes address size = stack width*/
- if(++i > 40)
- break;
- }
- return i;
-}
-
-int
-risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
- int i;
- Symbol s, f;
- uvlong oldpc;
-
- i = 0;
- while(findsym(pc, CTEXT, &s)) {
- if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
- break;
-
- if(pc == s.value) /* at first instruction */
- f.value = 0;
- else if(findlocal(&s, FRAMENAME, &f) == 0)
- break;
-
- oldpc = pc;
- if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
- pc = link;
- else
- if (geta(map, sp, &pc) < 0)
- break;
-
- if(pc == 0 || (pc == oldpc && f.value == 0))
- break;
-
- sp += f.value;
- (*trace)(map, pc-8, sp, &s);
-
- if(++i > 40)
- break;
- }
- return i;
-}
-
-uvlong
-ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
- Symbol s;
- uvlong moved;
-
- USED(link);
- for(;;) {
- moved = pc2sp(pc);
- if (moved == ~0)
- break;
- sp += moved;
- findsym(pc, CTEXT, &s);
- if (addr == s.value)
- return sp;
- if (geta(map, sp, &pc) < 0)
- break;
- sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/
- }
- return 0;
-}
-
-uvlong
-riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
- Symbol s, f;
-
- while (findsym(pc, CTEXT, &s)) {
- if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
- break;
-
- if(pc == s.value) /* at first instruction */
- f.value = 0;
- else
- if(findlocal(&s, FRAMENAME, &f) == 0)
- break;
-
- sp += f.value;
- if (s.value == addr)
- return sp;
-
- if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
- pc = link;
- else
- if (geta(map, sp-f.value, &pc) < 0)
- break;
- }
- return 0;
-}
diff --git a/src/libmach/macho.h b/src/libmach/macho.h
deleted file mode 100644
index 9dfea5a85..000000000
--- a/src/libmach/macho.h
+++ /dev/null
@@ -1,100 +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.
-
-/*
- * Definitions needed for accessing MACH object headers.
- */
-
-typedef struct {
- uint32 magic; /* mach magic number identifier */
- uint32 cputype; /* cpu specifier */
- uint32 cpusubtype; /* machine specifier */
- uint32 filetype; /* type of file */
- uint32 ncmds; /* number of load commands */
- uint32 sizeofcmds; /* the size of all the load commands */
- uint32 flags; /* flags */
- uint32 reserved; /* reserved */
-} Machhdr;
-
-typedef struct {
- uint32 type; /* type of load command */
- uint32 size; /* total size in bytes */
-} MachCmd;
-
-typedef struct {
- MachCmd cmd;
- char segname[16]; /* segment name */
- uint32 vmaddr; /* memory address of this segment */
- uint32 vmsize; /* memory size of this segment */
- uint32 fileoff; /* file offset of this segment */
- uint32 filesize; /* amount to map from the file */
- uint32 maxprot; /* maximum VM protection */
- uint32 initprot; /* initial VM protection */
- uint32 nsects; /* number of sections in segment */
- uint32 flags; /* flags */
-} MachSeg32; /* for 32-bit architectures */
-
-typedef struct {
- MachCmd cmd;
- char segname[16]; /* segment name */
- uvlong vmaddr; /* memory address of this segment */
- uvlong vmsize; /* memory size of this segment */
- uvlong fileoff; /* file offset of this segment */
- uvlong filesize; /* amount to map from the file */
- uint32 maxprot; /* maximum VM protection */
- uint32 initprot; /* initial VM protection */
- uint32 nsects; /* number of sections in segment */
- uint32 flags; /* flags */
-} MachSeg64; /* for 64-bit architectures */
-
-typedef struct {
- MachCmd cmd;
- uint32 fileoff; /* file offset of this segment */
- uint32 filesize; /* amount to map from the file */
-} MachSymSeg;
-
-typedef struct {
- char sectname[16]; /* name of this section */
- char segname[16]; /* segment this section goes in */
- uint32 addr; /* memory address of this section */
- uint32 size; /* size in bytes of this section */
- uint32 offset; /* file offset of this section */
- uint32 align; /* section alignment (power of 2) */
- uint32 reloff; /* file offset of relocation entries */
- uint32 nreloc; /* number of relocation entries */
- uint32 flags; /* flags (section type and attributes)*/
- uint32 reserved1; /* reserved (for offset or index) */
- uint32 reserved2; /* reserved (for count or sizeof) */
-} MachSect32; /* for 32-bit architectures */
-
-typedef struct {
- char sectname[16]; /* name of this section */
- char segname[16]; /* segment this section goes in */
- uvlong addr; /* memory address of this section */
- uvlong size; /* size in bytes of this section */
- uint32 offset; /* file offset of this section */
- uint32 align; /* section alignment (power of 2) */
- uint32 reloff; /* file offset of relocation entries */
- uint32 nreloc; /* number of relocation entries */
- uint32 flags; /* flags (section type and attributes)*/
- uint32 reserved1; /* reserved (for offset or index) */
- uint32 reserved2; /* reserved (for count or sizeof) */
- uint32 reserved3; /* reserved */
-} MachSect64; /* for 64-bit architectures */
-
-enum {
- MACH_CPU_TYPE_X86_64 = (1<<24)|7,
- MACH_CPU_TYPE_X86 = 7,
- MACH_CPU_SUBTYPE_X86 = 3,
- MACH_CPU_SUBTYPE_X86_64 = (1<<31)|3,
- MACH_EXECUTABLE_TYPE = 2,
- MACH_SEGMENT_32 = 1, /* 32-bit mapped segment */
- MACH_SEGMENT_64 = 0x19, /* 64-bit mapped segment */
- MACH_SYMSEG = 3, /* obsolete gdb symtab, reused by go */
- MACH_UNIXTHREAD = 0x5, /* thread (for stack) */
-};
-
-
-#define MACH64_MAG ((0xcf<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
-#define MACH32_MAG ((0xce<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
diff --git a/src/libmach/map.c b/src/libmach/map.c
deleted file mode 100644
index cd5ef0985..000000000
--- a/src/libmach/map.c
+++ /dev/null
@@ -1,183 +0,0 @@
-// Derived from Inferno libmach/map.c and
-// Plan 9 from User Space src/libmach/map.c
-//
-// http://code.swtch.com/plan9port/src/tip/src/libmach/map.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/map.c
-//
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// Portions Copyright © 2001-2007 Russ Cox.
-// 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.
-
-/*
- * file map routines
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-Map *
-newmap(Map *map, int n)
-{
- int size;
-
- size = sizeof(Map)+(n-1)*sizeof(Seg);
- if (map == 0)
- map = malloc(size);
- else
- map = realloc(map, size);
- if (map == 0) {
- werrstr("out of memory: %r");
- return 0;
- }
- memset(map, 0, size);
- map->nsegs = n;
- return map;
-}
-
-int
-setmap(Map *map, int fd, uvlong b, uvlong e, vlong f, char *name, Maprw *rw)
-{
- int i;
-
- if (map == 0)
- return 0;
- for (i = 0; i < map->nsegs; i++)
- if (!map->seg[i].inuse)
- break;
- if (i >= map->nsegs)
- return 0;
- map->seg[i].b = b;
- map->seg[i].e = e;
- map->seg[i].f = f;
- map->seg[i].inuse = 1;
- map->seg[i].name = name;
- map->seg[i].fd = fd;
- map->seg[i].rw = rw;
- return 1;
-}
-
-/*
-static uvlong
-stacktop(int pid)
-{
- char buf[64];
- int fd;
- int n;
- char *cp;
-
- snprint(buf, sizeof(buf), "/proc/%d/segment", pid);
- fd = open(buf, 0);
- if (fd < 0)
- return 0;
- n = read(fd, buf, sizeof(buf)-1);
- close(fd);
- buf[n] = 0;
- if (strncmp(buf, "Stack", 5))
- return 0;
- for (cp = buf+5; *cp && *cp == ' '; cp++)
- ;
- if (!*cp)
- return 0;
- cp = strchr(cp, ' ');
- if (!cp)
- return 0;
- while (*cp && *cp == ' ')
- cp++;
- if (!*cp)
- return 0;
- return strtoull(cp, 0, 16);
-}
-*/
-
-int
-findseg(Map *map, char *name)
-{
- int i;
-
- if (!map)
- return -1;
- for (i = 0; i < map->nsegs; i++)
- if (map->seg[i].inuse && !strcmp(map->seg[i].name, name))
- return i;
- return -1;
-}
-
-void
-unusemap(Map *map, int i)
-{
- if (map != 0 && 0 <= i && i < map->nsegs)
- map->seg[i].inuse = 0;
-}
-
-int
-fdrw(Map *map, Seg *s, uvlong addr, void *v, uint n, int isread)
-{
- int tot, m;
-
- USED(map);
-
- for(tot=0; tot<n; tot+=m){
- if(isread)
- m = pread(s->fd, (uchar*)v+tot, n-tot, addr+tot);
- else
- m = pwrite(s->fd, (uchar*)v+tot, n-tot, addr+tot);
- if(m == 0){
- werrstr("short %s", isread ? "read" : "write");
- return -1;
- }
- if(m < 0){
- werrstr("%s %d at %#llux (+%#llux): %r", isread ? "read" : "write", n, addr, s->f);
- return -1;
- }
- }
- return 0;
-}
-
-
-Map*
-loadmap(Map *map, int fd, Fhdr *fp)
-{
- map = newmap(map, 2);
- if (map == 0)
- return 0;
-
- map->seg[0].b = fp->txtaddr;
- map->seg[0].e = fp->txtaddr+fp->txtsz;
- map->seg[0].f = fp->txtoff;
- map->seg[0].fd = fd;
- map->seg[0].inuse = 1;
- map->seg[0].name = "text";
- map->seg[0].rw = fdrw;
- map->seg[1].b = fp->dataddr;
- map->seg[1].e = fp->dataddr+fp->datsz;
- map->seg[1].f = fp->datoff;
- map->seg[1].fd = fd;
- map->seg[1].inuse = 1;
- map->seg[1].name = "data";
- map->seg[0].rw = fdrw;
- return map;
-}
diff --git a/src/libmach/netbsd.c b/src/libmach/netbsd.c
deleted file mode 100644
index adeeff333..000000000
--- a/src/libmach/netbsd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in NetBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in NetBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in NetBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in NetBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in NetBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in NetBSD");
- return -1;
-}
diff --git a/src/libmach/obj.c b/src/libmach/obj.c
deleted file mode 100644
index 729a3eab8..000000000
--- a/src/libmach/obj.c
+++ /dev/null
@@ -1,393 +0,0 @@
-// Inferno libmach/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * obj.c
- * routines universal to all object files
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ar.h>
-#include <mach.h>
-#include "obj.h"
-
-#define islocal(t) ((t)=='a' || (t)=='p')
-
-enum
-{
- NNAMES = 50,
- MAXIS = 8, /* max length to determine if a file is a .? file */
- MAXOFF = 0x7fffffff, /* larger than any possible local offset */
- NHASH = 1024, /* must be power of two */
- HASHMUL = 79L,
-};
-
-int _is2(char*), /* in [$OS].c */
- _is5(char*),
- _is6(char*),
- _is7(char*),
- _is8(char*),
- _is9(char*),
- _isk(char*),
- _isq(char*),
- _isv(char*),
- _isu(char*),
- _read2(Biobuf*, Prog*),
- _read5(Biobuf*, Prog*),
- _read6(Biobuf*, Prog*),
- _read7(Biobuf*, Prog*),
- _read8(Biobuf*, Prog*),
- _read9(Biobuf*, Prog*),
- _readk(Biobuf*, Prog*),
- _readq(Biobuf*, Prog*),
- _readv(Biobuf*, Prog*),
- _readu(Biobuf*, Prog*);
-
-typedef struct Obj Obj;
-typedef struct Symtab Symtab;
-
-struct Obj /* functions to handle each intermediate (.$O) file */
-{
- char *name; /* name of each $O file */
- int (*is)(char*); /* test for each type of $O file */
- int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
-};
-
-static Obj obj[] =
-{ /* functions to identify and parse each type of obj */
- [Obj68020] = { "68020 .2", _is2, _read2 },
- [ObjAmd64] = { "amd64 .6", _is6 , _read6 },
- [ObjArm] = { "arm .5", _is5, _read5 },
- [ObjAlpha] = { "alpha .7", _is7, _read7 },
- [Obj386] = { "386 .8", _is8, _read8 },
- [ObjSparc] = { "sparc .k", _isk, _readk },
- [ObjPower] = { "power .q", _isq, _readq },
- [ObjMips] = { "mips .v", _isv, _readv },
- [ObjSparc64] = { "sparc64 .u", _isu, _readu },
- [ObjPower64] = { "power64 .9", _is9, _read9 },
- [Maxobjtype] = { 0, 0, 0 }
-};
-
-struct Symtab
-{
- struct Sym s;
- struct Symtab *next;
-};
-
-static Symtab *hash[NHASH];
-static Sym *names[NNAMES]; /* working set of active names */
-
-static int processprog(Prog*,int); /* decode each symbol reference */
-static void objreset(void);
-static void objlookup(int, char *, int, uint);
-static void objupdate(int, int);
-
-static int sequence;
-
-int
-objtype(Biobuf *bp, char **name)
-{
- int i;
- char buf[MAXIS];
- int c;
- char *p;
-
- /*
- * Look for import block.
- */
- p = Brdline(bp, '\n');
- if(p == nil)
- return -1;
- if(Blinelen(bp) < 10 || strncmp(p, "go object ", 10) != 0)
- return -1;
- Bseek(bp, -1, 1);
-
- /*
- * Found one. Skip until "\n!\n"
- */
- for(;;) {
- if((c = BGETC(bp)) == Beof)
- return -1;
- if(c != '\n')
- continue;
- c = BGETC(bp);
- if(c != '!'){
- Bungetc(bp);
- continue;
- }
- c = BGETC(bp);
- if(c != '\n'){
- Bungetc(bp);
- continue;
- }
- break;
- }
-
- if(Bread(bp, buf, MAXIS) < MAXIS)
- return -1;
- Bseek(bp, -MAXIS, 1);
- for (i = 0; i < Maxobjtype; i++) {
- if (obj[i].is && (*obj[i].is)(buf)) {
- if (name)
- *name = obj[i].name;
- return i;
- }
- }
-
- return -1;
-}
-
-int
-isar(Biobuf *bp)
-{
- int n;
- char magbuf[SARMAG];
-
- n = Bread(bp, magbuf, SARMAG);
- if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
- return 1;
- return 0;
-}
-
-/*
- * determine what kind of object file this is and process it.
- * return whether or not this was a recognized intermediate file.
- */
-int
-readobj(Biobuf *bp, int objtype)
-{
- Prog p;
-
- if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
- return 1;
- objreset();
- while ((*obj[objtype].read)(bp, &p))
- if (!processprog(&p, 1))
- return 0;
- return 1;
-}
-
-int
-readar(Biobuf *bp, int objtype, vlong end, int doautos)
-{
- Prog p;
-
- if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
- return 1;
- objreset();
- while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
- if (!processprog(&p, doautos))
- return 0;
- return 1;
-}
-
-/*
- * decode a symbol reference or definition
- */
-static int
-processprog(Prog *p, int doautos)
-{
- if(p->kind == aNone)
- return 1;
- if((schar)p->sym < 0 || p->sym >= NNAMES)
- return 0;
- switch(p->kind)
- {
- case aName:
- if (!doautos)
- if(p->type != 'U' && p->type != 'b')
- break;
- objlookup(p->sym, p->id, p->type, p->sig);
- break;
- case aText:
- objupdate(p->sym, 'T');
- break;
- case aData:
- objupdate(p->sym, 'D');
- break;
- default:
- break;
- }
- return 1;
-}
-
-/*
- * find the entry for s in the symbol array.
- * make a new entry if it is not already there.
- */
-static void
-objlookup(int id, char *name, int type, uint sig)
-{
- uint32 h;
- char *cp;
- Sym *s;
- Symtab *sp;
-
- s = names[id];
- if(s && strcmp(s->name, name) == 0) {
- s->type = type;
- s->sig = sig;
- return;
- }
-
- h = *name;
- for(cp = name+1; *cp; h += *cp++)
- h *= HASHMUL;
- h &= NHASH-1;
- if (type == 'U' || type == 'b' || islocal(type)) {
- for(sp = hash[h]; sp; sp = sp->next)
- if(strcmp(sp->s.name, name) == 0) {
- switch(sp->s.type) {
- case 'T':
- case 'D':
- case 'U':
- if (type == 'U') {
- names[id] = &sp->s;
- return;
- }
- break;
- case 't':
- case 'd':
- case 'b':
- if (type == 'b') {
- names[id] = &sp->s;
- return;
- }
- break;
- case 'a':
- case 'p':
- if (islocal(type)) {
- names[id] = &sp->s;
- return;
- }
- break;
- default:
- break;
- }
- }
- }
- sp = malloc(sizeof(Symtab));
- if(sp == nil)
- sysfatal("out of memory");
- sp->s.name = name;
- sp->s.type = type;
- sp->s.sig = sig;
- sp->s.value = islocal(type) ? MAXOFF : 0;
- sp->s.sequence = sequence++;
- names[id] = &sp->s;
- sp->next = hash[h];
- hash[h] = sp;
- return;
-}
-/*
- * traverse the symbol lists
- */
-void
-objtraverse(void (*fn)(Sym*, void*), void *pointer)
-{
- int i;
- Symtab *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s; s = s->next)
- (*fn)(&s->s, pointer);
-}
-
-/*
- * update the offset information for a 'a' or 'p' symbol in an intermediate file
- */
-void
-_offset(int id, vlong off)
-{
- Sym *s;
-
- s = names[id];
- if (s && s->name[0] && islocal(s->type) && s->value > off)
- s->value = off;
-}
-
-/*
- * update the type of a global text or data symbol
- */
-static void
-objupdate(int id, int type)
-{
- Sym *s;
-
- s = names[id];
- if (s && s->name[0])
- if (s->type == 'U')
- s->type = type;
- else if (s->type == 'b')
- s->type = tolower(type);
-}
-
-/*
- * look for the next file in an archive
- */
-int
-nextar(Biobuf *bp, int offset, char *buf)
-{
- struct ar_hdr a;
- int i, r;
- int32 arsize;
-
- if (offset&01)
- offset++;
- Bseek(bp, offset, 0);
- r = Bread(bp, &a, SAR_HDR);
- if(r != SAR_HDR)
- return 0;
- if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
- return -1;
- for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
- buf[i] = a.name[i];
- buf[i] = 0;
- arsize = strtol(a.size, 0, 0);
- if (arsize&1)
- arsize++;
- return arsize + SAR_HDR;
-}
-
-static void
-objreset(void)
-{
- int i;
- Symtab *s, *n;
-
- for(i = 0; i < NHASH; i++) {
- for(s = hash[i]; s; s = n) {
- n = s->next;
- free(s->s.name);
- free(s);
- }
- hash[i] = 0;
- }
- memset(names, 0, sizeof names);
-}
diff --git a/src/libmach/obj.h b/src/libmach/obj.h
deleted file mode 100644
index 35ec413a6..000000000
--- a/src/libmach/obj.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Inferno libmach/obj.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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.
-
-/*
- * obj.h -- defs for dealing with object files
- */
-
-typedef enum Kind /* variable defs and references in obj */
-{
- aNone, /* we don't care about this prog */
- aName, /* introduces a name */
- aText, /* starts a function */
- aData, /* references to a global object */
-} Kind;
-
-typedef struct Prog Prog;
-
-struct Prog /* info from .$O files */
-{
- Kind kind; /* what kind of symbol */
- char type; /* type of the symbol: ie, 'T', 'a', etc. */
- char sym; /* index of symbol's name */
- char *id; /* name for the symbol, if it introduces one */
- uint sig; /* type signature for symbol */
-};
-
-#define UNKNOWN '?'
-void _offset(int, vlong);
diff --git a/src/libmach/openbsd.c b/src/libmach/openbsd.c
deleted file mode 100644
index ace8a22a5..000000000
--- a/src/libmach/openbsd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in OpenBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in OpenBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in OpenBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in OpenBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in OpenBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in OpenBSD");
- return -1;
-}
diff --git a/src/libmach/plan9.c b/src/libmach/plan9.c
deleted file mode 100644
index 59e2649d0..000000000
--- a/src/libmach/plan9.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented on Plan 9");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented on Plan 9");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented on Plan 9");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented on Plan 9");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented on Plan 9");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented on Plan 9");
- return -1;
-}
-
-int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- USED(rqtp);
- USED(rmtp);
-
- sysfatal("nanosleep unimplemented on Plan 9");
- return -1;
-}
diff --git a/src/libmach/setmach.c b/src/libmach/setmach.c
deleted file mode 100644
index 0fa4d3192..000000000
--- a/src/libmach/setmach.c
+++ /dev/null
@@ -1,203 +0,0 @@
-// Inferno libmach/setmach.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/setmach.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
- /* table for selecting machine-dependent parameters */
-
-typedef struct machtab Machtab;
-
-struct machtab
-{
- char *name; /* machine name */
- short type; /* executable type */
- short boottype; /* bootable type */
- int asstype; /* disassembler code */
- Mach *mach; /* machine description */
- Machdata *machdata; /* machine functions */
-};
-
-/*
-extern Mach mmips, msparc, m68020, mi386, mamd64,
- marm, mmips2be, mmips2le, mpower, mpower64, malpha, msparc64;
-extern Machdata mipsmach, sparcmach, m68020mach, i386mach,
- armmach, mipsmach2le, powermach, alphamach, sparc64mach;
-*/
-extern Mach mi386, mamd64, marm;
-extern Machdata i386mach, armmach;
-
-/*
- * machine selection table. machines with native disassemblers should
- * follow the plan 9 variant in the table; native modes are selectable
- * only by name.
- */
-Machtab machines[] =
-{
- { "386", /*plan 9 386*/
- FI386,
- FI386B,
- AI386,
- &mi386,
- &i386mach, },
- { "amd64", /*amd64*/
- FAMD64,
- FAMD64B,
- AAMD64,
- &mamd64,
- &i386mach, },
- { "arm", /*ARM*/
- FARM,
- FARMB,
- AARM,
- &marm,
- &armmach, },
-#ifdef unused
- { "68020", /*68020*/
- F68020,
- F68020B,
- A68020,
- &m68020,
- &m68020mach, },
- { "68020", /*Next 68040 bootable*/
- F68020,
- FNEXTB,
- A68020,
- &m68020,
- &m68020mach, },
- { "mips2LE", /*plan 9 mips2 little endian*/
- FMIPS2LE,
- 0,
- AMIPS,
- &mmips2le,
- &mipsmach2le, },
- { "mips", /*plan 9 mips*/
- FMIPS,
- FMIPSB,
- AMIPS,
- &mmips,
- &mipsmach, },
- { "mips2", /*plan 9 mips2*/
- FMIPS2BE,
- FMIPSB,
- AMIPS,
- &mmips2be,
- &mipsmach, }, /* shares debuggers with native mips */
- { "mipsco", /*native mips - must follow plan 9*/
- FMIPS,
- FMIPSB,
- AMIPSCO,
- &mmips,
- &mipsmach, },
- { "sparc", /*plan 9 sparc */
- FSPARC,
- FSPARCB,
- ASPARC,
- &msparc,
- &sparcmach, },
- { "sunsparc", /*native sparc - must follow plan 9*/
- FSPARC,
- FSPARCB,
- ASUNSPARC,
- &msparc,
- &sparcmach, },
- { "86", /*8086 - a peach of a machine*/
- FI386,
- FI386B,
- AI8086,
- &mi386,
- &i386mach, },
- { "power", /*PowerPC*/
- FPOWER,
- FPOWERB,
- APOWER,
- &mpower,
- &powermach, },
- { "power64", /*PowerPC*/
- FPOWER64,
- FPOWER64B,
- APOWER64,
- &mpower64,
- &powermach, },
- { "alpha", /*Alpha*/
- FALPHA,
- FALPHAB,
- AALPHA,
- &malpha,
- &alphamach, },
- { "sparc64", /*plan 9 sparc64 */
- FSPARC64,
- FSPARCB, /* XXX? */
- ASPARC64,
- &msparc64,
- &sparc64mach, },
-#endif
- { 0 }, /*the terminator*/
-};
-
-/*
- * select a machine by executable file type
- */
-void
-machbytype(int type)
-{
- Machtab *mp;
-
- for (mp = machines; mp->name; mp++){
- if (mp->type == type || mp->boottype == type) {
- asstype = mp->asstype;
- machdata = mp->machdata;
- break;
- }
- }
-}
-/*
- * select a machine by name
- */
-int
-machbyname(char *name)
-{
- Machtab *mp;
-
- if (!name) {
- asstype = AAMD64;
- machdata = &i386mach;
- mach = &mamd64;
- return 1;
- }
- for (mp = machines; mp->name; mp++){
- if (strcmp(mp->name, name) == 0) {
- asstype = mp->asstype;
- machdata = mp->machdata;
- mach = mp->mach;
- return 1;
- }
- }
- return 0;
-}
diff --git a/src/libmach/swap.c b/src/libmach/swap.c
deleted file mode 100644
index bc296a3d7..000000000
--- a/src/libmach/swap.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// Inferno libmach/swap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/swap.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-
-/*
- * big-endian short
- */
-ushort
-beswab(ushort s)
-{
- uchar *p;
-
- p = (uchar*)&s;
- return (p[0]<<8) | p[1];
-}
-
-/*
- * big-endian int32
- */
-uint32
-beswal(uint32 l)
-{
- uchar *p;
-
- p = (uchar*)&l;
- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
-}
-
-/*
- * big-endian vlong
- */
-uvlong
-beswav(uvlong v)
-{
- uchar *p;
-
- p = (uchar*)&v;
- return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
- | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
- | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
- | (uvlong)p[7];
-}
-
-/*
- * little-endian short
- */
-ushort
-leswab(ushort s)
-{
- uchar *p;
-
- p = (uchar*)&s;
- return (p[1]<<8) | p[0];
-}
-
-/*
- * little-endian int32
- */
-uint32
-leswal(uint32 l)
-{
- uchar *p;
-
- p = (uchar*)&l;
- return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
-}
-
-/*
- * little-endian vlong
- */
-uvlong
-leswav(uvlong v)
-{
- uchar *p;
-
- p = (uchar*)&v;
- return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)
- | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)
- | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)
- | (uvlong)p[0];
-}
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
deleted file mode 100644
index 474cc0c62..000000000
--- a/src/libmach/sym.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-// Inferno libmach/sym.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-#define HUGEINT 0x7fffffff
-#define NNAME 20 /* a relic of the past */
-
-typedef struct txtsym Txtsym;
-typedef struct file File;
-typedef struct hist Hist;
-
-struct txtsym { /* Text Symbol table */
- int n; /* number of local vars */
- Sym **locals; /* array of ptrs to autos */
- Sym *sym; /* function symbol entry */
-};
-
-struct hist { /* Stack of include files & #line directives */
- char *name; /* Assumes names Null terminated in file */
- int32 line; /* line # where it was included */
- int32 offset; /* line # of #line directive */
-};
-
-struct file { /* Per input file header to history stack */
- uvlong addr; /* address of first text sym */
- union {
- Txtsym *txt; /* first text symbol */
- Sym *sym; /* only during initilization */
- };
- int n; /* size of history stack */
- Hist *hist; /* history stack */
-};
-
-static int debug = 0;
-
-static Sym **autos; /* Base of auto variables */
-static File *files; /* Base of file arena */
-static int fmaxi; /* largest file path index */
-static Sym **fnames; /* file names path component table */
-static Sym **globals; /* globals by addr table */
-static Hist *hist; /* base of history stack */
-static int isbuilt; /* internal table init flag */
-static int32 nauto; /* number of automatics */
-static int32 nfiles; /* number of files */
-static int32 nglob; /* number of globals */
-static int32 nhist; /* number of history stack entries */
-static int32 nsym; /* number of symbols */
-static int ntxt; /* number of text symbols */
-static uchar *pcline; /* start of pc-line state table */
-static uchar *pclineend; /* end of pc-line table */
-static uchar *spoff; /* start of pc-sp state table */
-static uchar *spoffend; /* end of pc-sp offset table */
-static Sym *symbols; /* symbol table */
-static Txtsym *txt; /* Base of text symbol table */
-static uvlong txtstart; /* start of text segment */
-static uvlong txtend; /* end of text segment */
-static uvlong firstinstr; /* as found from symtab; needed for amd64 */
-
-static void cleansyms(void);
-static int32 decodename(Biobuf*, Sym*);
-static short *encfname(char*);
-static int fline(char*, int, int32, Hist*, Hist**);
-static void fillsym(Sym*, Symbol*);
-static int findglobal(char*, Symbol*);
-static int findlocvar(Symbol*, char *, Symbol*);
-static int findtext(char*, Symbol*);
-static int hcomp(Hist*, short*);
-static int hline(File*, short*, int32*);
-static void printhist(char*, Hist*, int);
-static int buildtbls(void);
-static int symcomp(const void*, const void*);
-static int symerrmsg(int, char*);
-static int txtcomp(const void*, const void*);
-static int filecomp(const void*, const void*);
-
-/*
- * Go 1.2 pcln table (also contains pcsp).
- */
-#define Go12PclnMagic 0xfffffffb
-#define Go12PclnMagicRev 0xfbffffff
-static int isgo12pcline(void);
-static uvlong go12pc2sp(uvlong);
-static int32 go12fileline(char*, int, uvlong);
-static void go12clean(void);
-static uvlong go12file2pc(char*, int);
-
-/*
- * initialize the symbol tables
- */
-int
-syminit(int fd, Fhdr *fp)
-{
- Sym *p;
- int32 i, l, size, symsz;
- vlong vl;
- Biobuf b;
- int svalsz, newformat, shift;
- uvlong (*swav)(uvlong);
- uint32 (*swal)(uint32);
- uchar buf[8], c;
-
- if(fp->symsz == 0)
- return 0;
- if(fp->type == FNONE)
- return 0;
-
- swav = beswav;
- swal = beswal;
-
- cleansyms();
- textseg(fp->txtaddr, fp);
- /* minimum symbol record size = 4+1+2 bytes */
- symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
- if(symbols == 0) {
- werrstr("can't malloc %d bytes", fp->symsz);
- return -1;
- }
- Binit(&b, fd, OREAD);
- Bseek(&b, fp->symoff, 0);
- memset(buf, 0, sizeof buf);
- Bread(&b, buf, sizeof buf);
- newformat = 0;
- symsz = fp->symsz;
- if(memcmp(buf, "\xfd\xff\xff\xff\x00\x00\x00", 7) == 0) {
- swav = leswav;
- swal = leswal;
- newformat = 1;
- } else if(memcmp(buf, "\xff\xff\xff\xfd\x00\x00\x00", 7) == 0) {
- newformat = 1;
- } else if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) {
- // Table format used between Go 1.0 and Go 1.1:
- // little-endian but otherwise same as the old Go 1.0 table.
- // Not likely to be seen much in practice, but easy to handle.
- swav = leswav;
- swal = leswal;
- Bseek(&b, fp->symoff+6, 0);
- symsz -= 6;
- } else {
- Bseek(&b, fp->symoff, 0);
- }
- svalsz = 0;
- if(newformat) {
- svalsz = buf[7];
- if(svalsz != 4 && svalsz != 8) {
- werrstr("invalid word size %d bytes", svalsz);
- return -1;
- }
- symsz -= 8;
- }
-
- nsym = 0;
- size = 0;
- for(p = symbols; size < symsz; p++, nsym++) {
- if(newformat) {
- // Go 1.1 format. See comment at top of ../pkg/runtime/symtab.c.
- if(Bread(&b, &c, 1) != 1)
- return symerrmsg(1, "symbol");
- if((c&0x3F) < 26)
- p->type = (c&0x3F)+ 'A';
- else
- p->type = (c&0x3F) - 26 + 'a';
- size++;
-
- if(c&0x40) {
- // Fixed-width address.
- if(svalsz == 8) {
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->value = swav(vl);
- } else {
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->value = (u32int)swal(l);
- }
- size += svalsz;
- } else {
- // Varint address.
- shift = 0;
- p->value = 0;
- for(;;) {
- if(Bread(&b, buf, 1) != 1)
- return symerrmsg(1, "symbol");
- p->value |= (uint64)(buf[0]&0x7F)<<shift;
- shift += 7;
- size++;
- if((buf[0]&0x80) == 0)
- break;
- }
- }
- p->gotype = 0;
- if(c&0x80) {
- // Has Go type. Fixed-width address.
- if(svalsz == 8) {
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->gotype = swav(vl);
- } else {
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->gotype = (u32int)swal(l);
- }
- size += svalsz;
- }
-
- // Name.
- p->type |= 0x80; // for decodename
- i = decodename(&b, p);
- if(i < 0)
- return -1;
- size += i;
- } else {
- // Go 1.0 format: Plan 9 format + go type symbol.
- if(fp->_magic && (fp->magic & HDR_MAGIC)){
- svalsz = 8;
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->value = swav(vl);
- }
- else{
- svalsz = 4;
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->value = (u32int)swal(l);
- }
- if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
- return symerrmsg(sizeof(p->value), "symbol");
-
- i = decodename(&b, p);
- if(i < 0)
- return -1;
- size += i+svalsz+sizeof(p->type);
-
- if(svalsz == 8){
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->gotype = swav(vl);
- }
- else{
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->gotype = (u32int)swal(l);
- }
- size += svalsz;
- }
-
- /* count global & auto vars, text symbols, and file names */
- switch (p->type) {
- case 'l':
- case 'L':
- case 't':
- case 'T':
- ntxt++;
- break;
- case 'd':
- case 'D':
- case 'b':
- case 'B':
- nglob++;
- break;
- case 'f':
- if(strcmp(p->name, ".frame") == 0) {
- p->type = 'm';
- nauto++;
- }
- else if(p->value > fmaxi)
- fmaxi = p->value; /* highest path index */
- break;
- case 'a':
- case 'p':
- case 'm':
- nauto++;
- break;
- case 'z':
- if(p->value == 1) { /* one extra per file */
- nhist++;
- nfiles++;
- }
- nhist++;
- break;
- default:
- break;
- }
- }
- if (debug)
- print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmaxi);
- if (fp->sppcsz) { /* pc-sp offset table */
- spoff = (uchar *)malloc(fp->sppcsz);
- if(spoff == 0) {
- werrstr("can't malloc %d bytes", fp->sppcsz);
- return -1;
- }
- Bseek(&b, fp->sppcoff, 0);
- if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
- spoff = 0;
- return symerrmsg(fp->sppcsz, "sp-pc");
- }
- spoffend = spoff+fp->sppcsz;
- }
- if (fp->lnpcsz) { /* pc-line number table */
- pcline = (uchar *)malloc(fp->lnpcsz);
- if(pcline == 0) {
- werrstr("can't malloc %d bytes", fp->lnpcsz);
- return -1;
- }
- Bseek(&b, fp->lnpcoff, 0);
- if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
- pcline = 0;
- return symerrmsg(fp->lnpcsz, "pc-line");
- }
- pclineend = pcline+fp->lnpcsz;
- }
- return nsym;
-}
-
-static int
-symerrmsg(int n, char *table)
-{
- werrstr("can't read %d bytes of %s table", n, table);
- return -1;
-}
-
-static int32
-decodename(Biobuf *bp, Sym *p)
-{
- char *cp;
- int c1, c2;
- int32 n;
- vlong o;
-
- if((p->type & 0x80) == 0) { /* old-style, fixed length names */
- p->name = malloc(NNAME);
- if(p->name == 0) {
- werrstr("can't malloc %d bytes", NNAME);
- return -1;
- }
- if(Bread(bp, p->name, NNAME) != NNAME)
- return symerrmsg(NNAME, "symbol");
- Bseek(bp, 3, 1);
- return NNAME+3;
- }
-
- p->type &= ~0x80;
- if(p->type == 'z' || p->type == 'Z') {
- o = Bseek(bp, 0, 1);
- if(BGETC(bp) < 0) {
- werrstr("can't read symbol name");
- return -1;
- }
- for(;;) {
- c1 = BGETC(bp);
- c2 = BGETC(bp);
- if(c1 < 0 || c2 < 0) {
- werrstr("can't read symbol name");
- return -1;
- }
- if(c1 == 0 && c2 == 0)
- break;
- }
- n = Bseek(bp, 0, 1)-o;
- p->name = malloc(n);
- if(p->name == 0) {
- werrstr("can't malloc %d bytes", n);
- return -1;
- }
- Bseek(bp, -n, 1);
- if(Bread(bp, p->name, n) != n) {
- werrstr("can't read %d bytes of symbol name", n);
- return -1;
- }
- } else {
- cp = Brdline(bp, '\0');
- if(cp == 0) {
- werrstr("can't read symbol name");
- return -1;
- }
- n = Blinelen(bp);
- p->name = malloc(n);
- if(p->name == 0) {
- werrstr("can't malloc %d bytes", n);
- return -1;
- }
- strcpy(p->name, cp);
- }
- return n;
-}
-
-/*
- * free any previously loaded symbol tables
- */
-static void
-cleansyms(void)
-{
- if(globals)
- free(globals);
- globals = 0;
- nglob = 0;
- if(txt)
- free(txt);
- txt = 0;
- ntxt = 0;
- if(fnames)
- free(fnames);
- fnames = 0;
- fmaxi = 0;
-
- if(files)
- free(files);
- files = 0;
- nfiles = 0;
- if(hist)
- free(hist);
- hist = 0;
- nhist = 0;
- if(autos)
- free(autos);
- autos = 0;
- nauto = 0;
- isbuilt = 0;
- if(symbols)
- free(symbols);
- symbols = 0;
- nsym = 0;
- if(spoff)
- free(spoff);
- spoff = 0;
- if(pcline)
- free(pcline);
- pcline = 0;
- go12clean();
-}
-
-/*
- * delimit the text segment
- */
-void
-textseg(uvlong base, Fhdr *fp)
-{
- txtstart = base;
- txtend = base+fp->txtsz;
-}
-
-/*
- * symbase: return base and size of raw symbol table
- * (special hack for high access rate operations)
- */
-Sym *
-symbase(int32 *n)
-{
- *n = nsym;
- return symbols;
-}
-
-/*
- * Get the ith symbol table entry
- */
-Sym *
-getsym(int index)
-{
- if(index >= 0 && index < nsym)
- return &symbols[index];
- return 0;
-}
-
-/*
- * initialize internal symbol tables
- */
-static int
-buildtbls(void)
-{
- int32 i;
- int j, nh, ng, nt;
- File *f;
- Txtsym *tp;
- Hist *hp;
- Sym *p, **ap;
-
- if(isbuilt)
- return 1;
- isbuilt = 1;
- /* allocate the tables */
- firstinstr = 0;
- if(nglob) {
- globals = malloc(nglob*sizeof(*globals));
- if(!globals) {
- werrstr("can't malloc global symbol table");
- return 0;
- }
- }
- if(ntxt) {
- txt = malloc(ntxt*sizeof(*txt));
- if (!txt) {
- werrstr("can't malloc text symbol table");
- return 0;
- }
- }
- fnames = malloc((fmaxi+1)*sizeof(*fnames));
- if (!fnames) {
- werrstr("can't malloc file name table");
- return 0;
- }
- memset(fnames, 0, (fmaxi+1)*sizeof(*fnames));
- files = malloc(nfiles*sizeof(*files));
- if(!files) {
- werrstr("can't malloc file table");
- return 0;
- }
- hist = malloc(nhist*sizeof(Hist));
- if(hist == 0) {
- werrstr("can't malloc history stack");
- return 0;
- }
- autos = malloc(nauto*sizeof(Sym*));
- if(autos == 0) {
- werrstr("can't malloc auto symbol table");
- return 0;
- }
- /* load the tables */
- ng = nt = nh = 0;
- f = 0;
- tp = 0;
- i = nsym;
- hp = hist;
- ap = autos;
- for(p = symbols; i-- > 0; p++) {
-//print("sym %d type %c name %s value %llux\n", p-symbols, p->type, p->name, p->value);
- switch(p->type) {
- case 'D':
- case 'd':
- case 'B':
- case 'b':
- if(debug)
- print("Global: %s %llux\n", p->name, p->value);
- globals[ng++] = p;
- break;
- case 'z':
- if(p->value == 1) { /* New file */
- if(f) {
- f->n = nh;
- f->hist[nh].name = 0; /* one extra */
- hp += nh+1;
- f++;
- }
- else
- f = files;
- f->hist = hp;
- f->sym = 0;
- f->addr = 0;
- nh = 0;
- }
- /* alloc one slot extra as terminator */
- f->hist[nh].name = p->name;
- f->hist[nh].line = p->value;
- f->hist[nh].offset = 0;
- if(debug)
- printhist("-> ", &f->hist[nh], 1);
- nh++;
- break;
- case 'Z':
- if(f && nh > 0)
- f->hist[nh-1].offset = p->value;
- break;
- case 'T':
- case 't': /* Text: terminate history if first in file */
- case 'L':
- case 'l':
- tp = &txt[nt++];
- tp->n = 0;
- tp->sym = p;
- tp->locals = ap;
- if(debug)
- print("TEXT: %s at %llux\n", p->name, p->value);
- if (firstinstr == 0 || p->value < firstinstr)
- firstinstr = p->value;
- if(f && !f->sym) { /* first */
- f->sym = p;
- f->addr = p->value;
- }
- break;
- case 'a':
- case 'p':
- case 'm': /* Local Vars */
- if(!tp)
- print("Warning: Free floating local var: %s\n",
- p->name);
- else {
- if(debug)
- print("Local: %s %llux\n", p->name, p->value);
- tp->locals[tp->n] = p;
- tp->n++;
- ap++;
- }
- break;
- case 'f': /* File names */
- if(debug)
- print("Fname: %s\n", p->name);
- fnames[p->value] = p;
- break;
- default:
- break;
- }
- }
- /* sort global and text tables into ascending address order */
- qsort(globals, nglob, sizeof(Sym*), symcomp);
- qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
- qsort(files, nfiles, sizeof(File), filecomp);
- tp = txt;
- for(i = 0, f = files; i < nfiles; i++, f++) {
- for(j = 0; j < ntxt; j++) {
- if(f->sym == tp->sym) {
- if(debug) {
- print("LINK: %s to at %llux", f->sym->name, f->addr);
- printhist("... ", f->hist, 1);
- }
- f->txt = tp++;
- break;
- }
- if(++tp >= txt+ntxt) /* wrap around */
- tp = txt;
- }
- }
- return 1;
-}
-
-/*
- * find symbol function.var by name.
- * fn != 0 && var != 0 => look for fn in text, var in data
- * fn != 0 && var == 0 => look for fn in text
- * fn == 0 && var != 0 => look for var first in text then in data space.
- */
-int
-lookup(char *fn, char *var, Symbol *s)
-{
- int found;
-
- if(buildtbls() == 0)
- return 0;
- if(fn) {
- found = findtext(fn, s);
- if(var == 0) /* case 2: fn not in text */
- return found;
- else if(!found) /* case 1: fn not found */
- return 0;
- } else if(var) {
- found = findtext(var, s);
- if(found)
- return 1; /* case 3: var found in text */
- } else return 0; /* case 4: fn & var == zero */
-
- if(found)
- return findlocal(s, var, s); /* case 1: fn found */
- return findglobal(var, s); /* case 3: var not found */
-
-}
-
-/*
- * strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7)
- */
-int
-cdotstrcmp(char *sym, char *user)
-{
- for (;;) {
- while (*sym == *user) {
- if (*sym++ == '\0')
- return 0;
- user++;
- }
- /* unequal - but maybe '_' matches center dot */
- if (user[0] == '_' && (sym[0]&0xFF) == 0xc2 && (sym[1]&0xFF) == 0xb7) {
- /* '_' matches center dot - advance and continue */
- user++;
- sym += 2;
- continue;
- }
- break;
- }
- return *user - *sym;
-}
-
-/*
- * find a function by name
- */
-static int
-findtext(char *name, Symbol *s)
-{
- int i;
-
- for(i = 0; i < ntxt; i++) {
- if(cdotstrcmp(txt[i].sym->name, name) == 0) {
- fillsym(txt[i].sym, s);
- s->handle = (void *) &txt[i];
- s->index = i;
- return 1;
- }
- }
- return 0;
-}
-/*
- * find global variable by name
- */
-static int
-findglobal(char *name, Symbol *s)
-{
- int32 i;
-
- for(i = 0; i < nglob; i++) {
- if(cdotstrcmp(globals[i]->name, name) == 0) {
- fillsym(globals[i], s);
- s->index = i;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * find the local variable by name within a given function
- */
-int
-findlocal(Symbol *s1, char *name, Symbol *s2)
-{
- if(s1 == 0)
- return 0;
- if(buildtbls() == 0)
- return 0;
- return findlocvar(s1, name, s2);
-}
-
-/*
- * find the local variable by name within a given function
- * (internal function - does no parameter validation)
- */
-static int
-findlocvar(Symbol *s1, char *name, Symbol *s2)
-{
- Txtsym *tp;
- int i;
-
- tp = (Txtsym *)s1->handle;
- if(tp && tp->locals) {
- for(i = 0; i < tp->n; i++)
- if (cdotstrcmp(tp->locals[i]->name, name) == 0) {
- fillsym(tp->locals[i], s2);
- s2->handle = (void *)tp;
- s2->index = tp->n-1 - i;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Get ith text symbol
- */
-int
-textsym(Symbol *s, int index)
-{
-
- if(buildtbls() == 0)
- return 0;
- if(index < 0 || index >= ntxt)
- return 0;
- fillsym(txt[index].sym, s);
- s->handle = (void *)&txt[index];
- s->index = index;
- return 1;
-}
-
-/*
- * Get ith file name
- */
-int
-filesym(int index, char *buf, int n)
-{
- Hist *hp;
-
- if(buildtbls() == 0)
- return 0;
- if(index < 0 || index >= nfiles)
- return 0;
- hp = files[index].hist;
- if(!hp || !hp->name)
- return 0;
- return fileelem(fnames, (uchar*)hp->name, buf, n);
-}
-
-/*
- * Lookup name of local variable located at an offset into the frame.
- * The type selects either a parameter or automatic.
- */
-int
-getauto(Symbol *s1, int off, int type, Symbol *s2)
-{
- Txtsym *tp;
- Sym *p;
- int i, t;
-
- if(s1 == 0)
- return 0;
- if(type == CPARAM)
- t = 'p';
- else if(type == CAUTO)
- t = 'a';
- else
- return 0;
- if(buildtbls() == 0)
- return 0;
- tp = (Txtsym *)s1->handle;
- if(tp == 0)
- return 0;
- for(i = 0; i < tp->n; i++) {
- p = tp->locals[i];
- if(p->type == t && p->value == off) {
- fillsym(p, s2);
- s2->handle = s1->handle;
- s2->index = tp->n-1 - i;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Find text symbol containing addr; binary search assumes text array is sorted by addr
- */
-static int
-srchtext(uvlong addr)
-{
- uvlong val;
- int top, bot, mid;
- Sym *sp;
-
- val = addr;
- bot = 0;
- top = ntxt;
- for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
- sp = txt[mid].sym;
- if(val < sp->value)
- top = mid;
- else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
- bot = mid;
- else
- return mid;
- }
- return -1;
-}
-
-/*
- * Find data symbol containing addr; binary search assumes data array is sorted by addr
- */
-static int
-srchdata(uvlong addr)
-{
- uvlong val;
- int top, bot, mid;
- Sym *sp;
-
- bot = 0;
- top = nglob;
- val = addr;
- for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
- sp = globals[mid];
- if(val < sp->value)
- top = mid;
- else if(mid < nglob-1 && val >= globals[mid+1]->value)
- bot = mid;
- else
- return mid;
- }
- return -1;
-}
-
-/*
- * Find symbol containing val in specified search space
- * There is a special case when a value falls beyond the end
- * of the text segment; if the search space is CTEXT, that value
- * (usually etext) is returned. If the search space is CANY, symbols in the
- * data space are searched for a match.
- */
-int
-findsym(uvlong val, int type, Symbol *s)
-{
- int i;
-
- if(buildtbls() == 0)
- return 0;
-
- if(type == CTEXT || type == CANY) {
- i = srchtext(val);
- if(i >= 0) {
- if(type == CTEXT || i != ntxt-1) {
- fillsym(txt[i].sym, s);
- s->handle = (void *) &txt[i];
- s->index = i;
- return 1;
- }
- }
- }
- if(type == CDATA || type == CANY) {
- i = srchdata(val);
- if(i >= 0) {
- fillsym(globals[i], s);
- s->index = i;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Find the start and end address of the function containing addr
- */
-int
-fnbound(uvlong addr, uvlong *bounds)
-{
- int i;
-
- if(buildtbls() == 0)
- return 0;
-
- i = srchtext(addr);
- if(0 <= i && i < ntxt-1) {
- bounds[0] = txt[i].sym->value;
- bounds[1] = txt[i+1].sym->value;
- return 1;
- }
- return 0;
-}
-
-/*
- * get the ith local symbol for a function
- * the input symbol table is reverse ordered, so we reverse
- * accesses here to maintain approx. parameter ordering in a stack trace.
- */
-int
-localsym(Symbol *s, int index)
-{
- Txtsym *tp;
-
- if(s == 0 || index < 0)
- return 0;
- if(buildtbls() == 0)
- return 0;
-
- tp = (Txtsym *)s->handle;
- if(tp && tp->locals && index < tp->n) {
- fillsym(tp->locals[tp->n-index-1], s); /* reverse */
- s->handle = (void *)tp;
- s->index = index;
- return 1;
- }
- return 0;
-}
-
-/*
- * get the ith global symbol
- */
-int
-globalsym(Symbol *s, int index)
-{
- if(s == 0)
- return 0;
- if(buildtbls() == 0)
- return 0;
-
- if(index >=0 && index < nglob) {
- fillsym(globals[index], s);
- s->index = index;
- return 1;
- }
- return 0;
-}
-
-/*
- * find the pc given a file name and line offset into it.
- */
-uvlong
-file2pc(char *file, int32 line)
-{
- File *fp;
- int32 i;
- uvlong pc, start, end;
- short *name;
-
- if(isgo12pcline())
- return go12file2pc(file, line);
- if(buildtbls() == 0 || files == 0)
- return ~(uvlong)0;
- name = encfname(file);
- if(name == 0) { /* encode the file name */
- werrstr("file %s not found", file);
- return ~(uvlong)0;
- }
- /* find this history stack */
- for(i = 0, fp = files; i < nfiles; i++, fp++)
- if (hline(fp, name, &line))
- break;
- free(name);
- if(i >= nfiles) {
- werrstr("line %d in file %s not found", line, file);
- return ~(uvlong)0;
- }
- start = fp->addr; /* first text addr this file */
- if(i < nfiles-1)
- end = (fp+1)->addr; /* first text addr next file */
- else
- end = 0; /* last file in load module */
- /*
- * At this point, line contains the offset into the file.
- * run the state machine to locate the pc closest to that value.
- */
- if(debug)
- print("find pc for %d - between: %llux and %llux\n", line, start, end);
- pc = line2addr(line, start, end);
- if(pc == ~(uvlong)0) {
- werrstr("line %d not in file %s", line, file);
- return ~(uvlong)0;
- }
- return pc;
-}
-
-/*
- * search for a path component index
- */
-static int
-pathcomp(char *s, int n)
-{
- int i;
-
- for(i = 0; i <= fmaxi; i++)
- if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
- return i;
- return -1;
-}
-
-/*
- * Encode a char file name as a sequence of short indices
- * into the file name dictionary.
- */
-static short*
-encfname(char *file)
-{
- int i, j;
- char *cp, *cp2;
- short *dest;
-
- if(*file == '/') /* always check first '/' */
- cp2 = file+1;
- else {
- cp2 = strchr(file, '/');
- if(!cp2)
- cp2 = strchr(file, 0);
- }
- cp = file;
- dest = 0;
- for(i = 0; *cp; i++) {
- j = pathcomp(cp, cp2-cp);
- if(j < 0)
- return 0; /* not found */
- dest = realloc(dest, (i+1)*sizeof(short));
- dest[i] = j;
- cp = cp2;
- while(*cp == '/') /* skip embedded '/'s */
- cp++;
- cp2 = strchr(cp, '/');
- if(!cp2)
- cp2 = strchr(cp, 0);
- }
- dest = realloc(dest, (i+1)*sizeof(short));
- dest[i] = 0;
- return dest;
-}
-
-/*
- * Search a history stack for a matching file name accumulating
- * the size of intervening files in the stack.
- */
-static int
-hline(File *fp, short *name, int32 *line)
-{
- Hist *hp;
- int offset, depth;
- int32 ln;
-
- for(hp = fp->hist; hp->name; hp++) /* find name in stack */
- if(hp->name[1] || hp->name[2]) {
- if(hcomp(hp, name))
- break;
- }
- if(!hp->name) /* match not found */
- return 0;
- if(debug)
- printhist("hline found ... ", hp, 1);
- /*
- * unwind the stack until empty or we hit an entry beyond our line
- */
- ln = *line;
- offset = hp->line-1;
- depth = 1;
- for(hp++; depth && hp->name; hp++) {
- if(debug)
- printhist("hline inspect ... ", hp, 1);
- if(hp->name[1] || hp->name[2]) {
- if(hp->offset){ /* Z record */
- offset = 0;
- if(hcomp(hp, name)) {
- if(*line <= hp->offset)
- break;
- ln = *line+hp->line-hp->offset;
- depth = 1; /* implicit pop */
- } else
- depth = 2; /* implicit push */
- } else if(depth == 1 && ln < hp->line-offset)
- break; /* Beyond our line */
- else if(depth++ == 1) /* push */
- offset -= hp->line;
- } else if(--depth == 1) /* pop */
- offset += hp->line;
- }
- *line = ln+offset;
- return 1;
-}
-
-/*
- * compare two encoded file names
- */
-static int
-hcomp(Hist *hp, short *sp)
-{
- uchar *cp;
- int i, j;
- short *s;
-
- cp = (uchar *)hp->name;
- s = sp;
- if (*s == 0)
- return 0;
- for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
- if(j == 0)
- break;
- if(*s == j)
- s++;
- else
- s = sp;
- }
- return *s == 0;
-}
-
-/*
- * Convert a pc to a "file:line {file:line}" string.
- */
-int32
-fileline(char *str, int n, uvlong dot)
-{
- int32 line, top, bot, mid;
- File *f;
-
- if(isgo12pcline())
- return go12fileline(str, n, dot);
-
- *str = 0;
- if(buildtbls() == 0)
- return 0;
- /* binary search assumes file list is sorted by addr */
- bot = 0;
- top = nfiles;
- for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
- f = &files[mid];
- if(dot < f->addr)
- top = mid;
- else if(mid < nfiles-1 && dot >= (f+1)->addr)
- bot = mid;
- else {
- line = pc2line(dot);
- if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
- return 1;
- break;
- }
- }
- return 0;
-}
-
-/*
- * Convert a line number within a composite file to relative line
- * number in a source file. A composite file is the source
- * file with included files inserted in line.
- */
-static int
-fline(char *str, int n, int32 line, Hist *base, Hist **ret)
-{
- Hist *start; /* start of current level */
- Hist *h; /* current entry */
- int32 delta; /* sum of size of files this level */
- int k;
-
- start = base;
- h = base;
- delta = h->line;
- while(h && h->name && line > h->line) {
- if(h->name[1] || h->name[2]) {
- if(h->offset != 0) { /* #line Directive */
- delta = h->line-h->offset+1;
- start = h;
- base = h++;
- } else { /* beginning of File */
- if(start == base)
- start = h++;
- else {
- k = fline(str, n, line, start, &h);
- if(k <= 0)
- return k;
- }
- }
- } else {
- if(start == base && ret) { /* end of recursion level */
- *ret = h;
- return 1;
- } else { /* end of included file */
- delta += h->line-start->line;
- h++;
- start = base;
- }
- }
- }
- if(!h)
- return -1;
- if(start != base)
- line = line-start->line+1;
- else
- line = line-delta+1;
- if(!h->name)
- strncpy(str, "<eof>", n);
- else {
- k = fileelem(fnames, (uchar*)start->name, str, n);
- if(k+8 < n)
- sprint(str+k, ":%d", line);
- }
-/**********Remove comments for complete back-trace of include sequence
- * if(start != base) {
- * k = strlen(str);
- * if(k+2 < n) {
- * str[k++] = ' ';
- * str[k++] = '{';
- * }
- * k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
- * if(k+10 < n)
- * sprint(str+k, ":%ld}", start->line-delta);
- * }
- ********************/
- return 0;
-}
-
-/*
- * convert an encoded file name to a string.
- */
-int
-fileelem(Sym **fp, uchar *cp, char *buf, int n)
-{
- int i, j;
- char *c, *bp, *end;
-
- bp = buf;
- end = buf+n-1;
- for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
- c = fp[j]->name;
- if(bp != buf && bp[-1] != '/' && bp < end)
- *bp++ = '/';
- while(bp < end && *c)
- *bp++ = *c++;
- }
- *bp = 0;
- i = bp-buf;
- if(i > 1) {
- cleanname(buf);
- i = strlen(buf);
- }
- return i;
-}
-
-/*
- * compare the values of two symbol table entries.
- */
-static int
-symcomp(const void *a, const void *b)
-{
- int i;
-
- i = (*(Sym**)a)->value - (*(Sym**)b)->value;
- if (i)
- return i;
- return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
-}
-
-/*
- * compare the values of the symbols referenced by two text table entries
- */
-static int
-txtcomp(const void *a, const void *b)
-{
- return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
-}
-
-/*
- * compare the values of the symbols referenced by two file table entries
- */
-static int
-filecomp(const void *a, const void *b)
-{
- return ((File*)a)->addr - ((File*)b)->addr;
-}
-
-/*
- * fill an interface Symbol structure from a symbol table entry
- */
-static void
-fillsym(Sym *sp, Symbol *s)
-{
- s->type = sp->type;
- s->value = sp->value;
- s->name = sp->name;
- s->index = 0;
- switch(sp->type) {
- case 'b':
- case 'B':
- case 'D':
- case 'd':
- s->class = CDATA;
- break;
- case 't':
- case 'T':
- case 'l':
- case 'L':
- s->class = CTEXT;
- break;
- case 'a':
- s->class = CAUTO;
- break;
- case 'p':
- s->class = CPARAM;
- break;
- case 'm':
- s->class = CSTAB;
- break;
- default:
- s->class = CNONE;
- break;
- }
- s->handle = 0;
-}
-
-/*
- * find the stack frame, given the pc
- */
-uvlong
-pc2sp(uvlong pc)
-{
- uchar *c, u;
- uvlong currpc, currsp;
-
- if(isgo12pcline())
- return go12pc2sp(pc);
-
- if(spoff == 0)
- return ~(uvlong)0;
- currsp = 0;
- currpc = txtstart - mach->pcquant;
-
- if(pc<currpc || pc>txtend)
- return ~(uvlong)0;
- for(c = spoff; c < spoffend; c++) {
- if (currpc >= pc)
- return currsp;
- u = *c;
- if (u == 0) {
- currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
- c += 4;
- }
- else if (u < 65)
- currsp += 4*u;
- else if (u < 129)
- currsp -= 4*(u-64);
- else
- currpc += mach->pcquant*(u-129);
- currpc += mach->pcquant;
- }
- return ~(uvlong)0;
-}
-
-/*
- * find the source file line number for a given value of the pc
- */
-int32
-pc2line(uvlong pc)
-{
- uchar *c, u;
- uvlong currpc;
- int32 currline;
-
- if(pcline == 0)
- return -1;
- currline = 0;
- if (firstinstr != 0)
- currpc = firstinstr-mach->pcquant;
- else
- currpc = txtstart-mach->pcquant;
- if(pc<currpc || pc>txtend)
- return -1;
-
- for(c = pcline; c < pclineend && currpc < pc; c++) {
- u = *c;
- if(u == 0) {
- currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
- c += 4;
- }
- else if(u < 65)
- currline += u;
- else if(u < 129)
- currline -= (u-64);
- else
- currpc += mach->pcquant*(u-129);
- currpc += mach->pcquant;
- }
- return currline;
-}
-
-/*
- * find the pc associated with a line number
- * basepc and endpc are text addresses bounding the search.
- * if endpc == 0, the end of the table is used (i.e., no upper bound).
- * usually, basepc and endpc contain the first text address in
- * a file and the first text address in the following file, respectively.
- */
-uvlong
-line2addr(int32 line, uvlong basepc, uvlong endpc)
-{
- uchar *c, u;
- uvlong currpc, pc;
- int32 currline;
- int32 delta, d;
- int found;
-
- if(pcline == 0 || line == 0)
- return ~(uvlong)0;
-
- currline = 0;
- currpc = txtstart-mach->pcquant;
- pc = ~(uvlong)0;
- found = 0;
- delta = HUGEINT;
-
- for(c = pcline; c < pclineend; c++) {
- if(endpc && currpc >= endpc) /* end of file of interest */
- break;
- if(currpc >= basepc) { /* proper file */
- if(currline >= line) {
- d = currline-line;
- found = 1;
- } else
- d = line-currline;
- if(d < delta) {
- delta = d;
- pc = currpc;
- }
- }
- u = *c;
- if(u == 0) {
- currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
- c += 4;
- }
- else if(u < 65)
- currline += u;
- else if(u < 129)
- currline -= (u-64);
- else
- currpc += mach->pcquant*(u-129);
- currpc += mach->pcquant;
- }
- if(found)
- return pc;
- return ~(uvlong)0;
-}
-
-/*
- * Print a history stack (debug). if count is 0, prints the whole stack
- */
-static void
-printhist(char *msg, Hist *hp, int count)
-{
- int i;
- uchar *cp;
- char buf[128];
-
- i = 0;
- while(hp->name) {
- if(count && ++i > count)
- break;
- print("%s Line: %x (%d) Offset: %x (%d) Name: ", msg,
- hp->line, hp->line, hp->offset, hp->offset);
- for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
- if (cp != (uchar *)hp->name+1)
- print("/");
- print("%x", (*cp<<8)|cp[1]);
- }
- fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
- print(" (%s)\n", buf);
- hp++;
- }
-}
-
-#ifdef DEBUG
-/*
- * print the history stack for a file. (debug only)
- * if (name == 0) => print all history stacks.
- */
-void
-dumphist(char *name)
-{
- int i;
- File *f;
- short *fname;
-
- if(buildtbls() == 0)
- return;
- if(name)
- fname = encfname(name);
- for(i = 0, f = files; i < nfiles; i++, f++)
- if(fname == 0 || hcomp(f->hist, fname))
- printhist("> ", f->hist, f->n);
-
- if(fname)
- free(fname);
-}
-#endif
-
-// Go 1.2 pcln table
-// See golang.org/s/go12symtab.
-
-// Func layout
-#define FuncEntry (0)
-#define FuncName (pcptrsize)
-#define FuncArgs (pcptrsize+4)
-#define FuncFrame (pcptrsize+2*4)
-#define FuncPCSP (pcptrsize+3*4)
-#define FuncPCFile (pcptrsize+4*4)
-#define FuncPCLine (pcptrsize+5*4)
-
-static int32 pcquantum;
-static int32 pcptrsize;
-static uvlong (*pcswav)(uvlong);
-static uint32 (*pcswal)(uint32);
-static uvlong (*pcuintptr)(uchar*);
-static uchar *functab;
-static uint32 nfunctab;
-static uint32 *filetab;
-static uint32 nfiletab;
-
-static uint32
-xswal(uint32 v)
-{
- return (v>>24) | ((v>>8)&0xFF00) | ((v<<8)&0xFF0000) | v<<24;
-}
-
-static uvlong
-xswav(uvlong v)
-{
- return (uvlong)xswal(v)<<32 | xswal(v>>32);
-}
-
-static uvlong
-noswav(uvlong v)
-{
- return v;
-}
-
-static uint32
-noswal(uint32 v)
-{
- return v;
-}
-
-static uvlong
-readuintptr64(uchar *p)
-{
- return pcswav(*(uvlong*)p);
-}
-
-static uvlong
-readuintptr32(uchar *p)
-{
- return pcswal(*(uint32*)p);
-}
-
-static void
-go12clean(void)
-{
- pcquantum = 0;
- pcswav = nil;
- pcswal = nil;
- functab = nil;
- nfunctab = 0;
- filetab = nil;
- nfiletab = 0;
-}
-
-static void
-go12init(void)
-{
- uint32 m;
- uchar *p;
-
- if(pcquantum != 0)
- return;
- pcquantum = -1; // not go 1.2
- if(pcline == nil || pclineend - pcline < 16 ||
- pcline[4] != 0 || pcline[5] != 0 ||
- (pcline[6] != 1 && pcline[6] != 4) ||
- (pcline[7] != 4 && pcline[7] != 8))
- return;
-
- // header is magic, 00 00 pcquantum ptrsize
- m = *(uint32*)pcline;
- if(m == Go12PclnMagic) {
- pcswav = noswav;
- pcswal = noswal;
- } else {
- pcswav = xswav;
- pcswal = xswal;
- }
- pcptrsize = pcline[7];
-
- if(pcptrsize == 4)
- pcuintptr = readuintptr32;
- else
- pcuintptr = readuintptr64;
-
- nfunctab = pcuintptr(pcline+8);
- functab = pcline + 8 + pcptrsize;
-
- // functab is 2*nfunctab pointer-sized values.
- // The offset to the file table follows.
- p = functab + nfunctab*2*pcptrsize + pcptrsize;
- if(p+4 > pclineend)
- return;
- filetab = (uint32*)(pcline + pcswal(*(uint32*)p));
- if((uchar*)filetab+4 > pclineend)
- return;
-
- // File table begins with count.
- nfiletab = pcswal(filetab[0]);
- if((uchar*)(filetab + nfiletab) > pclineend)
- return;
-
- // Committed.
- pcquantum = pcline[6];
-}
-
-static int
-isgo12pcline(void)
-{
- go12init();
- return pcquantum > 0;
-}
-
-static uchar*
-go12findfunc(uvlong pc)
-{
- uchar *f, *fm;
- int32 nf, m;
-
- if(pc < pcuintptr(functab) || pc >= pcuintptr(functab+2*nfunctab*pcptrsize))
- return nil;
-
- // binary search to find func with entry <= addr.
- f = functab;
- nf = nfunctab;
- while(nf > 0) {
- m = nf/2;
- fm = f + 2*pcptrsize*m;
- if(pcuintptr(fm) <= pc && pc < pcuintptr(fm+2*pcptrsize)) {
- f = pcline + pcuintptr(fm+pcptrsize);
- if(f >= pclineend)
- return nil;
- return f;
- } else if(pc < pcuintptr(fm))
- nf = m;
- else {
- f += (m+1)*2*pcptrsize;
- nf -= m+1;
- }
- }
- return nil;
-}
-
-static uint32
-readvarint(uchar **pp)
-{
- uchar *p;
- uint32 v;
- int32 shift;
-
- v = 0;
- p = *pp;
- for(shift = 0;; shift += 7) {
- v |= (*p & 0x7F) << shift;
- if(!(*p++ & 0x80))
- break;
- }
- *pp = p;
- return v;
-}
-
-static char*
-pcstring(uint32 off)
-{
- if(off == 0 || off >= pclineend - pcline ||
- memchr(pcline + off, '\0', pclineend - (pcline + off)) == nil)
- return "?";
- return (char*)pcline+off;
-}
-
-
-static int
-step(uchar **pp, uvlong *pc, int32 *value, int first)
-{
- uint32 uvdelta, pcdelta;
- int32 vdelta;
-
- uvdelta = readvarint(pp);
- if(uvdelta == 0 && !first)
- return 0;
- if(uvdelta&1)
- uvdelta = ~(uvdelta>>1);
- else
- uvdelta >>= 1;
- vdelta = (int32)uvdelta;
- pcdelta = readvarint(pp) * pcquantum;
- *value += vdelta;
- *pc += pcdelta;
- return 1;
-}
-
-static int32
-pcvalue(uint32 off, uvlong entry, uvlong targetpc)
-{
- uvlong pc;
- int32 val;
- uchar *p;
-
- val = -1;
- pc = entry;
- if(off == 0 || off >= pclineend - pcline)
- return -1;
- p = pcline + off;
- while(step(&p, &pc, &val, pc == entry)) {
- if(targetpc < pc)
- return val;
- }
- return -1;
-}
-
-static uvlong
-go12pc2sp(uvlong pc)
-{
- uchar *f;
- uint32 off;
- uvlong entry;
- int32 sp;
-
- f = go12findfunc(pc);
- if(f == nil)
- return ~(uvlong)0;
- entry = pcuintptr(f+FuncEntry);
- off = pcswal(*(uint32*)(f+FuncPCSP));
- sp = pcvalue(off, entry, pc);
- if(sp < 0)
- return ~(uvlong)0;
- return sp;
-}
-
-static int32
-go12fileline(char *str, int n, uvlong pc)
-{
- uchar *f;
- uint32 fileoff, lineoff;
- uvlong entry;
- int lno, fno;
-
- f = go12findfunc(pc);
- if(f == nil)
- return 0;
- entry = pcuintptr(f+FuncEntry);
- fileoff = pcswal(*(uint32*)(f+FuncPCFile));
- lineoff = pcswal(*(uint32*)(f+FuncPCLine));
- lno = pcvalue(lineoff, entry, pc);
- fno = pcvalue(fileoff, entry, pc);
- if(lno < 0 || fno <= 0 || fno >= nfiletab) {
- return 0;
- }
- snprint(str, n, "%s:%d", pcstring(pcswal(filetab[fno])), lno);
- return 1;
-}
-
-static uvlong
-go12file2pc(char *file, int line)
-{
- int fno;
- int32 i, fval, lval;
- uchar *func, *fp, *lp;
- uvlong fpc, lpc, fstartpc, lstartpc, entry;
-
- // Map file to file number.
- // NOTE(rsc): Could introduce a hash table for repeated
- // lookups if anyone ever calls this.
- for(fno=1; fno<nfiletab; fno++)
- if(strcmp(pcstring(pcswal(filetab[fno])), file) == 0)
- goto havefile;
- werrstr("cannot find file");
- return ~(uvlong)0;
-
-havefile:
- // Consider each func.
- // Run file number program to find file match,
- // then run line number program to find line match.
- // Most file number programs are tiny, and most will
- // not mention the file number, so this should be fairly
- // quick.
- for(i=0; i<nfunctab; i++) {
- func = pcline + pcuintptr(functab+i*2*pcptrsize+pcptrsize);
- entry = pcuintptr(func+FuncEntry);
- fp = pcline + pcswal(*(uint32*)(func+FuncPCFile));
- lp = pcline + pcswal(*(uint32*)(func+FuncPCLine));
- fval = lval = -1;
- fpc = lpc = entry;
- fstartpc = fpc;
- while(step(&fp, &fpc, &fval, fpc==entry)) {
- if(fval == fno && fstartpc < fpc) {
- lstartpc = lpc;
- while(lpc < fpc && step(&lp, &lpc, &lval, lpc==entry)) {
- if(lval == line) {
- if(fstartpc <= lstartpc) {
- return lstartpc;
- }
- if(fstartpc < lpc) {
- return fstartpc;
- }
- }
- lstartpc = lpc;
- }
- }
- fstartpc = fpc;
- }
- }
- werrstr("cannot find line in file");
- return ~(uvlong)0;
-}
diff --git a/src/libmach/windows.c b/src/libmach/windows.c
deleted file mode 100644
index 9ffc3af01..000000000
--- a/src/libmach/windows.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in Windows");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in Windows");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in Windows");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in Windows");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in Windows");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in Windows");
- return -1;
-}
-
-int
-pread(int fd, void *buf, int count, int offset)
-{
- int oldoffset, n;
-
- oldoffset = seek(fd, offset, 0);
- n = read(fd, buf, count);
- seek(fd, oldoffset, 0);
- return n;
-}
-
-int
-pwrite(int fd, void *buf, int count, int offset)
-{
- USED(fd);
- USED(buf);
- USED(count);
- USED(offset);
- sysfatal("pwrite unimplemented in Windows");
- return -1;
-}
-
-int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- USED(rqtp);
- USED(rmtp);
- sysfatal("nanosleep unimplemented in Windows");
- return -1;
-}
diff --git a/src/make.bash b/src/make.bash
index 877d1e5eb..d7b63ff09 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -35,10 +35,15 @@
# controls the default behavior of the linker's -linkmode option. The
# default value depends on the system.
#
-# CC: Command line to run to get at host C compiler.
+# CC: Command line to run to compile C code for GOHOSTARCH.
# Default is "gcc". Also supported: "clang".
-# CXX: Command line to run to get at host C++ compiler, only recorded
-# for cgo use. Default is "g++". Also supported: "clang++".
+#
+# CC_FOR_TARGET: Command line to run to compile C code for GOARCH.
+# This is used by cgo. Default is CC.
+#
+# CXX_FOR_TARGET: Command line to run to compile C++ code for GOARCH.
+# This is used by cgo. Default is CXX, or, if that is not set,
+# "g++" or "clang++".
#
# GO_DISTFLAGS: extra flags to provide to "dist bootstrap". Use "-s"
# to build a statically linked toolchain.
@@ -120,6 +125,10 @@ if [ "$(uname)" == "Darwin" ]; then
# golang.org/issue/5261
mflag="$mflag -mmacosx-version-min=10.6"
fi
+# if gcc does not exist and $CC is not set, try clang if available.
+if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then
+ export CC=clang CXX=clang++
+fi
${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
# -e doesn't propagate out of eval, so check success by hand.
@@ -144,6 +153,7 @@ echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH
buildall="-a"
if [ "$1" = "--no-clean" ]; then
buildall=""
+ shift
fi
./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
# Delay move of dist tool to now, because bootstrap may clear tool directory.
@@ -153,13 +163,15 @@ echo
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
- GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+ # CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,
+ # use the host compiler, CC, from `cmd/dist/dist env` instead.
+ CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
echo
fi
echo "# Building packages and commands for $GOOS/$GOARCH."
-"$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
echo
rm -f "$GOTOOLDIR"/go_bootstrap
diff --git a/src/make.rc b/src/make.rc
index 222bb8a18..ab152c0db 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -36,6 +36,9 @@ if(! test -f run.rc){
exit wrongdir
}
+# Generate libc_plan9.h.
+../include/plan9/mklibc.rc > ../include/plan9/libc_plan9.h
+
# Clean old generated file that will cause problems in the build.
rm -f ./pkg/runtime/runtime_defs.go
diff --git a/src/nacltest.bash b/src/nacltest.bash
new file mode 100755
index 000000000..33fc8c1c4
--- /dev/null
+++ b/src/nacltest.bash
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2014 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# For testing Native Client on builders or locally.
+# Builds a test file system and embeds it into package syscall
+# in every generated binary.
+#
+# Assumes that sel_ldr binaries and go_nacl_$GOARCH_exec scripts are in $PATH;
+# see ../misc/nacl/README.
+
+set -e
+ulimit -c 0
+
+# Check GOARCH.
+naclGOARCH=${GOARCH:-386}
+case "$naclGOARCH" in
+amd64p32)
+ if ! which sel_ldr_x86_64 >/dev/null; then
+ echo 'cannot find sel_ldr_x86_64' 1>&2
+ exit 1
+ fi
+ ;;
+386)
+ if ! which sel_ldr_x86_32 >/dev/null; then
+ echo 'cannot find sel_ldr_x86_32' 1>&2
+ exit 1
+ fi
+ ;;
+*)
+ echo 'unsupported $GOARCH for nacl: '"$naclGOARCH" 1>&2
+ exit 1
+esac
+
+if ! which go_nacl_${naclGOARCH}_exec >/dev/null; then
+ echo "cannot find go_nacl_${naclGOARCH}_exec, see ../misc/nacl/README." 1>&2
+ exit 1
+fi
+
+# Run host build to get toolchain for running zip generator.
+unset GOOS GOARCH
+if [ ! -f make.bash ]; then
+ echo 'nacl.bash must be run from $GOROOT/src' 1>&2
+ exit 1
+fi
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH ./make.bash
+
+# Build zip file embedded in package syscall.
+gobin=${GOBIN:-$(pwd)/../bin}
+rm -f pkg/syscall/fstest_nacl.go
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto pkg/syscall/fstest_nacl.go
+
+# Run standard build and tests.
+export PATH=$(pwd)/../misc/nacl:$PATH
+GOOS=nacl GOARCH=$naclGOARCH ./all.bash --no-clean
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
index 1b961e3ec..e363aa793 100644
--- a/src/pkg/archive/tar/common.go
+++ b/src/pkg/archive/tar/common.go
@@ -38,6 +38,7 @@ const (
TypeXGlobalHeader = 'g' // global extended header
TypeGNULongName = 'L' // Next file has a long name
TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
+ TypeGNUSparse = 'S' // sparse file
)
// A Header represents a single header in a tar archive.
@@ -57,6 +58,7 @@ type Header struct {
Devminor int64 // minor number of character or block device
AccessTime time.Time // access time
ChangeTime time.Time // status change time
+ Xattrs map[string]string
}
// File name constants from the tar spec.
@@ -189,6 +191,7 @@ const (
paxSize = "size"
paxUid = "uid"
paxUname = "uname"
+ paxXattr = "SCHILY.xattr."
paxNone = ""
)
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index b2d62f3c5..920a9b08f 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -29,12 +29,57 @@ const maxNanoSecondIntSize = 9
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
type Reader struct {
- r io.Reader
- err error
- nb int64 // number of unread bytes for current file entry
- pad int64 // amount of padding (ignored) after current file entry
+ r io.Reader
+ err error
+ pad int64 // amount of padding (ignored) after current file entry
+ curr numBytesReader // reader for current file entry
}
+// A numBytesReader is an io.Reader with a numBytes method, returning the number
+// of bytes remaining in the underlying encoded data.
+type numBytesReader interface {
+ io.Reader
+ numBytes() int64
+}
+
+// A regFileReader is a numBytesReader for reading file data from a tar archive.
+type regFileReader struct {
+ r io.Reader // underlying reader
+ nb int64 // number of unread bytes for current file entry
+}
+
+// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive.
+type sparseFileReader struct {
+ rfr *regFileReader // reads the sparse-encoded file data
+ sp []sparseEntry // the sparse map for the file
+ pos int64 // keeps track of file position
+ tot int64 // total size of the file
+}
+
+// Keywords for GNU sparse files in a PAX extended header
+const (
+ paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
+ paxGNUSparseOffset = "GNU.sparse.offset"
+ paxGNUSparseNumBytes = "GNU.sparse.numbytes"
+ paxGNUSparseMap = "GNU.sparse.map"
+ paxGNUSparseName = "GNU.sparse.name"
+ paxGNUSparseMajor = "GNU.sparse.major"
+ paxGNUSparseMinor = "GNU.sparse.minor"
+ paxGNUSparseSize = "GNU.sparse.size"
+ paxGNUSparseRealSize = "GNU.sparse.realsize"
+)
+
+// Keywords for old GNU sparse headers
+const (
+ oldGNUSparseMainHeaderOffset = 386
+ oldGNUSparseMainHeaderIsExtendedOffset = 482
+ oldGNUSparseMainHeaderNumEntries = 4
+ oldGNUSparseExtendedHeaderIsExtendedOffset = 504
+ oldGNUSparseExtendedHeaderNumEntries = 21
+ oldGNUSparseOffsetSize = 12
+ oldGNUSparseNumBytesSize = 12
+)
+
// NewReader creates a new Reader reading from r.
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
@@ -64,6 +109,18 @@ func (tr *Reader) Next() (*Header, error) {
tr.skipUnread()
hdr = tr.readHeader()
mergePAX(hdr, headers)
+
+ // Check for a PAX format sparse file
+ sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
+ if err != nil {
+ tr.err = err
+ return nil, err
+ }
+ if sp != nil {
+ // Current file is a PAX format GNU sparse file.
+ // Set the current file reader to a sparse file reader.
+ tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+ }
return hdr, nil
case TypeGNULongName:
// We have a GNU long name header. Its contents are the real file name.
@@ -87,6 +144,67 @@ func (tr *Reader) Next() (*Header, error) {
return hdr, tr.err
}
+// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
+// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
+// be treated as a regular file.
+func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
+ var sparseFormat string
+
+ // Check for sparse format indicators
+ major, majorOk := headers[paxGNUSparseMajor]
+ minor, minorOk := headers[paxGNUSparseMinor]
+ sparseName, sparseNameOk := headers[paxGNUSparseName]
+ _, sparseMapOk := headers[paxGNUSparseMap]
+ sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
+ sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
+
+ // Identify which, if any, sparse format applies from which PAX headers are set
+ if majorOk && minorOk {
+ sparseFormat = major + "." + minor
+ } else if sparseNameOk && sparseMapOk {
+ sparseFormat = "0.1"
+ } else if sparseSizeOk {
+ sparseFormat = "0.0"
+ } else {
+ // Not a PAX format GNU sparse file.
+ return nil, nil
+ }
+
+ // Check for unknown sparse format
+ if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
+ return nil, nil
+ }
+
+ // Update hdr from GNU sparse PAX headers
+ if sparseNameOk {
+ hdr.Name = sparseName
+ }
+ if sparseSizeOk {
+ realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ hdr.Size = realSize
+ } else if sparseRealSizeOk {
+ realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ hdr.Size = realSize
+ }
+
+ // Set up the sparse map, according to the particular sparse format in use
+ var sp []sparseEntry
+ var err error
+ switch sparseFormat {
+ case "0.0", "0.1":
+ sp, err = readGNUSparseMap0x1(headers)
+ case "1.0":
+ sp, err = readGNUSparseMap1x0(tr.curr)
+ }
+ return sp, err
+}
+
// mergePAX merges well known headers according to PAX standard.
// In general headers with the same name as those found
// in the header struct overwrite those found in the header
@@ -139,8 +257,14 @@ func mergePAX(hdr *Header, headers map[string]string) error {
return err
}
hdr.Size = int64(size)
+ default:
+ if strings.HasPrefix(k, paxXattr) {
+ if hdr.Xattrs == nil {
+ hdr.Xattrs = make(map[string]string)
+ }
+ hdr.Xattrs[k[len(paxXattr):]] = v
+ }
}
-
}
return nil
}
@@ -188,6 +312,11 @@ func parsePAX(r io.Reader) (map[string]string, error) {
if err != nil {
return nil, err
}
+
+ // For GNU PAX sparse format 0.0 support.
+ // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
+ var sparseMap bytes.Buffer
+
headers := make(map[string]string)
// Each record is constructed as
// "%d %s=%s\n", length, keyword, value
@@ -205,7 +334,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
return nil, ErrHeader
}
// Extract everything between the decimal and the n -1 on the
- // beginning to to eat the ' ', -1 on the end to skip the newline.
+ // beginning to eat the ' ', -1 on the end to skip the newline.
var record []byte
record, buf = buf[sp+1:n-1], buf[n:]
// The first equals is guaranteed to mark the end of the key.
@@ -215,7 +344,21 @@ func parsePAX(r io.Reader) (map[string]string, error) {
return nil, ErrHeader
}
key, value := record[:eq], record[eq+1:]
- headers[string(key)] = string(value)
+
+ keyStr := string(key)
+ if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
+ // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
+ sparseMap.Write(value)
+ sparseMap.Write([]byte{','})
+ } else {
+ // Normal key. Set the value in the headers map.
+ headers[keyStr] = string(value)
+ }
+ }
+ if sparseMap.Len() != 0 {
+ // Add sparse info to headers, chopping off the extra comma
+ sparseMap.Truncate(sparseMap.Len() - 1)
+ headers[paxGNUSparseMap] = sparseMap.String()
}
return headers, nil
}
@@ -262,8 +405,8 @@ func (tr *Reader) octal(b []byte) int64 {
// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
func (tr *Reader) skipUnread() {
- nr := tr.nb + tr.pad // number of bytes to skip
- tr.nb, tr.pad = 0, 0
+ nr := tr.numBytes() + tr.pad // number of bytes to skip
+ tr.curr, tr.pad = nil, 0
if sr, ok := tr.r.(io.Seeker); ok {
if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
return
@@ -325,14 +468,14 @@ func (tr *Reader) readHeader() *Header {
// so its magic bytes, like the rest of the block, are NULs.
magic := string(s.next(8)) // contains version field as well.
var format string
- switch magic {
- case "ustar\x0000": // POSIX tar (1003.1-1988)
+ switch {
+ case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
if string(header[508:512]) == "tar\x00" {
format = "star"
} else {
format = "posix"
}
- case "ustar \x00": // old GNU tar
+ case magic == "ustar \x00": // old GNU tar
format = "gnu"
}
@@ -367,30 +510,308 @@ func (tr *Reader) readHeader() *Header {
// Maximum value of hdr.Size is 64 GB (12 octal digits),
// so there's no risk of int64 overflowing.
- tr.nb = int64(hdr.Size)
- tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+ nb := int64(hdr.Size)
+ tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+
+ // Set the current file reader.
+ tr.curr = &regFileReader{r: tr.r, nb: nb}
+
+ // Check for old GNU sparse format entry.
+ if hdr.Typeflag == TypeGNUSparse {
+ // Get the real size of the file.
+ hdr.Size = tr.octal(header[483:495])
+
+ // Read the sparse map.
+ sp := tr.readOldGNUSparseMap(header)
+ if tr.err != nil {
+ return nil
+ }
+ // Current file is a GNU sparse file. Update the current file reader.
+ tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+ }
return hdr
}
+// A sparseEntry holds a single entry in a sparse file's sparse map.
+// A sparse entry indicates the offset and size in a sparse file of a
+// block of data.
+type sparseEntry struct {
+ offset int64
+ numBytes int64
+}
+
+// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
+// then one or more extension headers are used to store the rest of the sparse map.
+func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
+ isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
+ spCap := oldGNUSparseMainHeaderNumEntries
+ if isExtended {
+ spCap += oldGNUSparseExtendedHeaderNumEntries
+ }
+ sp := make([]sparseEntry, 0, spCap)
+ s := slicer(header[oldGNUSparseMainHeaderOffset:])
+
+ // Read the four entries from the main tar header
+ for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
+ offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+ numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+ if tr.err != nil {
+ tr.err = ErrHeader
+ return nil
+ }
+ if offset == 0 && numBytes == 0 {
+ break
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ for isExtended {
+ // There are more entries. Read an extension header and parse its entries.
+ sparseHeader := make([]byte, blockSize)
+ if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+ return nil
+ }
+ isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
+ s = slicer(sparseHeader)
+ for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
+ offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+ numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+ if tr.err != nil {
+ tr.err = ErrHeader
+ return nil
+ }
+ if offset == 0 && numBytes == 0 {
+ break
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+ }
+ return sp
+}
+
+// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
+// The sparse map is stored just before the file data and padded out to the nearest block boundary.
+func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
+ buf := make([]byte, 2*blockSize)
+ sparseHeader := buf[:blockSize]
+
+ // readDecimal is a helper function to read a decimal integer from the sparse map
+ // while making sure to read from the file in blocks of size blockSize
+ readDecimal := func() (int64, error) {
+ // Look for newline
+ nl := bytes.IndexByte(sparseHeader, '\n')
+ if nl == -1 {
+ if len(sparseHeader) >= blockSize {
+ // This is an error
+ return 0, ErrHeader
+ }
+ oldLen := len(sparseHeader)
+ newLen := oldLen + blockSize
+ if cap(sparseHeader) < newLen {
+ // There's more header, but we need to make room for the next block
+ copy(buf, sparseHeader)
+ sparseHeader = buf[:newLen]
+ } else {
+ // There's more header, and we can just reslice
+ sparseHeader = sparseHeader[:newLen]
+ }
+
+ // Now that sparseHeader is large enough, read next block
+ if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
+ return 0, err
+ }
+
+ // Look for a newline in the new data
+ nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
+ if nl == -1 {
+ // This is an error
+ return 0, ErrHeader
+ }
+ nl += oldLen // We want the position from the beginning
+ }
+ // Now that we've found a newline, read a number
+ n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
+ if err != nil {
+ return 0, ErrHeader
+ }
+
+ // Update sparseHeader to consume this number
+ sparseHeader = sparseHeader[nl+1:]
+ return n, nil
+ }
+
+ // Read the first block
+ if _, err := io.ReadFull(r, sparseHeader); err != nil {
+ return nil, err
+ }
+
+ // The first line contains the number of entries
+ numEntries, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+
+ // Read all the entries
+ sp := make([]sparseEntry, 0, numEntries)
+ for i := int64(0); i < numEntries; i++ {
+ // Read the offset
+ offset, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+ // Read numBytes
+ numBytes, err := readDecimal()
+ if err != nil {
+ return nil, err
+ }
+
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ return sp, nil
+}
+
+// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1.
+// The sparse map is stored in the PAX headers.
+func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) {
+ // Get number of entries
+ numEntriesStr, ok := headers[paxGNUSparseNumBlocks]
+ if !ok {
+ return nil, ErrHeader
+ }
+ numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+
+ sparseMap := strings.Split(headers[paxGNUSparseMap], ",")
+
+ // There should be two numbers in sparseMap for each entry
+ if int64(len(sparseMap)) != 2*numEntries {
+ return nil, ErrHeader
+ }
+
+ // Loop through the entries in the sparse map
+ sp := make([]sparseEntry, 0, numEntries)
+ for i := int64(0); i < numEntries; i++ {
+ offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+ }
+
+ return sp, nil
+}
+
+// numBytes returns the number of bytes left to read in the current file's entry
+// in the tar archive, or 0 if there is no current file.
+func (tr *Reader) numBytes() int64 {
+ if tr.curr == nil {
+ // No current file, so no bytes
+ return 0
+ }
+ return tr.curr.numBytes()
+}
+
// Read reads from the current entry in the tar archive.
// It returns 0, io.EOF when it reaches the end of that entry,
// until Next is called to advance to the next entry.
func (tr *Reader) Read(b []byte) (n int, err error) {
- if tr.nb == 0 {
- // file consumed
+ if tr.curr == nil {
return 0, io.EOF
}
+ n, err = tr.curr.Read(b)
+ if err != nil && err != io.EOF {
+ tr.err = err
+ }
+ return
+}
- if int64(len(b)) > tr.nb {
- b = b[0:tr.nb]
+func (rfr *regFileReader) Read(b []byte) (n int, err error) {
+ if rfr.nb == 0 {
+ // file consumed
+ return 0, io.EOF
}
- n, err = tr.r.Read(b)
- tr.nb -= int64(n)
+ if int64(len(b)) > rfr.nb {
+ b = b[0:rfr.nb]
+ }
+ n, err = rfr.r.Read(b)
+ rfr.nb -= int64(n)
- if err == io.EOF && tr.nb > 0 {
+ if err == io.EOF && rfr.nb > 0 {
err = io.ErrUnexpectedEOF
}
- tr.err = err
return
}
+
+// numBytes returns the number of bytes left to read in the file's data in the tar archive.
+func (rfr *regFileReader) numBytes() int64 {
+ return rfr.nb
+}
+
+// readHole reads a sparse file hole ending at offset toOffset
+func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int {
+ n64 := toOffset - sfr.pos
+ if n64 > int64(len(b)) {
+ n64 = int64(len(b))
+ }
+ n := int(n64)
+ for i := 0; i < n; i++ {
+ b[i] = 0
+ }
+ sfr.pos += n64
+ return n
+}
+
+// Read reads the sparse file data in expanded form.
+func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
+ if len(sfr.sp) == 0 {
+ // No more data fragments to read from.
+ if sfr.pos < sfr.tot {
+ // We're in the last hole
+ n = sfr.readHole(b, sfr.tot)
+ return
+ }
+ // Otherwise, we're at the end of the file
+ return 0, io.EOF
+ }
+ if sfr.pos < sfr.sp[0].offset {
+ // We're in a hole
+ n = sfr.readHole(b, sfr.sp[0].offset)
+ return
+ }
+
+ // We're not in a hole, so we'll read from the next data fragment
+ posInFragment := sfr.pos - sfr.sp[0].offset
+ bytesLeft := sfr.sp[0].numBytes - posInFragment
+ if int64(len(b)) > bytesLeft {
+ b = b[0:bytesLeft]
+ }
+
+ n, err = sfr.rfr.Read(b)
+ sfr.pos += int64(n)
+
+ if int64(n) == bytesLeft {
+ // We're done with this fragment
+ sfr.sp = sfr.sp[1:]
+ }
+
+ if err == io.EOF && sfr.pos < sfr.tot {
+ // We reached the end of the last fragment's data, but there's a final hole
+ err = nil
+ }
+ return
+}
+
+// numBytes returns the number of bytes left to read in the sparse file's
+// sparse-encoded data in the tar archive.
+func (sfr *sparseFileReader) numBytes() int64 {
+ return sfr.rfr.nb
+}
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index 128561656..9601ffe45 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -9,6 +9,7 @@ import (
"crypto/md5"
"fmt"
"io"
+ "io/ioutil"
"os"
"reflect"
"strings"
@@ -54,8 +55,92 @@ var gnuTarTest = &untarTest{
},
}
+var sparseTarTest = &untarTest{
+ file: "testdata/sparse-formats.tar",
+ headers: []*Header{
+ {
+ Name: "sparse-gnu",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392395740, 0),
+ Typeflag: 0x53,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-0.0",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392342187, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-0.1",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392340456, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "sparse-posix-1.0",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 200,
+ ModTime: time.Unix(1392337404, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ {
+ Name: "end",
+ Mode: 420,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 4,
+ ModTime: time.Unix(1392398319, 0),
+ Typeflag: 0x30,
+ Linkname: "",
+ Uname: "david",
+ Gname: "david",
+ Devmajor: 0,
+ Devminor: 0,
+ },
+ },
+ cksums: []string{
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "b0061974914468de549a2af8ced10316",
+ },
+}
+
var untarTests = []*untarTest{
gnuTarTest,
+ sparseTarTest,
{
file: "testdata/star.tar",
headers: []*Header{
@@ -161,6 +246,46 @@ var untarTests = []*untarTest{
},
},
},
+ {
+ file: "testdata/xattrs.tar",
+ headers: []*Header{
+ {
+ Name: "small.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 5,
+ ModTime: time.Unix(1386065770, 448252320),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1389782956, 794414986),
+ Xattrs: map[string]string{
+ "user.key": "value",
+ "user.key2": "value2",
+ // Interestingly, selinux encodes the terminating null inside the xattr
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+ },
+ },
+ {
+ Name: "small2.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 11,
+ ModTime: time.Unix(1386065770, 449252304),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1386065770, 449252304),
+ Xattrs: map[string]string{
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+ },
+ },
+ },
+ },
}
func TestReader(t *testing.T) {
@@ -180,7 +305,7 @@ testLoop:
f.Close()
continue testLoop
}
- if *hdr != *header {
+ if !reflect.DeepEqual(*hdr, *header) {
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
i, j, *hdr, *header)
}
@@ -253,7 +378,7 @@ func TestIncrementalRead(t *testing.T) {
}
// check the header
- if *hdr != *headers[nread] {
+ if !reflect.DeepEqual(*hdr, *headers[nread]) {
t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
*hdr, headers[nread])
}
@@ -321,7 +446,7 @@ func TestParsePAXHeader(t *testing.T) {
{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
for _, test := range paxTests {
key, expected, raw := test[0], test[1], test[2]
- reader := bytes.NewBuffer([]byte(raw))
+ reader := bytes.NewReader([]byte(raw))
headers, err := parsePAX(reader)
if err != nil {
t.Errorf("Couldn't parse correctly formatted headers: %v", err)
@@ -337,7 +462,7 @@ func TestParsePAXHeader(t *testing.T) {
t.Error("Buffer wasn't consumed")
}
}
- badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
+ badHeader := bytes.NewReader([]byte("3 somelongkey="))
if _, err := parsePAX(badHeader); err != ErrHeader {
t.Fatal("Unexpected success when parsing bad header")
}
@@ -346,7 +471,7 @@ func TestParsePAXHeader(t *testing.T) {
func TestParsePAXTime(t *testing.T) {
// Some valid PAX time values
timestamps := map[string]time.Time{
- "1350244992.023960108": time.Unix(1350244992, 23960108), // The commoon case
+ "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
"1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
"1350244992": time.Unix(1350244992, 0), // Low precision value
@@ -383,3 +508,236 @@ func TestMergePAX(t *testing.T) {
t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
}
}
+
+func TestSparseEndToEnd(t *testing.T) {
+ test := sparseTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ headers := test.headers
+ cksums := test.cksums
+ nread := 0
+
+ // loop over all files
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == io.EOF {
+ break
+ }
+
+ // check the header
+ if !reflect.DeepEqual(*hdr, *headers[nread]) {
+ t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+ *hdr, headers[nread])
+ }
+
+ // read and checksum the file data
+ h := md5.New()
+ _, err = io.Copy(h, tr)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+
+ // verify checksum
+ have := fmt.Sprintf("%x", h.Sum(nil))
+ want := cksums[nread]
+ if want != have {
+ t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+ }
+ }
+ if nread != len(headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+ }
+}
+
+type sparseFileReadTest struct {
+ sparseData []byte
+ sparseMap []sparseEntry
+ realSize int64
+ expected []byte
+}
+
+var sparseFileReadTests = []sparseFileReadTest{
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 0, numBytes: 2},
+ {offset: 5, numBytes: 3},
+ },
+ realSize: 8,
+ expected: []byte("ab\x00\x00\x00cde"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 0, numBytes: 2},
+ {offset: 5, numBytes: 3},
+ },
+ realSize: 10,
+ expected: []byte("ab\x00\x00\x00cde\x00\x00"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 1, numBytes: 3},
+ {offset: 6, numBytes: 2},
+ },
+ realSize: 8,
+ expected: []byte("\x00abc\x00\x00de"),
+ },
+ {
+ sparseData: []byte("abcde"),
+ sparseMap: []sparseEntry{
+ {offset: 1, numBytes: 3},
+ {offset: 6, numBytes: 2},
+ },
+ realSize: 10,
+ expected: []byte("\x00abc\x00\x00de\x00\x00"),
+ },
+ {
+ sparseData: []byte(""),
+ sparseMap: nil,
+ realSize: 2,
+ expected: []byte("\x00\x00"),
+ },
+}
+
+func TestSparseFileReader(t *testing.T) {
+ for i, test := range sparseFileReadTests {
+ r := bytes.NewReader(test.sparseData)
+ nb := int64(r.Len())
+ sfr := &sparseFileReader{
+ rfr: &regFileReader{r: r, nb: nb},
+ sp: test.sparseMap,
+ pos: 0,
+ tot: test.realSize,
+ }
+ if sfr.numBytes() != nb {
+ t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb)
+ }
+ buf, err := ioutil.ReadAll(sfr)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ }
+ if e := test.expected; !bytes.Equal(buf, e) {
+ t.Errorf("test %d: Contents = %v, want %v", i, buf, e)
+ }
+ if sfr.numBytes() != 0 {
+ t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i)
+ }
+ }
+}
+
+func TestSparseIncrementalRead(t *testing.T) {
+ sparseMap := []sparseEntry{{10, 2}}
+ sparseData := []byte("Go")
+ expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00"
+
+ r := bytes.NewReader(sparseData)
+ nb := int64(r.Len())
+ sfr := &sparseFileReader{
+ rfr: &regFileReader{r: r, nb: nb},
+ sp: sparseMap,
+ pos: 0,
+ tot: int64(len(expected)),
+ }
+
+ // We'll read the data 6 bytes at a time, with a hole of size 10 at
+ // the beginning and one of size 8 at the end.
+ var outputBuf bytes.Buffer
+ buf := make([]byte, 6)
+ for {
+ n, err := sfr.Read(buf)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Read: unexpected error %v\n", err)
+ }
+ if n > 0 {
+ _, err := outputBuf.Write(buf[:n])
+ if err != nil {
+ t.Errorf("Write: unexpected error %v\n", err)
+ }
+ }
+ }
+ got := outputBuf.String()
+ if got != expected {
+ t.Errorf("Contents = %v, want %v", got, expected)
+ }
+}
+
+func TestReadGNUSparseMap0x1(t *testing.T) {
+ headers := map[string]string{
+ paxGNUSparseNumBlocks: "4",
+ paxGNUSparseMap: "0,5,10,5,20,5,30,5",
+ }
+ expected := []sparseEntry{
+ {offset: 0, numBytes: 5},
+ {offset: 10, numBytes: 5},
+ {offset: 20, numBytes: 5},
+ {offset: 30, numBytes: 5},
+ }
+
+ sp, err := readGNUSparseMap0x1(headers)
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if !reflect.DeepEqual(sp, expected) {
+ t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+ }
+}
+
+func TestReadGNUSparseMap1x0(t *testing.T) {
+ // This test uses lots of holes so the sparse header takes up more than two blocks
+ numEntries := 100
+ expected := make([]sparseEntry, 0, numEntries)
+ sparseMap := new(bytes.Buffer)
+
+ fmt.Fprintf(sparseMap, "%d\n", numEntries)
+ for i := 0; i < numEntries; i++ {
+ offset := int64(2048 * i)
+ numBytes := int64(1024)
+ expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
+ fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
+ }
+
+ // Make the header the smallest multiple of blockSize that fits the sparseMap
+ headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
+ bufLen := blockSize * headerBlocks
+ buf := make([]byte, bufLen)
+ copy(buf, sparseMap.Bytes())
+
+ // Get an reader to read the sparse map
+ r := bytes.NewReader(buf)
+
+ // Read the sparse map
+ sp, err := readGNUSparseMap1x0(r)
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if !reflect.DeepEqual(sp, expected) {
+ t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+ }
+}
+
+func TestUninitializedRead(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+ _, err = tr.Read([]byte{})
+ if err == nil || err != io.EOF {
+ t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
+ }
+
+}
diff --git a/src/pkg/archive/tar/stat_atim.go b/src/pkg/archive/tar/stat_atim.go
index 6029b0871..cf9cc79c5 100644
--- a/src/pkg/archive/tar/stat_atim.go
+++ b/src/pkg/archive/tar/stat_atim.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux openbsd
+// +build linux dragonfly openbsd solaris
package tar
diff --git a/src/pkg/archive/tar/stat_unix.go b/src/pkg/archive/tar/stat_unix.go
index 92bc92424..cb843db4c 100644
--- a/src/pkg/archive/tar/stat_unix.go
+++ b/src/pkg/archive/tar/stat_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux darwin freebsd openbsd netbsd
+// +build linux darwin dragonfly freebsd openbsd netbsd solaris
package tar
diff --git a/src/pkg/archive/tar/tar_test.go b/src/pkg/archive/tar/tar_test.go
index 616a9cc57..ed333f3ea 100644
--- a/src/pkg/archive/tar/tar_test.go
+++ b/src/pkg/archive/tar/tar_test.go
@@ -36,6 +36,10 @@ func TestFileInfoHeader(t *testing.T) {
if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
t.Errorf("ModTime = %v; want %v", g, e)
}
+ // FileInfoHeader should error when passing nil FileInfo
+ if _, err := FileInfoHeader(nil, ""); err == nil {
+ t.Fatalf("Expected error when passing nil to FileInfoHeader")
+ }
}
func TestFileInfoHeaderDir(t *testing.T) {
diff --git a/src/pkg/archive/tar/testdata/sparse-formats.tar b/src/pkg/archive/tar/testdata/sparse-formats.tar
new file mode 100644
index 000000000..8bd4e74d5
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/sparse-formats.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer-big-long.tar b/src/pkg/archive/tar/testdata/writer-big-long.tar
new file mode 100644
index 000000000..5960ee824
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/writer-big-long.tar
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/xattrs.tar b/src/pkg/archive/tar/testdata/xattrs.tar
new file mode 100644
index 000000000..9701950ed
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/xattrs.tar
Binary files differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index 549f1464c..6eff6f6f8 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -218,8 +218,8 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
// Use the ustar magic if we used ustar long names.
- if len(prefix) > 0 {
- copy(header[257:265], []byte("ustar\000"))
+ if len(prefix) > 0 && !tw.usedBinary {
+ copy(header[257:265], []byte("ustar\x00"))
}
}
}
@@ -236,6 +236,12 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
return tw.err
}
+ if allowPax {
+ for k, v := range hdr.Xattrs {
+ paxHeaders[paxXattr+k] = v
+ }
+ }
+
if len(paxHeaders) > 0 {
if !allowPax {
return errInvalidHeader
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 30ebf977a..512fab1a6 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/archive/tar/writer_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
"testing/iotest"
@@ -102,6 +103,29 @@ var writerTests = []*writerTest{
},
},
},
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
+ // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
+ {
+ file: "testdata/writer-big-long.tar",
+ entries: []*writerTestEntry{
+ {
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "16gig.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1399583047, 0),
+ Typeflag: '0',
+ Uname: "guillaume",
+ Gname: "guillaume",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ },
+ },
+ },
// This file was produced using gnu tar 1.17
// gnutar -b 4 --format=ustar (longname/)*15 + file.txt
{
@@ -338,6 +362,45 @@ func TestPaxNonAscii(t *testing.T) {
}
}
+func TestPaxXattrs(t *testing.T) {
+ xattrs := map[string]string{
+ "user.key": "value",
+ }
+
+ // Create an archive with an xattr
+ fileinfo, err := os.Stat("testdata/small.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ hdr, err := FileInfoHeader(fileinfo, "")
+ if err != nil {
+ t.Fatalf("os.Stat: %v", err)
+ }
+ contents := "Kilts"
+ hdr.Xattrs = xattrs
+ var buf bytes.Buffer
+ writer := NewWriter(&buf)
+ if err := writer.WriteHeader(hdr); err != nil {
+ t.Fatal(err)
+ }
+ if _, err = writer.Write([]byte(contents)); err != nil {
+ t.Fatal(err)
+ }
+ if err := writer.Close(); err != nil {
+ t.Fatal(err)
+ }
+ // Test that we can get the xattrs back out of the archive.
+ reader := NewReader(&buf)
+ hdr, err = reader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
+ t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
+ hdr.Xattrs, xattrs)
+ }
+}
+
func TestPAXHeader(t *testing.T) {
medName := strings.Repeat("CD", 50)
longName := strings.Repeat("AB", 100)
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index 116737337..80ee03006 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -253,7 +253,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
}
if tag == zip64ExtraId {
// update directory values from the zip64 extra block
- eb := readBuf(b)
+ eb := readBuf(b[:size])
if len(eb) >= 8 {
f.UncompressedSize64 = eb.uint64()
}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index 78875ecbf..5652f3a50 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -235,6 +235,18 @@ var tests = []ZipTest{
},
},
},
+ // Another zip64 file with different Extras fields. (golang.org/issue/7069)
+ {
+ Name: "zip64-2.zip",
+ File: []ZipTestFile{
+ {
+ Name: "README",
+ Content: []byte("This small file is in ZIP64 format.\n"),
+ Mtime: "08-10-12 14:33:32",
+ Mode: 0644,
+ },
+ },
+ },
}
var crossPlatform = []ZipTestFile{
@@ -343,19 +355,13 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
testFileMode(t, zt.Name, f, ft.Mode)
- size0 := f.UncompressedSize
-
var b bytes.Buffer
r, err := f.Open()
if err != nil {
- t.Error(err)
+ t.Errorf("%s: %v", zt.Name, err)
return
}
- if size1 := f.UncompressedSize; size0 != size1 {
- t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
- }
-
_, err = io.Copy(&b, r)
if err != ft.ContentErr {
t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
@@ -365,6 +371,14 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
}
r.Close()
+ size := uint64(f.UncompressedSize)
+ if size == uint32max {
+ size = f.UncompressedSize64
+ }
+ if g := uint64(b.Len()); g != size {
+ t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
+ }
+
var c []byte
if ft.Content != nil {
c = ft.Content
diff --git a/src/pkg/archive/zip/register.go b/src/pkg/archive/zip/register.go
index c046f081b..4211ec7af 100644
--- a/src/pkg/archive/zip/register.go
+++ b/src/pkg/archive/zip/register.go
@@ -6,6 +6,7 @@ package zip
import (
"compress/flate"
+ "errors"
"io"
"io/ioutil"
"sync"
@@ -21,12 +22,50 @@ type Compressor func(io.Writer) (io.WriteCloser, error)
// when they're finished reading.
type Decompressor func(io.Reader) io.ReadCloser
+var flateWriterPool sync.Pool
+
+func newFlateWriter(w io.Writer) io.WriteCloser {
+ fw, ok := flateWriterPool.Get().(*flate.Writer)
+ if ok {
+ fw.Reset(w)
+ } else {
+ fw, _ = flate.NewWriter(w, 5)
+ }
+ return &pooledFlateWriter{fw: fw}
+}
+
+type pooledFlateWriter struct {
+ mu sync.Mutex // guards Close and Write
+ fw *flate.Writer
+}
+
+func (w *pooledFlateWriter) Write(p []byte) (n int, err error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ if w.fw == nil {
+ return 0, errors.New("Write after Close")
+ }
+ return w.fw.Write(p)
+}
+
+func (w *pooledFlateWriter) Close() error {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ var err error
+ if w.fw != nil {
+ err = w.fw.Close()
+ flateWriterPool.Put(w.fw)
+ w.fw = nil
+ }
+ return err
+}
+
var (
mu sync.RWMutex // guards compressor and decompressor maps
compressors = map[uint16]Compressor{
Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
- Deflate: func(w io.Writer) (io.WriteCloser, error) { return flate.NewWriter(w, 5) },
+ Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
}
decompressors = map[uint16]Decompressor{
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 65e5238c3..cb28e8324 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -174,13 +174,13 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
return
}
-// ModTime returns the modification time.
+// ModTime returns the modification time in UTC.
// The resolution is 2s.
func (h *FileHeader) ModTime() time.Time {
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
}
-// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC.
// The resolution is 2s.
func (h *FileHeader) SetModTime(t time.Time) {
h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
diff --git a/src/pkg/archive/zip/testdata/zip64-2.zip b/src/pkg/archive/zip/testdata/zip64-2.zip
new file mode 100644
index 000000000..f844e3537
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/zip64-2.zip
Binary files differ
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
index 8b1c4dfd2..4bfa87080 100644
--- a/src/pkg/archive/zip/writer_test.go
+++ b/src/pkg/archive/zip/writer_test.go
@@ -125,3 +125,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
t.Errorf("File contents %q, want %q", b, wt.Data)
}
}
+
+func BenchmarkCompressedZipGarbage(b *testing.B) {
+ b.ReportAllocs()
+ var buf bytes.Buffer
+ bigBuf := bytes.Repeat([]byte("a"), 1<<20)
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ zw := NewWriter(&buf)
+ for j := 0; j < 3; j++ {
+ w, _ := zw.CreateHeader(&FileHeader{
+ Name: "foo",
+ Method: Deflate,
+ })
+ w.Write(bigBuf)
+ }
+ zw.Close()
+ }
+}
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index d1ff3c9ed..61ef26191 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -38,6 +38,7 @@ type Reader struct {
}
const minReadBufferSize = 16
+const maxConsecutiveEmptyReads = 100
// NewReaderSize returns a new Reader whose buffer has at least the specified
// size. If the argument io.Reader is already a Reader with large enough
@@ -87,15 +88,26 @@ func (b *Reader) fill() {
b.r = 0
}
- // Read new data.
- n, err := b.rd.Read(b.buf[b.w:])
- if n < 0 {
- panic(errNegativeRead)
+ if b.w >= len(b.buf) {
+ panic("bufio: tried to fill full buffer")
}
- b.w += n
- if err != nil {
- b.err = err
+
+ // Read new data: try a limited number of times.
+ for i := maxConsecutiveEmptyReads; i > 0; i-- {
+ n, err := b.rd.Read(b.buf[b.w:])
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ b.w += n
+ if err != nil {
+ b.err = err
+ return
+ }
+ if n > 0 {
+ return
+ }
}
+ b.err = io.ErrNoProgress
}
func (b *Reader) readErr() error {
@@ -115,8 +127,9 @@ func (b *Reader) Peek(n int) ([]byte, error) {
if n > len(b.buf) {
return nil, ErrBufferFull
}
+ // 0 <= n <= len(b.buf)
for b.w-b.r < n && b.err == nil {
- b.fill()
+ b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
m := b.w - b.r
if m > n {
@@ -142,7 +155,7 @@ func (b *Reader) Read(p []byte) (n int, err error) {
if n == 0 {
return 0, b.readErr()
}
- if b.w == b.r {
+ if b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
@@ -150,13 +163,16 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
n, b.err = b.rd.Read(p)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
if n > 0 {
b.lastByte = int(p[n-1])
b.lastRuneSize = -1
}
return n, b.readErr()
}
- b.fill()
+ b.fill() // buffer is empty
if b.w == b.r {
return 0, b.readErr()
}
@@ -176,11 +192,11 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// If no byte is available, returns an error.
func (b *Reader) ReadByte() (c byte, err error) {
b.lastRuneSize = -1
- for b.w == b.r {
+ for b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
- b.fill()
+ b.fill() // buffer is empty
}
c = b.buf[b.r]
b.r++
@@ -190,19 +206,19 @@ func (b *Reader) ReadByte() (c byte, err error) {
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
func (b *Reader) UnreadByte() error {
- b.lastRuneSize = -1
- if b.r == b.w && b.lastByte >= 0 {
- b.w = 1
- b.r = 0
- b.buf[0] = byte(b.lastByte)
- b.lastByte = -1
- return nil
- }
- if b.r <= 0 {
+ if b.lastByte < 0 || b.r == 0 && b.w > 0 {
return ErrInvalidUnreadByte
}
- b.r--
+ // b.r > 0 || b.w == 0
+ if b.r > 0 {
+ b.r--
+ } else {
+ // b.r == 0 && b.w == 0
+ b.w = 1
+ }
+ b.buf[b.r] = byte(b.lastByte)
b.lastByte = -1
+ b.lastRuneSize = -1
return nil
}
@@ -210,8 +226,8 @@ func (b *Reader) UnreadByte() error {
// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte
// and returns unicode.ReplacementChar (U+FFFD) with a size of 1.
func (b *Reader) ReadRune() (r rune, size int, err error) {
- for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
- b.fill()
+ for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) {
+ b.fill() // b.w-b.r < len(buf) => buffer is not full
}
b.lastRuneSize = -1
if b.r == b.w {
@@ -232,7 +248,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
// regard it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Reader) UnreadRune() error {
- if b.lastRuneSize < 0 || b.r == 0 {
+ if b.lastRuneSize < 0 || b.r < b.lastRuneSize {
return ErrInvalidUnreadRune
}
b.r -= b.lastRuneSize
@@ -255,37 +271,39 @@ func (b *Reader) Buffered() int { return b.w - b.r }
// ReadBytes or ReadString instead.
// ReadSlice returns err != nil if and only if line does not end in delim.
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
- // Look in buffer.
- if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
- line1 := b.buf[b.r : b.r+i+1]
- b.r += i + 1
- return line1, nil
- }
-
- // Read more into buffer, until buffer fills or we find delim.
for {
- if b.err != nil {
- line := b.buf[b.r:b.w]
- b.r = b.w
- return line, b.readErr()
+ // Search buffer.
+ if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+ line = b.buf[b.r : b.r+i+1]
+ b.r += i + 1
+ break
}
- n := b.Buffered()
- b.fill()
-
- // Search new part of buffer
- if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
- line := b.buf[0 : n+i+1]
- b.r = n + i + 1
- return line, nil
+ // Pending error?
+ if b.err != nil {
+ line = b.buf[b.r:b.w]
+ b.r = b.w
+ err = b.readErr()
+ break
}
- // Buffer is full?
- if b.Buffered() >= len(b.buf) {
+ // Buffer full?
+ if n := b.Buffered(); n >= len(b.buf) {
b.r = b.w
- return b.buf, ErrBufferFull
+ line = b.buf
+ err = ErrBufferFull
+ break
}
+
+ b.fill() // buffer is not full
}
+
+ // Handle last byte, if any.
+ if i := len(line) - 1; i >= 0 {
+ b.lastByte = int(line[i])
+ }
+
+ return
}
// ReadLine is a low-level line-reading primitive. Most callers should use
@@ -301,6 +319,9 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
//
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
// No indication or error is given if the input ends without a final line end.
+// Calling UnreadByte after ReadLine will always unread the last byte read
+// (possibly a character belonging to the line end) even if that byte is not
+// part of the line returned by ReadLine.
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == ErrBufferFull {
@@ -410,12 +431,24 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
return n, err
}
- for b.fill(); b.r < b.w; b.fill() {
+ if w, ok := w.(io.ReaderFrom); ok {
+ m, err := w.ReadFrom(b.rd)
+ n += m
+ return n, err
+ }
+
+ if b.w-b.r < len(b.buf) {
+ b.fill() // buffer not full
+ }
+
+ for b.r < b.w {
+ // b.r < b.w => buffer is not empty
m, err := b.writeBuf(w)
n += m
if err != nil {
return n, err
}
+ b.fill() // buffer is empty
}
if b.err == io.EOF {
@@ -428,6 +461,9 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
// writeBuf writes the Reader's buffer to the writer.
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
n, err := w.Write(b.buf[b.r:b.w])
+ if n < b.r-b.w {
+ panic(errors.New("bufio: writer did not write all data"))
+ }
b.r += n
return int64(n), err
}
@@ -619,9 +655,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
- m, err = r.Read(b.buf[b.n:])
- if m == 0 {
- break
+ nr := 0
+ for nr < maxConsecutiveEmptyReads {
+ m, err = r.Read(b.buf[b.n:])
+ if m != 0 || err != nil {
+ break
+ }
+ nr++
+ }
+ if nr == maxConsecutiveEmptyReads {
+ return n, io.ErrNoProgress
}
b.n += m
n += int64(m)
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 41bd3d456..76d3c8ead 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -14,6 +14,7 @@ import (
"strings"
"testing"
"testing/iotest"
+ "time"
"unicode/utf8"
)
@@ -65,12 +66,12 @@ func readBytes(buf *Reader) string {
func TestReaderSimple(t *testing.T) {
data := "hello world"
- b := NewReader(bytes.NewBufferString(data))
+ b := NewReader(strings.NewReader(data))
if s := readBytes(b); s != "hello world" {
t.Errorf("simple hello world test failed: got %q", s)
}
- b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+ b = NewReader(newRot13Reader(strings.NewReader(data)))
if s := readBytes(b); s != "uryyb jbeyq" {
t.Errorf("rot13 hello world test failed: got %q", s)
}
@@ -139,7 +140,7 @@ var bufreaders = []bufReader{
const minReadBufferSize = 16
var bufsizes = []int{
- minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
+ 0, minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
}
func TestReader(t *testing.T) {
@@ -161,7 +162,7 @@ func TestReader(t *testing.T) {
readmaker := readMakers[i]
bufreader := bufreaders[j]
bufsize := bufsizes[k]
- read := readmaker.fn(bytes.NewBufferString(text))
+ read := readmaker.fn(strings.NewReader(text))
buf := NewReaderSize(read, bufsize)
s := bufreader.fn(buf)
if s != text {
@@ -174,6 +175,34 @@ func TestReader(t *testing.T) {
}
}
+type zeroReader struct{}
+
+func (zeroReader) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func TestZeroReader(t *testing.T) {
+ var z zeroReader
+ r := NewReader(z)
+
+ c := make(chan error)
+ go func() {
+ _, err := r.ReadByte()
+ c <- err
+ }()
+
+ select {
+ case err := <-c:
+ if err == nil {
+ t.Error("error expected")
+ } else if err != io.ErrNoProgress {
+ t.Error("unexpected error:", err)
+ }
+ case <-time.After(time.Second):
+ t.Error("test timed out (endless loop in ReadByte?)")
+ }
+}
+
// A StringReader delivers its data one string segment at a time via Read.
type StringReader struct {
data []string
@@ -228,34 +257,150 @@ func TestReadRune(t *testing.T) {
}
func TestUnreadRune(t *testing.T) {
- got := ""
segments := []string{"Hello, world:", "日本語"}
- data := strings.Join(segments, "")
r := NewReader(&StringReader{data: segments})
+ got := ""
+ want := strings.Join(segments, "")
// Normal execution.
for {
r1, _, err := r.ReadRune()
if err != nil {
if err != io.EOF {
- t.Error("unexpected EOF")
+ t.Error("unexpected error on ReadRune:", err)
}
break
}
got += string(r1)
- // Put it back and read it again
+ // Put it back and read it again.
if err = r.UnreadRune(); err != nil {
- t.Error("unexpected error on UnreadRune:", err)
+ t.Fatal("unexpected error on UnreadRune:", err)
}
r2, _, err := r.ReadRune()
if err != nil {
- t.Error("unexpected error reading after unreading:", err)
+ t.Fatal("unexpected error reading after unreading:", err)
}
if r1 != r2 {
- t.Errorf("incorrect rune after unread: got %c wanted %c", r1, r2)
+ t.Fatalf("incorrect rune after unread: got %c, want %c", r1, r2)
+ }
+ }
+ if got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
+
+func TestUnreadByte(t *testing.T) {
+ segments := []string{"Hello, ", "world"}
+ r := NewReader(&StringReader{data: segments})
+ got := ""
+ want := strings.Join(segments, "")
+ // Normal execution.
+ for {
+ b1, err := r.ReadByte()
+ if err != nil {
+ if err != io.EOF {
+ t.Error("unexpected error on ReadByte:", err)
+ }
+ break
+ }
+ got += string(b1)
+ // Put it back and read it again.
+ if err = r.UnreadByte(); err != nil {
+ t.Fatal("unexpected error on UnreadByte:", err)
}
+ b2, err := r.ReadByte()
+ if err != nil {
+ t.Fatal("unexpected error reading after unreading:", err)
+ }
+ if b1 != b2 {
+ t.Fatalf("incorrect byte after unread: got %q, want %q", b1, b2)
+ }
+ }
+ if got != want {
+ t.Errorf("got %q, want %q", got, want)
}
- if got != data {
- t.Errorf("want=%q got=%q", data, got)
+}
+
+func TestUnreadByteMultiple(t *testing.T) {
+ segments := []string{"Hello, ", "world"}
+ data := strings.Join(segments, "")
+ for n := 0; n <= len(data); n++ {
+ r := NewReader(&StringReader{data: segments})
+ // Read n bytes.
+ for i := 0; i < n; i++ {
+ b, err := r.ReadByte()
+ if err != nil {
+ t.Fatalf("n = %d: unexpected error on ReadByte: %v", n, err)
+ }
+ if b != data[i] {
+ t.Fatalf("n = %d: incorrect byte returned from ReadByte: got %q, want %q", n, b, data[i])
+ }
+ }
+ // Unread one byte if there is one.
+ if n > 0 {
+ if err := r.UnreadByte(); err != nil {
+ t.Errorf("n = %d: unexpected error on UnreadByte: %v", n, err)
+ }
+ }
+ // Test that we cannot unread any further.
+ if err := r.UnreadByte(); err == nil {
+ t.Errorf("n = %d: expected error on UnreadByte", n)
+ }
+ }
+}
+
+func TestUnreadByteOthers(t *testing.T) {
+ // A list of readers to use in conjunction with UnreadByte.
+ var readers = []func(*Reader, byte) ([]byte, error){
+ (*Reader).ReadBytes,
+ (*Reader).ReadSlice,
+ func(r *Reader, delim byte) ([]byte, error) {
+ data, err := r.ReadString(delim)
+ return []byte(data), err
+ },
+ // ReadLine doesn't fit the data/pattern easily
+ // so we leave it out. It should be covered via
+ // the ReadSlice test since ReadLine simply calls
+ // ReadSlice, and it's that function that handles
+ // the last byte.
+ }
+
+ // Try all readers with UnreadByte.
+ for rno, read := range readers {
+ // Some input data that is longer than the minimum reader buffer size.
+ const n = 10
+ var buf bytes.Buffer
+ for i := 0; i < n; i++ {
+ buf.WriteString("abcdefg")
+ }
+
+ r := NewReaderSize(&buf, minReadBufferSize)
+ readTo := func(delim byte, want string) {
+ data, err := read(r, delim)
+ if err != nil {
+ t.Fatalf("#%d: unexpected error reading to %c: %v", rno, delim, err)
+ }
+ if got := string(data); got != want {
+ t.Fatalf("#%d: got %q, want %q", rno, got, want)
+ }
+ }
+
+ // Read the data with occasional UnreadByte calls.
+ for i := 0; i < n; i++ {
+ readTo('d', "abcd")
+ for j := 0; j < 3; j++ {
+ if err := r.UnreadByte(); err != nil {
+ t.Fatalf("#%d: unexpected error on UnreadByte: %v", rno, err)
+ }
+ readTo('d', "d")
+ }
+ readTo('g', "efg")
+ }
+
+ // All data should have been read.
+ _, err := r.ReadByte()
+ if err != io.EOF {
+ t.Errorf("#%d: got error %v; want EOF", rno, err)
+ }
}
}
@@ -447,7 +592,7 @@ func TestWriteErrors(t *testing.T) {
func TestNewReaderSizeIdempotent(t *testing.T) {
const BufSize = 1000
- b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+ b := NewReaderSize(strings.NewReader("hello world"), BufSize)
// Does it recognize itself?
b1 := NewReaderSize(b, BufSize)
if b1 != b {
@@ -516,6 +661,9 @@ func TestPeek(t *testing.T) {
if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
}
+ if _, err := buf.Peek(-1); err != ErrNegativeCount {
+ t.Fatalf("want ErrNegativeCount got %v", err)
+ }
if _, err := buf.Peek(32); err != ErrBufferFull {
t.Fatalf("want ErrBufFull got %v", err)
}
@@ -642,7 +790,7 @@ func TestLineTooLong(t *testing.T) {
for i := 0; i < minReadBufferSize*5/2; i++ {
data = append(data, '0'+byte(i%10))
}
- buf := bytes.NewBuffer(data)
+ buf := bytes.NewReader(data)
l := NewReaderSize(buf, minReadBufferSize)
line, isPrefix, err := l.ReadLine()
if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
@@ -667,7 +815,7 @@ func TestLineTooLong(t *testing.T) {
func TestReadAfterLines(t *testing.T) {
line1 := "this is line1"
restData := "this is line2\nthis is line 3\n"
- inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
+ inbuf := bytes.NewReader([]byte(line1 + "\n" + restData))
outbuf := new(bytes.Buffer)
maxLineLength := len(line1) + len(restData)/2
l := NewReaderSize(inbuf, maxLineLength)
@@ -693,7 +841,7 @@ func TestReadEmptyBuffer(t *testing.T) {
}
func TestLinesAfterRead(t *testing.T) {
- l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
+ l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
_, err := ioutil.ReadAll(l)
if err != nil {
t.Error(err)
@@ -783,7 +931,7 @@ func createTestInput(n int) []byte {
func TestReaderWriteTo(t *testing.T) {
input := createTestInput(8192)
- r := NewReader(onlyReader{bytes.NewBuffer(input)})
+ r := NewReader(onlyReader{bytes.NewReader(input)})
w := new(bytes.Buffer)
if n, err := r.WriteTo(w); err != nil || n != int64(len(input)) {
t.Fatalf("r.WriteTo(w) = %d, %v, want %d, nil", n, err, len(input))
@@ -842,7 +990,7 @@ func TestWriterReadFrom(t *testing.T) {
input := createTestInput(8192)
b := new(bytes.Buffer)
w := NewWriter(wfunc(b))
- r := rfunc(bytes.NewBuffer(input))
+ r := rfunc(bytes.NewReader(input))
if n, err := w.ReadFrom(r); err != nil || n != int64(len(input)) {
t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
continue
@@ -1021,7 +1169,61 @@ func TestWriterReadFromWhileFull(t *testing.T) {
// Use ReadFrom to read in some data.
n2, err := w.ReadFrom(strings.NewReader("abcdef"))
if n2 != 6 || err != nil {
- t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err)
+ t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n2, err)
+ }
+}
+
+type emptyThenNonEmptyReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *emptyThenNonEmptyReader) Read(p []byte) (int, error) {
+ if r.n <= 0 {
+ return r.r.Read(p)
+ }
+ r.n--
+ return 0, nil
+}
+
+// Test for golang.org/issue/7611
+func TestWriterReadFromUntilEOF(t *testing.T) {
+ buf := new(bytes.Buffer)
+ w := NewWriterSize(buf, 5)
+
+ // Partially fill buffer
+ n, err := w.Write([]byte("0123"))
+ if n != 4 || err != nil {
+ t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+ }
+
+ // Use ReadFrom to read in some data.
+ r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 3}
+ n2, err := w.ReadFrom(r)
+ if n2 != 4 || err != nil {
+ t.Fatalf("ReadFrom returned (%v, %v), want (4, nil)", n2, err)
+ }
+ w.Flush()
+ if got, want := string(buf.Bytes()), "0123abcd"; got != want {
+ t.Fatalf("buf.Bytes() returned %q, want %q", got, want)
+ }
+}
+
+func TestWriterReadFromErrNoProgress(t *testing.T) {
+ buf := new(bytes.Buffer)
+ w := NewWriterSize(buf, 5)
+
+ // Partially fill buffer
+ n, err := w.Write([]byte("0123"))
+ if n != 4 || err != nil {
+ t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+ }
+
+ // Use ReadFrom to read in some data.
+ r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 100}
+ n2, err := w.ReadFrom(r)
+ if n2 != 0 || err != io.ErrNoProgress {
+ t.Fatalf("buf.Bytes() returned (%v, %v), want (0, io.ErrNoProgress)", n2, err)
}
}
@@ -1059,81 +1261,114 @@ func TestWriterReset(t *testing.T) {
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
- r io.Reader
-}
-
-func (r onlyReader) Read(b []byte) (int, error) {
- return r.r.Read(b)
+ io.Reader
}
// An onlyWriter only implements io.Writer, no matter what other methods the underlying implementation may have.
type onlyWriter struct {
- w io.Writer
-}
-
-func (w onlyWriter) Write(b []byte) (int, error) {
- return w.w.Write(b)
+ io.Writer
}
func BenchmarkReaderCopyOptimal(b *testing.B) {
// Optimal case is where the underlying reader implements io.WriterTo
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := NewReader(srcBuf)
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := NewReader(bytes.NewBuffer(make([]byte, 8192)))
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ src.Reset(srcBuf)
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyUnoptimal(b *testing.B) {
// Unoptimal case is where the underlying reader doesn't implement io.WriterTo
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := NewReader(onlyReader{srcBuf})
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := NewReader(onlyReader{bytes.NewBuffer(make([]byte, 8192))})
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ src.Reset(onlyReader{srcBuf})
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyNoWriteTo(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ srcReader := NewReader(srcBuf)
+ src := onlyReader{srcReader}
+ dstBuf := new(bytes.Buffer)
+ dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
- dst := onlyWriter{new(bytes.Buffer)}
- b.StartTimer()
+ srcBuf.Reset()
+ srcReader.Reset(srcBuf)
+ dstBuf.Reset()
io.Copy(dst, src)
}
}
+func BenchmarkReaderWriteToOptimal(b *testing.B) {
+ const bufSize = 16 << 10
+ buf := make([]byte, bufSize)
+ r := bytes.NewReader(buf)
+ srcReader := NewReaderSize(onlyReader{r}, 1<<10)
+ if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
+ b.Fatal("ioutil.Discard doesn't support ReaderFrom")
+ }
+ for i := 0; i < b.N; i++ {
+ r.Seek(0, 0)
+ srcReader.Reset(onlyReader{r})
+ n, err := srcReader.WriteTo(ioutil.Discard)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if n != bufSize {
+ b.Fatalf("n = %d; want %d", n, bufSize)
+ }
+ }
+}
+
func BenchmarkWriterCopyOptimal(b *testing.B) {
// Optimal case is where the underlying writer implements io.ReaderFrom
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dst := NewWriter(dstBuf)
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := NewWriter(new(bytes.Buffer))
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dst.Reset(dstBuf)
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyUnoptimal(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dst := NewWriter(onlyWriter{dstBuf})
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := NewWriter(onlyWriter{new(bytes.Buffer)})
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dst.Reset(onlyWriter{dstBuf})
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyNoReadFrom(b *testing.B) {
+ srcBuf := bytes.NewBuffer(make([]byte, 8192))
+ src := onlyReader{srcBuf}
+ dstBuf := new(bytes.Buffer)
+ dstWriter := NewWriter(dstBuf)
+ dst := onlyWriter{dstWriter}
for i := 0; i < b.N; i++ {
- b.StopTimer()
- src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
- dst := onlyWriter{NewWriter(new(bytes.Buffer))}
- b.StartTimer()
+ srcBuf.Reset()
+ dstBuf.Reset()
+ dstWriter.Reset(dstBuf)
io.Copy(dst, src)
}
}
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 423505fbc..715ce071e 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -135,7 +135,7 @@ func (s *Scanner) Scan() bool {
}
// Must read more data.
// First, shift data to beginning of buffer if there's lots of empty space
- // or space is neded.
+ // or space is needed.
if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
copy(s.buf, s.buf[s.start:s.end])
s.end -= s.start
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
@@ -306,7 +306,7 @@ func isSpace(r rune) bool {
return true
}
switch r {
- case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
+ case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
return true
}
return false
diff --git a/src/pkg/bufio/scan_test.go b/src/pkg/bufio/scan_test.go
index c1483b268..0db7cad20 100644
--- a/src/pkg/bufio/scan_test.go
+++ b/src/pkg/bufio/scan_test.go
@@ -38,7 +38,7 @@ var scanTests = []string{
func TestScanByte(t *testing.T) {
for n, test := range scanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanBytes)
var i int
@@ -60,7 +60,7 @@ func TestScanByte(t *testing.T) {
// Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
func TestScanRune(t *testing.T) {
for n, test := range scanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanRunes)
var i, runeCount int
@@ -104,7 +104,7 @@ var wordScanTests = []string{
// Test that the word splitter returns the same data as strings.Fields.
func TestScanWords(t *testing.T) {
for n, test := range wordScanTests {
- buf := bytes.NewBufferString(test)
+ buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanWords)
words := strings.Fields(test)
@@ -135,7 +135,7 @@ func TestScanWords(t *testing.T) {
// reads in Scanner.Scan.
type slowReader struct {
max int
- buf *bytes.Buffer
+ buf io.Reader
}
func (sr *slowReader) Read(p []byte) (n int, err error) {
@@ -248,7 +248,7 @@ func TestScanLineTooLong(t *testing.T) {
// Test that the line splitter handles a final line without a newline.
func testNoNewline(text string, lines []string, t *testing.T) {
- buf := bytes.NewBufferString(text)
+ buf := strings.NewReader(text)
s := NewScanner(&slowReader{7, buf})
s.Split(ScanLines)
for lineNum := 0; s.Scan(); lineNum++ {
@@ -277,7 +277,7 @@ func TestScanLineNoNewline(t *testing.T) {
testNoNewline(text, lines, t)
}
-// Test that the line splitter handles a final line with a carriage return but nonewline.
+// Test that the line splitter handles a final line with a carriage return but no newline.
func TestScanLineReturnButNoNewline(t *testing.T) {
const text = "abcdefghijklmn\nopqrstuvwxyz\r"
lines := []string{
@@ -328,7 +328,7 @@ func TestSplitError(t *testing.T) {
}
// Read the data.
const text = "abcdefghijklmnopqrstuvwxyz"
- buf := bytes.NewBufferString(text)
+ buf := strings.NewReader(text)
s := NewScanner(&slowReader{1, buf})
s.Split(errorSplit)
var i int
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 01a5d9ae4..0c53e4c0b 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -265,8 +265,8 @@ func Fields(s []byte) [][]byte {
// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s. If no code points in s satisfy f(c), an
-// empty slice is returned.
+// returns a slice of subslices of s. If all code points in s satisfy f(c), or
+// len(s) == 0, an empty slice is returned.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
@@ -356,7 +356,11 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
}
r = mapping(r)
if r >= 0 {
- if nbytes+utf8.RuneLen(r) > maxbytes {
+ rl := utf8.RuneLen(r)
+ if rl < 0 {
+ rl = len(string(utf8.RuneError))
+ }
+ if nbytes+rl > maxbytes {
// Grow the buffer.
maxbytes = maxbytes*2 + utf8.UTFMax
nb := make([]byte, maxbytes)
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index ab5da4fbf..394dd7a44 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -785,6 +785,16 @@ func TestMap(t *testing.T) {
if string(m) != expect {
t.Errorf("drop: expected %q got %q", expect, m)
}
+
+ // 6. Invalid rune
+ invalidRune := func(r rune) rune {
+ return utf8.MaxRune + 1
+ }
+ m = Map(invalidRune, []byte("x"))
+ expect = "\uFFFD"
+ if string(m) != expect {
+ t.Errorf("invalidRune: expected %q got %q", expect, m)
+ }
}
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
@@ -1073,6 +1083,8 @@ var TitleTests = []TitleTest{
{"123a456", "123a456"},
{"double-blind", "Double-Blind"},
{"ÿøû", "Ÿøû"},
+ {"with_underscore", "With_underscore"},
+ {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
}
func TestTitle(t *testing.T) {
@@ -1132,7 +1144,7 @@ func TestEqualFold(t *testing.T) {
func TestBufferGrowNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Grow(-1) should have paniced")
+ t.Fatal("Grow(-1) should have panicked")
}
}()
var b Buffer
@@ -1142,7 +1154,7 @@ func TestBufferGrowNegative(t *testing.T) {
func TestBufferTruncateNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(-1) should have paniced")
+ t.Fatal("Truncate(-1) should have panicked")
}
}()
var b Buffer
@@ -1152,7 +1164,7 @@ func TestBufferTruncateNegative(t *testing.T) {
func TestBufferTruncateOutOfRange(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(20) should have paniced")
+ t.Fatal("Truncate(20) should have panicked")
}
}()
var b Buffer
@@ -1160,6 +1172,24 @@ func TestBufferTruncateOutOfRange(t *testing.T) {
b.Truncate(20)
}
+var containsTests = []struct {
+ b, subslice []byte
+ want bool
+}{
+ {[]byte("hello"), []byte("hel"), true},
+ {[]byte("日本語"), []byte("日本"), true},
+ {[]byte("hello"), []byte("Hello, world"), false},
+ {[]byte("東京"), []byte("京東"), false},
+}
+
+func TestContains(t *testing.T) {
+ for _, tt := range containsTests {
+ if got := Contains(tt.b, tt.subslice); got != tt.want {
+ t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
+ }
+ }
+}
+
var makeFieldsInput = func() []byte {
x := make([]byte, 1<<20)
// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
diff --git a/src/pkg/bytes/compare_test.go b/src/pkg/bytes/compare_test.go
index 0a36f5ad3..63522374e 100644
--- a/src/pkg/bytes/compare_test.go
+++ b/src/pkg/bytes/compare_test.go
@@ -1,3 +1,7 @@
+// 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 bytes_test
import (
diff --git a/src/pkg/bytes/reader.go b/src/pkg/bytes/reader.go
index 77511b945..d2d40fa7c 100644
--- a/src/pkg/bytes/reader.go
+++ b/src/pkg/bytes/reader.go
@@ -16,40 +16,41 @@ import (
// Unlike a Buffer, a Reader is read-only and supports seeking.
type Reader struct {
s []byte
- i int // current reading index
- prevRune int // index of previous rune; or < 0
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// slice.
func (r *Reader) Len() int {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0
}
- return len(r.s) - r.i
+ return int(int64(len(r.s)) - r.i)
}
func (r *Reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[r.i:])
- r.i += n
r.prevRune = -1
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
return
}
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ // cannot modify state - see io.ReaderAt
if off < 0 {
- return 0, errors.New("bytes: invalid offset")
+ return 0, errors.New("bytes.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[int(off):])
+ n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
@@ -57,49 +58,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
}
func (r *Reader) ReadByte() (b byte, err error) {
- if r.i >= len(r.s) {
+ r.prevRune = -1
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
b = r.s[r.i]
r.i++
- r.prevRune = -1
return
}
func (r *Reader) UnreadByte() error {
+ r.prevRune = -1
if r.i <= 0 {
- return errors.New("bytes.Reader: at beginning of slice")
+ return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
}
r.i--
- r.prevRune = -1
return nil
}
func (r *Reader) ReadRune() (ch rune, size int, err error) {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
+ r.prevRune = -1
return 0, 0, io.EOF
}
- r.prevRune = r.i
+ r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRune(r.s[r.i:])
- r.i += size
+ r.i += int64(size)
return
}
func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return errors.New("bytes.Reader: previous operation was not ReadRune")
+ return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune")
}
- r.i = r.prevRune
+ r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ r.prevRune = -1
var abs int64
switch whence {
case 0:
@@ -109,22 +112,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
case 2:
abs = int64(len(r.s)) + offset
default:
- return 0, errors.New("bytes: invalid whence")
+ return 0, errors.New("bytes.Reader.Seek: invalid whence")
}
if abs < 0 {
- return 0, errors.New("bytes: negative position")
- }
- if abs >= 1<<31 {
- return 0, errors.New("bytes: position out of range")
+ return 0, errors.New("bytes.Reader.Seek: negative position")
}
- r.i = int(abs)
+ r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, nil
}
b := r.s[r.i:]
@@ -132,7 +132,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
if m > len(b) {
panic("bytes.Reader.WriteTo: invalid Write count")
}
- r.i += m
+ r.i += int64(m)
n = int64(m)
if m != len(b) && err == nil {
err = io.ErrShortWrite
diff --git a/src/pkg/bytes/reader_test.go b/src/pkg/bytes/reader_test.go
index 19f014da0..d3dce5349 100644
--- a/src/pkg/bytes/reader_test.go
+++ b/src/pkg/bytes/reader_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
+ "sync"
"testing"
)
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"},
- {seek: os.SEEK_SET, off: 1<<31 - 1},
- {seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+ {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
{seek: os.SEEK_SET, n: 5, want: "01234"},
{seek: os.SEEK_CUR, n: 5, want: "56789"},
{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
}
}
+func TestReadAfterBigSeek(t *testing.T) {
+ r := NewReader([]byte("0123456789"))
+ if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ t.Fatal(err)
+ }
+ if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+ }
+}
+
func TestReaderAt(t *testing.T) {
r := NewReader([]byte("0123456789"))
tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
- {-1, 0, "", "bytes: invalid offset"},
+ {-1, 0, "", "bytes.Reader.ReadAt: negative offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
}
}
+func TestReaderAtConcurrent(t *testing.T) {
+ // Test for the race detector, to verify ReadAt doesn't mutate
+ // any state.
+ r := NewReader([]byte("0123456789"))
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var buf [1]byte
+ r.ReadAt(buf[:], int64(i))
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+ // Test for the race detector, to verify a Read that doesn't yield any bytes
+ // is okay to use from multiple goroutines. This was our historic behavior.
+ // See golang.org/issue/7856
+ r := NewReader([]byte{})
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ var buf [1]byte
+ r.Read(buf[:])
+ }()
+ go func() {
+ defer wg.Done()
+ r.Read(nil)
+ }()
+ }
+ wg.Wait()
+}
+
func TestReaderWriteTo(t *testing.T) {
for i := 0; i < 30; i += 3 {
var l int
@@ -133,6 +181,32 @@ func TestReaderLen(t *testing.T) {
}
}
+var UnreadRuneErrorTests = []struct {
+ name string
+ f func(*Reader)
+}{
+ {"Read", func(r *Reader) { r.Read([]byte{0}) }},
+ {"ReadByte", func(r *Reader) { r.ReadByte() }},
+ {"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+ {"Seek", func(r *Reader) { r.Seek(0, 1) }},
+ {"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+ for _, tt := range UnreadRuneErrorTests {
+ reader := NewReader([]byte("0123456789"))
+ if _, _, err := reader.ReadRune(); err != nil {
+ // should not happen
+ t.Fatal(err)
+ }
+ tt.f(reader)
+ err := reader.UnreadRune()
+ if err == nil {
+ t.Errorf("Unreading after %s: expected error", tt.name)
+ }
+ }
+}
+
func TestReaderDoubleUnreadRune(t *testing.T) {
buf := NewBuffer([]byte("groucho"))
if _, _, err := buf.ReadRune(); err != nil {
diff --git a/src/pkg/compress/bzip2/bzip2_test.go b/src/pkg/compress/bzip2/bzip2_test.go
index ada1f9a00..727249dc4 100644
--- a/src/pkg/compress/bzip2/bzip2_test.go
+++ b/src/pkg/compress/bzip2/bzip2_test.go
@@ -14,7 +14,7 @@ import (
)
func TestBitReader(t *testing.T) {
- buf := bytes.NewBuffer([]byte{0xaa})
+ buf := bytes.NewReader([]byte{0xaa})
br := newBitReader(buf)
if n := br.ReadBits(1); n != 1 {
t.Errorf("read 1 wrong")
@@ -31,7 +31,7 @@ func TestBitReader(t *testing.T) {
}
func TestBitReaderLarge(t *testing.T) {
- buf := bytes.NewBuffer([]byte{0x12, 0x34, 0x56, 0x78})
+ buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
br := newBitReader(buf)
if n := br.ReadBits(32); n != 0x12345678 {
t.Errorf("got: %x want: %x", n, 0x12345678)
@@ -43,7 +43,7 @@ func readerFromHex(s string) io.Reader {
if err != nil {
panic("readerFromHex: bad input")
}
- return bytes.NewBuffer(data)
+ return bytes.NewReader(data)
}
func decompressHex(s string) (out []byte, err error) {
@@ -177,7 +177,7 @@ const (
var testfiles = []string{
// Digits is the digits of the irrational number e. Its decimal representation
- // does not repeat, but there are only 10 posible digits, so it should be
+ // does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
digits: "testdata/e.txt.bz2",
// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
@@ -191,7 +191,7 @@ func benchmarkDecode(b *testing.B, testfile int) {
}
b.SetBytes(int64(len(compressed)))
for i := 0; i < b.N; i++ {
- r := bytes.NewBuffer(compressed)
+ r := bytes.NewReader(compressed)
io.Copy(ioutil.Discard, NewReader(r))
}
}
@@ -201,7 +201,7 @@ func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
func TestBufferOverrun(t *testing.T) {
// Tests https://code.google.com/p/go/issues/detail?id=5747.
- buffer := bytes.NewBuffer([]byte(bufferOverrunBase64))
+ buffer := bytes.NewReader([]byte(bufferOverrunBase64))
decoder := base64.NewDecoder(base64.StdEncoding, buffer)
decompressor := NewReader(decoder)
// This shouldn't panic.
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
index 8f6b0c9ca..75a6223d8 100644
--- a/src/pkg/compress/bzip2/huffman.go
+++ b/src/pkg/compress/bzip2/huffman.go
@@ -190,7 +190,37 @@ func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIn
right := codes[firstRightIndex:]
if len(left) == 0 || len(right) == 0 {
- return 0, StructuralError("superfluous level in Huffman tree")
+ // There is a superfluous level in the Huffman tree indicating
+ // a bug in the encoder. However, this bug has been observed in
+ // the wild so we handle it.
+
+ // If this function was called recursively then we know that
+ // len(codes) >= 2 because, otherwise, we would have hit the
+ // "leaf node" case, below, and not recursed.
+ //
+ // However, for the initial call it's possible that len(codes)
+ // is zero or one. Both cases are invalid because a zero length
+ // tree cannot encode anything and a length-1 tree can only
+ // encode EOF and so is superfluous. We reject both.
+ if len(codes) < 2 {
+ return 0, StructuralError("empty Huffman tree")
+ }
+
+ // In this case the recursion doesn't always reduce the length
+ // of codes so we need to ensure termination via another
+ // mechanism.
+ if level == 31 {
+ // Since len(codes) >= 2 the only way that the values
+ // can match at all 32 bits is if they are equal, which
+ // is invalid. This ensures that we never enter
+ // infinite recursion.
+ return 0, StructuralError("equal symbols in Huffman tree")
+ }
+
+ if len(left) == 0 {
+ return buildHuffmanNode(t, right, level+1)
+ }
+ return buildHuffmanNode(t, left, level+1)
}
nodeIndex = uint16(t.nextNode)
diff --git a/src/pkg/compress/flate/fixedhuff.go b/src/pkg/compress/flate/fixedhuff.go
index 41a6b25df..9be3d5349 100644
--- a/src/pkg/compress/flate/fixedhuff.go
+++ b/src/pkg/compress/flate/fixedhuff.go
@@ -1,3 +1,7 @@
+// 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 flate
// autogenerated by gen.go, DO NOT EDIT
diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go
index 57fea5ab4..068766323 100644
--- a/src/pkg/compress/flate/flate_test.go
+++ b/src/pkg/compress/flate/flate_test.go
@@ -14,7 +14,7 @@ import (
)
func TestUncompressedSource(t *testing.T) {
- decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+ decoder := NewReader(bytes.NewReader([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
output := make([]byte, 1)
n, error := decoder.Read(output)
if n != 1 || error != nil {
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index 3eb3b2b83..ce4923eca 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -54,7 +54,7 @@ func (e *WriteError) Error() string {
return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
}
-// Note that much of the implemenation of huffmanDecoder is also copied
+// Note that much of the implementation of huffmanDecoder is also copied
// into gen.go (in package main) for the purpose of precomputing the
// fixed huffman tables so they can be included statically.
@@ -180,7 +180,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
// the NewReader will introduce its own buffering.
type Reader interface {
io.Reader
- ReadByte() (c byte, err error)
+ io.ByteReader
}
// Decompress state.
diff --git a/src/pkg/compress/flate/reader_test.go b/src/pkg/compress/flate/reader_test.go
index 2a8ebbc94..a62ef741d 100644
--- a/src/pkg/compress/flate/reader_test.go
+++ b/src/pkg/compress/flate/reader_test.go
@@ -29,7 +29,7 @@ const (
var testfiles = []string{
// Digits is the digits of the irrational number e. Its decimal representation
- // does not repeat, but there are only 10 posible digits, so it should be
+ // does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
digits: "../testdata/e.txt",
// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index 1fb9b0964..4f398b194 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -89,6 +89,21 @@ func NewReader(r io.Reader) (*Reader, error) {
return z, nil
}
+// Reset discards the Reader z's state and makes it equivalent to the
+// result of its original state from NewReader, but reading from r instead.
+// This permits reusing a Reader rather than allocating a new one.
+func (z *Reader) Reset(r io.Reader) error {
+ z.r = makeReader(r)
+ if z.digest == nil {
+ z.digest = crc32.NewIEEE()
+ } else {
+ z.digest.Reset()
+ }
+ z.size = 0
+ z.err = nil
+ return z.readHeader(true)
+}
+
// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
func get4(p []byte) uint32 {
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
index 572fb5848..2471038f5 100644
--- a/src/pkg/compress/gzip/gunzip_test.go
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -284,7 +284,7 @@ var gunzipTests = []gunzipTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range gunzipTests {
- in := bytes.NewBuffer(tt.gzip)
+ in := bytes.NewReader(tt.gzip)
gzip, err := NewReader(in)
if err != nil {
t.Errorf("%s: NewReader: %s", tt.name, err)
@@ -303,6 +303,26 @@ func TestDecompressor(t *testing.T) {
if s != tt.raw {
t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
}
+
+ // Test Reader Reset.
+ in = bytes.NewReader(tt.gzip)
+ err = gzip.Reset(in)
+ if err != nil {
+ t.Errorf("%s: Reset: %s", tt.name, err)
+ continue
+ }
+ if tt.name != gzip.Name {
+ t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ }
+ b.Reset()
+ n, err = io.Copy(b, gzip)
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ }
+ s = b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ }
}
}
@@ -333,3 +353,17 @@ func TestIssue6550(t *testing.T) {
// ok
}
}
+
+func TestInitialReset(t *testing.T) {
+ var r Reader
+ if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil {
+ t.Error(err)
+ }
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, &r); err != nil {
+ t.Error(err)
+ }
+ if s := buf.String(); s != gunzipTests[1].raw {
+ t.Errorf("got %q want %q", s, gunzipTests[1].raw)
+ }
+}
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
index fe32d6871..3a0bf54e1 100644
--- a/src/pkg/compress/gzip/gzip.go
+++ b/src/pkg/compress/gzip/gzip.go
@@ -22,8 +22,8 @@ const (
DefaultCompression = flate.DefaultCompression
)
-// A Writer is an io.WriteCloser that satisfies writes by compressing data written
-// to its wrapped io.Writer.
+// A Writer is an io.WriteCloser.
+// Writes to a Writer are compressed and written to w.
type Writer struct {
Header
w io.Writer
@@ -37,8 +37,8 @@ type Writer struct {
err error
}
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter returns a new Writer.
+// Writes to the returned writer are compressed and written to w.
//
// It is the caller's responsibility to call Close on the WriteCloser when done.
// Writes may be buffered and not flushed until Close.
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
index 119be2e13..09271b24e 100644
--- a/src/pkg/compress/gzip/gzip_test.go
+++ b/src/pkg/compress/gzip/gzip_test.go
@@ -85,7 +85,7 @@ func TestRoundTrip(t *testing.T) {
func TestLatin1(t *testing.T) {
latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
utf8 := "Äußerung"
- z := Reader{r: bufio.NewReader(bytes.NewBuffer(latin1))}
+ z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))}
s, err := z.readString()
if err != nil {
t.Fatalf("readString: %v", err)
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index efbc758f9..ef5969910 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -216,8 +216,8 @@ func (d *decoder) Close() error {
return nil
}
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
-// the data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
// It is the caller's responsibility to call Close on the ReadCloser when
// finished reading.
// The number of bits to use for literal codes, litWidth, must be in the
diff --git a/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
index 6f155b1bd..9006c91c2 100644
--- a/src/pkg/compress/lzw/reader_test.go
+++ b/src/pkg/compress/lzw/reader_test.go
@@ -127,7 +127,7 @@ func benchmarkDecoder(b *testing.B, n int) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
- io.Copy(w, bytes.NewBuffer(buf0))
+ w.Write(buf0)
}
w.Close()
buf1 := compressed.Bytes()
@@ -135,7 +135,7 @@ func benchmarkDecoder(b *testing.B, n int) {
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1), LSB, 8))
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
}
}
diff --git a/src/pkg/compress/lzw/writer.go b/src/pkg/compress/lzw/writer.go
index b20691864..961b25f94 100644
--- a/src/pkg/compress/lzw/writer.go
+++ b/src/pkg/compress/lzw/writer.go
@@ -225,8 +225,8 @@ func (e *encoder) Close() error {
return e.w.Flush()
}
-// NewWriter creates a new io.WriteCloser that satisfies writes by compressing
-// the data and writing it to w.
+// NewWriter creates a new io.WriteCloser.
+// Writes to the returned io.WriteCloser are compressed and written to w.
// It is the caller's responsibility to call Close on the WriteCloser when
// finished writing.
// The number of bits to use for literal codes, litWidth, must be in the
diff --git a/src/pkg/compress/zlib/example_test.go b/src/pkg/compress/zlib/example_test.go
index b934ffa61..70408895f 100644
--- a/src/pkg/compress/zlib/example_test.go
+++ b/src/pkg/compress/zlib/example_test.go
@@ -25,7 +25,7 @@ func ExampleNewWriter() {
func ExampleNewReader() {
buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
- b := bytes.NewBuffer(buff)
+ b := bytes.NewReader(buff)
r, err := zlib.NewReader(b)
if err != nil {
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
index d54746f4c..9e1aafda9 100644
--- a/src/pkg/compress/zlib/reader.go
+++ b/src/pkg/compress/zlib/reader.go
@@ -51,7 +51,8 @@ type reader struct {
scratch [4]byte
}
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
// The implementation buffers input and may read more data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when done.
func NewReader(r io.Reader) (io.ReadCloser, error) {
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
index 3b02a0868..218ccba14 100644
--- a/src/pkg/compress/zlib/reader_test.go
+++ b/src/pkg/compress/zlib/reader_test.go
@@ -102,7 +102,7 @@ var zlibTests = []zlibTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range zlibTests {
- in := bytes.NewBuffer(tt.compressed)
+ in := bytes.NewReader(tt.compressed)
zlib, err := NewReaderDict(in, tt.dict)
if err != nil {
if err != tt.err {
diff --git a/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go
index 99ff6549a..fac7e15a7 100644
--- a/src/pkg/compress/zlib/writer.go
+++ b/src/pkg/compress/zlib/writer.go
@@ -34,8 +34,8 @@ type Writer struct {
wroteHeader bool
}
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter creates a new Writer.
+// Writes to the returned Writer are compressed and written to w.
//
// It is the caller's responsibility to call Close on the WriteCloser when done.
// Writes may be buffered and not flushed until Close.
diff --git a/src/pkg/compress/zlib/writer_test.go b/src/pkg/compress/zlib/writer_test.go
index cf9c83254..71ba81aaa 100644
--- a/src/pkg/compress/zlib/writer_test.go
+++ b/src/pkg/compress/zlib/writer_test.go
@@ -120,7 +120,7 @@ func testFileLevelDictReset(t *testing.T, fn string, level int, dict []byte) {
}
out := buf.String()
- // Reset and comprses again.
+ // Reset and compress again.
buf2 := new(bytes.Buffer)
zlibw.Reset(buf2)
_, err = zlibw.Write(b0)
diff --git a/src/pkg/container/heap/example_pq_test.go b/src/pkg/container/heap/example_pq_test.go
index 8cbeb8d70..7017095cb 100644
--- a/src/pkg/container/heap/example_pq_test.go
+++ b/src/pkg/container/heap/example_pq_test.go
@@ -52,13 +52,12 @@ func (pq *PriorityQueue) Pop() interface{} {
// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
- heap.Remove(pq, item.index)
item.value = value
item.priority = priority
- heap.Push(pq, item)
+ heap.Fix(pq, item.index)
}
-// This example inserts some items into a PriorityQueue, manipulates an item,
+// This example creates a PriorityQueue with some items, adds and manipulates an item,
// and then removes the items in priority order.
func Example_priorityQueue() {
// Some items and their priorities.
@@ -66,28 +65,31 @@ func Example_priorityQueue() {
"banana": 3, "apple": 2, "pear": 4,
}
- // Create a priority queue and put the items in it.
- pq := &PriorityQueue{}
- heap.Init(pq)
+ // Create a priority queue, put the items in it, and
+ // establish the priority queue (heap) invariants.
+ pq := make(PriorityQueue, len(items))
+ i := 0
for value, priority := range items {
- item := &Item{
+ pq[i] = &Item{
value: value,
priority: priority,
+ index: i,
}
- heap.Push(pq, item)
+ i++
}
+ heap.Init(&pq)
// Insert a new item and then modify its priority.
item := &Item{
value: "orange",
priority: 1,
}
- heap.Push(pq, item)
+ heap.Push(&pq, item)
pq.update(item, item.value, 5)
// Take the items out; they arrive in decreasing priority order.
for pq.Len() > 0 {
- item := heap.Pop(pq).(*Item)
+ item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
// Output:
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 52c8507b4..c467a1191 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/container/heap/heap.go
@@ -22,7 +22,7 @@ import "sort"
// min-heap with the following invariants (established after
// Init has been called or if the data is empty or sorted):
//
-// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+// !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
//
// Note that Push and Pop in this interface are for package heap's
// implementation to call. To add and remove things from the heap,
@@ -78,7 +78,7 @@ func Remove(h Interface, i int) interface{} {
return h.Pop()
}
-// Fix reestablishes the heap ordering after the element at index i has changed its value.
+// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log(n)) where n = h.Len().
diff --git a/src/pkg/container/list/example_test.go b/src/pkg/container/list/example_test.go
index 7361212d7..362178401 100644
--- a/src/pkg/container/list/example_test.go
+++ b/src/pkg/container/list/example_test.go
@@ -17,7 +17,7 @@ func Example() {
l.InsertBefore(3, e4)
l.InsertAfter(2, e1)
- // Iterate through list and and print its contents.
+ // Iterate through list and print its contents.
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
index ed2d15a45..0256768ef 100644
--- a/src/pkg/container/list/list.go
+++ b/src/pkg/container/list/list.go
@@ -65,7 +65,7 @@ func New() *List { return new(List).Init() }
// The complexity is O(1).
func (l *List) Len() int { return l.len }
-// Front returns the first element of list l or nil
+// Front returns the first element of list l or nil.
func (l *List) Front() *Element {
if l.len == 0 {
return nil
@@ -180,18 +180,18 @@ func (l *List) MoveToBack(e *Element) {
}
// MoveBefore moves element e to its new position before mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveBefore(e, mark *Element) {
- if e.list != l || e == mark {
+ if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark.prev)
}
// MoveAfter moves element e to its new position after mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveAfter(e, mark *Element) {
- if e.list != l || e == mark {
+ if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark)
diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
index ee52afe82..4d8bfc2bf 100644
--- a/src/pkg/container/list/list_test.go
+++ b/src/pkg/container/list/list_test.go
@@ -285,3 +285,59 @@ func TestMove(t *testing.T) {
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
e1, e2, e3, e4 = e1, e3, e2, e4
}
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
+func TestZeroList(t *testing.T) {
+ var l1 = new(List)
+ l1.PushFront(1)
+ checkList(t, l1, []interface{}{1})
+
+ var l2 = new(List)
+ l2.PushBack(1)
+ checkList(t, l2, []interface{}{1})
+
+ var l3 = new(List)
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1})
+
+ var l4 = new(List)
+ l4.PushBackList(l2)
+ checkList(t, l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark(t *testing.T) {
+ var l List
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertBefore(1, new(Element))
+ checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark(t *testing.T) {
+ var l List
+ l.PushBack(1)
+ l.PushBack(2)
+ l.PushBack(3)
+ l.InsertAfter(1, new(Element))
+ checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnkownMark(t *testing.T) {
+ var l1 List
+ e1 := l1.PushBack(1)
+
+ var l2 List
+ e2 := l2.PushBack(2)
+
+ l1.MoveAfter(e1, e2)
+ checkList(t, &l1, []interface{}{1})
+ checkList(t, &l2, []interface{}{2})
+
+ l1.MoveBefore(e1, e2)
+ checkList(t, &l1, []interface{}{1})
+ checkList(t, &l2, []interface{}{2})
+}
diff --git a/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
index 099d92b25..552f0e24b 100644
--- a/src/pkg/container/ring/ring_test.go
+++ b/src/pkg/container/ring/ring_test.go
@@ -218,3 +218,11 @@ func TestLinkUnlink(t *testing.T) {
}
}
}
+
+// Test that calling Move() on an empty Ring initializes it.
+func TestMoveEmptyRing(t *testing.T) {
+ var r Ring
+
+ r.Move(1)
+ verify(t, &r, 1, 0)
+}
diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
index 6261dd09f..363180931 100644
--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -354,6 +354,34 @@ func TestCipherDecrypt(t *testing.T) {
}
}
+// Test short input/output.
+// Assembly used to not notice.
+// See issue 7928.
+func TestShortBlocks(t *testing.T) {
+ bytes := func(n int) []byte { return make([]byte, n) }
+
+ c, _ := NewCipher(bytes(16))
+
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Encrypt(bytes(1), bytes(100)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Decrypt(bytes(1), bytes(100)) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("function did not panic, wanted %q", msg)
+ } else if err != msg {
+ t.Errorf("got panic %v, wanted %q", err, msg)
+ }
+ }()
+ f()
+}
+
func BenchmarkEncrypt(b *testing.B) {
tt := encryptTests[0]
c, err := NewCipher(tt.key)
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index d931134a7..2c6bb0a89 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/crypto/aes/cipher.go
@@ -46,9 +46,21 @@ func NewCipher(key []byte) (cipher.Block, error) {
func (c *aesCipher) BlockSize() int { return BlockSize }
func (c *aesCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
encryptBlock(c.enc, dst, src)
}
func (c *aesCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
decryptBlock(c.dec, dst, src)
}
diff --git a/src/pkg/crypto/aes/cipher_asm.go b/src/pkg/crypto/aes/cipher_asm.go
index 21369fc38..964eaaa6f 100644
--- a/src/pkg/crypto/aes/cipher_asm.go
+++ b/src/pkg/crypto/aes/cipher_asm.go
@@ -21,6 +21,7 @@ func encryptBlock(xk []uint32, dst, src []byte) {
encryptBlockGo(xk, dst, src)
}
}
+
func decryptBlock(xk []uint32, dst, src []byte) {
if useAsm {
decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
@@ -28,6 +29,7 @@ func decryptBlock(xk []uint32, dst, src []byte) {
decryptBlockGo(xk, dst, src)
}
}
+
func expandKey(key []byte, enc, dec []uint32) {
if useAsm {
rounds := 10
diff --git a/src/pkg/crypto/cipher/benchmark_test.go b/src/pkg/crypto/cipher/benchmark_test.go
new file mode 100644
index 000000000..027b24851
--- /dev/null
+++ b/src/pkg/crypto/cipher/benchmark_test.go
@@ -0,0 +1,139 @@
+// 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 cipher_test
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+func BenchmarkAESGCMSeal1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var nonce [12]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+ }
+}
+
+func BenchmarkAESGCMOpen1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var nonce [12]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+ out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := aesgcm.Open(buf[:0], nonce[:], out, nonce[:])
+ if err != nil {
+ b.Errorf("Open: %v", err)
+ }
+ }
+}
+
+// If we test exactly 1K blocks, we would generate exact multiples of
+// the cipher's block size, and the cipher stream fragments would
+// always be wordsize aligned, whereas non-aligned is a more typical
+// use-case.
+const almost1K = 1024 - 5
+
+func BenchmarkAESCFBEncrypt1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCFBEncrypter(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCFBDecrypt1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCFBDecrypter(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESOFB1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewOFB(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCTR1K(b *testing.B) {
+ buf := make([]byte, almost1K)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ ctr := cipher.NewCTR(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkAESCBCEncrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCEncrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
+
+func BenchmarkAESCBCDecrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCDecrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
index 4189677e3..241e122ee 100644
--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -48,17 +48,22 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
+
+ iv := x.iv
+
for len(src) > 0 {
- for i := 0; i < x.blockSize; i++ {
- x.iv[i] ^= src[i]
- }
- x.b.Encrypt(x.iv, x.iv)
- for i := 0; i < x.blockSize; i++ {
- dst[i] = x.iv[i]
- }
+ // Write the xor to dst, then encrypt in place.
+ xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
+ x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
+
+ // Move to the next block with this block as the next iv.
+ iv = dst[:x.blockSize]
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
+
+ // Save the iv for the next CryptBlocks call.
+ copy(x.iv, iv)
}
func (x *cbcEncrypter) SetIV(iv []byte) {
@@ -89,17 +94,35 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
- for len(src) > 0 {
- x.b.Decrypt(x.tmp, src[:x.blockSize])
- for i := 0; i < x.blockSize; i++ {
- x.tmp[i] ^= x.iv[i]
- x.iv[i] = src[i]
- dst[i] = x.tmp[i]
- }
+ if len(src) == 0 {
+ return
+ }
- src = src[x.blockSize:]
- dst = dst[x.blockSize:]
+ // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
+ // To avoid making a copy each time, we loop over the blocks BACKWARDS.
+ end := len(src)
+ start := end - x.blockSize
+ prev := start - x.blockSize
+
+ // Copy the last block of ciphertext in preparation as the new iv.
+ copy(x.tmp, src[start:end])
+
+ // Loop over all but the first block.
+ for start > 0 {
+ x.b.Decrypt(dst[start:end], src[start:end])
+ xorBytes(dst[start:end], dst[start:end], src[prev:start])
+
+ end = start
+ start = prev
+ prev -= x.blockSize
}
+
+ // The first block is special because it uses the saved iv.
+ x.b.Decrypt(dst[start:end], src[start:end])
+ xorBytes(dst[start:end], dst[start:end], x.iv)
+
+ // Set the new iv to the first block we copied earlier.
+ x.iv, x.tmp = x.tmp, x.iv
}
func (x *cbcDecrypter) SetIV(iv []byte) {
diff --git a/src/pkg/crypto/cipher/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
index cee3a784b..bf9e7ad70 100644
--- a/src/pkg/crypto/cipher/cbc_aes_test.go
+++ b/src/pkg/crypto/cipher/cbc_aes_test.go
@@ -63,28 +63,42 @@ var cbcAESTests = []struct {
},
}
-func TestCBC_AES(t *testing.T) {
- for _, tt := range cbcAESTests {
- test := tt.name
-
- c, err := aes.NewCipher(tt.key)
+func TestCBCEncrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
if err != nil {
- t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
- encrypter := cipher.NewCBCEncrypter(c, tt.iv)
- d := make([]byte, len(tt.in))
- encrypter.CryptBlocks(d, tt.in)
- if !bytes.Equal(tt.out, d) {
- t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+ encrypter := cipher.NewCBCEncrypter(c, test.iv)
+
+ data := make([]byte, len(test.in))
+ copy(data, test.in)
+
+ encrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.out, data) {
+ t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
}
+ }
+}
+
+func TestCBCDecrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
+ continue
+ }
+
+ decrypter := cipher.NewCBCDecrypter(c, test.iv)
+
+ data := make([]byte, len(test.out))
+ copy(data, test.out)
- decrypter := cipher.NewCBCDecrypter(c, tt.iv)
- p := make([]byte, len(d))
- decrypter.CryptBlocks(p, d)
- if !bytes.Equal(tt.in, p) {
- t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+ decrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.in, data) {
+ t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
}
}
}
diff --git a/src/pkg/crypto/cipher/cfb.go b/src/pkg/crypto/cipher/cfb.go
index 99006b546..9b4eebf5b 100644
--- a/src/pkg/crypto/cipher/cfb.go
+++ b/src/pkg/crypto/cipher/cfb.go
@@ -8,18 +8,41 @@ package cipher
type cfb struct {
b Block
+ next []byte
out []byte
outUsed int
+
decrypt bool
}
+func (x *cfb) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.next)
+ x.outUsed = 0
+ }
+
+ if x.decrypt {
+ // We can precompute a larger segment of the
+ // keystream on decryption. This will allow
+ // larger batches for xor, and we should be
+ // able to match CTR/OFB performance.
+ copy(x.next[x.outUsed:], src)
+ }
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ if !x.decrypt {
+ copy(x.next[x.outUsed:], dst)
+ }
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
+ }
+}
+
// NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
// using the given Block. The iv must be the same length as the Block's block
// size.
func NewCFBEncrypter(block Block, iv []byte) Stream {
- if len(iv) != block.BlockSize() {
- panic("cipher.NewCBFEncrypter: IV length must equal block size")
- }
return newCFB(block, iv, false)
}
@@ -27,44 +50,23 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
// using the given Block. The iv must be the same length as the Block's block
// size.
func NewCFBDecrypter(block Block, iv []byte) Stream {
- if len(iv) != block.BlockSize() {
- panic("cipher.NewCBFEncrypter: IV length must equal block size")
- }
return newCFB(block, iv, true)
}
func newCFB(block Block, iv []byte, decrypt bool) Stream {
blockSize := block.BlockSize()
if len(iv) != blockSize {
- return nil
+ // stack trace will indicate whether it was de or encryption
+ panic("cipher.newCFB: IV length must equal block size")
}
-
x := &cfb{
b: block,
out: make([]byte, blockSize),
- outUsed: 0,
+ next: make([]byte, blockSize),
+ outUsed: blockSize,
decrypt: decrypt,
}
- block.Encrypt(x.out, iv)
+ copy(x.next, iv)
return x
}
-
-func (x *cfb) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.out) {
- x.b.Encrypt(x.out, x.out)
- x.outUsed = 0
- }
-
- if x.decrypt {
- t := src[i]
- dst[i] = src[i] ^ x.out[x.outUsed]
- x.out[x.outUsed] = t
- } else {
- x.out[x.outUsed] ^= src[i]
- dst[i] = x.out[x.outUsed]
- }
- x.outUsed++
- }
-}
diff --git a/src/pkg/crypto/cipher/cfb_test.go b/src/pkg/crypto/cipher/cfb_test.go
index f704b337e..ec708ab2b 100644
--- a/src/pkg/crypto/cipher/cfb_test.go
+++ b/src/pkg/crypto/cipher/cfb_test.go
@@ -19,16 +19,18 @@ func TestCFB(t *testing.T) {
return
}
- plaintext := []byte("this is the plaintext")
+ plaintext := []byte("this is the plaintext. this is the plaintext.")
iv := make([]byte, block.BlockSize())
rand.Reader.Read(iv)
cfb := cipher.NewCFBEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
- cfb.XORKeyStream(ciphertext, plaintext)
+ copy(ciphertext, plaintext)
+ cfb.XORKeyStream(ciphertext, ciphertext)
cfbdec := cipher.NewCFBDecrypter(block, iv)
plaintextCopy := make([]byte, len(plaintext))
- cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+ copy(plaintextCopy, ciphertext)
+ cfbdec.XORKeyStream(plaintextCopy, plaintextCopy)
if !bytes.Equal(plaintextCopy, plaintext) {
t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
diff --git a/src/pkg/crypto/cipher/cipher.go b/src/pkg/crypto/cipher/cipher.go
index 1ffaa8c2c..67afdb1e0 100644
--- a/src/pkg/crypto/cipher/cipher.go
+++ b/src/pkg/crypto/cipher/cipher.go
@@ -46,16 +46,6 @@ type BlockMode interface {
// Utility routines
-func shift1(dst, src []byte) byte {
- var b byte
- for i := len(src) - 1; i >= 0; i-- {
- bb := src[i] >> 7
- dst[i] = src[i]<<1 | b
- b = bb
- }
- return b
-}
-
func dup(p []byte) []byte {
q := make([]byte, len(p))
copy(q, p)
diff --git a/src/pkg/crypto/cipher/ctr.go b/src/pkg/crypto/cipher/ctr.go
index d9ee9d827..70ac40f6a 100644
--- a/src/pkg/crypto/cipher/ctr.go
+++ b/src/pkg/crypto/cipher/ctr.go
@@ -19,37 +19,58 @@ type ctr struct {
outUsed int
}
+const streamBufferSize = 512
+
// NewCTR returns a Stream which encrypts/decrypts using the given Block in
// counter mode. The length of iv must be the same as the Block's block size.
func NewCTR(block Block, iv []byte) Stream {
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: IV length must equal block size")
}
-
+ bufSize := streamBufferSize
+ if bufSize < block.BlockSize() {
+ bufSize = block.BlockSize()
+ }
return &ctr{
b: block,
ctr: dup(iv),
- out: make([]byte, len(iv)),
- outUsed: len(iv),
+ out: make([]byte, 0, bufSize),
+ outUsed: 0,
}
}
-func (x *ctr) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.ctr) {
- x.b.Encrypt(x.out, x.ctr)
- x.outUsed = 0
-
- // Increment counter
- for i := len(x.ctr) - 1; i >= 0; i-- {
- x.ctr[i]++
- if x.ctr[i] != 0 {
- break
- }
+func (x *ctr) refill() {
+ remain := len(x.out) - x.outUsed
+ if remain > x.outUsed {
+ return
+ }
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ bs := x.b.BlockSize()
+ for remain < len(x.out)-bs {
+ x.b.Encrypt(x.out[remain:], x.ctr)
+ remain += bs
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
}
}
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
- dst[i] = src[i] ^ x.out[x.outUsed]
- x.outUsed++
+func (x *ctr) XORKeyStream(dst, src []byte) {
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
+ }
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
}
}
diff --git a/src/pkg/crypto/cipher/gcm.go b/src/pkg/crypto/cipher/gcm.go
index 2bcb46985..bdafd85fc 100644
--- a/src/pkg/crypto/cipher/gcm.go
+++ b/src/pkg/crypto/cipher/gcm.go
@@ -30,9 +30,9 @@ type AEAD interface {
// Open decrypts and authenticates ciphertext, authenticates the
// additional data and, if successful, appends the resulting plaintext
- // to dst, returning the updated slice and true. On error, nil and
- // false is returned. The nonce must be NonceSize() bytes long and both
- // it and the additional data must match the value passed to Seal.
+ // to dst, returning the updated slice. The nonce must be NonceSize()
+ // bytes long and both it and the additional data must match the
+ // value passed to Seal.
//
// The ciphertext and dst may alias exactly or not at all.
Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
@@ -258,11 +258,11 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) {
// gcmInc32 treats the final four bytes of counterBlock as a big-endian value
// and increments it.
func gcmInc32(counterBlock *[16]byte) {
- c := 1
for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- {
- c += int(counterBlock[i])
- counterBlock[i] = byte(c)
- c >>= 8
+ counterBlock[i]++
+ if counterBlock[i] != 0 {
+ break
+ }
}
}
@@ -289,9 +289,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
- for i := range mask {
- out[i] = in[i] ^ mask[i]
- }
+ xorWords(out, in, mask[:])
out = out[gcmBlockSize:]
in = in[gcmBlockSize:]
}
@@ -299,10 +297,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
if len(in) > 0 {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
-
- for i := range in {
- out[i] = in[i] ^ mask[i]
- }
+ xorBytes(out, in, mask[:])
}
}
@@ -321,9 +316,7 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]
putUint64(out, y.low)
putUint64(out[8:], y.high)
- for i := range tagMask {
- out[i] ^= tagMask[i]
- }
+ xorWords(out, out, tagMask[:])
}
func getUint64(data []byte) uint64 {
diff --git a/src/pkg/crypto/cipher/gcm_test.go b/src/pkg/crypto/cipher/gcm_test.go
index 02d421590..0c502ce40 100644
--- a/src/pkg/crypto/cipher/gcm_test.go
+++ b/src/pkg/crypto/cipher/gcm_test.go
@@ -157,19 +157,3 @@ func TestAESGCM(t *testing.T) {
ct[0] ^= 0x80
}
}
-
-func BenchmarkAESGCM(b *testing.B) {
- buf := make([]byte, 1024)
- b.SetBytes(int64(len(buf)))
-
- var key [16]byte
- var nonce [12]byte
- aes, _ := aes.NewCipher(key[:])
- aesgcm, _ := cipher.NewGCM(aes)
- var out []byte
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
- }
-}
diff --git a/src/pkg/crypto/cipher/ofb.go b/src/pkg/crypto/cipher/ofb.go
index 85e5f02b0..e86ebcb23 100644
--- a/src/pkg/crypto/cipher/ofb.go
+++ b/src/pkg/crypto/cipher/ofb.go
@@ -8,6 +8,7 @@ package cipher
type ofb struct {
b Block
+ cipher []byte
out []byte
outUsed int
}
@@ -20,25 +21,46 @@ func NewOFB(b Block, iv []byte) Stream {
if len(iv) != blockSize {
return nil
}
-
+ bufSize := streamBufferSize
+ if bufSize < blockSize {
+ bufSize = blockSize
+ }
x := &ofb{
b: b,
- out: make([]byte, blockSize),
+ cipher: make([]byte, blockSize),
+ out: make([]byte, 0, bufSize),
outUsed: 0,
}
- b.Encrypt(x.out, iv)
+ copy(x.cipher, iv)
return x
}
+func (x *ofb) refill() {
+ bs := x.b.BlockSize()
+ remain := len(x.out) - x.outUsed
+ if remain > x.outUsed {
+ return
+ }
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ for remain < len(x.out)-bs {
+ x.b.Encrypt(x.cipher, x.cipher)
+ copy(x.out[remain:], x.cipher)
+ remain += bs
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
+
func (x *ofb) XORKeyStream(dst, src []byte) {
- for i, s := range src {
- if x.outUsed == len(x.out) {
- x.b.Encrypt(x.out, x.out)
- x.outUsed = 0
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
}
-
- dst[i] = s ^ x.out[x.outUsed]
- x.outUsed++
+ n := xorBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
}
}
diff --git a/src/pkg/crypto/cipher/xor.go b/src/pkg/crypto/cipher/xor.go
new file mode 100644
index 000000000..f88dc8914
--- /dev/null
+++ b/src/pkg/crypto/cipher/xor.go
@@ -0,0 +1,84 @@
+// 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 cipher
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
+
+// fastXORBytes xors in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+
+ w := n / wordSize
+ if w > 0 {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ for i := 0; i < w; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+ }
+
+ for i := (n - n%wordSize); i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+
+ return n
+}
+
+func safeXORBytes(dst, a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+ for i := 0; i < n; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ return n
+}
+
+// xorBytes xors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes xor'd.
+func xorBytes(dst, a, b []byte) int {
+ if supportsUnaligned {
+ return fastXORBytes(dst, a, b)
+ } else {
+ // TODO(hanwen): if (dst, a, b) have common alignment
+ // we could still try fastXORBytes. It is not clear
+ // how often this happens, and it's only worth it if
+ // the block encryption itself is hardware
+ // accelerated.
+ return safeXORBytes(dst, a, b)
+ }
+}
+
+// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The arguments are assumed to be of equal length.
+func fastXORWords(dst, a, b []byte) {
+ dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+ aw := *(*[]uintptr)(unsafe.Pointer(&a))
+ bw := *(*[]uintptr)(unsafe.Pointer(&b))
+ n := len(b) / wordSize
+ for i := 0; i < n; i++ {
+ dw[i] = aw[i] ^ bw[i]
+ }
+}
+
+func xorWords(dst, a, b []byte) {
+ if supportsUnaligned {
+ fastXORWords(dst, a, b)
+ } else {
+ safeXORBytes(dst, a, b)
+ }
+}
diff --git a/src/pkg/crypto/cipher/xor_test.go b/src/pkg/crypto/cipher/xor_test.go
new file mode 100644
index 000000000..cc1c9d72d
--- /dev/null
+++ b/src/pkg/crypto/cipher/xor_test.go
@@ -0,0 +1,28 @@
+// 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 cipher
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestXOR(t *testing.T) {
+ for alignP := 0; alignP < 2; alignP++ {
+ for alignQ := 0; alignQ < 2; alignQ++ {
+ for alignD := 0; alignD < 2; alignD++ {
+ p := make([]byte, 1024)[alignP:]
+ q := make([]byte, 1024)[alignQ:]
+ d1 := make([]byte, 1024+alignD)[alignD:]
+ d2 := make([]byte, 1024+alignD)[alignD:]
+ xorBytes(d1, p, q)
+ safeXORBytes(d2, p, q)
+ if bytes.Compare(d1, d2) != 0 {
+ t.Error("not equal")
+ }
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index 5a2a65744..b7565a61b 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error {
return nil
}
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+ two := big.NewInt(2)
+ pMinus2 := new(big.Int).Sub(P, two)
+ return new(big.Int).Exp(k, pMinus2, P)
+}
+
// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
@@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
}
}
- kInv := new(big.Int).ModInverse(k, priv.Q)
+ kInv := fermatInverse(k, priv.Q)
r = new(big.Int).Exp(priv.G, k, priv.P)
r.Mod(r, priv.Q)
diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
index d02f15c34..1bec7437a 100644
--- a/src/pkg/crypto/ecdsa/ecdsa.go
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -84,6 +84,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
return ret
}
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, N *big.Int) *big.Int {
+ two := big.NewInt(2)
+ nMinus2 := new(big.Int).Sub(N, two)
+ return new(big.Int).Exp(k, nMinus2, N)
+}
+
// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
@@ -102,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
return
}
- kInv = new(big.Int).ModInverse(k, N)
+ kInv = fermatInverse(k, N)
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
r.Mod(r, N)
if r.Sign() != 0 {
diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go
index d4860424e..e80b7e0ba 100644
--- a/src/pkg/crypto/hmac/hmac_test.go
+++ b/src/pkg/crypto/hmac/hmac_test.go
@@ -15,10 +15,12 @@ import (
)
type hmacTest struct {
- hash func() hash.Hash
- key []byte
- in []byte
- out string
+ hash func() hash.Hash
+ key []byte
+ in []byte
+ out string
+ size int
+ blocksize int
}
var hmacTests = []hmacTest{
@@ -38,6 +40,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #1"),
"4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -48,6 +52,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #2"),
"0922d3405faa3d194f82a45830737d5cc6c75d24",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -68,6 +74,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample #3"),
"bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+ sha1.Size,
+ sha1.BlockSize,
},
// Test from Plan 9.
@@ -76,6 +84,8 @@ var hmacTests = []hmacTest{
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"750c783e6ab0b503eaa86e310a5db738",
+ md5.Size,
+ md5.BlockSize,
},
// Tests from RFC 4231
@@ -88,12 +98,16 @@ var hmacTests = []hmacTest{
},
[]byte("Hi There"),
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -112,6 +126,8 @@ var hmacTests = []hmacTest{
0xdd, 0xdd,
},
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -131,6 +147,8 @@ var hmacTests = []hmacTest{
0xcd, 0xcd,
},
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -155,6 +173,8 @@ var hmacTests = []hmacTest{
},
[]byte("Test Using Larger Than Block-Size Key - Hash Key First"),
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -181,6 +201,8 @@ var hmacTests = []hmacTest{
"and a larger than block-size data. The key needs to " +
"be hashed before being used by the HMAC algorithm."),
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ sha256.Size,
+ sha256.BlockSize,
},
// Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html
@@ -199,6 +221,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"5fd596ee78d5553c8ff4e72d266dfd192366da29",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -209,6 +233,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha1.New,
@@ -229,6 +255,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"2d51b2f7750e410584662e38f133435f4c4fd42a",
+ sha1.Size,
+ sha1.BlockSize,
},
{
sha256.New224,
@@ -244,6 +272,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"c7405e3ae058e8cd30b08b4140248581ed174cb34e1224bcc1efc81b",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New224,
@@ -255,6 +285,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New224,
@@ -275,6 +307,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"91c52509e5af8531601ae6230099d90bef88aaefb961f4080abc014d",
+ sha256.Size224,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -290,6 +324,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -301,6 +337,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha256.New,
@@ -321,6 +359,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d",
+ sha256.Size,
+ sha256.BlockSize,
},
{
sha512.New384,
@@ -344,6 +384,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"63c5daa5e651847ca897c95814ab830bededc7d25e83eef9195cd45857a37f448947858f5af50cc2b1b730ddf29671a9",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New384,
@@ -357,6 +399,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen<blocklen"),
"6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New384,
@@ -389,6 +433,8 @@ var hmacTests = []hmacTest{
},
[]byte("Sample message for keylen=blocklen"),
"5b664436df69b0ca22551231a3f0a3d5b4f97991713cfa84bff4d0792eff96c27dccbbb6f79b65d548b40e8564cef594",
+ sha512.Size384,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -414,6 +460,8 @@ var hmacTests = []hmacTest{
"fc25e240658ca785b7a811a8d3f7b4ca" +
"48cfa26a8a366bf2cd1f836b05fcb024bd36853081811d6c" +
"ea4216ebad79da1cfcb95ea4586b8a0ce356596a55fb1347",
+ sha512.Size,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -431,6 +479,8 @@ var hmacTests = []hmacTest{
"fd44c18bda0bb0a6ce0e82b031bf2818" +
"f6539bd56ec00bdc10a8a2d730b3634de2545d639b0f2cf7" +
"10d0692c72a1896f1f211c2b922d1a96c392e07e7ea9fedc",
+ sha512.Size,
+ sha512.BlockSize,
},
{
sha512.New,
@@ -465,12 +515,20 @@ var hmacTests = []hmacTest{
"d93ec8d2de1ad2a9957cb9b83f14e76a" +
"d6b5e0cce285079a127d3b14bccb7aa7286d4ac0d4ce6421" +
"5f2bc9e6870b33d97438be4aaa20cda5c5a912b48b8e27f3",
+ sha512.Size,
+ sha512.BlockSize,
},
}
func TestHMAC(t *testing.T) {
for i, tt := range hmacTests {
h := New(tt.hash, tt.key)
+ if s := h.Size(); s != tt.size {
+ t.Errorf("Size: got %v, want %v", s, tt.size)
+ }
+ if b := h.BlockSize(); b != tt.blocksize {
+ t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
+ }
for j := 0; j < 2; j++ {
n, err := h.Write(tt.in)
if n != len(tt.in) || err != nil {
diff --git a/src/pkg/crypto/md5/example_test.go b/src/pkg/crypto/md5/example_test.go
index 28be770a7..d47bb4570 100644
--- a/src/pkg/crypto/md5/example_test.go
+++ b/src/pkg/crypto/md5/example_test.go
@@ -17,3 +17,9 @@ func ExampleNew() {
fmt.Printf("%x", h.Sum(nil))
// Output: e2c569be17396eca2a2e3c11578123ed
}
+
+func ExampleSum() {
+ data := []byte("These pretzels are making me thirsty.")
+ fmt.Printf("%x", md5.Sum(data))
+ // Output: b0804ec967f48520697662a204f5fe72
+}
diff --git a/src/pkg/crypto/md5/gen.go b/src/pkg/crypto/md5/gen.go
index ccaa7c13d..75295e4fc 100644
--- a/src/pkg/crypto/md5/gen.go
+++ b/src/pkg/crypto/md5/gen.go
@@ -160,12 +160,13 @@ var data = Data{
},
}
-var program = `
+var program = `// 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.
+
// DO NOT EDIT.
// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
-// +build !amd64,!386,!arm
-
package md5
import (
@@ -201,7 +202,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
index a8b7a1a52..e7faf4961 100644
--- a/src/pkg/crypto/md5/md5_test.go
+++ b/src/pkg/crypto/md5/md5_test.go
@@ -5,6 +5,7 @@
package md5
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -105,6 +106,18 @@ func TestLarge(t *testing.T) {
}
}
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())
diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go
index 3e739e36f..e2a176777 100644
--- a/src/pkg/crypto/md5/md5block.go
+++ b/src/pkg/crypto/md5/md5block.go
@@ -1,8 +1,10 @@
+// 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.
+
// DO NOT EDIT.
// Generate with: go run gen.go -full | gofmt >md5block.go
-// +build !amd64,!386,!arm
-
package md5
import (
@@ -20,7 +22,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
diff --git a/src/pkg/crypto/md5/md5block_amd64p32.s b/src/pkg/crypto/md5/md5block_amd64p32.s
new file mode 100644
index 000000000..a78a3f610
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_amd64p32.s
@@ -0,0 +1,184 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+//
+// Restrictions to make code safe for Native Client:
+// replace BP with R11, reloaded before use at return.
+// replace R15 with R11.
+
+#include "../../../cmd/ld/textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT ·block(SB),NOSPLIT,$0-32
+ MOVL dig+0(FP), R11
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(R11), AX
+ MOVL (1*4)(R11), BX
+ MOVL (2*4)(R11), CX
+ MOVL (3*4)(R11), DX
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R12
+ MOVL BX, R13
+ MOVL CX, R14
+ MOVL DX, R11
+
+ MOVL (0*4)(SI), R8
+ MOVL DX, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, R9; \
+ LEAL const(a)(R8*1), a; \
+ ANDL b, R9; \
+ XORL d, R9; \
+ MOVL (index*4)(SI), R8; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL c, R9; \
+ ADDL b, a
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), R8
+ MOVL DX, R9
+ MOVL DX, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ NOTL R9; \
+ LEAL const(a)(R8*1),a; \
+ ANDL b, R10; \
+ ANDL c, R9; \
+ MOVL (index*4)(SI),R8; \
+ ORL R9, R10; \
+ MOVL c, R9; \
+ ADDL R10, a; \
+ MOVL c, R10; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), R8
+ MOVL CX, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ MOVL (index*4)(SI),R8; \
+ XORL d, R9; \
+ XORL b, R9; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL b, R9; \
+ ADDL b, a
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), R8
+ MOVL $0xffffffff, R9
+ XORL DX, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ ORL b, R9; \
+ XORL c, R9; \
+ ADDL R9, a; \
+ MOVL (index*4)(SI),R8; \
+ MOVL $0xffffffff, R9; \
+ ROLL $shift, a; \
+ XORL c, R9; \
+ ADDL b, a
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL R12, AX
+ ADDL R13, BX
+ ADDL R14, CX
+ ADDL R11, DX
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVL dig+0(FP), R11
+ MOVL AX, (0*4)(R11)
+ MOVL BX, (1*4)(R11)
+ MOVL CX, (2*4)(R11)
+ MOVL DX, (3*4)(R11)
+ RET
diff --git a/src/pkg/crypto/md5/md5block_decl.go b/src/pkg/crypto/md5/md5block_decl.go
index c4d6aaaf0..d7956a6d2 100644
--- a/src/pkg/crypto/md5/md5block_decl.go
+++ b/src/pkg/crypto/md5/md5block_decl.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 386 arm
+// +build amd64 amd64p32 386 arm
package md5
diff --git a/src/pkg/crypto/md5/md5block_generic.go b/src/pkg/crypto/md5/md5block_generic.go
new file mode 100644
index 000000000..263463e51
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!amd64p32,!386,!arm
+
+package md5
+
+var block = blockGeneric
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
index 238ceee55..1e741fda1 100644
--- a/src/pkg/crypto/rand/rand_unix.go
+++ b/src/pkg/crypto/rand/rand_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd plan9
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
// Unix cryptographically secure pseudorandom number
// generator.
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
index 0cd5e0e02..5f7440785 100644
--- a/src/pkg/crypto/rand/util.go
+++ b/src/pkg/crypto/rand/util.go
@@ -27,9 +27,11 @@ var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)
// Prime returns a number, p, of the given size, such that p is prime
// with high probability.
+// Prime will return error for any error returned by rand.Read or if bits < 2.
func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
- if bits < 1 {
- err = errors.New("crypto/rand: prime size must be positive")
+ if bits < 2 {
+ err = errors.New("crypto/rand: prime size must be at least 2-bit")
+ return
}
b := uint(bits % 8)
@@ -79,7 +81,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
for delta := uint64(0); delta < 1<<20; delta += 2 {
m := mod + delta
for _, prime := range smallPrimes {
- if m%uint64(prime) == 0 {
+ if m%uint64(prime) == 0 && (bits > 6 || m != uint64(prime)) {
continue NextDelta
}
}
diff --git a/src/pkg/crypto/rand/util_test.go b/src/pkg/crypto/rand/util_test.go
new file mode 100644
index 000000000..1e2a4dd84
--- /dev/null
+++ b/src/pkg/crypto/rand/util_test.go
@@ -0,0 +1,65 @@
+// 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 rand_test
+
+import (
+ "crypto/rand"
+ "math/big"
+ "testing"
+)
+
+// http://golang.org/issue/6849.
+func TestPrimeSmall(t *testing.T) {
+ for n := 2; n < 10; n++ {
+ p, err := rand.Prime(rand.Reader, n)
+ if err != nil {
+ t.Fatalf("Can't generate %d-bit prime: %v", n, err)
+ }
+ if p.BitLen() != n {
+ t.Fatalf("%v is not %d-bit", p, n)
+ }
+ if !p.ProbablyPrime(32) {
+ t.Fatalf("%v is not prime", p)
+ }
+ }
+}
+
+// Test that passing bits < 2 causes Prime to return nil, error
+func TestPrimeBitsLt2(t *testing.T) {
+ if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
+ t.Errorf("Prime should return nil, error when called with bits < 2")
+ }
+}
+
+func TestInt(t *testing.T) {
+ // start at 128 so the case of (max.BitLen() % 8) == 0 is covered
+ for n := 128; n < 140; n++ {
+ b := new(big.Int).SetInt64(int64(n))
+ if i, err := rand.Int(rand.Reader, b); err != nil {
+ t.Fatalf("Can't generate random value: %v, %v", i, err)
+ }
+ }
+}
+
+func testIntPanics(t *testing.T, b *big.Int) {
+ defer func() {
+ if err := recover(); err == nil {
+ t.Errorf("Int should panic when called with max <= 0: %v", b)
+ }
+ }()
+ rand.Int(rand.Reader, b)
+}
+
+// Test that passing a new big.Int as max causes Int to panic
+func TestIntEmptyMaxPanics(t *testing.T) {
+ b := new(big.Int)
+ testIntPanics(t, b)
+}
+
+// Test that passing a negative value as max causes Int to panic
+func TestIntNegativeMaxPanics(t *testing.T) {
+ b := new(big.Int).SetInt64(int64(-1))
+ testIntPanics(t, b)
+}
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index 3d717c63b..9acb681bf 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -50,3 +50,20 @@ func (c *Cipher) Reset() {
}
c.i, c.j = 0, 0
}
+
+// xorKeyStreamGeneric sets dst to the result of XORing src with the
+// key stream. Dst and src may be the same slice but otherwise should
+// not overlap.
+//
+// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
+// implementations. This is here for tests and to prevent bitrot.
+func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
+ i, j := c.i, c.j
+ for k, v := range src {
+ i += 1
+ j += uint8(c.s[i])
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ dst[k] = v ^ uint8(c.s[uint8(c.s[i]+c.s[j])])
+ }
+ c.i, c.j = i, j
+}
diff --git a/src/pkg/crypto/rc4/rc4_amd64p32.s b/src/pkg/crypto/rc4/rc4_amd64p32.s
new file mode 100644
index 000000000..27d849507
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_amd64p32.s
@@ -0,0 +1,192 @@
+// Original source:
+// http://www.zorinaq.com/papers/rc4-amd64.html
+// http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+#include "../../../cmd/ld/textflag.h"
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+//
+// Converted to amd64p32.
+//
+// To make safe for Native Client, avoid use of BP, R15,
+// and two-register addressing modes.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
+
+TEXT ·xorKeyStream(SB),NOSPLIT,$0
+ MOVL n+8(FP), BX // rbx = ARG(len)
+ MOVL src+4(FP), SI // in = ARG(in)
+ MOVL dst+0(FP), DI // out = ARG(out)
+ MOVL state+12(FP), R10 // d = ARG(data)
+ MOVL i+16(FP), AX
+ MOVBQZX 0(AX), CX // x = *xp
+ MOVL j+20(FP), AX
+ MOVBQZX 0(AX), DX // y = *yp
+
+ LEAQ (SI)(BX*1), R9 // limit = in+len
+
+l1: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
+
+ INCB CX
+ EXTEND(CX)
+ TESTL $15, CX
+ JZ wordloop
+ LEAL (R10)(CX*4), R12
+
+ MOVBLZX (R12), AX
+
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ LEAL (R10)(DX*4), R11
+ MOVBLZX (R11), BX // ty = d[y]
+ MOVB BX, (R12) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ LEAL (R10)(BX*4), R13
+ MOVB AX, (R11) // d[y] = tx
+ MOVBLZX (R13), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l1
+
+wordloop:
+ SUBQ $16, R9
+ CMPQ SI, R9
+ JGT end
+
+start:
+ ADDQ $16, SI // increment in
+ ADDQ $16, DI // increment out
+
+ // Each KEYROUND generates one byte of key and
+ // inserts it into an XMM register at the given 16-bit index.
+ // The key state array is uint32 words only using the bottom
+ // byte of each word, so the 16-bit OR only copies 8 useful bits.
+ // We accumulate alternating bytes into X0 and X1, and then at
+ // the end we OR X1<<8 into X0 to produce the actual key.
+ //
+ // At the beginning of the loop, CX%16 == 0, so the 16 loads
+ // at state[CX], state[CX+1], ..., state[CX+15] can precompute
+ // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+ // without fear of the byte computation CX+15 wrapping around.
+ //
+ // The first round needs R12[0], the second needs R12[1], and so on.
+ // We can avoid memory stalls by starting the load for round n+1
+ // before the end of round n, using the LOAD macro.
+ LEAQ (R10)(CX*4), R12
+
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+ LEAL (R10)(DX*4), R11; \
+ MOVBLZX (R11), R8; \
+ MOVB r1, (R11); \
+ load((off+1), r2); \
+ MOVB R8, (off*4)(R12); \
+ ADDB r1, R8; \
+ EXTEND(R8); \
+ LEAL (R10)(R8*4), R14; \
+ PINSRW $index, (R14), xmm
+
+#define LOAD(off, reg) \
+ MOVBLZX (off*4)(R12), reg; \
+ ADDB reg, DX; \
+ EXTEND(DX)
+
+#define SKIP(off, reg)
+
+ LOAD(0, AX)
+ KEYROUND(X0, LOAD, 0, AX, BX, 0)
+ KEYROUND(X1, LOAD, 1, BX, AX, 0)
+ KEYROUND(X0, LOAD, 2, AX, BX, 1)
+ KEYROUND(X1, LOAD, 3, BX, AX, 1)
+ KEYROUND(X0, LOAD, 4, AX, BX, 2)
+ KEYROUND(X1, LOAD, 5, BX, AX, 2)
+ KEYROUND(X0, LOAD, 6, AX, BX, 3)
+ KEYROUND(X1, LOAD, 7, BX, AX, 3)
+ KEYROUND(X0, LOAD, 8, AX, BX, 4)
+ KEYROUND(X1, LOAD, 9, BX, AX, 4)
+ KEYROUND(X0, LOAD, 10, AX, BX, 5)
+ KEYROUND(X1, LOAD, 11, BX, AX, 5)
+ KEYROUND(X0, LOAD, 12, AX, BX, 6)
+ KEYROUND(X1, LOAD, 13, BX, AX, 6)
+ KEYROUND(X0, LOAD, 14, AX, BX, 7)
+ KEYROUND(X1, SKIP, 15, BX, AX, 7)
+
+ ADDB $16, CX
+
+ PSLLQ $8, X1
+ PXOR X1, X0
+ MOVOU -16(SI), X2
+ PXOR X0, X2
+ MOVOU X2, -16(DI)
+
+ CMPQ SI, R9 // cmp in with in+len-16
+ JLE start // jump if (in <= in+len-16)
+
+end:
+ DECB CX
+ ADDQ $16, R9 // tmp = in+len
+
+ // handle the last bytes, one by one
+l2: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
+
+ INCB CX
+ EXTEND(CX)
+ LEAL (R10)(CX*4), R12
+ MOVBLZX (R12), AX
+
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ LEAL (R10)(DX*4), R11
+ MOVBLZX (R11), BX // ty = d[y]
+ MOVB BX, (R12) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ LEAL (R10)(BX*4), R13
+ MOVB AX, (R11) // d[y] = tx
+ MOVBLZX (R13), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l2
+
+finished:
+ MOVL j+20(FP), BX
+ MOVB DX, 0(BX)
+ MOVL i+16(FP), AX
+ MOVB CX, 0(AX)
+ RET
diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go
index c582a4488..fc71b9a6f 100644
--- a/src/pkg/crypto/rc4/rc4_asm.go
+++ b/src/pkg/crypto/rc4/rc4_asm.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
package rc4
diff --git a/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go
index 44d380436..1ecce1a7f 100644
--- a/src/pkg/crypto/rc4/rc4_ref.go
+++ b/src/pkg/crypto/rc4/rc4_ref.go
@@ -2,19 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!arm,!386
+// +build !amd64,!amd64p32,!arm,!386
package rc4
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
- i, j := c.i, c.j
- for k, v := range src {
- i += 1
- j += c.s[i]
- c.s[i], c.s[j] = c.s[j], c.s[i]
- dst[k] = v ^ c.s[c.s[i]+c.s[j]]
- }
- c.i, c.j = i, j
+ c.xorKeyStreamGeneric(dst, src)
}
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 7b4df6791..af7988246 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -117,19 +117,30 @@ func TestGolden(t *testing.T) {
}
func TestBlock(t *testing.T) {
+ testBlock(t, (*Cipher).XORKeyStream)
+}
+
+// Test the pure Go version.
+// Because we have assembly for amd64, 386, and arm, this prevents
+// bitrot of the reference implementations.
+func TestBlockGeneric(t *testing.T) {
+ testBlock(t, (*Cipher).xorKeyStreamGeneric)
+}
+
+func testBlock(t *testing.T, xor func(c *Cipher, dst, src []byte)) {
c1a, _ := NewCipher(golden[0].key)
c1b, _ := NewCipher(golden[1].key)
data1 := make([]byte, 1<<20)
for i := range data1 {
- c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
- c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ xor(c1a, data1[i:i+1], data1[i:i+1])
+ xor(c1b, data1[i:i+1], data1[i:i+1])
}
c2a, _ := NewCipher(golden[0].key)
c2b, _ := NewCipher(golden[1].key)
data2 := make([]byte, 1<<20)
- c2a.XORKeyStream(data2, data2)
- c2b.XORKeyStream(data2, data2)
+ xor(c2a, data2, data2)
+ xor(c2b, data2, data2)
if !bytes.Equal(data1, data2) {
t.Fatalf("bad block")
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 1a055a3d6..d9957aec1 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -176,7 +176,8 @@ var hashPrefixes = map[crypto.Hash][]byte{
// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
// Note that hashed must be the result of hashing the input message using the
-// given hash function.
+// given hash function. If hash is zero, hashed is signed directly. This isn't
+// advisable except for interoperability.
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
@@ -212,7 +213,8 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
// hashed is the result of hashing the input message using the given hash
// function and sig is the signature. A valid signature is indicated by
-// returning a nil error.
+// returning a nil error. If hash is zero then hashed is used directly. This
+// isn't advisable except for interoperability.
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
@@ -249,6 +251,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
}
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
+ // Special case: crypto.Hash(0) is used to indicate that the data is
+ // signed directly.
+ if hash == 0 {
+ return inLen, nil, nil
+ }
+
hashLen = hash.Size()
if inLen != hashLen {
return 0, nil, errors.New("crypto/rsa: input must be hashed message")
diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
index 70bb22889..37c14d1d9 100644
--- a/src/pkg/crypto/rsa/pkcs1v15_test.go
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -205,6 +205,28 @@ func TestOverlongMessagePKCS1v15(t *testing.T) {
}
}
+func TestUnpaddedSignature(t *testing.T) {
+ msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
+ // This base64 value was generated with:
+ // % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
+ // % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
+ //
+ // Where "key" contains the RSA private key given at the bottom of this
+ // file.
+ expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
+
+ sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
+ if err != nil {
+ t.Fatalf("SignPKCS1v15 failed: %s", err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
+ }
+ if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
+ t.Fatalf("signature failed to verify: %s", err)
+ }
+}
+
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
diff --git a/src/pkg/crypto/rsa/pss.go b/src/pkg/crypto/rsa/pss.go
index f9abec394..18eafbc05 100644
--- a/src/pkg/crypto/rsa/pss.go
+++ b/src/pkg/crypto/rsa/pss.go
@@ -4,7 +4,7 @@
package rsa
-// This file implementes the PSS signature scheme [1].
+// This file implements the PSS signature scheme [1].
//
// [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf
@@ -189,7 +189,7 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
// signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt.
// Note that hashed must be the result of hashing the input message using the
-// given hash funcion. salt is a random sequence of bytes whose length will be
+// given hash function. salt is a random sequence of bytes whose length will be
// later used to verify the signature.
func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) {
nBits := priv.N.BitLen()
@@ -233,7 +233,7 @@ func (opts *PSSOptions) saltLength() int {
// SignPSS calculates the signature of hashed using RSASSA-PSS [1].
// Note that hashed must be the result of hashing the input message using the
-// given hash funcion. The opts argument may be nil, in which case sensible
+// given hash function. The opts argument may be nil, in which case sensible
// defaults are used.
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) {
saltLength := opts.saltLength()
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index c7353ea31..bce6ba4eb 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -60,7 +60,7 @@ type PrivateKey struct {
type PrecomputedValues struct {
Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
- Qinv *big.Int // Q^-1 mod Q
+ Qinv *big.Int // Q^-1 mod P
// CRTValues is used for the 3rd and subsequent primes. Due to a
// historical accident, the CRT for the first two primes is handled
@@ -120,16 +120,18 @@ func (priv *PrivateKey) Validate() error {
return nil
}
-// GenerateKey generates an RSA keypair of the given bit size.
+// GenerateKey generates an RSA keypair of the given bit size using the
+// random source random (for example, crypto/rand.Reader).
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
return GenerateMultiPrimeKey(random, 2, bits)
}
// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
-// size, as suggested in [1]. Although the public keys are compatible
-// (actually, indistinguishable) from the 2-prime case, the private keys are
-// not. Thus it may not be possible to export multi-prime private keys in
-// certain formats or to subsequently import them into other code.
+// size and the given random source, as suggested in [1]. Although the public
+// keys are compatible (actually, indistinguishable) from the 2-prime case,
+// the private keys are not. Thus it may not be possible to export multi-prime
+// private keys in certain formats or to subsequently import them into other
+// code.
//
// Table 1 in [2] suggests maximum numbers of primes for a given size.
//
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index cf193c669..4ee1c3a8b 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -197,7 +197,7 @@ func TestEncryptOAEP(t *testing.T) {
public := PublicKey{n, test.e}
for j, message := range test.msgs {
- randomSource := bytes.NewBuffer(message.seed)
+ randomSource := bytes.NewReader(message.seed)
out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
if err != nil {
t.Errorf("#%d,%d error: %s", i, j, err)
diff --git a/src/pkg/crypto/sha1/example_test.go b/src/pkg/crypto/sha1/example_test.go
index 25fe5f308..42aec8afa 100644
--- a/src/pkg/crypto/sha1/example_test.go
+++ b/src/pkg/crypto/sha1/example_test.go
@@ -12,7 +12,14 @@ import (
func ExampleNew() {
h := sha1.New()
- io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+ io.WriteString(h, "His money is twice tainted:")
+ io.WriteString(h, " 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
}
+
+func ExampleSum() {
+ data := []byte("This page intentionally left blank.")
+ fmt.Printf("% x", sha1.Sum(data))
+ // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 8eb3f7a79..9f1a96e36 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -62,16 +62,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index c3868d702..4a629518b 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -7,6 +7,7 @@
package sha1
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -76,6 +77,32 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
index 92224fc0e..fde3c981c 100644
--- a/src/pkg/crypto/sha1/sha1block.go
+++ b/src/pkg/crypto/sha1/sha1block.go
@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!386
-
-// SHA1 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
package sha1
const (
@@ -17,7 +11,9 @@ const (
_K3 = 0xCA62C1D6
)
-func block(dig *digest, p []byte) {
+// blockGeneric is a portable, pure Go version of the SHA1 block step.
+// It's used by sha1block_generic.go and tests.
+func blockGeneric(dig *digest, p []byte) {
var w [16]uint32
h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
diff --git a/src/pkg/crypto/sha1/sha1block_386.s b/src/pkg/crypto/sha1/sha1block_386.s
index 890b3ae81..688851c31 100644
--- a/src/pkg/crypto/sha1/sha1block_386.s
+++ b/src/pkg/crypto/sha1/sha1block_386.s
@@ -46,12 +46,10 @@
ADDL DI, e
#define FUNC1(a, b, c, d, e) \
- MOVL b, SI; \
- ANDL c, SI; \
- MOVL b, DI; \
- NOTL DI; \
- ANDL d, DI; \
- ORL SI, DI
+ MOVL d, DI; \
+ XORL c, DI; \
+ ANDL b, DI; \
+ XORL d, DI
#define FUNC2(a, b, c, d, e) \
MOVL b, DI; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64.s b/src/pkg/crypto/sha1/sha1block_amd64.s
index 0bb6c204c..8ffb9d5d6 100644
--- a/src/pkg/crypto/sha1/sha1block_amd64.s
+++ b/src/pkg/crypto/sha1/sha1block_amd64.s
@@ -34,12 +34,10 @@
MOVL R10, (((index)&0xf)*4)(SP)
#define FUNC1(a, b, c, d, e) \
- MOVL b, R8; \
- ANDL c, R8; \
- MOVL b, R9; \
- NOTL R9; \
- ANDL d, R9; \
- ORL R8, R9
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
#define FUNC2(a, b, c, d, e) \
MOVL b, R9; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644
index 000000000..3c589d94f
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64p32.s
@@ -0,0 +1,216 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+ MOVL (index*4)(SI), R10; \
+ BSWAPL R10; \
+ MOVL R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+ MOVL (((index)&0xf)*4)(SP), R10; \
+ XORL (((index-3)&0xf)*4)(SP), R10; \
+ XORL (((index-8)&0xf)*4)(SP), R10; \
+ XORL (((index-14)&0xf)*4)(SP), R10; \
+ ROLL $1, R10; \
+ MOVL R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, R9; \
+ XORL c, R9; \
+ XORL d, R9
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, R8; \
+ ORL c, R8; \
+ ANDL d, R8; \
+ MOVL b, R9; \
+ ANDL c, R9; \
+ ORL R8, R9
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL R9, e; \
+ MOVL a, R8; \
+ ROLL $5, R8; \
+ LEAL const(e)(R10*1), e; \
+ ADDL R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),NOSPLIT,$64-32
+ MOVL dig+0(FP), R14
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(R14), AX
+ MOVL (1*4)(R14), BX
+ MOVL (2*4)(R14), CX
+ MOVL (3*4)(R14), DX
+ MOVL (4*4)(R14), R13
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+ ADDL (0*4)(R14), AX
+ ADDL (1*4)(R14), BX
+ ADDL (2*4)(R14), CX
+ ADDL (3*4)(R14), DX
+ ADDL (4*4)(R14), R13
+
+ MOVL AX, (0*4)(R14)
+ MOVL BX, (1*4)(R14)
+ MOVL CX, (2*4)(R14)
+ MOVL DX, (3*4)(R14)
+ MOVL R13, (4*4)(R14)
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_arm.s b/src/pkg/crypto/sha1/sha1block_arm.s
new file mode 100644
index 000000000..5917e8b24
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_arm.s
@@ -0,0 +1,217 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// ARM version of md5block.go
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Register definitions
+data = 0 // Pointer to incoming data
+const = 1 // Current constant for SHA round
+a = 2 // SHA1 accumulator
+b = 3 // SHA1 accumulator
+c = 4 // SHA1 accumulator
+d = 5 // SHA1 accumulator
+e = 6 // SHA1 accumulator
+t0 = 7 // Temporary
+t1 = 8 // Temporary
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+t2 = 11 // Temporary
+ctr = 12 // loop counter
+w = 14 // point to w buffer
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+p_end = -4 // -4(SP) pointer to the end of data
+p_data = p_end - 4 // -8(SP) current data pointer
+w_buf = p_data - 4*80 // -328(SP) 80 words temporary buffer w uint32[80]
+saved = w_buf - 4*5 // -348(SP) saved sha1 registers a,b,c,d,e - these must be last
+// Total size +4 for saved LR is 352
+
+ // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
+ // e += w[i]
+#define LOAD(e) \
+ MOVBU 2(R(data)), R(t0) ; \
+ MOVBU 3(R(data)), R(t1) ; \
+ MOVBU 1(R(data)), R(t2) ; \
+ ORR R(t0)<<8, R(t1), R(t0) ; \
+ MOVBU.P 4(R(data)), R(t1) ; \
+ ORR R(t2)<<16, R(t0), R(t0) ; \
+ ORR R(t1)<<24, R(t0), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ // w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ // e += w[i&0xf]
+#define SHUFFLE(e) \
+ MOVW (-16*4)(R(w)), R(t0) ; \
+ MOVW (-14*4)(R(w)), R(t1) ; \
+ MOVW (-8*4)(R(w)), R(t2) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW (-3*4)(R(w)), R(t1) ; \
+ EOR R(t2), R(t0), R(t0) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW R(t0)@>(32-1), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // t1 = (b & c) | ((~b) & d)
+#define FUNC1(a, b, c, d, e) \
+ MVN R(b), R(t1) ; \
+ AND R(b), R(c), R(t0) ; \
+ AND R(d), R(t1), R(t1) ; \
+ ORR R(t0), R(t1), R(t1)
+
+ // t1 = b ^ c ^ d
+#define FUNC2(a, b, c, d, e) \
+ EOR R(b), R(c), R(t1) ; \
+ EOR R(d), R(t1), R(t1)
+
+ // t1 = (b & c) | (b & d) | (c & d) =
+ // t1 = (b & c) | ((b | c) & d)
+#define FUNC3(a, b, c, d, e) \
+ ORR R(b), R(c), R(t0) ; \
+ AND R(b), R(c), R(t1) ; \
+ AND R(d), R(t0), R(t0) ; \
+ ORR R(t0), R(t1), R(t1)
+
+#define FUNC4 FUNC2
+
+ // a5 := a<<5 | a>>(32-5)
+ // b = b<<30 | b>>(32-30)
+ // e = a5 + t1 + e + const
+#define MIX(a, b, c, d, e) \
+ ADD R(t1), R(e), R(e) ; \
+ MOVW R(b)@>(32-30), R(b) ; \
+ ADD R(a)@>(32-5), R(e), R(e) ; \
+ ADD R(const), R(e), R(e)
+
+#define ROUND1(a, b, c, d, e) \
+ LOAD(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND1x(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND2(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC2(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND3(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC3(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND4(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC4(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), 0, $352-16
+ MOVW p+4(FP), R(data) // pointer to the data
+ MOVW p_len+8(FP), R(t0) // number of bytes
+ ADD R(data), R(t0)
+ MOVW R(t0), p_end(SP) // pointer to end of data
+
+ // Load up initial SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)]
+
+loop:
+ // Save registers at SP+4 onwards
+ MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13)
+
+ MOVW $w_buf(SP), R(w)
+ MOVW $0x5A827999, R(const)
+ MOVW $3, R(ctr)
+loop1: ROUND1(a, b, c, d, e)
+ ROUND1(e, a, b, c, d)
+ ROUND1(d, e, a, b, c)
+ ROUND1(c, d, e, a, b)
+ ROUND1(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop1
+
+ ROUND1(a, b, c, d, e)
+ ROUND1x(e, a, b, c, d)
+ ROUND1x(d, e, a, b, c)
+ ROUND1x(c, d, e, a, b)
+ ROUND1x(b, c, d, e, a)
+
+ MOVW $0x6ED9EBA1, R(const)
+ MOVW $4, R(ctr)
+loop2: ROUND2(a, b, c, d, e)
+ ROUND2(e, a, b, c, d)
+ ROUND2(d, e, a, b, c)
+ ROUND2(c, d, e, a, b)
+ ROUND2(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop2
+
+ MOVW $0x8F1BBCDC, R(const)
+ MOVW $4, R(ctr)
+loop3: ROUND3(a, b, c, d, e)
+ ROUND3(e, a, b, c, d)
+ ROUND3(d, e, a, b, c)
+ ROUND3(c, d, e, a, b)
+ ROUND3(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop3
+
+ MOVW $0xCA62C1D6, R(const)
+ MOVW $4, R(ctr)
+loop4: ROUND4(a, b, c, d, e)
+ ROUND4(e, a, b, c, d)
+ ROUND4(d, e, a, b, c)
+ ROUND4(c, d, e, a, b)
+ ROUND4(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop4
+
+ // Accumulate - restoring registers from SP+4
+ MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)]
+ ADD R(t0), R(a)
+ ADD R(t1), R(b)
+ ADD R(t2), R(c)
+ ADD R(ctr), R(d)
+ ADD R(w), R(e)
+
+ MOVW p_end(SP), R(t0)
+ CMP R(t0), R(data)
+ BLO loop
+
+ // Save final SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0))
+
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
index 4cb157fff..24e521af1 100644
--- a/src/pkg/crypto/sha1/sha1block_decl.go
+++ b/src/pkg/crypto/sha1/sha1block_decl.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 386
+// +build amd64 amd64p32 arm 386
package sha1
diff --git a/src/pkg/crypto/sha1/sha1block_generic.go b/src/pkg/crypto/sha1/sha1block_generic.go
new file mode 100644
index 000000000..696e26b62
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!amd64p32,!386,!arm
+
+package sha1
+
+var block = blockGeneric
diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
index d69ed24a3..d84cebf2f 100644
--- a/src/pkg/crypto/sha256/sha256.go
+++ b/src/pkg/crypto/sha256/sha256.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
-// in FIPS 180-2.
+// in FIPS 180-4.
package sha256
import (
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
index bb1ec3b16..1d883d390 100644
--- a/src/pkg/crypto/sha256/sha256_test.go
+++ b/src/pkg/crypto/sha256/sha256_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New224()
+ if got := c.Size(); got != Size224 {
+ t.Errorf("New224.Size = %d; want %d", got, Size224)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d want %d", got, BlockSize)
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/src/pkg/crypto/sha256/sha256block.go b/src/pkg/crypto/sha256/sha256block.go
index 2ac49100a..ca5efd156 100644
--- a/src/pkg/crypto/sha256/sha256block.go
+++ b/src/pkg/crypto/sha256/sha256block.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !386,!amd64
+
// SHA256 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/src/pkg/crypto/sha256/sha256block_386.s b/src/pkg/crypto/sha256/sha256block_386.s
new file mode 100644
index 000000000..73ae2bf30
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_386.s
@@ -0,0 +1,283 @@
+// 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.
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, BX, CX and DX registers.
+// Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ MOVL (h*4)(DI), BX; \
+ ADDL AX, BX; \
+ MOVL (e*4)(DI), AX; \
+ ADDL $const, BX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $6, AX; \
+ MOVL (e*4)(DI), DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $25, DX; \
+ ANDL (f*4)(DI), CX; \
+ XORL AX, DX; \
+ MOVL (e*4)(DI), AX; \
+ NOTL AX; \
+ ADDL DX, BX; \
+ ANDL (g*4)(DI), AX; \
+ XORL CX, AX; \
+ ADDL BX, AX
+
+// Calculate T2 in BX - uses AX, BX, CX and DX registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL (a*4)(DI), AX; \
+ MOVL (c*4)(DI), BX; \
+ RORL $2, AX; \
+ MOVL (a*4)(DI), DX; \
+ ANDL (b*4)(DI), BX; \
+ RORL $13, DX; \
+ MOVL (a*4)(DI), CX; \
+ ANDL (c*4)(DI), CX; \
+ XORL DX, AX; \
+ XORL CX, BX; \
+ MOVL (a*4)(DI), DX; \
+ MOVL (b*4)(DI), CX; \
+ RORL $22, DX; \
+ ANDL (a*4)(DI), CX; \
+ XORL CX, BX; \
+ XORL DX, AX; \
+ ADDL AX, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ MOVL AX, 292(SP); \
+ SHA256T2(a, b, c); \
+ MOVL 292(SP), AX; \
+ ADDL AX, BX; \
+ ADDL AX, (d*4)(DI); \
+ MOVL BX, (h*4)(DI)
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$296-12
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL DI, 288(SP)
+ CMPL SI, DI
+ JEQ end
+
+ LEAL 256(SP), DI // variables
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // a = H0
+ MOVL AX, (0*4)(DI)
+ MOVL (1*4)(BP), BX // b = H1
+ MOVL BX, (1*4)(DI)
+ MOVL (2*4)(BP), CX // c = H2
+ MOVL CX, (2*4)(DI)
+ MOVL (3*4)(BP), DX // d = H3
+ MOVL DX, (3*4)(DI)
+ MOVL (4*4)(BP), AX // e = H4
+ MOVL AX, (4*4)(DI)
+ MOVL (5*4)(BP), BX // f = H5
+ MOVL BX, (5*4)(DI)
+ MOVL (6*4)(BP), CX // g = H6
+ MOVL CX, (6*4)(DI)
+ MOVL (7*4)(BP), DX // h = H7
+ MOVL DX, (7*4)(DI)
+
+loop:
+ MOVL SP, BP // message schedule
+
+ SHA256ROUND0(0, 0x428a2f98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(1, 0x71374491, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(2, 0xb5c0fbcf, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(3, 0xe9b5dba5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(4, 0x3956c25b, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(5, 0x59f111f1, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(6, 0x923f82a4, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(7, 0xab1c5ed5, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND0(8, 0xd807aa98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(9, 0x12835b01, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(10, 0x243185be, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(11, 0x550c7dc3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(12, 0x72be5d74, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(13, 0x80deb1fe, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(14, 0x9bdc06a7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(15, 0xc19bf174, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ SHA256ROUND1(16, 0xe49b69c1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(17, 0xefbe4786, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(18, 0x0fc19dc6, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(19, 0x240ca1cc, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(20, 0x2de92c6f, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(21, 0x4a7484aa, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(22, 0x5cb0a9dc, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(23, 0x76f988da, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(24, 0x983e5152, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(25, 0xa831c66d, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(26, 0xb00327c8, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(27, 0xbf597fc7, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(28, 0xc6e00bf3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(29, 0xd5a79147, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(30, 0x06ca6351, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(31, 0x14292967, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(32, 0x27b70a85, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(33, 0x2e1b2138, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(34, 0x4d2c6dfc, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(35, 0x53380d13, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(36, 0x650a7354, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(37, 0x766a0abb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(38, 0x81c2c92e, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(39, 0x92722c85, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(40, 0xa2bfe8a1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(41, 0xa81a664b, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(42, 0xc24b8b70, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(43, 0xc76c51a3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(44, 0xd192e819, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(45, 0xd6990624, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(46, 0xf40e3585, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(47, 0x106aa070, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(48, 0x19a4c116, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(49, 0x1e376c08, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(50, 0x2748774c, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(51, 0x34b0bcb5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(52, 0x391c0cb3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(53, 0x4ed8aa4a, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(54, 0x5b9cca4f, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(55, 0x682e6ff3, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(56, 0x748f82ee, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(57, 0x78a5636f, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(58, 0x84c87814, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(59, 0x8cc70208, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(60, 0x90befffa, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(61, 0xa4506ceb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(62, 0xbef9a3f7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(63, 0xc67178f2, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // H0 = a + H0
+ ADDL (0*4)(DI), AX
+ MOVL AX, (0*4)(DI)
+ MOVL AX, (0*4)(BP)
+ MOVL (1*4)(BP), BX // H1 = b + H1
+ ADDL (1*4)(DI), BX
+ MOVL BX, (1*4)(DI)
+ MOVL BX, (1*4)(BP)
+ MOVL (2*4)(BP), CX // H2 = c + H2
+ ADDL (2*4)(DI), CX
+ MOVL CX, (2*4)(DI)
+ MOVL CX, (2*4)(BP)
+ MOVL (3*4)(BP), DX // H3 = d + H3
+ ADDL (3*4)(DI), DX
+ MOVL DX, (3*4)(DI)
+ MOVL DX, (3*4)(BP)
+ MOVL (4*4)(BP), AX // H4 = e + H4
+ ADDL (4*4)(DI), AX
+ MOVL AX, (4*4)(DI)
+ MOVL AX, (4*4)(BP)
+ MOVL (5*4)(BP), BX // H5 = f + H5
+ ADDL (5*4)(DI), BX
+ MOVL BX, (5*4)(DI)
+ MOVL BX, (5*4)(BP)
+ MOVL (6*4)(BP), CX // H6 = g + H6
+ ADDL (6*4)(DI), CX
+ MOVL CX, (6*4)(DI)
+ MOVL CX, (6*4)(BP)
+ MOVL (7*4)(BP), DX // H7 = h + H7
+ ADDL (7*4)(DI), DX
+ MOVL DX, (7*4)(DI)
+ MOVL DX, (7*4)(BP)
+
+ ADDL $64, SI
+ CMPL SI, 288(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha256/sha256block_amd64.s b/src/pkg/crypto/sha256/sha256block_amd64.s
new file mode 100644
index 000000000..95aebbe76
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_amd64.s
@@ -0,0 +1,256 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ ADDL AX, h; \
+ MOVL e, AX; \
+ ADDL $const, h; \
+ MOVL e, CX; \
+ RORL $6, AX; \
+ MOVL e, DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL e, CX; \
+ RORL $25, DX; \
+ ANDL f, CX; \
+ XORL AX, DX; \
+ MOVL e, AX; \
+ NOTL AX; \
+ ADDL DX, h; \
+ ANDL g, AX; \
+ XORL CX, AX; \
+ ADDL h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL a, DI; \
+ MOVL c, BX; \
+ RORL $2, DI; \
+ MOVL a, DX; \
+ ANDL b, BX; \
+ RORL $13, DX; \
+ MOVL a, CX; \
+ ANDL c, CX; \
+ XORL DX, DI; \
+ XORL CX, BX; \
+ MOVL a, DX; \
+ MOVL b, CX; \
+ RORL $22, DX; \
+ ANDL a, CX; \
+ XORL CX, BX; \
+ XORL DX, DI; \
+ ADDL DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ SHA256T2(a, b, c); \
+ MOVL BX, h; \
+ ADDL AX, d; \
+ ADDL AX, h
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$264-32
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 256(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVL (0*4)(BP), R8 // a = H0
+ MOVL (1*4)(BP), R9 // b = H1
+ MOVL (2*4)(BP), R10 // c = H2
+ MOVL (3*4)(BP), R11 // d = H3
+ MOVL (4*4)(BP), R12 // e = H4
+ MOVL (5*4)(BP), R13 // f = H5
+ MOVL (6*4)(BP), R14 // g = H6
+ MOVL (7*4)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP // message schedule
+
+ SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDL (0*4)(BP), R8 // H0 = a + H0
+ MOVL R8, (0*4)(BP)
+ ADDL (1*4)(BP), R9 // H1 = b + H1
+ MOVL R9, (1*4)(BP)
+ ADDL (2*4)(BP), R10 // H2 = c + H2
+ MOVL R10, (2*4)(BP)
+ ADDL (3*4)(BP), R11 // H3 = d + H3
+ MOVL R11, (3*4)(BP)
+ ADDL (4*4)(BP), R12 // H4 = e + H4
+ MOVL R12, (4*4)(BP)
+ ADDL (5*4)(BP), R13 // H5 = f + H5
+ MOVL R13, (5*4)(BP)
+ ADDL (6*4)(BP), R14 // H6 = g + H6
+ MOVL R14, (6*4)(BP)
+ ADDL (7*4)(BP), R15 // H7 = h + H7
+ MOVL R15, (7*4)(BP)
+
+ ADDQ $64, SI
+ CMPQ SI, 256(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha256/sha256block_decl.go b/src/pkg/crypto/sha256/sha256block_decl.go
new file mode 100644
index 000000000..a50c97871
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_decl.go
@@ -0,0 +1,11 @@
+// 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.
+
+// +build 386 amd64
+
+package sha256
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
index d2ada5137..bca7a91e2 100644
--- a/src/pkg/crypto/sha512/sha512.go
+++ b/src/pkg/crypto/sha512/sha512.go
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
index 167c20ad0..541860f70 100644
--- a/src/pkg/crypto/sha512/sha512_test.go
+++ b/src/pkg/crypto/sha512/sha512_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New384()
+ if got := c.Size(); got != Size384 {
+ t.Errorf("New384.Size = %d; want %d", got, Size384)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/src/pkg/crypto/sha512/sha512block.go b/src/pkg/crypto/sha512/sha512block.go
index 3577b4f3d..648ae8f7e 100644
--- a/src/pkg/crypto/sha512/sha512block.go
+++ b/src/pkg/crypto/sha512/sha512block.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !amd64
+
// SHA512 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/src/pkg/crypto/sha512/sha512block_amd64.s b/src/pkg/crypto/sha512/sha512block_amd64.s
new file mode 100644
index 000000000..344d8d2c3
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block_amd64.s
@@ -0,0 +1,273 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVQ (index*8)(SI), AX; \
+ BSWAPQ AX; \
+ MOVQ AX, (index*8)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+// SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x)
+// SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x)
+#define MSGSCHEDULE1(index) \
+ MOVQ ((index-2)*8)(BP), AX; \
+ MOVQ AX, CX; \
+ RORQ $19, AX; \
+ MOVQ CX, DX; \
+ RORQ $61, CX; \
+ SHRQ $6, DX; \
+ MOVQ ((index-15)*8)(BP), BX; \
+ XORQ CX, AX; \
+ MOVQ BX, CX; \
+ XORQ DX, AX; \
+ RORQ $1, BX; \
+ MOVQ CX, DX; \
+ SHRQ $7, DX; \
+ RORQ $8, CX; \
+ ADDQ ((index-7)*8)(BP), AX; \
+ XORQ CX, BX; \
+ XORQ DX, BX; \
+ ADDQ ((index-16)*8)(BP), BX; \
+ ADDQ BX, AX; \
+ MOVQ AX, ((index)*8)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA512T1(const, e, f, g, h) \
+ MOVQ $const, DX; \
+ ADDQ AX, h; \
+ MOVQ e, AX; \
+ ADDQ DX, h; \
+ MOVQ e, CX; \
+ RORQ $14, AX; \
+ MOVQ e, DX; \
+ RORQ $18, CX; \
+ XORQ CX, AX; \
+ MOVQ e, CX; \
+ RORQ $41, DX; \
+ ANDQ f, CX; \
+ XORQ AX, DX; \
+ MOVQ e, AX; \
+ NOTQ AX; \
+ ADDQ DX, h; \
+ ANDQ g, AX; \
+ XORQ CX, AX; \
+ ADDQ h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA512T2(a, b, c) \
+ MOVQ a, DI; \
+ MOVQ c, BX; \
+ RORQ $28, DI; \
+ MOVQ a, DX; \
+ ANDQ b, BX; \
+ RORQ $34, DX; \
+ MOVQ a, CX; \
+ ANDQ c, CX; \
+ XORQ DX, DI; \
+ XORQ CX, BX; \
+ MOVQ a, DX; \
+ MOVQ b, CX; \
+ RORQ $39, DX; \
+ ANDQ a, CX; \
+ XORQ CX, BX; \
+ XORQ DX, DI; \
+ ADDQ DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA512T1(const, e, f, g, h); \
+ SHA512T2(a, b, c); \
+ MOVQ BX, h; \
+ ADDQ AX, d; \
+ ADDQ AX, h
+
+#define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$648-32
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $7, DX
+ SHLQ $7, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 640(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVQ (0*8)(BP), R8 // a = H0
+ MOVQ (1*8)(BP), R9 // b = H1
+ MOVQ (2*8)(BP), R10 // c = H2
+ MOVQ (3*8)(BP), R11 // d = H3
+ MOVQ (4*8)(BP), R12 // e = H4
+ MOVQ (5*8)(BP), R13 // f = H5
+ MOVQ (6*8)(BP), R14 // g = H6
+ MOVQ (7*8)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP // message schedule
+
+ SHA512ROUND0(0, 0x428a2f98d728ae22, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(1, 0x7137449123ef65cd, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(3, 0xe9b5dba58189dbbc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(4, 0x3956c25bf348b538, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(5, 0x59f111f1b605d019, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(6, 0x923f82a4af194f9b, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(7, 0xab1c5ed5da6d8118, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND0(8, 0xd807aa98a3030242, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(9, 0x12835b0145706fbe, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(10, 0x243185be4ee4b28c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(12, 0x72be5d74f27b896f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(13, 0x80deb1fe3b1696b1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(14, 0x9bdc06a725c71235, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(15, 0xc19bf174cf692694, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA512ROUND1(16, 0xe49b69c19ef14ad2, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(17, 0xefbe4786384f25e3, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(19, 0x240ca1cc77ac9c65, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(20, 0x2de92c6f592b0275, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(21, 0x4a7484aa6ea6e483, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(23, 0x76f988da831153b5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(24, 0x983e5152ee66dfab, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(25, 0xa831c66d2db43210, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(26, 0xb00327c898fb213f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(27, 0xbf597fc7beef0ee4, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(28, 0xc6e00bf33da88fc2, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(29, 0xd5a79147930aa725, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(30, 0x06ca6351e003826f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(31, 0x142929670a0e6e70, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(32, 0x27b70a8546d22ffc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(33, 0x2e1b21385c26c926, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(35, 0x53380d139d95b3df, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(36, 0x650a73548baf63de, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(37, 0x766a0abb3c77b2a8, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(38, 0x81c2c92e47edaee6, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(39, 0x92722c851482353b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(40, 0xa2bfe8a14cf10364, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(41, 0xa81a664bbc423001, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(42, 0xc24b8b70d0f89791, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(43, 0xc76c51a30654be30, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(44, 0xd192e819d6ef5218, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(45, 0xd69906245565a910, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(46, 0xf40e35855771202a, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(47, 0x106aa07032bbd1b8, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(49, 0x1e376c085141ab53, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(50, 0x2748774cdf8eeb99, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(52, 0x391c0cb3c5c95a63, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(54, 0x5b9cca4f7763e373, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(56, 0x748f82ee5defb2fc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(57, 0x78a5636f43172f60, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(58, 0x84c87814a1f0ab72, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(59, 0x8cc702081a6439ec, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(60, 0x90befffa23631e28, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(61, 0xa4506cebde82bde9, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(62, 0xbef9a3f7b2c67915, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(63, 0xc67178f2e372532b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(64, 0xca273eceea26619c, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(65, 0xd186b8c721c0c207, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(67, 0xf57d4f7fee6ed178, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(68, 0x06f067aa72176fba, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(69, 0x0a637dc5a2c898a6, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(70, 0x113f9804bef90dae, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(71, 0x1b710b35131c471b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(72, 0x28db77f523047d84, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(73, 0x32caab7b40c72493, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(75, 0x431d67c49c100d4c, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(77, 0x597f299cfc657e2a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(79, 0x6c44198c4a475817, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDQ (0*8)(BP), R8 // H0 = a + H0
+ MOVQ R8, (0*8)(BP)
+ ADDQ (1*8)(BP), R9 // H1 = b + H1
+ MOVQ R9, (1*8)(BP)
+ ADDQ (2*8)(BP), R10 // H2 = c + H2
+ MOVQ R10, (2*8)(BP)
+ ADDQ (3*8)(BP), R11 // H3 = d + H3
+ MOVQ R11, (3*8)(BP)
+ ADDQ (4*8)(BP), R12 // H4 = e + H4
+ MOVQ R12, (4*8)(BP)
+ ADDQ (5*8)(BP), R13 // H5 = f + H5
+ MOVQ R13, (5*8)(BP)
+ ADDQ (6*8)(BP), R14 // H6 = g + H6
+ MOVQ R14, (6*8)(BP)
+ ADDQ (7*8)(BP), R15 // H7 = h + H7
+ MOVQ R15, (7*8)(BP)
+
+ ADDQ $128, SI
+ CMPQ SI, 640(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha512/sha512block_decl.go b/src/pkg/crypto/sha512/sha512block_decl.go
new file mode 100644
index 000000000..bef99de2e
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block_decl.go
@@ -0,0 +1,11 @@
+// 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.
+
+// +build amd64
+
+package sha512
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/subtle/constant_time.go b/src/pkg/crypto/subtle/constant_time.go
index dfb658465..de1a4e8c5 100644
--- a/src/pkg/crypto/subtle/constant_time.go
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -10,6 +10,10 @@ package subtle
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
+ if len(x) != len(y) {
+ panic("subtle: slices have different lengths")
+ }
+
var v byte
for i := 0; i < len(x); i++ {
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index b7229d29f..fca98bdd1 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -5,9 +5,11 @@
package tls
import (
+ "container/list"
"crypto"
"crypto/rand"
"crypto/x509"
+ "fmt"
"io"
"math/big"
"strings"
@@ -64,7 +66,7 @@ const (
)
// TLS extension numbers
-var (
+const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
@@ -72,19 +74,27 @@ var (
extensionSignatureAlgorithms uint16 = 13
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ extensionRenegotiationInfo uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
)
-// TLS Elliptic Curves
+// CurveID is the type of a TLS identifier for an elliptic curve. See
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
-var (
- curveP256 uint16 = 23
- curveP384 uint16 = 24
- curveP521 uint16 = 25
+type CurveID uint16
+
+const (
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
)
// TLS Elliptic Curve Point Formats
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
-var (
+const (
pointFormatUncompressed uint8 = 0
)
@@ -145,6 +155,7 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{
// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
+ Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
HandshakeComplete bool // TLS handshake is complete
DidResume bool // connection resumes a previous TLS connection
CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
@@ -167,12 +178,38 @@ const (
RequireAndVerifyClientCert
)
-// A Config structure is used to configure a TLS client or server. After one
-// has been passed to a TLS function it must not be modified.
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+ sessionTicket []uint8 // Encrypted ticket used for session resumption with server
+ vers uint16 // SSL/TLS version negotiated for the session
+ cipherSuite uint16 // Ciphersuite negotiated for the session
+ masterSecret []byte // MasterSecret generated by client on a full handshake
+ serverCertificates []*x509.Certificate // Certificate chain presented by the server
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ClientSessionCache interface {
+ // Get searches for a ClientSessionState associated with the given key.
+ // On return, ok is true if one was found.
+ Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+ // Put adds the ClientSessionState to the cache with the given key.
+ Put(sessionKey string, cs *ClientSessionState)
+}
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
type Config struct {
// Rand provides the source of entropy for nonces and RSA blinding.
// If Rand is nil, TLS uses the cryptographic random reader in package
// crypto/rand.
+ // The Reader must be safe for use by multiple goroutines.
Rand io.Reader
// Time returns the current time as the number of seconds since the epoch.
@@ -200,8 +237,9 @@ type Config struct {
// NextProtos is a list of supported, application level protocols.
NextProtos []string
- // ServerName is included in the client's handshake to support virtual
- // hosting.
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting.
ServerName string
// ClientAuth determines the server's policy for
@@ -245,6 +283,10 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
+ // SessionCache is a cache of ClientSessionState entries for TLS session
+ // resumption.
+ ClientSessionCache ClientSessionCache
+
// MinVersion contains the minimum SSL/TLS version that is acceptable.
// If zero, then SSLv3 is taken as the minimum.
MinVersion uint16
@@ -254,6 +296,11 @@ type Config struct {
// which is currently TLS 1.2.
MaxVersion uint16
+ // CurvePreferences contains the elliptic curves that will be used in
+ // an ECDHE handshake, in preference order. If empty, the default will
+ // be used.
+ CurvePreferences []CurveID
+
serverInitOnce sync.Once // guards calling (*Config).serverInit
}
@@ -312,6 +359,15 @@ func (c *Config) maxVersion() uint16 {
return c.MaxVersion
}
+var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultCurvePreferences
+ }
+ return c.CurvePreferences
+}
+
// mutualVersion returns the protocol version to use given the advertised
// version of the peer.
func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
@@ -406,6 +462,77 @@ type handshakeMessage interface {
unmarshal([]byte) bool
}
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+ sync.Mutex
+
+ m map[string]*list.Element
+ q *list.List
+ capacity int
+}
+
+type lruSessionCacheEntry struct {
+ sessionKey string
+ state *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ }
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ entry := elem.Value.(*lruSessionCacheEntry)
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ return
+ }
+
+ if c.q.Len() < c.capacity {
+ entry := &lruSessionCacheEntry{sessionKey, cs}
+ c.m[sessionKey] = c.q.PushFront(entry)
+ return
+ }
+
+ elem := c.q.Back()
+ entry := elem.Value.(*lruSessionCacheEntry)
+ delete(c.m, entry.sessionKey)
+ entry.sessionKey = sessionKey
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ c.q.MoveToFront(elem)
+ return elem.Value.(*lruSessionCacheEntry).state, true
+ }
+ return nil, false
+}
+
// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
type dsaSignature struct {
R, S *big.Int
@@ -435,3 +562,7 @@ func initDefaultCipherSuites() {
varDefaultCipherSuites[i] = suite.id
}
}
+
+func unexpectedMessageError(wanted, got interface{}) error {
+ return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 2e64b88a6..8f7d2c144 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -12,6 +12,7 @@ import (
"crypto/subtle"
"crypto/x509"
"errors"
+ "fmt"
"io"
"net"
"sync"
@@ -27,6 +28,7 @@ type Conn struct {
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ handshakeErr error // error resulting from handshake
vers uint16 // TLS version
haveVers bool // version has been negotiated
config *Config // configuration passed to constructor
@@ -44,9 +46,6 @@ type Conn struct {
clientProtocol string
clientProtocolFallback bool
- // first permanent error
- connErr
-
// input/output
in, out halfConn // in.Mutex < out.Mutex
rawInput *block // raw input, right off the wire
@@ -56,27 +55,6 @@ type Conn struct {
tmp [16]byte
}
-type connErr struct {
- mu sync.Mutex
- value error
-}
-
-func (e *connErr) setError(err error) error {
- e.mu.Lock()
- defer e.mu.Unlock()
-
- if e.value == nil {
- e.value = err
- }
- return err
-}
-
-func (e *connErr) error() error {
- e.mu.Lock()
- defer e.mu.Unlock()
- return e.value
-}
-
// Access to net.Conn methods.
// Cannot just embed net.Conn because that would
// export the struct field too.
@@ -104,7 +82,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
-// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// SetWriteDeadline sets the write deadline on the underlying connection.
// A zero value for t means Write will not time out.
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
func (c *Conn) SetWriteDeadline(t time.Time) error {
@@ -115,6 +93,8 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
// connection, either sending or receiving.
type halfConn struct {
sync.Mutex
+
+ err error // first permanent error
version uint16 // protocol version
cipher interface{} // cipher algorithm
mac macFunction
@@ -128,6 +108,18 @@ type halfConn struct {
inDigestBuf, outDigestBuf []byte
}
+func (hc *halfConn) setErrorLocked(err error) error {
+ hc.err = err
+ return err
+}
+
+func (hc *halfConn) error() error {
+ hc.Lock()
+ err := hc.err
+ hc.Unlock()
+ return err
+}
+
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -459,6 +451,8 @@ func (b *block) readFromUntil(r io.Reader, n int) error {
m, err := r.Read(b.data[len(b.data):cap(b.data)])
b.data = b.data[0 : len(b.data)+m]
if len(b.data) >= n {
+ // TODO(bradfitz,agl): slightly suspicious
+ // that we're throwing away r.Read's err here.
break
}
if err != nil {
@@ -518,14 +512,17 @@ func (c *Conn) readRecord(want recordType) error {
// else application data. (We don't support renegotiation.)
switch want {
default:
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
case recordTypeHandshake, recordTypeChangeCipherSpec:
if c.handshakeComplete {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
}
case recordTypeApplicationData:
if !c.handshakeComplete {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
}
}
@@ -544,7 +541,7 @@ Again:
// err = io.ErrUnexpectedEOF
// }
if e, ok := err.(net.Error); !ok || !e.Temporary() {
- c.setError(err)
+ c.in.setErrorLocked(err)
}
return err
}
@@ -556,16 +553,18 @@ Again:
// an SSLv2 client.
if want == recordTypeHandshake && typ == 0x80 {
c.sendAlert(alertProtocolVersion)
- return errors.New("tls: unsupported SSLv2 handshake received")
+ return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
}
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4])
if c.haveVers && vers != c.vers {
- return c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
}
if n > maxCiphertext {
- return c.sendAlert(alertRecordOverflow)
+ c.sendAlert(alertRecordOverflow)
+ return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
}
if !c.haveVers {
// First message, be extra suspicious:
@@ -577,7 +576,8 @@ Again:
// well under a kilobyte. If the length is >= 12 kB,
// it's probably not real.
if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
}
}
if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
@@ -585,7 +585,7 @@ Again:
err = io.ErrUnexpectedEOF
}
if e, ok := err.(net.Error); !ok || !e.Temporary() {
- c.setError(err)
+ c.in.setErrorLocked(err)
}
return err
}
@@ -594,27 +594,27 @@ Again:
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
ok, off, err := c.in.decrypt(b)
if !ok {
- return c.sendAlert(err)
+ c.in.setErrorLocked(c.sendAlert(err))
}
b.off = off
data := b.data[b.off:]
if len(data) > maxPlaintext {
- c.sendAlert(alertRecordOverflow)
+ err := c.sendAlert(alertRecordOverflow)
c.in.freeBlock(b)
- return c.error()
+ return c.in.setErrorLocked(err)
}
switch typ {
default:
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
case recordTypeAlert:
if len(data) != 2 {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
if alert(data[1]) == alertCloseNotify {
- c.setError(io.EOF)
+ c.in.setErrorLocked(io.EOF)
break
}
switch data[0] {
@@ -623,24 +623,24 @@ Again:
c.in.freeBlock(b)
goto Again
case alertLevelError:
- c.setError(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
default:
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
case recordTypeChangeCipherSpec:
if typ != want || len(data) != 1 || data[0] != 1 {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
err := c.in.changeCipherSpec()
if err != nil {
- c.sendAlert(err.(alert))
+ c.in.setErrorLocked(c.sendAlert(err.(alert)))
}
case recordTypeApplicationData:
if typ != want {
- c.sendAlert(alertUnexpectedMessage)
+ c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
c.input = b
@@ -649,7 +649,7 @@ Again:
case recordTypeHandshake:
// TODO(rsc): Should at least pick off connection close.
if typ != want {
- return c.sendAlert(alertNoRenegotiation)
+ return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
}
c.hand.Write(data)
}
@@ -657,7 +657,7 @@ Again:
if b != nil {
c.in.freeBlock(b)
}
- return c.error()
+ return c.in.err
}
// sendAlert sends a TLS alert message.
@@ -673,7 +673,7 @@ func (c *Conn) sendAlertLocked(err alert) error {
c.writeRecord(recordTypeAlert, c.tmp[0:2])
// closeNotify is a special case in that it isn't an error:
if err != alertCloseNotify {
- return c.setError(&net.OpError{Op: "local error", Err: err})
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
return nil
}
@@ -759,7 +759,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
c.tmp[0] = alertLevelError
c.tmp[1] = byte(err.(alert))
c.writeRecord(recordTypeAlert, c.tmp[0:2])
- return n, c.setError(&net.OpError{Op: "local error", Err: err})
+ return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
}
}
return
@@ -770,7 +770,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
// c.in.Mutex < L; c.out.Mutex < L.
func (c *Conn) readHandshake() (interface{}, error) {
for c.hand.Len() < 4 {
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return nil, err
}
if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -781,11 +781,10 @@ func (c *Conn) readHandshake() (interface{}, error) {
data := c.hand.Bytes()
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
if n > maxHandshake {
- c.sendAlert(alertInternalError)
- return nil, c.error()
+ return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
}
for c.hand.Len() < 4+n {
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return nil, err
}
if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -799,6 +798,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(clientHelloMsg)
case typeServerHello:
m = new(serverHelloMsg)
+ case typeNewSessionTicket:
+ m = new(newSessionTicketMsg)
case typeCertificate:
m = new(certificateMsg)
case typeCertificateRequest:
@@ -822,8 +823,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
case typeFinished:
m = new(finishedMsg)
default:
- c.sendAlert(alertUnexpectedMessage)
- return nil, alertUnexpectedMessage
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
// The handshake message unmarshallers
@@ -832,25 +832,24 @@ func (c *Conn) readHandshake() (interface{}, error) {
data = append([]byte(nil), data...)
if !m.unmarshal(data) {
- c.sendAlert(alertUnexpectedMessage)
- return nil, alertUnexpectedMessage
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
return m, nil
}
// Write writes data to the connection.
func (c *Conn) Write(b []byte) (int, error) {
- if err := c.error(); err != nil {
- return 0, err
- }
-
if err := c.Handshake(); err != nil {
- return 0, c.setError(err)
+ return 0, err
}
c.out.Lock()
defer c.out.Unlock()
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
if !c.handshakeComplete {
return 0, alertInternalError
}
@@ -869,14 +868,14 @@ func (c *Conn) Write(b []byte) (int, error) {
if _, ok := c.out.cipher.(cipher.BlockMode); ok {
n, err := c.writeRecord(recordTypeApplicationData, b[:1])
if err != nil {
- return n, c.setError(err)
+ return n, c.out.setErrorLocked(err)
}
m, b = 1, b[1:]
}
}
n, err := c.writeRecord(recordTypeApplicationData, b)
- return n + m, c.setError(err)
+ return n + m, c.out.setErrorLocked(err)
}
// Read can be made to time out and return a net.Error with Timeout() == true
@@ -885,6 +884,11 @@ func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
+ if len(b) == 0 {
+ // Put this after Handshake, in case people were calling
+ // Read(nil) for the side effect of the Handshake.
+ return
+ }
c.in.Lock()
defer c.in.Unlock()
@@ -893,13 +897,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// CBC IV. So this loop ignores a limited number of empty records.
const maxConsecutiveEmptyRecords = 100
for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
- for c.input == nil && c.error() == nil {
+ for c.input == nil && c.in.err == nil {
if err := c.readRecord(recordTypeApplicationData); err != nil {
// Soft error, like EAGAIN
return 0, err
}
}
- if err := c.error(); err != nil {
+ if err := c.in.err; err != nil {
return 0, err
}
@@ -909,6 +913,25 @@ func (c *Conn) Read(b []byte) (n int, err error) {
c.input = nil
}
+ // If a close-notify alert is waiting, read it so that
+ // we can return (n, EOF) instead of (n, nil), to signal
+ // to the HTTP response reading goroutine that the
+ // connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would
+ // otherwise not observe the EOF until its next read,
+ // by which time a client goroutine might have already
+ // tried to reuse the HTTP connection for a new
+ // request.
+ // See https://codereview.appspot.com/76400046
+ // and http://golang.org/issue/3514
+ if ri := c.rawInput; ri != nil &&
+ n != 0 && err == nil &&
+ c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+ if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+ err = recErr // will be io.EOF on closeNotify
+ }
+ }
+
if n != 0 || err != nil {
return n, err
}
@@ -940,16 +963,19 @@ func (c *Conn) Close() error {
func (c *Conn) Handshake() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- if err := c.error(); err != nil {
+ if err := c.handshakeErr; err != nil {
return err
}
if c.handshakeComplete {
return nil
}
+
if c.isClient {
- return c.clientHandshake()
+ c.handshakeErr = c.clientHandshake()
+ } else {
+ c.handshakeErr = c.serverHandshake()
}
- return c.serverHandshake()
+ return c.handshakeErr
}
// ConnectionState returns basic TLS details about the connection.
@@ -960,6 +986,7 @@ func (c *Conn) ConnectionState() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
if c.handshakeComplete {
+ state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
@@ -988,10 +1015,10 @@ func (c *Conn) VerifyHostname(host string) error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return errors.New("VerifyHostname called on TLS server connection")
+ return errors.New("tls: VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return errors.New("TLS handshake has not yet been performed")
+ return errors.New("tls: handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/src/pkg/crypto/tls/example_test.go b/src/pkg/crypto/tls/example_test.go
new file mode 100644
index 000000000..7628e431b
--- /dev/null
+++ b/src/pkg/crypto/tls/example_test.go
@@ -0,0 +1,57 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+)
+
+func ExampleDial() {
+ // Connecting with a custom root-certificate set.
+
+ const rootPEM = `
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
+ RootCAs: roots,
+ })
+ if err != nil {
+ panic("failed to connect: " + err.Error())
+ }
+ conn.Close()
+}
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
index b417ea464..5c6d8396d 100644
--- a/src/pkg/crypto/tls/generate_cert.go
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -43,7 +43,6 @@ func main() {
priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
if err != nil {
log.Fatalf("failed to generate private key: %s", err)
- return
}
var notBefore time.Time
@@ -59,14 +58,14 @@ func main() {
notAfter := notBefore.Add(*validFor)
- // end of ASN.1 time
- endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
- if notAfter.After(endOfTime) {
- notAfter = endOfTime
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ log.Fatalf("failed to generate serial number: %s", err)
}
template := x509.Certificate{
- SerialNumber: new(big.Int).SetInt64(0),
+ SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
@@ -95,13 +94,11 @@ func main() {
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
log.Fatalf("Failed to create certificate: %s", err)
- return
}
certOut, err := os.Create("cert.pem")
if err != nil {
log.Fatalf("failed to open cert.pem for writing: %s", err)
- return
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 85e4adefc..a320fde1b 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -12,24 +12,41 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
+ "fmt"
"io"
+ "net"
"strconv"
)
+type clientHandshakeState struct {
+ c *Conn
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ suite *cipherSuite
+ finishedHash finishedHash
+ masterSecret []byte
+ session *ClientSessionState
+}
+
func (c *Conn) clientHandshake() error {
if c.config == nil {
c.config = defaultConfig()
}
+ if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
+ return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+ }
+
hello := &clientHelloMsg{
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- serverName: c.config.ServerName,
- supportedCurves: []uint16{curveP256, curveP384, curveP521},
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: c.config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: true,
}
possibleCipherSuites := c.config.cipherSuites()
@@ -51,21 +68,61 @@ NextCipherSuite:
}
}
- t := uint32(c.config.time().Unix())
- hello.random[0] = byte(t >> 24)
- hello.random[1] = byte(t >> 16)
- hello.random[2] = byte(t >> 8)
- hello.random[3] = byte(t)
- _, err := io.ReadFull(c.config.rand(), hello.random[4:])
+ _, err := io.ReadFull(c.config.rand(), hello.random)
if err != nil {
c.sendAlert(alertInternalError)
- return errors.New("short read from Rand")
+ return errors.New("tls: short read from Rand: " + err.Error())
}
if hello.vers >= VersionTLS12 {
hello.signatureAndHashes = supportedSKXSignatureAlgorithms
}
+ var session *ClientSessionState
+ var cacheKey string
+ sessionCache := c.config.ClientSessionCache
+ if c.config.SessionTicketsDisabled {
+ sessionCache = nil
+ }
+
+ if sessionCache != nil {
+ hello.ticketSupported = true
+
+ // Try to resume a previously negotiated TLS session, if
+ // available.
+ cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ candidateSession, ok := sessionCache.Get(cacheKey)
+ if ok {
+ // Check that the ciphersuite/version used for the
+ // previous session are still valid.
+ cipherSuiteOk := false
+ for _, id := range hello.cipherSuites {
+ if id == candidateSession.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+
+ versOk := candidateSession.vers >= c.config.minVersion() &&
+ candidateSession.vers <= c.config.maxVersion()
+ if versOk && cipherSuiteOk {
+ session = candidateSession
+ }
+ }
+ }
+
+ if session != nil {
+ hello.sessionTicket = session.sessionTicket
+ // A random session ID is used to detect when the
+ // server accepted the ticket and is resuming a session
+ // (see RFC 5077).
+ hello.sessionId = make([]byte, 16)
+ if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ }
+
c.writeRecord(recordTypeHandshake, hello.marshal())
msg, err := c.readHandshake()
@@ -74,51 +131,103 @@ NextCipherSuite:
}
serverHello, ok := msg.(*serverHelloMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
}
vers, ok := c.config.mutualVersion(serverHello.vers)
if !ok || vers < VersionTLS10 {
// TLS 1.0 is the minimum version supported as a client.
- return c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
}
c.vers = vers
c.haveVers = true
- finishedHash := newFinishedHash(c.vers)
- finishedHash.Write(hello.marshal())
- finishedHash.Write(serverHello.marshal())
+ suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ if suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return fmt.Errorf("tls: server selected an unsupported cipher suite")
+ }
- if serverHello.compressionMethod != compressionNone {
- return c.sendAlert(alertUnexpectedMessage)
+ hs := &clientHandshakeState{
+ c: c,
+ serverHello: serverHello,
+ hello: hello,
+ suite: suite,
+ finishedHash: newFinishedHash(c.vers),
+ session: session,
}
- if !hello.nextProtoNeg && serverHello.nextProtoNeg {
- c.sendAlert(alertHandshakeFailure)
- return errors.New("server advertised unrequested NPN")
+ hs.finishedHash.Write(hs.hello.marshal())
+ hs.finishedHash.Write(hs.serverHello.marshal())
+
+ isResume, err := hs.processServerHello()
+ if err != nil {
+ return err
}
- suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
- if suite == nil {
- return c.sendAlert(alertHandshakeFailure)
+ if isResume {
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(); err != nil {
+ return err
+ }
+ } else {
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(); err != nil {
+ return err
+ }
}
- msg, err = c.readHandshake()
+ if sessionCache != nil && hs.session != nil && session != hs.session {
+ sessionCache.Put(cacheKey, hs.session)
+ }
+
+ c.didResume = isResume
+ c.handshakeComplete = true
+ c.cipherSuite = suite.id
+ return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ msg, err := c.readHandshake()
if err != nil {
return err
}
certMsg, ok := msg.(*certificateMsg)
if !ok || len(certMsg.certificates) == 0 {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
}
- finishedHash.Write(certMsg.marshal())
+ hs.finishedHash.Write(certMsg.marshal())
certs := make([]*x509.Certificate, len(certMsg.certificates))
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return errors.New("failed to parse certificate from server: " + err.Error())
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
}
certs[i] = cert
}
@@ -148,21 +257,23 @@ NextCipherSuite:
case *rsa.PublicKey, *ecdsa.PublicKey:
break
default:
- return c.sendAlert(alertUnsupportedCertificate)
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
}
c.peerCertificates = certs
- if serverHello.ocspStapling {
+ if hs.serverHello.ocspStapling {
msg, err = c.readHandshake()
if err != nil {
return err
}
cs, ok := msg.(*certificateStatusMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(cs, msg)
}
- finishedHash.Write(cs.marshal())
+ hs.finishedHash.Write(cs.marshal())
if cs.statusType == statusTypeOCSP {
c.ocspResponse = cs.response
@@ -174,12 +285,12 @@ NextCipherSuite:
return err
}
- keyAgreement := suite.ka(c.vers)
+ keyAgreement := hs.suite.ka(c.vers)
skx, ok := msg.(*serverKeyExchangeMsg)
if ok {
- finishedHash.Write(skx.marshal())
- err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+ hs.finishedHash.Write(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
if err != nil {
c.sendAlert(alertUnexpectedMessage)
return err
@@ -208,7 +319,7 @@ NextCipherSuite:
// ClientCertificateType, unless there is some external
// arrangement to the contrary.
- finishedHash.Write(certReq.marshal())
+ hs.finishedHash.Write(certReq.marshal())
var rsaAvail, ecdsaAvail bool
for _, certType := range certReq.certificateTypes {
@@ -271,9 +382,10 @@ NextCipherSuite:
shd, ok := msg.(*serverHelloDoneMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(shd, msg)
}
- finishedHash.Write(shd.marshal())
+ hs.finishedHash.Write(shd.marshal())
// If the server requested a certificate then we have to send a
// Certificate message, even if it's empty because we don't have a
@@ -283,17 +395,17 @@ NextCipherSuite:
if chainToSend != nil {
certMsg.certificates = chainToSend.Certificate
}
- finishedHash.Write(certMsg.marshal())
+ hs.finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
- preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
if err != nil {
c.sendAlert(alertInternalError)
return err
}
if ckx != nil {
- finishedHash.Write(ckx.marshal())
+ hs.finishedHash.Write(ckx.marshal())
c.writeRecord(recordTypeHandshake, ckx.marshal())
}
@@ -305,7 +417,7 @@ NextCipherSuite:
switch key := c.config.Certificates[0].PrivateKey.(type) {
case *ecdsa.PrivateKey:
- digest, _, hashId := finishedHash.hashForClientCertificate(signatureECDSA)
+ digest, _, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
if err == nil {
signed, err = asn1.Marshal(ecdsaSignature{r, s})
@@ -313,7 +425,7 @@ NextCipherSuite:
certVerify.signatureAndHash.signature = signatureECDSA
certVerify.signatureAndHash.hash = hashId
case *rsa.PrivateKey:
- digest, hashFunc, hashId := finishedHash.hashForClientCertificate(signatureRSA)
+ digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
certVerify.signatureAndHash.signature = signatureRSA
certVerify.signatureAndHash.hash = hashId
@@ -321,79 +433,157 @@ NextCipherSuite:
err = errors.New("unknown private key type")
}
if err != nil {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
}
certVerify.signature = signed
- finishedHash.Write(certVerify.marshal())
+ hs.finishedHash.Write(certVerify.marshal())
c.writeRecord(recordTypeHandshake, certVerify.marshal())
}
- masterSecret := masterFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random)
- clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
- keysFromMasterSecret(c.vers, masterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+ c := hs.c
- var clientCipher interface{}
- var clientHash macFunction
- if suite.cipher != nil {
- clientCipher = suite.cipher(clientKey, clientIV, false /* not for reading */)
- clientHash = suite.mac(c.vers, clientMAC)
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash macFunction
+ if hs.suite.cipher != nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash = hs.suite.mac(c.vers, clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash = hs.suite.mac(c.vers, serverMAC)
} else {
- clientCipher = suite.aead(clientKey, clientIV)
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
}
+
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
- c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ return nil
+}
- if serverHello.nextProtoNeg {
- nextProto := new(nextProtoMsg)
- proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
- nextProto.proto = proto
- c.clientProtocol = proto
- c.clientProtocolFallback = fallback
+func (hs *clientHandshakeState) serverResumedSession() bool {
+ // If the server responded with the same sessionId then it means the
+ // sessionTicket is being used to resume a TLS session.
+ return hs.session != nil && hs.hello.sessionId != nil &&
+ bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
- finishedHash.Write(nextProto.marshal())
- c.writeRecord(recordTypeHandshake, nextProto.marshal())
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+ c := hs.c
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertUnexpectedMessage)
+ return false, errors.New("tls: server selected unsupported compression format")
}
- finished := new(finishedMsg)
- finished.verifyData = finishedHash.clientSum(masterSecret)
- finishedHash.Write(finished.marshal())
- c.writeRecord(recordTypeHandshake, finished.marshal())
+ if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("server advertised unrequested NPN extension")
+ }
- var serverCipher interface{}
- var serverHash macFunction
- if suite.cipher != nil {
- serverCipher = suite.cipher(serverKey, serverIV, true /* for reading */)
- serverHash = suite.mac(c.vers, serverMAC)
- } else {
- serverCipher = suite.aead(serverKey, serverIV)
+ if hs.serverResumedSession() {
+ // Restore masterSecret and peerCerts from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ return true, nil
}
- c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+ return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished() error {
+ c := hs.c
+
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.error(); err != nil {
+ if err := c.in.error(); err != nil {
return err
}
- msg, err = c.readHandshake()
+ msg, err := c.readHandshake()
if err != nil {
return err
}
serverFinished, ok := msg.(*finishedMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
}
- verify := finishedHash.serverSum(masterSecret)
+ verify := hs.finishedHash.serverSum(hs.masterSecret)
if len(verify) != len(serverFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+ hs.finishedHash.Write(serverFinished.marshal())
+ return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+ if !hs.serverHello.ticketSupported {
+ return nil
+ }
+
+ c := hs.c
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+ hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+ hs.session = &ClientSessionState{
+ sessionTicket: sessionTicketMsg.ticket,
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ masterSecret: hs.masterSecret,
+ serverCertificates: c.peerCertificates,
}
- c.handshakeComplete = true
- c.cipherSuite = suite.id
return nil
}
+func (hs *clientHandshakeState) sendFinished() error {
+ c := hs.c
+
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ if hs.serverHello.nextProtoNeg {
+ nextProto := new(nextProtoMsg)
+ proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
+ nextProto.proto = proto
+ c.clientProtocol = proto
+ c.clientProtocolFallback = fallback
+
+ hs.finishedHash.Write(nextProto.marshal())
+ c.writeRecord(recordTypeHandshake, nextProto.marshal())
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+ hs.finishedHash.Write(finished.marshal())
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+ return nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+ if len(config.ServerName) > 0 {
+ return config.ServerName
+ }
+ return serverAddr.String()
+}
+
// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
// set of client and server supported protocols. The set of client supported
// protocols must not be empty. It returns the resulting protocol and flag
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 6c564001b..0d73c8e2f 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -6,3045 +6,434 @@ package tls
import (
"bytes"
- "flag"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
"io"
"net"
"os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
"testing"
+ "time"
)
-func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) {
- c, s := net.Pipe()
- cli := Client(c, config)
- go func() {
- cli.Write([]byte("hello\n"))
- cli.Close()
- c.Close()
- }()
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
- defer c.Close()
- for i, b := range clientScript {
- if i%2 == 1 {
- s.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- _, err := io.ReadFull(s, bb)
- if err != nil {
- t.Fatalf("%s #%d: %s", name, i, err)
- }
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
- }
- }
-}
-
-func TestHandshakeClientRSARC4(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
- testClientScript(t, "RSA-RC4", rsaRC4ClientScript, &config)
-}
+// blockingSource is an io.Reader that blocks a Read call until it's closed.
+type blockingSource chan bool
-func TestHandshakeClientECDHERSAAES(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- testClientScript(t, "ECDHE-RSA-AES", ecdheRSAAESClientScript, &config)
+func (b blockingSource) Read([]byte) (n int, err error) {
+ <-b
+ return 0, io.EOF
}
-func TestHandshakeClientECDHECDSAAES(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}
- config.Certificates = nil
- config.BuildNameToCertificate()
- testClientScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESClientScript, &config)
+// clientTest represents a test of the TLS client handshake against a reference
+// implementation.
+type clientTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // command, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ command []string
+ // config, if not nil, contains a custom Config to use for this test.
+ config *Config
+ // cert, if not empty, contains a DER-encoded certificate for the
+ // reference server.
+ cert []byte
+ // key, if not nil, contains either a *rsa.PrivateKey or
+ // *ecdsa.PrivateKey which is the private key for the reference server.
+ key interface{}
}
-func TestLongClientCerticiateChain(t *testing.T) {
- config := *testConfig
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "Long client certificate chains", clientChainCertificateScript, &config)
-}
+var defaultServerCommand = []string{"openssl", "s_server"}
-func TestHandshakeClientTLS11(t *testing.T) {
- var config = *testConfig
- config.MaxVersion = VersionTLS11
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- testClientScript(t, "TLS11-ECDHE-AES", tls11ECDHEAESClientScript, &config)
-}
+// connFromCommand starts the reference server process, connects to it and
+// returns a recordingConn for the connection. The stdin return value is a
+// blockingSource for the stdin of the child process. It must be closed before
+// Waiting for child.
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) {
+ cert := testRSACertificate
+ if len(test.cert) > 0 {
+ cert = test.cert
+ }
+ certPath := tempFile(string(cert))
+ defer os.Remove(certPath)
-func TestHandshakeClientTLS12(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "TLS12", clientTLS12Script, &config)
-}
+ var key interface{} = testRSAPrivateKey
+ if test.key != nil {
+ key = test.key
+ }
+ var pemType string
+ var derBytes []byte
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ pemType = "RSA"
+ derBytes = x509.MarshalPKCS1PrivateKey(key)
+ case *ecdsa.PrivateKey:
+ pemType = "EC"
+ var err error
+ derBytes, err = x509.MarshalECPrivateKey(key)
+ if err != nil {
+ panic(err)
+ }
+ default:
+ panic("unknown key type")
+ }
-func TestHandshakeClientTLS12ClientCert(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
- cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
- config.Certificates = []Certificate{cert}
- testClientScript(t, "TLS12ClientCert", clientTLS12ClientCertScript, &config)
-}
+ var pemOut bytes.Buffer
+ pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes})
-var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+ keyPath := tempFile(string(pemOut.Bytes()))
+ defer os.Remove(keyPath)
-func TestRunClient(t *testing.T) {
- if !*connect {
- return
+ var command []string
+ if len(test.command) > 0 {
+ command = append(command, test.command...)
+ } else {
+ command = append(command, defaultServerCommand...)
+ }
+ command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath)
+ // serverPort contains the port that OpenSSL will listen on. OpenSSL
+ // can't take "0" as an argument here so we have to pick a number and
+ // hope that it's not in use on the machine. Since this only occurs
+ // when -update is given and thus when there's a human watching the
+ // test, this isn't too bad.
+ const serverPort = 24323
+ command = append(command, "-accept", strconv.Itoa(serverPort))
+
+ cmd := exec.Command(command[0], command[1:]...)
+ stdin = blockingSource(make(chan bool))
+ cmd.Stdin = stdin
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ cmd.Stderr = &out
+ if err := cmd.Start(); err != nil {
+ return nil, nil, nil, err
}
- tcpConn, err := net.Dial("tcp", "127.0.0.1:10443")
- if err != nil {
- t.Fatal(err)
+ // OpenSSL does print an "ACCEPT" banner, but it does so *before*
+ // opening the listening socket, so we can't use that to wait until it
+ // has started listening. Thus we are forced to poll until we get a
+ // connection.
+ var tcpConn net.Conn
+ for i := uint(0); i < 5; i++ {
+ var err error
+ tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
+ IP: net.IPv4(127, 0, 0, 1),
+ Port: serverPort,
+ })
+ if err == nil {
+ break
+ }
+ time.Sleep((1 << i) * 5 * time.Millisecond)
+ }
+ if tcpConn == nil {
+ close(stdin)
+ out.WriteTo(os.Stdout)
+ cmd.Process.Kill()
+ return nil, nil, nil, cmd.Wait()
}
record := &recordingConn{
Conn: tcpConn,
}
- config := GetTestConfig()
- conn := Client(record, config)
- if err := conn.Handshake(); err != nil {
- t.Fatalf("error from TLS handshake: %s", err)
- }
-
- conn.Write([]byte("hello\n"))
- conn.Close()
+ return record, cmd, stdin, nil
+}
- record.WriteTo(os.Stdout)
+func (test *clientTest) dataPath() string {
+ return filepath.Join("testdata", "Client-"+test.name)
}
-func TestEmptyRecords(t *testing.T) {
- // emptyRecordScript contains a TLS connection with an empty record as
- // the first application data from the server. This test ensures that
- // the empty record doesn't cause (0, nil) to be returned from
- // Conn.Read.
- config := *testConfig
- config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+func (test *clientTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
+ }
+ defer in.Close()
+ return parseTestData(in)
+}
- c, s := net.Pipe()
- cli := Client(c, &config)
- go func() {
- buf := make([]byte, 1024)
- n, err := cli.Read(buf)
- defer c.Close()
- defer cli.Close()
+func (test *clientTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
+ var stdin blockingSource
+ if write {
+ var err error
+ recordingConn, childProcess, stdin, err = test.connFromCommand()
if err != nil {
- t.Fatalf("error reading from tls.Client: %s", err)
+ t.Fatalf("Failed to start subcommand: %s", err)
}
- const expectedLength = 197
- if n != expectedLength {
- t.Fatalf("incorrect length reading from tls.Client, got %d, want %d", n, expectedLength)
+ clientConn = recordingConn
+ } else {
+ clientConn, serverConn = net.Pipe()
+ }
+
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ client := Client(clientConn, config)
+
+ doneChan := make(chan bool)
+ go func() {
+ if _, err := client.Write([]byte("hello\n")); err != nil {
+ t.Logf("Client.Write failed: %s", err)
}
+ client.Close()
+ clientConn.Close()
+ doneChan <- true
}()
- defer c.Close()
- for i, b := range emptyRecordScript {
- if i%2 == 1 {
- s.Write(b)
- continue
+ if !write {
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+ }
+ for i, b := range flows {
+ if i%2 == 1 {
+ serverConn.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(serverConn, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", test.name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b)
+ }
}
- bb := make([]byte, len(b))
- _, err := io.ReadFull(s, bb)
+ serverConn.Close()
+ }
+
+ <-doneChan
+
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- t.Fatalf("#%d: %s", i, err)
+ t.Fatalf("Failed to create output file: %s", err)
}
- if !bytes.Equal(b, bb) {
- t.Fatalf("#%d: mismatch on read: got:%x want:%x", i, bb, b)
+ defer out.Close()
+ recordingConn.Close()
+ close(stdin)
+ childProcess.Process.Kill()
+ childProcess.Wait()
+ if len(recordingConn.flows) < 3 {
+ childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ t.Fatalf("Client connection didn't work")
}
+ recordingConn.WriteTo(out)
+ fmt.Printf("Wrote %s\n", path)
}
}
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in client mode:
-// % go test -test.run "TestRunClient" -connect
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-// -----BEGIN RSA PRIVATE KEY-----
-// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
-// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
-// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
-// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
-// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
-// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
-// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
-// -----END RSA PRIVATE KEY-----
-//
-// and certificate is:
-// -----BEGIN CERTIFICATE-----
-// MIICKzCCAdWgAwIBAgIJALE1E2URIMWSMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-// BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-// aWRnaXRzIFB0eSBMdGQwHhcNMTIwNDA2MTcxMDEzWhcNMTUwNDA2MTcxMDEzWjBF
-// MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
-// ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+z
-// w4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/
-// 7tdkuD8Ey2//Kv7+ue0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUeKaXmmO1xaGlM7oi
-// fCNuWxt6zCswdQYDVR0jBG4wbIAUeKaXmmO1xaGlM7oifCNuWxt6zCuhSaRHMEUx
-// CzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRl
-// cm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCxNRNlESDFkjAMBgNVHRMEBTADAQH/MA0G
-// CSqGSIb3DQEBBQUAA0EAhTZAc8G7GtrUWZ8tonAxRnTsg26oyDxRrzms7EC86CJG
-// HZnWRiok1IsFCEv7NRFukrt3uuQSu/TIXpyBqJdgTA==
-// -----END CERTIFICATE-----
-var rsaRC4ClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 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, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x1b, 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,
- },
+func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) {
+ test := *template
+ test.name = prefix + test.name
+ if len(test.command) == 0 {
+ test.command = defaultClientCommand
+ }
+ test.command = append([]string(nil), test.command...)
+ test.command = append(test.command, option)
+ test.run(t, *update)
+}
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5,
- 0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3,
- 0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56,
- 0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea,
- 0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6,
- 0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8,
- 0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a,
- 0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a,
- 0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3,
- 0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82,
- 0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01,
- 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
- 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73,
- 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43,
- 0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20,
- 0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34,
- 0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17,
- 0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32,
- 0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d,
- 0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32,
- 0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51,
- 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e,
- 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70,
- 0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30,
- 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a,
- 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74,
- 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
- 0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69,
- 0x74, 0x29, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48,
- 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, 0x27,
- 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, 0xef,
- 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, 0x5b,
- 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, 0xfc,
- 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, 0x45,
- 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, 0xa0,
- 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, 0x64,
- 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, 0xfe,
- 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03,
- 0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41,
- 0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4,
- 0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c,
- 0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3,
- 0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06,
- 0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6,
- 0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65,
- 0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf,
- 0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec,
- 0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2,
- 0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57,
- 0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf,
- 0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed,
- 0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e,
- 0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0,
- 0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29,
- 0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04,
- 0x0e, 0x00, 0x00, 0x00,
- },
+func runClientTestTLS10(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv10-", "-tls1")
+}
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1,
- 0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce,
- 0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82,
- 0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67,
- 0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69,
- 0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47,
- 0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c,
- 0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28,
- 0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8,
- 0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b,
- 0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63,
- 0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c,
- 0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54,
- 0x25, 0x2a,
- },
+func runClientTestTLS11(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv11-", "-tls1_1")
+}
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6,
- 0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e,
- 0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70,
- 0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90,
- 0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,
- },
+func runClientTestTLS12(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-var ecdheRSAAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 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, 0x1b, 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,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
- 0x4e, 0x03, 0x01, 0x50, 0xad, 0x72, 0xb1, 0x14,
- 0x45, 0xce, 0x0a, 0x95, 0xf9, 0x63, 0xef, 0xa8,
- 0xe5, 0x07, 0x34, 0x04, 0xe9, 0x08, 0x0f, 0x38,
- 0xe4, 0x28, 0x27, 0x91, 0x07, 0x03, 0xe2, 0xfe,
- 0xe3, 0x25, 0xf7, 0x20, 0x08, 0x42, 0xa2, 0x01,
- 0x69, 0x53, 0xf0, 0xd9, 0x4c, 0xfa, 0x01, 0xa1,
- 0xce, 0x4b, 0xf8, 0x28, 0x21, 0xad, 0x06, 0xbe,
- 0xe0, 0x1b, 0x3b, 0xf7, 0xec, 0xd2, 0x52, 0xae,
- 0x2a, 0x57, 0xb7, 0xa8, 0xc0, 0x13, 0x00, 0x00,
- 0x06, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0x39, 0x0b, 0x00, 0x02, 0x35,
- 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f, 0x30, 0x82,
- 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb1, 0x35,
- 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x32, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37,
- 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17, 0x0d, 0x31,
- 0x35, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
- 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30,
- 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84,
- 0x27, 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15,
- 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36,
- 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0,
- 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66,
- 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8,
- 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7,
- 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a,
- 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30,
- 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
- 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, 0xb5,
- 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, 0x23,
- 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0x30, 0x75,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30,
- 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63,
- 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c,
- 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0xa1,
- 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1, 0x35, 0x13,
- 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0c, 0x06,
- 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
- 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x03, 0x41, 0x00, 0x85, 0x36, 0x40,
- 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4, 0x59, 0x9f,
- 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74, 0xec, 0x83,
- 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf, 0x39, 0xac,
- 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46, 0x1d, 0x99,
- 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b, 0x05, 0x08,
- 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92, 0xbb, 0x77,
- 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8, 0x5e, 0x9c,
- 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16, 0x03, 0x01,
- 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87, 0x03, 0x00,
- 0x17, 0x41, 0x04, 0x1c, 0x8f, 0x9c, 0x6d, 0xe7,
- 0xab, 0x3e, 0xf8, 0x0a, 0x5d, 0xe1, 0x86, 0xb4,
- 0xe2, 0x8e, 0xb2, 0x1c, 0x3b, 0xd9, 0xb6, 0x08,
- 0x80, 0x58, 0x21, 0xe9, 0x0e, 0xc6, 0x66, 0x67,
- 0x97, 0xcb, 0xb9, 0x92, 0x07, 0x00, 0xc4, 0xe5,
- 0xec, 0x5f, 0xb4, 0xe2, 0x20, 0xa9, 0xc9, 0x62,
- 0xd0, 0x98, 0xd5, 0xe3, 0x53, 0xff, 0xd0, 0x0a,
- 0x6e, 0x29, 0x69, 0x39, 0x2a, 0x4b, 0x5c, 0xd8,
- 0x6c, 0xf5, 0xfe, 0x00, 0x40, 0x35, 0xa7, 0x26,
- 0x2e, 0xc2, 0x48, 0x93, 0x32, 0xf7, 0x7d, 0x0f,
- 0x0d, 0x77, 0x56, 0x9a, 0x85, 0x0c, 0xa6, 0x74,
- 0x06, 0xb8, 0x3d, 0x90, 0x56, 0x12, 0x63, 0xff,
- 0x00, 0x5e, 0x0f, 0xf7, 0x24, 0xf7, 0xdb, 0x48,
- 0x71, 0xe9, 0x2e, 0x03, 0xd3, 0xfa, 0x3a, 0xae,
- 0xa0, 0xc1, 0x77, 0x3c, 0x4c, 0x59, 0xce, 0x33,
- 0x1a, 0xd2, 0x47, 0x83, 0xfa, 0xea, 0xd8, 0x1e,
- 0x06, 0xe7, 0x7d, 0xa0, 0x9b, 0x16, 0x03, 0x01,
- 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xd9, 0xa7,
- 0x80, 0x56, 0x3f, 0xa3, 0x8f, 0x96, 0x72, 0x4e,
- 0x4e, 0x6e, 0x23, 0x41, 0x8f, 0xda, 0x91, 0xb2,
- 0x9e, 0x63, 0x23, 0x82, 0x64, 0xcd, 0x07, 0x24,
- 0xd3, 0x40, 0x20, 0x22, 0x4c, 0xe3, 0xff, 0x38,
- 0xbb, 0x43, 0x9d, 0x57, 0x11, 0xd5, 0x46, 0xa5,
- 0x05, 0x29, 0x92, 0x02, 0xce, 0xdf,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x90, 0xe7, 0xba, 0x0e, 0xb1, 0xda,
- 0x92, 0xb5, 0x77, 0x56, 0x38, 0xa6, 0x22, 0xc1,
- 0x72, 0xeb, 0x8a, 0x68, 0x09, 0xb6, 0x74, 0xad,
- 0xb3, 0x4a, 0xf2, 0xdd, 0x09, 0x9b, 0xc9, 0x4f,
- 0x84, 0x73, 0x8b, 0xd6, 0x97, 0x50, 0x23, 0x1c,
- 0xa0, 0xc2, 0x0c, 0x25, 0x18, 0xdd, 0x5e, 0x15,
- 0x4d, 0xd9, 0xef, 0x4f, 0x6a, 0x43, 0x61, 0x9c,
- 0x95, 0xde, 0x3c, 0x66, 0xc4, 0xc1, 0x33, 0x56,
- 0xdd, 0x2f, 0x90, 0xaf, 0x68, 0x5c, 0x9c, 0xa4,
- 0x90, 0x6d, 0xbf, 0x51, 0x1d, 0x68, 0xcb, 0x81,
- 0x77, 0x52, 0xa0, 0x93, 0x2a, 0xf8, 0xc7, 0x61,
- 0x87, 0x76, 0xca, 0x93, 0x9e, 0xd6, 0xee, 0x6f,
- 0x3f, 0xeb, 0x7d, 0x06, 0xdd, 0x73, 0x4e, 0x27,
- 0x16, 0x63, 0x92, 0xe4, 0xb2, 0x3f, 0x91, 0x23,
- 0x21, 0x97, 0x90, 0xce, 0x53, 0xb8, 0xb0, 0x9d,
- 0xbd, 0xbd, 0x33, 0x84, 0xad, 0x6b, 0x2e, 0x7b,
- 0xf5, 0xeb, 0x1d, 0x64, 0x37, 0x2e, 0x29, 0x4e,
- 0xb0, 0x93, 0xdb, 0x92, 0xc7, 0xaa, 0x94, 0xa5,
- 0x3b, 0x64, 0xd0,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x20, 0x11, 0xd8, 0x6b,
- 0x3c, 0xf6, 0xbe, 0xf4, 0x54, 0x87, 0xec, 0x75,
- 0x0c, 0x44, 0xdb, 0x92, 0xfc, 0xde, 0x7e, 0x0f,
- 0x9f, 0x87, 0x87, 0x9c, 0x03, 0xd5, 0x07, 0x84,
- 0xe0, 0x3a, 0xf8, 0xae, 0x14, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0xba, 0x54, 0xef, 0x5b, 0xce, 0xfd,
- 0x47, 0x76, 0x6d, 0xa1, 0x8b, 0xfd, 0x48, 0xde,
- 0x6e, 0x26, 0xc1, 0x0c, 0x9d, 0x54, 0xbf, 0x98,
- 0xf6, 0x1c, 0x80, 0xb9, 0xca, 0x93, 0x81, 0x0a,
- 0x2e, 0x06, 0x15, 0x03, 0x01, 0x00, 0x20, 0x93,
- 0x3e, 0x38, 0x17, 0xc9, 0x0a, 0xc3, 0xea, 0xd3,
- 0x92, 0x75, 0xa6, 0x53, 0x37, 0x4d, 0x74, 0x94,
- 0xbe, 0x01, 0xdc, 0x5c, 0x5a, 0x0f, 0x09, 0xf6,
- 0x57, 0x33, 0xc3, 0xbc, 0x3f, 0x7a, 0x4d,
- },
+func TestHandshakeClientRSARC4(t *testing.T) {
+ test := &clientTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA"},
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
}
-var emptyRecordScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 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, 0x00, 0x35,
- 0x01, 0x00, 0x00, 0x1b, 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,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x51, 0x71, 0x8e, 0x03, 0x02,
- 0xef, 0x09, 0xf2, 0x0e, 0xf5, 0x3b, 0x29, 0x9a,
- 0xa8, 0x8b, 0x46, 0xa3, 0xd4, 0xb4, 0xc1, 0x14,
- 0xc3, 0x19, 0x99, 0xba, 0x3d, 0x78, 0xcf, 0x50,
- 0xd1, 0xe7, 0x26, 0x20, 0xa0, 0x37, 0x6d, 0xc9,
- 0xae, 0x93, 0x33, 0x81, 0x20, 0xe3, 0xc1, 0x90,
- 0x64, 0x6e, 0x67, 0x93, 0xdb, 0xb4, 0x04, 0x16,
- 0xc4, 0x25, 0xdd, 0x10, 0x79, 0x3c, 0x18, 0x0a,
- 0x7c, 0xfd, 0x28, 0x65, 0x00, 0x35, 0x00, 0x16,
- 0x03, 0x01, 0x09, 0x9e, 0x0b, 0x00, 0x09, 0x9a,
- 0x00, 0x09, 0x97, 0x00, 0x04, 0xea, 0x30, 0x82,
- 0x04, 0xe6, 0x30, 0x82, 0x03, 0xce, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0xff, 0xab,
- 0x02, 0x93, 0xe0, 0x72, 0x99, 0x18, 0x6c, 0x9e,
- 0x96, 0xb8, 0xb9, 0xf7, 0x47, 0xcb, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x41, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x47,
- 0x41, 0x4e, 0x44, 0x49, 0x20, 0x53, 0x41, 0x53,
- 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x15, 0x47, 0x61, 0x6e, 0x64, 0x69,
- 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
- 0x64, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41,
- 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31,
- 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x31,
- 0x34, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
- 0x30, 0x62, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d,
- 0x61, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74,
- 0x72, 0x6f, 0x6c, 0x20, 0x56, 0x61, 0x6c, 0x69,
- 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x24, 0x30,
- 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1b,
- 0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53, 0x74,
- 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x57,
- 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x20,
- 0x53, 0x53, 0x4c, 0x31, 0x17, 0x30, 0x15, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x14, 0x0e, 0x2a, 0x2e,
- 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
- 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xdc, 0xe3, 0xfd,
- 0xce, 0xc1, 0x66, 0x62, 0x28, 0x8b, 0x99, 0x65,
- 0x72, 0x52, 0x88, 0x93, 0x5b, 0x3f, 0x8d, 0xde,
- 0x2b, 0xb0, 0xa0, 0xf4, 0xbd, 0xb4, 0x07, 0x5f,
- 0x9e, 0x01, 0x47, 0x60, 0x57, 0x5f, 0xdf, 0xdc,
- 0x63, 0x28, 0x1c, 0x1e, 0x5b, 0xc8, 0xe6, 0x29,
- 0xdd, 0xeb, 0x26, 0x63, 0xd5, 0xbf, 0x83, 0xb2,
- 0x2d, 0xcd, 0x2c, 0xa0, 0xb6, 0x91, 0xad, 0xaf,
- 0x95, 0x21, 0x1d, 0x1f, 0x39, 0x8d, 0x3e, 0x17,
- 0xd6, 0xbd, 0x99, 0xf5, 0x6c, 0xd4, 0xcb, 0x79,
- 0x12, 0x3e, 0x11, 0xb9, 0x7e, 0x62, 0xbc, 0x2d,
- 0xbf, 0xe0, 0x55, 0x1b, 0x5c, 0x1e, 0xce, 0x31,
- 0xd9, 0xf8, 0x56, 0x68, 0x95, 0x2b, 0x15, 0x84,
- 0x35, 0xae, 0x98, 0x2c, 0x63, 0x01, 0xb2, 0x0d,
- 0xab, 0xa8, 0x61, 0xef, 0x7f, 0x15, 0x2c, 0x6d,
- 0xf7, 0x67, 0x1d, 0xb8, 0x8d, 0xf6, 0xa2, 0x1c,
- 0x4e, 0x85, 0xf0, 0xea, 0x1a, 0x2b, 0xc8, 0xac,
- 0x70, 0x86, 0x9a, 0xbb, 0x9e, 0x9d, 0xbd, 0xc9,
- 0x87, 0x2b, 0x9f, 0x5e, 0x40, 0x44, 0x9b, 0xba,
- 0x96, 0x45, 0x24, 0xbc, 0x49, 0xb8, 0xfe, 0x26,
- 0x3a, 0x1d, 0x1a, 0x0a, 0x3a, 0x90, 0x9c, 0x75,
- 0x51, 0x59, 0x89, 0x98, 0x1a, 0x56, 0xe1, 0x3a,
- 0x1a, 0xba, 0xff, 0xb4, 0x37, 0x7d, 0xd8, 0x99,
- 0xe2, 0xeb, 0x45, 0x27, 0xe2, 0x42, 0x42, 0x46,
- 0xbb, 0x00, 0x29, 0x9f, 0x30, 0xc9, 0x1e, 0x6c,
- 0xce, 0x59, 0x0e, 0xbe, 0x16, 0x03, 0x31, 0xec,
- 0x10, 0xc1, 0x6d, 0xca, 0x9d, 0x5f, 0x6d, 0xf1,
- 0x26, 0x11, 0xe5, 0x50, 0xa1, 0xbb, 0x67, 0xb2,
- 0xe0, 0x2b, 0xed, 0x76, 0x5b, 0xc7, 0x68, 0xc0,
- 0x18, 0xad, 0x91, 0x9e, 0xb5, 0xd4, 0x4d, 0x21,
- 0xcd, 0x98, 0xd9, 0xe0, 0x05, 0x0a, 0x4d, 0x24,
- 0xa3, 0xe6, 0x12, 0x04, 0xdd, 0x50, 0xe6, 0xc8,
- 0x7a, 0x69, 0xb9, 0x32, 0x43, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x82, 0x01, 0xb6, 0x30, 0x82,
- 0x01, 0xb2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb6,
- 0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6, 0xcd,
- 0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10, 0x31,
- 0xa7, 0x79, 0x21, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x62, 0x37,
- 0xd4, 0x3c, 0xbf, 0xd9, 0xc2, 0x99, 0xf3, 0x28,
- 0x3e, 0xdb, 0xca, 0xee, 0xf3, 0xb3, 0xc8, 0x73,
- 0xb0, 0x3c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
- 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
- 0x05, 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
- 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
- 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
- 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01,
- 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
- 0x60, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x59,
- 0x30, 0x57, 0x30, 0x4b, 0x06, 0x0b, 0x2b, 0x06,
- 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02,
- 0x1a, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
- 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
- 0x77, 0x77, 0x77, 0x2e, 0x67, 0x61, 0x6e, 0x64,
- 0x69, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f,
- 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x2f,
- 0x66, 0x72, 0x2f, 0x73, 0x73, 0x6c, 0x2f, 0x63,
- 0x70, 0x73, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x30,
- 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02,
- 0x01, 0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f,
- 0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f,
- 0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70,
- 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67,
- 0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65, 0x74,
- 0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53, 0x74,
- 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53, 0x53,
- 0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30,
- 0x6a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x01, 0x01, 0x04, 0x5e, 0x30, 0x5c, 0x30,
- 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x30, 0x02, 0x86, 0x2b, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e,
- 0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65,
- 0x74, 0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53,
- 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53,
- 0x53, 0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74,
- 0x30, 0x21, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x01, 0x86, 0x15, 0x68, 0x74,
- 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73,
- 0x70, 0x2e, 0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e,
- 0x6e, 0x65, 0x74, 0x30, 0x27, 0x06, 0x03, 0x55,
- 0x1d, 0x11, 0x04, 0x20, 0x30, 0x1e, 0x82, 0x0e,
- 0x2a, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f,
- 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x82, 0x0c,
- 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
- 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x5b, 0x4a, 0x3a, 0x1d, 0x75, 0xe0, 0xc0, 0x9e,
- 0xc9, 0x16, 0x66, 0x7f, 0x73, 0x95, 0x6e, 0x35,
- 0xe4, 0x27, 0xfa, 0x8c, 0x9d, 0xee, 0xb1, 0x37,
- 0x42, 0x3f, 0x54, 0x6a, 0x9d, 0x41, 0x84, 0x57,
- 0xe1, 0x03, 0x3d, 0x69, 0x61, 0x77, 0x3b, 0x91,
- 0xa2, 0x70, 0x94, 0xb6, 0x8e, 0x41, 0x63, 0x70,
- 0xf2, 0x16, 0x04, 0x50, 0x05, 0x14, 0xfb, 0x59,
- 0x7d, 0x89, 0x09, 0x3f, 0xb6, 0xef, 0xca, 0x3c,
- 0x89, 0x88, 0x08, 0xe9, 0xa1, 0xf3, 0x33, 0x31,
- 0x05, 0x4d, 0x70, 0xff, 0xdd, 0xa7, 0xd2, 0xe2,
- 0xa0, 0x94, 0x3a, 0xf7, 0xc2, 0x9f, 0xad, 0x2b,
- 0x2e, 0x20, 0xfa, 0x6c, 0xe1, 0xfc, 0xe6, 0x62,
- 0x22, 0xa1, 0x38, 0x93, 0xec, 0x3e, 0xce, 0xfd,
- 0x1f, 0xdd, 0xd4, 0x7c, 0x39, 0x46, 0x8b, 0xb4,
- 0x64, 0xfa, 0xa1, 0x46, 0x87, 0x78, 0x2c, 0xd7,
- 0x9c, 0xdd, 0x60, 0xd6, 0xda, 0x8e, 0xd8, 0x29,
- 0x6d, 0x61, 0xa7, 0x29, 0x07, 0x76, 0xfc, 0xf9,
- 0xbd, 0xfd, 0x14, 0xeb, 0x44, 0x70, 0xff, 0xd0,
- 0x23, 0x99, 0x83, 0xc5, 0x5c, 0x56, 0x88, 0xaa,
- 0x34, 0xda, 0xa6, 0xb3, 0x9a, 0xbf, 0xda, 0x58,
- 0x1e, 0xa4, 0xb8, 0xc0, 0x40, 0x9d, 0xf0, 0xfc,
- 0xf1, 0x23, 0xc2, 0xbc, 0x59, 0xe1, 0x82, 0xed,
- 0x5d, 0xfb, 0x99, 0xaf, 0xf5, 0xf5, 0x15, 0xb8,
- 0x8b, 0x59, 0xce, 0xaa, 0xca, 0xdf, 0xdc, 0x94,
- 0x11, 0xe0, 0x96, 0xbf, 0x9f, 0x54, 0xa4, 0x9f,
- 0x54, 0x36, 0x4a, 0xe8, 0x93, 0xda, 0xf4, 0x8c,
- 0xb0, 0x6b, 0x8d, 0x4a, 0x9e, 0x11, 0xae, 0xcb,
- 0xcb, 0x33, 0x8a, 0x4d, 0xcd, 0x4e, 0xa5, 0x9b,
- 0xe9, 0x14, 0x46, 0x43, 0x9b, 0x96, 0x5f, 0x6d,
- 0xf2, 0xea, 0x40, 0xef, 0x14, 0xc3, 0x99, 0x9f,
- 0x23, 0x1e, 0xa5, 0x13, 0xab, 0x08, 0xea, 0x8f,
- 0x68, 0x5b, 0x7d, 0x71, 0xdf, 0x18, 0xd1, 0x57,
- 0x00, 0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x30,
- 0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x10, 0x5a, 0xb6, 0x1d, 0xac, 0x1e, 0x4d,
- 0xa2, 0x06, 0x14, 0xc7, 0x55, 0x3d, 0x3d, 0xa9,
- 0xb2, 0xdc, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x02, 0x55, 0x54, 0x31, 0x17,
- 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
- 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61,
- 0x6b, 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31,
- 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53,
- 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
- 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b,
- 0x13, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65,
- 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
- 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
- 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
- 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77,
- 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x30,
- 0x38, 0x31, 0x30, 0x32, 0x33, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30,
- 0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x34, 0x38,
- 0x33, 0x38, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x09, 0x47, 0x41, 0x4e,
- 0x44, 0x49, 0x20, 0x53, 0x41, 0x53, 0x31, 0x1e,
- 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
- 0x15, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53,
- 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
- 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6,
- 0x54, 0x3d, 0xa5, 0xdb, 0x0d, 0x22, 0x78, 0x50,
- 0x6a, 0x5a, 0x23, 0x89, 0x3f, 0x97, 0xa1, 0xd4,
- 0x07, 0x1a, 0xa9, 0x58, 0x08, 0x9b, 0xa0, 0x15,
- 0xc3, 0x32, 0xb6, 0xb7, 0xf1, 0xe8, 0xb9, 0xa5,
- 0x6f, 0xad, 0x37, 0xf6, 0x6e, 0x71, 0x1b, 0xb4,
- 0x75, 0x2d, 0x48, 0x5e, 0x9f, 0xc6, 0x15, 0xaa,
- 0x81, 0xef, 0xe5, 0xc4, 0x88, 0x95, 0x8a, 0x3a,
- 0x6c, 0x77, 0xcc, 0xb5, 0xcd, 0x65, 0xe4, 0x67,
- 0xe5, 0x73, 0xc9, 0x50, 0x52, 0x94, 0xc1, 0x27,
- 0x49, 0x3e, 0xa0, 0x6b, 0x41, 0x16, 0x41, 0xb6,
- 0x94, 0x99, 0x41, 0xae, 0x3e, 0xcb, 0xe2, 0x06,
- 0x46, 0x09, 0xe9, 0x4d, 0xbe, 0xc9, 0x4c, 0x55,
- 0xa9, 0x18, 0x7e, 0xa6, 0xdf, 0x6e, 0xfd, 0x4a,
- 0xb2, 0xcc, 0x6c, 0x4e, 0xd9, 0xc8, 0x50, 0x15,
- 0x93, 0xb3, 0xf2, 0xe9, 0xe3, 0xc2, 0x6a, 0xad,
- 0x3a, 0xd5, 0xfb, 0xc3, 0x79, 0x50, 0x9f, 0x25,
- 0x79, 0x29, 0xb2, 0x47, 0x64, 0x7c, 0x20, 0x3e,
- 0xe2, 0x08, 0x4d, 0x93, 0x29, 0x14, 0xb6, 0x34,
- 0x6e, 0xcf, 0x71, 0x46, 0x7e, 0x76, 0x10, 0xf4,
- 0xfd, 0x6c, 0xaa, 0x01, 0xd2, 0xc2, 0x06, 0xde,
- 0x92, 0x83, 0xcc, 0x58, 0x90, 0x2e, 0x92, 0xde,
- 0x1e, 0x65, 0xb7, 0x63, 0x2f, 0x3d, 0xb2, 0xeb,
- 0x70, 0x8c, 0x4c, 0xe0, 0xbe, 0x15, 0x9d, 0xde,
- 0xc1, 0x4d, 0x56, 0xf8, 0x0b, 0xc6, 0x8e, 0x07,
- 0xb9, 0x5d, 0xdf, 0x95, 0xf0, 0x7b, 0x40, 0x1f,
- 0x1a, 0x2c, 0xd7, 0x9c, 0x2b, 0x4b, 0x76, 0xf4,
- 0x59, 0xf5, 0x43, 0xc1, 0x2c, 0x66, 0x10, 0x9e,
- 0x9e, 0x66, 0x96, 0x60, 0x9d, 0x1c, 0x74, 0x1b,
- 0x4e, 0x18, 0x5c, 0x08, 0xb0, 0x6e, 0x6c, 0xca,
- 0x69, 0x1a, 0x02, 0xe9, 0xbb, 0xca, 0x78, 0xef,
- 0x66, 0x2e, 0xe3, 0x32, 0xfd, 0x41, 0x5c, 0x95,
- 0x74, 0x81, 0x4d, 0xf4, 0xda, 0xfe, 0x4b, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x3e,
- 0x30, 0x82, 0x01, 0x3a, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
- 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
- 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96,
- 0x9d, 0x4b, 0xd2, 0xc3, 0x45, 0x30, 0x1d, 0x06,
- 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
- 0xb6, 0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6,
- 0xcd, 0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10,
- 0x31, 0xa7, 0x79, 0x21, 0x30, 0x0e, 0x06, 0x03,
- 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
- 0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03,
- 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
- 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
- 0x30, 0x18, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
- 0x11, 0x30, 0x0f, 0x30, 0x0d, 0x06, 0x0b, 0x2b,
- 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02,
- 0x02, 0x1a, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d,
- 0x1f, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0xa0,
- 0x37, 0xa0, 0x35, 0x86, 0x33, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
- 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73,
- 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54,
- 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69,
- 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64,
- 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c,
- 0x30, 0x74, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x01, 0x01, 0x04, 0x68, 0x30, 0x66,
- 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x02, 0x86, 0x31, 0x68, 0x74,
- 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74,
- 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
- 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55,
- 0x54, 0x4e, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75,
- 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30,
- 0x25, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x30, 0x01, 0x86, 0x19, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70,
- 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
- 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,
- 0x01, 0x00, 0x19, 0x53, 0xbf, 0x03, 0x3d, 0x9b,
- 0xe2, 0x6b, 0x5a, 0xfd, 0xba, 0x49, 0x1f, 0x4f,
- 0xec, 0xe1, 0xc6, 0x82, 0x39, 0x3c, 0xd2, 0x03,
- 0x04, 0x0f, 0xab, 0x7b, 0x3e, 0x82, 0xa9, 0x85,
- 0x10, 0x1f, 0xf4, 0xde, 0x32, 0xaf, 0x58, 0x3f,
- 0xff, 0x70, 0xf3, 0x30, 0x1d, 0x97, 0x2d, 0x4c,
- 0x9a, 0xe2, 0xec, 0x0c, 0x3e, 0x14, 0x2d, 0x2f,
- 0x98, 0x48, 0x9d, 0xae, 0x16, 0x6a, 0xac, 0x2d,
- 0x42, 0xaa, 0xb5, 0x64, 0xa4, 0x70, 0xbb, 0xeb,
- 0x73, 0x94, 0x7b, 0x46, 0x4c, 0xe7, 0x7a, 0x14,
- 0x76, 0x5b, 0x4c, 0x1d, 0x84, 0xa1, 0x20, 0x74,
- 0x1f, 0x2e, 0x4b, 0x5c, 0x70, 0x88, 0xdc, 0xbd,
- 0xf7, 0x19, 0x3d, 0xed, 0x59, 0x0d, 0xe2, 0x3f,
- 0x26, 0xe2, 0x9c, 0xac, 0xa4, 0x3c, 0x95, 0x1c,
- 0xf8, 0xbe, 0x8c, 0x03, 0xae, 0xf0, 0xe5, 0x9c,
- 0x4d, 0xbc, 0xc7, 0x9b, 0x58, 0x00, 0xbf, 0xaf,
- 0xad, 0xfa, 0x37, 0x6e, 0x71, 0x6d, 0x18, 0x34,
- 0x0e, 0xc1, 0xea, 0x6a, 0xf8, 0x0d, 0xdf, 0x69,
- 0x54, 0x56, 0x15, 0xf2, 0x28, 0xb3, 0xfe, 0xa4,
- 0x63, 0xec, 0xc5, 0x04, 0x64, 0x60, 0xbb, 0xfe,
- 0x2a, 0xf0, 0xf4, 0x87, 0xa1, 0xb0, 0xae, 0xbd,
- 0xaa, 0xe4, 0x2f, 0xe3, 0x03, 0x0b, 0x2f, 0x66,
- 0x5f, 0x85, 0xa4, 0x32, 0x7b, 0x46, 0xed, 0x25,
- 0x0c, 0xe7, 0xf1, 0xb7, 0xe7, 0x19, 0xfd, 0x60,
- 0xba, 0x5f, 0x87, 0x77, 0xde, 0x98, 0x07, 0x96,
- 0xe4, 0x5e, 0xea, 0x63, 0x7d, 0xa8, 0xde, 0x55,
- 0xda, 0x61, 0x5c, 0x3c, 0x90, 0x83, 0x43, 0x04,
- 0x07, 0x3c, 0xdd, 0xf3, 0xf8, 0x9f, 0x06, 0x52,
- 0x0a, 0xde, 0xc7, 0xb6, 0x7b, 0x8f, 0xe1, 0x11,
- 0xf7, 0x04, 0x7a, 0x35, 0xff, 0x6a, 0xbc, 0x5b,
- 0xc7, 0x50, 0x49, 0x08, 0x70, 0x6f, 0x94, 0x43,
- 0xcd, 0x9e, 0xc7, 0x70, 0xf1, 0xdb, 0xd0, 0x6d,
- 0xda, 0x8f, 0x16, 0x03, 0x01, 0x00, 0x0e, 0x0d,
- 0x00, 0x00, 0x06, 0x03, 0x01, 0x02, 0x40, 0x00,
- 0x00, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02,
- 0xba, 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30,
- 0x82, 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30,
- 0x39, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d,
- 0x31, 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81,
- 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
- 0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5,
- 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6,
- 0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a,
- 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5,
- 0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5,
- 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e,
- 0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12,
- 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa,
- 0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3,
- 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54,
- 0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe,
- 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d,
- 0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51,
- 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66,
- 0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a,
- 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d,
- 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
- 0xa7, 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03,
- 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55,
- 0x1d, 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14,
- 0xb1, 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28,
- 0xdb, 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26,
- 0x8e, 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47,
- 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49,
- 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20,
- 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20,
- 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82,
- 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f,
- 0xb8, 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
- 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
- 0x81, 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7,
- 0x6b, 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2,
- 0xb0, 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75,
- 0xb5, 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e,
- 0xae, 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3,
- 0x6e, 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08,
- 0xb5, 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb,
- 0x30, 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec,
- 0xe7, 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d,
- 0x78, 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a,
- 0x2d, 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9,
- 0x75, 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5,
- 0xcd, 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0,
- 0x1c, 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd,
- 0x57, 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99,
- 0x9b, 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90,
- 0xa7, 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x01, 0x06,
- 0x10, 0x00, 0x01, 0x02, 0x01, 0x00, 0x25, 0x48,
- 0x6c, 0x0a, 0xde, 0x9d, 0x3a, 0x57, 0xe4, 0x2e,
- 0xb9, 0xfc, 0xb4, 0x46, 0x1f, 0x20, 0x4f, 0x58,
- 0x4d, 0x12, 0x08, 0xb4, 0x3e, 0x4c, 0xf5, 0xa8,
- 0xa5, 0x16, 0x40, 0x29, 0x19, 0x04, 0x4d, 0xf9,
- 0x54, 0x3a, 0x32, 0xd7, 0x79, 0xf2, 0x0e, 0xc1,
- 0x7b, 0x0c, 0x62, 0x71, 0xbb, 0xb4, 0x8c, 0xe7,
- 0x84, 0xd5, 0xf8, 0x11, 0x77, 0x7f, 0x87, 0x6c,
- 0xfc, 0x25, 0xf3, 0x2d, 0x97, 0x3d, 0x1f, 0xf5,
- 0xfc, 0x64, 0x94, 0x9f, 0xdd, 0x90, 0x82, 0xdd,
- 0x11, 0x74, 0x74, 0x59, 0xa2, 0x1a, 0x71, 0xb2,
- 0x55, 0x6d, 0x18, 0xca, 0x85, 0x47, 0x8b, 0x79,
- 0x73, 0x06, 0x24, 0x38, 0xc3, 0x34, 0x98, 0x84,
- 0x62, 0x81, 0xd8, 0xad, 0x54, 0xad, 0x13, 0xa5,
- 0xf4, 0xe4, 0x82, 0x85, 0xd3, 0xe3, 0x9e, 0xeb,
- 0xb5, 0xf5, 0x95, 0x83, 0x0e, 0xb9, 0x7d, 0xb6,
- 0xda, 0x0c, 0xf6, 0x14, 0x6a, 0x60, 0x8c, 0x75,
- 0x56, 0xf0, 0xe9, 0x60, 0xe0, 0x4c, 0xf4, 0x4e,
- 0x84, 0x8b, 0x4f, 0xf4, 0x2f, 0xde, 0xb7, 0xec,
- 0x61, 0xd3, 0x77, 0x07, 0x6e, 0x41, 0x57, 0xc9,
- 0xd9, 0x1d, 0x75, 0xee, 0x42, 0x63, 0xdc, 0x58,
- 0xad, 0xfc, 0xc7, 0xe1, 0x77, 0x49, 0xb1, 0x58,
- 0x21, 0x96, 0x00, 0x55, 0x90, 0x6b, 0xf6, 0x2a,
- 0x5a, 0x19, 0x25, 0x93, 0x59, 0x9d, 0xaf, 0x79,
- 0x9b, 0x18, 0x5d, 0xf6, 0x5d, 0x64, 0x4b, 0x9a,
- 0xf4, 0xde, 0xf2, 0x7f, 0xbd, 0x93, 0x7e, 0x45,
- 0x3e, 0x17, 0xae, 0xbf, 0x52, 0xe1, 0xba, 0x8e,
- 0x0b, 0xbc, 0x1e, 0x91, 0x9d, 0xf1, 0x4e, 0x0b,
- 0xab, 0x9e, 0x5c, 0x4c, 0x6f, 0xf7, 0xf3, 0x8d,
- 0x8c, 0x6d, 0xeb, 0x46, 0x05, 0x36, 0x7e, 0x2f,
- 0x9c, 0xa1, 0x86, 0x15, 0xe1, 0xe4, 0xb4, 0x20,
- 0x06, 0x44, 0x7b, 0x3c, 0x8b, 0x13, 0x96, 0xf5,
- 0x02, 0xb1, 0x4f, 0x3c, 0x2d, 0x4a, 0x16, 0x03,
- 0x01, 0x00, 0x86, 0x0f, 0x00, 0x00, 0x82, 0x00,
- 0x80, 0x52, 0xb1, 0x0d, 0xfc, 0x85, 0x34, 0x56,
- 0xb9, 0xdf, 0xa7, 0x8e, 0xf4, 0xfd, 0x02, 0x46,
- 0x8a, 0x23, 0xcc, 0x53, 0x3b, 0x0f, 0xa7, 0x61,
- 0xf3, 0xb5, 0xbf, 0xfe, 0x59, 0x77, 0x10, 0xd6,
- 0x56, 0x93, 0x19, 0x6b, 0x2c, 0xf1, 0x35, 0x71,
- 0xe3, 0x36, 0x2f, 0xa0, 0x90, 0x4e, 0x5a, 0xdf,
- 0x8d, 0x06, 0x88, 0xcf, 0xb1, 0x06, 0x56, 0x8b,
- 0x74, 0x8f, 0x02, 0x8e, 0x10, 0xd2, 0xab, 0x8d,
- 0x3f, 0x3e, 0x02, 0xf1, 0x1a, 0x80, 0x6d, 0x0f,
- 0x9e, 0x77, 0xd8, 0xfa, 0x92, 0xb3, 0x16, 0x40,
- 0xeb, 0x9e, 0xca, 0xd7, 0xe4, 0x31, 0xcc, 0x63,
- 0x5f, 0xe2, 0x4c, 0x85, 0x0e, 0xf2, 0xdd, 0xd3,
- 0xfe, 0x7e, 0xa7, 0x60, 0x1c, 0xb4, 0x00, 0xd8,
- 0xbe, 0x4b, 0x9b, 0x66, 0x78, 0x0f, 0xfb, 0x3b,
- 0x52, 0x30, 0x2b, 0x8b, 0xd9, 0xef, 0x82, 0x0a,
- 0xa4, 0x18, 0x1d, 0xb0, 0xb5, 0xbf, 0x54, 0x97,
- 0x0c, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16,
- 0x03, 0x01, 0x00, 0x30, 0xa1, 0x74, 0x22, 0xd8,
- 0x86, 0x6a, 0xbe, 0x53, 0x34, 0x1d, 0xb3, 0x73,
- 0xff, 0x51, 0xc0, 0xce, 0x8e, 0x7d, 0x9b, 0xab,
- 0xcb, 0x8b, 0x79, 0xae, 0x04, 0x01, 0xa7, 0xf2,
- 0x8e, 0x9d, 0xab, 0xa3, 0x73, 0x80, 0x5c, 0xff,
- 0x96, 0x20, 0xbb, 0x8d, 0xc0, 0x02, 0x66, 0x6c,
- 0x83, 0x4b, 0x78, 0x20,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x30, 0x29, 0xd4, 0xfd, 0x03, 0x8b,
- 0x30, 0x20, 0xf7, 0xca, 0xc0, 0x6c, 0x83, 0x5d,
- 0x73, 0xcb, 0x81, 0x60, 0xe0, 0x9a, 0x09, 0xcb,
- 0x33, 0x03, 0x80, 0x81, 0x4e, 0x84, 0x47, 0xd5,
- 0x74, 0x6c, 0x3b, 0xb5, 0xc0, 0x48, 0x0d, 0x52,
- 0xdd, 0xbe, 0xc2, 0x06, 0xf5, 0x79, 0x2b, 0x3e,
- 0x99, 0x56, 0x94, 0x17, 0x03, 0x01, 0x00, 0x20,
- 0x26, 0x46, 0x90, 0x9d, 0xef, 0x59, 0x00, 0xb6,
- 0x70, 0xe8, 0x1e, 0x1a, 0x80, 0x8b, 0x04, 0xb2,
- 0xfc, 0x51, 0xf8, 0x93, 0xbe, 0x00, 0x28, 0xba,
- 0xb8, 0xdc, 0x51, 0x7e, 0x92, 0x80, 0xfa, 0xf2,
- 0x17, 0x03, 0x01, 0x00, 0xe0, 0xb8, 0x2e, 0xc4,
- 0x6b, 0x3f, 0xda, 0x39, 0x87, 0x7f, 0x03, 0x43,
- 0x28, 0xdd, 0xb9, 0xf9, 0x9e, 0x16, 0xf5, 0xce,
- 0x3f, 0x7e, 0x6a, 0x7b, 0xb3, 0x60, 0x14, 0xe1,
- 0xea, 0x54, 0xc5, 0xe6, 0x05, 0x0a, 0x6c, 0xe0,
- 0xef, 0x58, 0x29, 0x8a, 0x77, 0x64, 0x77, 0x5d,
- 0x9c, 0xe2, 0xe0, 0x3c, 0x6d, 0x87, 0x82, 0xbe,
- 0x47, 0x63, 0xd4, 0xfd, 0x0c, 0x25, 0xc4, 0xb1,
- 0xfe, 0x29, 0x6f, 0x84, 0xfb, 0xab, 0x6e, 0xa7,
- 0xf9, 0x22, 0x89, 0x97, 0x5b, 0x91, 0x0a, 0x07,
- 0xe0, 0xef, 0x3d, 0x67, 0xee, 0x87, 0xa8, 0x33,
- 0x02, 0x64, 0x33, 0xca, 0x15, 0x10, 0xb9, 0x57,
- 0xd8, 0xe5, 0x1a, 0x4b, 0xe3, 0x45, 0xc1, 0x62,
- 0x85, 0x50, 0xf1, 0x79, 0x54, 0xe1, 0x2e, 0x25,
- 0x01, 0x3c, 0xdb, 0x2d, 0x39, 0x14, 0x2f, 0x9b,
- 0xd0, 0x1d, 0xc1, 0xac, 0x73, 0x7d, 0xa4, 0xed,
- 0x89, 0x98, 0xb1, 0xae, 0x8a, 0x9e, 0xc8, 0xa7,
- 0xfe, 0x55, 0x27, 0xb5, 0xb5, 0xa2, 0xec, 0x7e,
- 0xe3, 0x6b, 0x45, 0x19, 0xfa, 0x20, 0x1c, 0x33,
- 0x83, 0x22, 0x33, 0x97, 0xd2, 0x5a, 0xc4, 0xf8,
- 0x9a, 0x03, 0x13, 0x85, 0xf2, 0x2b, 0x04, 0x59,
- 0x27, 0xd7, 0x0b, 0x42, 0x47, 0x9b, 0x7d, 0x4d,
- 0xb2, 0x1a, 0x85, 0x7f, 0x97, 0xc2, 0xf2, 0x10,
- 0xf0, 0xfa, 0x4e, 0x4b, 0x62, 0x43, 0x3a, 0x09,
- 0x2e, 0xcd, 0x8f, 0xa8, 0xb6, 0x0b, 0x5f, 0x34,
- 0xd7, 0x3b, 0xba, 0xd9, 0xe5, 0x01, 0x2d, 0x35,
- 0xae, 0xc5, 0x4c, 0xab, 0x40, 0x64, 0xc2, 0xc9,
- 0x8c, 0x69, 0x44, 0xf4, 0xb8, 0xb5, 0x3a, 0x05,
- 0x3c, 0x29, 0x19, 0xb4, 0x09, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0xc8, 0xc5, 0xb7, 0xe3, 0xd2, 0x3e,
- 0x27, 0xb5, 0x71, 0x8f, 0x52, 0x0b, 0xce, 0x17,
- 0x64, 0x86, 0xa4, 0x34, 0x16, 0x1b, 0x61, 0x64,
- 0x7c, 0xb3, 0xf2, 0xe5, 0x3e, 0xfd, 0xdd, 0xfb,
- 0x40, 0x78, 0x17, 0x03, 0x01, 0x00, 0x50, 0x8e,
- 0x79, 0xf0, 0x8e, 0x76, 0x5d, 0x34, 0x09, 0xdc,
- 0xec, 0x6d, 0xc3, 0x43, 0x1d, 0xcb, 0x2d, 0xaa,
- 0x08, 0x7a, 0x51, 0x94, 0x4e, 0xc5, 0x26, 0xe4,
- 0x0b, 0x8e, 0x8f, 0x51, 0xf2, 0x9f, 0xeb, 0xc3,
- 0x18, 0x43, 0x95, 0x15, 0xfc, 0x59, 0x18, 0x25,
- 0x47, 0xb6, 0x4a, 0x6e, 0xa3, 0xa4, 0x3b, 0xa3,
- 0x47, 0x34, 0x74, 0x6b, 0xc5, 0x3d, 0x41, 0x14,
- 0x64, 0xd5, 0x69, 0x5f, 0x77, 0xf3, 0x7c, 0x41,
- 0xc6, 0xed, 0x2e, 0xcf, 0xff, 0x40, 0xf2, 0xce,
- 0xbb, 0xa7, 0x4e, 0x73, 0x88, 0x98, 0x10,
- },
- {
- 0x15, 0x03, 0x01, 0x00, 0x20, 0x1a, 0xbc, 0x70,
- 0x24, 0xf8, 0xfb, 0xf2, 0x4a, 0xf9, 0x44, 0x1e,
- 0x58, 0xf8, 0xaa, 0x41, 0x24, 0xe8, 0x80, 0x33,
- 0x45, 0x18, 0xa1, 0x5d, 0xee, 0x16, 0x80, 0xae,
- 0x40, 0x41, 0x8e, 0x41, 0x9b,
- },
+func TestHandshakeClientECDHERSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"},
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
}
-var tls11ECDHEAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x02, 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, 0x1b, 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,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x02, 0x51, 0x9f, 0xa2, 0x21, 0x1a,
- 0xb7, 0x75, 0x42, 0x69, 0xd3, 0x14, 0xdd, 0x05,
- 0x1e, 0xda, 0x13, 0x71, 0x8d, 0x6a, 0x45, 0x97,
- 0xcb, 0xee, 0x0e, 0x77, 0x01, 0x0d, 0x6e, 0xe5,
- 0x22, 0x70, 0x16, 0x20, 0x69, 0xfc, 0xa6, 0x9a,
- 0xe8, 0x21, 0xcc, 0x46, 0x65, 0x05, 0xb4, 0x48,
- 0x0f, 0x34, 0x63, 0x2c, 0xac, 0xa4, 0xf5, 0x4b,
- 0x64, 0xd1, 0x07, 0x13, 0xa7, 0xe4, 0x5b, 0xa3,
- 0x4d, 0x31, 0x41, 0x53, 0xc0, 0x13, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x02, 0x02, 0x39, 0x0b, 0x00,
- 0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
- 0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
- 0x03, 0x02, 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87,
- 0x03, 0x00, 0x17, 0x41, 0x04, 0x34, 0xde, 0x50,
- 0x32, 0x8f, 0x25, 0x6b, 0x37, 0x2c, 0x36, 0x24,
- 0x27, 0x0e, 0xf9, 0x67, 0xb4, 0xf8, 0x29, 0x1c,
- 0xa5, 0xa4, 0x59, 0x9a, 0xca, 0x40, 0x26, 0x15,
- 0x61, 0x72, 0x34, 0x4a, 0xd3, 0x0c, 0xac, 0x69,
- 0xcb, 0x2a, 0x9e, 0xf8, 0x80, 0xfb, 0x7a, 0xc4,
- 0xd4, 0x4b, 0x91, 0x1b, 0xbe, 0x24, 0x26, 0xad,
- 0x19, 0x24, 0xbe, 0x32, 0x58, 0xfb, 0xc7, 0x77,
- 0xce, 0x7e, 0x71, 0x51, 0x1a, 0x00, 0x40, 0x1a,
- 0x0b, 0xe8, 0x91, 0x84, 0x64, 0x54, 0xb6, 0x19,
- 0xe8, 0xd4, 0x43, 0x7c, 0x09, 0x0c, 0x2e, 0xba,
- 0x42, 0xb9, 0x74, 0xc3, 0x6c, 0x06, 0x9b, 0xa6,
- 0x7e, 0x92, 0xe9, 0xee, 0x7c, 0x74, 0xa9, 0xd3,
- 0x63, 0xf0, 0x16, 0x20, 0x60, 0x71, 0x8e, 0x24,
- 0xc7, 0x7f, 0xc5, 0x5b, 0x9c, 0x19, 0x0c, 0x80,
- 0x15, 0x61, 0xbf, 0xb6, 0xed, 0x5b, 0x7b, 0x90,
- 0xc5, 0x05, 0x13, 0x72, 0x45, 0x79, 0xdf, 0x16,
- 0x03, 0x02, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x02, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x02, 0x00, 0x40, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x50,
- 0x32, 0x26, 0x51, 0xbd, 0xbd, 0x3c, 0x4f, 0x72,
- 0xbf, 0xbc, 0x91, 0x70, 0x4b, 0x5d, 0x43, 0x4a,
- 0x65, 0x26, 0x0d, 0xaa, 0xed, 0x00, 0x91, 0xaf,
- 0x4f, 0x47, 0x09, 0xaa, 0x79, 0xc4, 0x47, 0x21,
- 0x71, 0xd8, 0x2b, 0xc1, 0x51, 0xc8, 0xef, 0xed,
- 0x67, 0xde, 0x97, 0xef, 0x18, 0x53,
- },
- {
- 0x14, 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x02, 0x00, 0x40, 0x72, 0x20, 0xbf, 0xd1, 0xbd,
- 0x83, 0x53, 0x57, 0xb0, 0x4e, 0xac, 0xba, 0x1a,
- 0x2b, 0x2d, 0xeb, 0x8a, 0x48, 0x17, 0xfa, 0x69,
- 0xf9, 0xb5, 0x94, 0x8e, 0x6f, 0x9c, 0xda, 0x59,
- 0xba, 0x6c, 0x7c, 0x82, 0xe2, 0x53, 0xa9, 0x46,
- 0xdc, 0x33, 0xa0, 0x9b, 0xf0, 0x1e, 0xf1, 0x53,
- 0x83, 0x48, 0xbf, 0x5e, 0xef, 0x03, 0x2b, 0x50,
- 0x7a, 0xa6, 0xf8, 0xc3, 0x9e, 0x24, 0x43, 0x3a,
- 0xdf, 0x44, 0x3e,
- },
- {
- 0x17, 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0b, 0x8f,
- 0x6b, 0xf9, 0xd3, 0x9f, 0x2b, 0x49, 0xe0, 0x62,
- 0x9a, 0x0b, 0x3e, 0xa2, 0x72, 0x8b, 0x96, 0x0c,
- 0x41, 0x09, 0x95, 0x9e, 0x6b, 0x26, 0xa1, 0x46,
- 0xca, 0xb8, 0xb6, 0xd2, 0xd4, 0x15, 0x03, 0x02,
- 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xa0, 0xd4, 0x84, 0xc6, 0x7e, 0x1c,
- 0x2f, 0xbd, 0x6b, 0x45, 0x31, 0x1d, 0x7d, 0x8f,
- 0x31, 0x39, 0x5a, 0x4e, 0xaa, 0xf1, 0x0a, 0x8a,
- 0x6c, 0x33, 0x59, 0x19, 0xd8, 0x75, 0x80, 0xab,
- 0x93, 0x81,
- },
+func TestHandshakeClientECDHEECDSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
}
-var clientChainCertificateScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 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, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x1b, 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,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
- 0x46, 0x03, 0x01, 0x51, 0xa2, 0x9b, 0x8b, 0xd4,
- 0xe6, 0x33, 0xa2, 0x70, 0x38, 0x37, 0xba, 0x55,
- 0x86, 0xcf, 0x87, 0xea, 0x6d, 0x2c, 0x3e, 0x17,
- 0xc2, 0x09, 0xf8, 0x4d, 0xb0, 0x5d, 0x93, 0x2b,
- 0x15, 0x99, 0x0c, 0x20, 0x5d, 0x61, 0x21, 0x2c,
- 0xed, 0x49, 0x32, 0x29, 0x08, 0x6e, 0x21, 0x58,
- 0x00, 0xdb, 0x34, 0xb7, 0x37, 0xcd, 0x27, 0x75,
- 0x31, 0x1e, 0x6c, 0x74, 0xa6, 0xef, 0xa2, 0xc4,
- 0x2b, 0x6c, 0xc3, 0x03, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x03, 0xef, 0x0b, 0x00, 0x03, 0xeb,
- 0x00, 0x03, 0xe8, 0x00, 0x03, 0xe5, 0x30, 0x82,
- 0x03, 0xe1, 0x30, 0x82, 0x02, 0xc9, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xcc, 0x22,
- 0x4c, 0x4b, 0x98, 0xa2, 0x88, 0xfc, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x86,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02,
- 0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
- 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f,
- 0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18,
- 0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41,
- 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e,
- 0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35, 0x32, 0x36,
- 0x32, 0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x17,
- 0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x34, 0x32,
- 0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x30, 0x81,
- 0x86, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
- 0x02, 0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72,
- 0x6f, 0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
- 0x18, 0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
- 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
- 0x04, 0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61,
- 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73,
- 0x68, 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d,
- 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
- 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
- 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
- 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
- 0xf0, 0xfb, 0xad, 0x80, 0x5e, 0x37, 0xd3, 0x6d,
- 0xee, 0x2e, 0xcc, 0xbc, 0x0c, 0xd7, 0x56, 0x4b,
- 0x56, 0x45, 0xcd, 0x28, 0xb6, 0x22, 0xe9, 0xe2,
- 0x0f, 0xd1, 0x87, 0x2a, 0x27, 0xce, 0x77, 0x8d,
- 0x6e, 0x0e, 0x0f, 0xfb, 0x66, 0xe1, 0xb5, 0x0e,
- 0x9a, 0xb6, 0x05, 0x8e, 0xb3, 0xe1, 0xc5, 0x77,
- 0x86, 0x5b, 0x46, 0xd2, 0x0b, 0x92, 0x03, 0x1b,
- 0x89, 0x0c, 0x1b, 0x10, 0x0e, 0x99, 0x8f, 0xe2,
- 0x17, 0xe8, 0xc2, 0x30, 0x00, 0x47, 0xd6, 0xfc,
- 0xf9, 0x0f, 0x3b, 0x75, 0x34, 0x8d, 0x4d, 0xb0,
- 0x99, 0xb7, 0xa0, 0x6d, 0xa0, 0xb6, 0xad, 0xda,
- 0x07, 0x5e, 0x38, 0x2e, 0x02, 0xe4, 0x30, 0x6d,
- 0xae, 0x13, 0x72, 0xd4, 0xc8, 0xce, 0x14, 0x07,
- 0xae, 0x23, 0x8c, 0x8f, 0x9e, 0x8c, 0x60, 0xd6,
- 0x06, 0xb9, 0xef, 0x00, 0x18, 0xc0, 0x1d, 0x25,
- 0x1e, 0xda, 0x3e, 0x2f, 0xcf, 0x2b, 0x56, 0x84,
- 0x9e, 0x30, 0x21, 0xc7, 0x29, 0xf6, 0x03, 0x8a,
- 0x24, 0xf9, 0x34, 0xac, 0x65, 0x9d, 0x80, 0x36,
- 0xc8, 0x3b, 0x15, 0x10, 0xbd, 0x51, 0xe9, 0xbc,
- 0x02, 0xe1, 0xe9, 0xb3, 0x5a, 0x9a, 0x99, 0x41,
- 0x1b, 0x27, 0xa0, 0x4d, 0x50, 0x9e, 0x27, 0x7f,
- 0xa1, 0x7d, 0x09, 0x87, 0xbd, 0x8a, 0xca, 0x5f,
- 0xb1, 0xa5, 0x08, 0xb8, 0x04, 0xd4, 0x52, 0x89,
- 0xaa, 0xe0, 0x7d, 0x42, 0x2e, 0x2f, 0x15, 0xee,
- 0x66, 0x57, 0x0f, 0x13, 0x19, 0x45, 0xa8, 0x4b,
- 0x5d, 0x81, 0x66, 0xcc, 0x12, 0x37, 0x94, 0x5e,
- 0xfd, 0x3c, 0x10, 0x81, 0x51, 0x3f, 0xfa, 0x0f,
- 0xdd, 0xa1, 0x89, 0x03, 0xa9, 0x78, 0x91, 0xf5,
- 0x3b, 0xf3, 0xbc, 0xac, 0xbe, 0x93, 0x30, 0x2e,
- 0xbe, 0xca, 0x7f, 0x46, 0xd3, 0x28, 0xb4, 0x4e,
- 0x91, 0x7b, 0x5b, 0x43, 0x6c, 0xaf, 0x9b, 0x5c,
- 0x6a, 0x6d, 0x5a, 0xdb, 0x79, 0x5e, 0x6a, 0x6b,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30,
- 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x6b, 0x1e, 0x00, 0xa8,
- 0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f,
- 0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x18, 0x30, 0x16, 0x80, 0x14, 0x6b, 0x1e, 0x00,
- 0xa8, 0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d,
- 0x0f, 0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b,
- 0xda, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x01, 0x00, 0xcd, 0x6f, 0x73, 0x4d, 0x56,
- 0x0b, 0xf3, 0x2e, 0x1c, 0xe2, 0x02, 0x0c, 0x14,
- 0xbb, 0x2f, 0xdd, 0x3c, 0x43, 0xfe, 0xdf, 0x94,
- 0x2d, 0xa9, 0x89, 0x81, 0x51, 0xf8, 0x5f, 0xa7,
- 0xa0, 0x13, 0xaa, 0xcc, 0xb0, 0x18, 0xe2, 0x57,
- 0x3e, 0x0d, 0x29, 0x93, 0xe8, 0x95, 0xd5, 0x1b,
- 0x53, 0xd2, 0x51, 0xf2, 0xbd, 0xf5, 0x9e, 0x7b,
- 0x22, 0x65, 0x62, 0x5c, 0xc4, 0x4c, 0x1d, 0xe8,
- 0xe9, 0xc3, 0xd4, 0x2b, 0xe7, 0x78, 0xcb, 0x10,
- 0xf3, 0xfe, 0x06, 0x83, 0xdc, 0x3a, 0x1e, 0x62,
- 0x10, 0xc0, 0x46, 0x77, 0xc6, 0x9d, 0x9f, 0xab,
- 0x96, 0x25, 0x5c, 0xfb, 0x26, 0xc1, 0x15, 0x1f,
- 0xa5, 0x33, 0xee, 0x4f, 0x9a, 0x14, 0x6a, 0x14,
- 0x97, 0x93, 0x2b, 0x95, 0x0b, 0xdc, 0xa8, 0xd7,
- 0x69, 0x2e, 0xf0, 0x01, 0x0e, 0xfd, 0x4e, 0xd0,
- 0xd9, 0xa8, 0xe5, 0x65, 0xde, 0xfb, 0xca, 0xca,
- 0x1c, 0x5f, 0xf9, 0x53, 0xa0, 0x87, 0xe7, 0x33,
- 0x9b, 0x2f, 0xcf, 0xe4, 0x13, 0xfc, 0xec, 0x7a,
- 0x6c, 0xb0, 0x90, 0x13, 0x9b, 0xb6, 0xc5, 0x03,
- 0xf6, 0x0e, 0x5e, 0xe2, 0xe4, 0x26, 0xc1, 0x7e,
- 0x53, 0xfe, 0x69, 0xa3, 0xc7, 0xd8, 0x8e, 0x6e,
- 0x94, 0x32, 0xa0, 0xde, 0xca, 0xb6, 0xcc, 0xd6,
- 0x01, 0xd5, 0x78, 0x40, 0x28, 0x63, 0x9b, 0xee,
- 0xcf, 0x09, 0x3b, 0x35, 0x04, 0xf0, 0x14, 0x02,
- 0xf6, 0x80, 0x0e, 0x90, 0xb2, 0x94, 0xd2, 0x25,
- 0x16, 0xb8, 0x7a, 0x76, 0x87, 0x84, 0x9f, 0x84,
- 0xc5, 0xaf, 0xc2, 0x6d, 0x68, 0x7a, 0x84, 0x9c,
- 0xc6, 0x8a, 0x63, 0x60, 0x87, 0x6a, 0x25, 0xc1,
- 0xa1, 0x78, 0x0f, 0xba, 0xe8, 0x5f, 0xe1, 0xba,
- 0xac, 0xa4, 0x6f, 0xdd, 0x09, 0x3f, 0x12, 0xcb,
- 0x1d, 0xf3, 0xcf, 0x48, 0xd7, 0xd3, 0x26, 0xe8,
- 0x9c, 0xc3, 0x53, 0xb3, 0xba, 0xdc, 0x32, 0x99,
- 0x98, 0x96, 0xd6, 0x16, 0x03, 0x01, 0x00, 0x99,
- 0x0d, 0x00, 0x00, 0x91, 0x03, 0x01, 0x02, 0x40,
- 0x00, 0x8b, 0x00, 0x89, 0x30, 0x81, 0x86, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e,
- 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
- 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f,
- 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d,
- 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75,
- 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f,
- 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
- 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61,
- 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69,
- 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
- 0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
- 0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
- 0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
- 0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
- 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
- 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
- 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
- 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
- 0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
- 0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
- 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
- 0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
- 0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
- 0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
- 0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
- 0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
- 0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
- 0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
- 0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
- 0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
- 0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
- 0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
- 0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
- 0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
- 0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
- 0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
- 0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
- 0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
- 0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
- 0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
- 0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
- 0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
- 0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
- 0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
- 0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
- 0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
- 0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
- 0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
- 0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
- 0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
- 0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
- 0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
- 0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
- 0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
- 0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
- 0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
- 0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
- 0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
- 0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
- 0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
- 0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
- 0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
- 0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
- 0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
- 0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
- 0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
- 0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
- 0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
- 0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
- 0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
- 0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
- 0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
- 0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
- 0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
- 0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
- 0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
- 0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
- 0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
- 0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
- 0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
- 0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
- 0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
- 0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
- 0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
- 0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
- 0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
- 0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
- 0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
- 0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
- 0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
- 0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
- 0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
- 0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
- 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
- 0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
- 0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
- 0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
- 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
- 0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
- 0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
- 0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
- 0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
- 0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
- 0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
- 0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
- 0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
- 0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
- 0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
- 0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
- 0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
- 0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
- 0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
- 0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
- 0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
- 0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
- 0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
- 0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
- 0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
- 0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
- 0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
- 0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
- 0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
- 0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
- 0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
- 0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
- 0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
- 0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
- 0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
- 0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
- 0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
- 0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
- 0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
- 0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
- 0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
- 0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
- 0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
- 0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
- 0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
- 0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
- 0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
- 0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
- 0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
- 0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
- 0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
- 0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
- 0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
- 0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
- 0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
- 0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
- 0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
- 0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
- 0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
- 0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
- 0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
- 0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
- 0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
- 0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
- 0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
- 0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
- 0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
- 0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
- 0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
- 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
- 0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
- 0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
- 0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
- 0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
- 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
- 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
- 0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
- 0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
- 0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
- 0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
- 0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
- 0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
- 0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
- 0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
- 0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
- 0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
- 0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
- 0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
- 0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
- 0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
- 0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
- 0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
- 0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
- 0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
- 0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
- 0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
- 0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
- 0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
- 0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
- 0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
- 0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
- 0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
- 0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
- 0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
- 0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
- 0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
- 0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
- 0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
- 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
- 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
- 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
- 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
- 0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
- 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
- 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
- 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
- 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
- 0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
- 0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
- 0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
- 0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
- 0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
- 0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
- 0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
- 0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
- 0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
- 0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
- 0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
- 0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
- 0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
- 0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
- 0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
- 0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
- 0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
- 0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
- 0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
- 0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
- 0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
- 0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
- 0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
- 0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
- 0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
- 0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
- 0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
- 0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
- 0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
- 0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
- 0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
- 0x16, 0x03, 0x01, 0x01, 0x06, 0x10, 0x00, 0x01,
- 0x02, 0x01, 0x00, 0x6e, 0xea, 0x15, 0x6f, 0x21,
- 0xbd, 0x2d, 0x14, 0xde, 0x9d, 0x02, 0xeb, 0xdf,
- 0x3b, 0x09, 0x75, 0xaf, 0x32, 0x80, 0x0c, 0xe2,
- 0xc2, 0x7b, 0x0d, 0xca, 0x24, 0x96, 0xf6, 0x3e,
- 0xa5, 0x97, 0xba, 0x0c, 0x50, 0x7e, 0xb3, 0x68,
- 0x58, 0xc6, 0xd8, 0xec, 0xab, 0xa9, 0xd9, 0x3a,
- 0xb1, 0x49, 0xea, 0x2f, 0xd7, 0xdb, 0x15, 0x1b,
- 0xb5, 0xaf, 0xec, 0xcc, 0x40, 0x5c, 0xe6, 0x0f,
- 0xc4, 0x33, 0x71, 0xe7, 0x41, 0xc0, 0x04, 0x89,
- 0x60, 0x3e, 0xb7, 0xe6, 0xda, 0x38, 0x62, 0x27,
- 0x6a, 0xd9, 0xfb, 0x93, 0x94, 0x9d, 0xc1, 0x63,
- 0x92, 0x5c, 0x88, 0x19, 0x38, 0x81, 0x79, 0x9d,
- 0x59, 0x48, 0x5e, 0xd3, 0xc8, 0xea, 0xcb, 0x6e,
- 0x66, 0x66, 0x03, 0xdc, 0x0c, 0x2d, 0x95, 0xb1,
- 0x4d, 0x68, 0xc7, 0xc5, 0x6e, 0xfa, 0x94, 0x14,
- 0xdf, 0x2c, 0x70, 0x69, 0x04, 0xf4, 0x69, 0xf1,
- 0xf0, 0x07, 0xbd, 0x23, 0x53, 0x63, 0xb3, 0x41,
- 0xec, 0xa7, 0x10, 0xa5, 0x04, 0x84, 0x24, 0xb5,
- 0xf5, 0x0c, 0x0f, 0x5d, 0x02, 0x47, 0x79, 0x60,
- 0x76, 0xbb, 0xdf, 0x60, 0xa6, 0xd7, 0x4d, 0x08,
- 0x7d, 0xa6, 0x85, 0x4f, 0x61, 0xac, 0x96, 0x3d,
- 0xbc, 0xaf, 0x07, 0xb0, 0x7c, 0xb6, 0x23, 0x3e,
- 0x1f, 0x0a, 0x62, 0x77, 0x97, 0x77, 0xae, 0x33,
- 0x55, 0x0f, 0x85, 0xdf, 0xdc, 0xbe, 0xc6, 0xe0,
- 0xe0, 0x14, 0x83, 0x4c, 0x50, 0xf0, 0xe5, 0x2d,
- 0xdc, 0x0b, 0x74, 0x7f, 0xc3, 0x28, 0x98, 0x16,
- 0xda, 0x74, 0xe6, 0x40, 0xc2, 0xf0, 0xea, 0xc0,
- 0x00, 0xd5, 0xfc, 0x16, 0xe4, 0x43, 0xa1, 0xfc,
- 0x31, 0x19, 0x81, 0x62, 0xec, 0x2b, 0xfe, 0xcc,
- 0xe8, 0x19, 0xed, 0xa1, 0x1e, 0x6a, 0x49, 0x73,
- 0xde, 0xc4, 0xe9, 0x22, 0x0a, 0x21, 0xde, 0x45,
- 0x1e, 0x55, 0x12, 0xd9, 0x44, 0xef, 0x4e, 0xaa,
- 0x5e, 0x26, 0x57, 0x16, 0x03, 0x01, 0x01, 0x06,
- 0x0f, 0x00, 0x01, 0x02, 0x01, 0x00, 0x23, 0xde,
- 0xb0, 0x39, 0x60, 0xe9, 0x82, 0xb8, 0xed, 0x17,
- 0x78, 0xd2, 0x37, 0x0e, 0x85, 0x69, 0xda, 0xcc,
- 0x9f, 0x54, 0x4d, 0xda, 0xce, 0xe8, 0x5a, 0xeb,
- 0x3c, 0x61, 0x4c, 0x7a, 0x84, 0x1f, 0x21, 0x03,
- 0xb3, 0x8a, 0x74, 0x3b, 0x6a, 0x9e, 0x4f, 0x44,
- 0xd9, 0x75, 0x0a, 0xd8, 0x7e, 0x56, 0xa3, 0xef,
- 0x5a, 0xfe, 0x8a, 0x35, 0xce, 0x29, 0x18, 0xfe,
- 0xa6, 0x61, 0x8e, 0x8f, 0x00, 0x90, 0x2d, 0x85,
- 0xe3, 0x6c, 0x0e, 0x8d, 0x8c, 0x27, 0x80, 0x8c,
- 0x9f, 0x51, 0xe9, 0xd3, 0xe6, 0x7d, 0x70, 0xe9,
- 0xfb, 0xcb, 0xb8, 0x24, 0x94, 0x30, 0x9b, 0xba,
- 0x01, 0x14, 0x49, 0x9f, 0xaf, 0x09, 0xd8, 0x26,
- 0x1b, 0x23, 0xa4, 0xb8, 0xd9, 0x44, 0x0a, 0xdc,
- 0x4e, 0x27, 0xe7, 0x32, 0xf5, 0x9c, 0xf3, 0x8d,
- 0xa0, 0xc5, 0xc4, 0xbe, 0x92, 0x02, 0x85, 0x4f,
- 0x33, 0x8f, 0xa7, 0xf7, 0x87, 0xa9, 0x44, 0xf3,
- 0x64, 0xbd, 0x32, 0x04, 0xeb, 0xc5, 0xc3, 0x62,
- 0xe9, 0xda, 0x2f, 0x95, 0x5c, 0xf7, 0x58, 0x3e,
- 0xad, 0x35, 0xd7, 0x7e, 0xad, 0xdd, 0x32, 0x8d,
- 0xce, 0x81, 0x08, 0xad, 0x49, 0xf7, 0xdb, 0xf7,
- 0xaf, 0xe3, 0xc6, 0xb2, 0xdd, 0x76, 0x0c, 0xcf,
- 0x0f, 0x87, 0x79, 0x90, 0x10, 0x79, 0xc6, 0xc8,
- 0x7b, 0xe6, 0x23, 0xf2, 0xda, 0x33, 0xca, 0xe1,
- 0xf0, 0x59, 0x42, 0x43, 0x03, 0x56, 0x19, 0xe3,
- 0x8b, 0xe6, 0xa8, 0x70, 0xbc, 0x80, 0xfa, 0x24,
- 0xae, 0x03, 0x13, 0x30, 0x0d, 0x1f, 0xab, 0xb7,
- 0x82, 0xd9, 0x24, 0x90, 0x80, 0xbf, 0x75, 0xe1,
- 0x0d, 0x1c, 0xb2, 0xfe, 0x92, 0x2c, 0x4d, 0x21,
- 0xe9, 0x5d, 0xa1, 0x68, 0xf3, 0x16, 0xd8, 0x3f,
- 0xb2, 0xc3, 0x00, 0x3e, 0xd8, 0x42, 0x25, 0x5c,
- 0x90, 0x11, 0xc0, 0x1b, 0xd4, 0x26, 0x5c, 0x37,
- 0x47, 0xbd, 0xf8, 0x1e, 0x34, 0xa9, 0x14, 0x03,
- 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
- 0x24, 0x8f, 0x94, 0x7e, 0x01, 0xee, 0xd5, 0x4f,
- 0x83, 0x41, 0x31, 0xc0, 0x36, 0x81, 0x46, 0xc3,
- 0xc0, 0xcc, 0x9c, 0xea, 0x0f, 0x29, 0x04, 0x10,
- 0x43, 0x1e, 0x08, 0x6e, 0x08, 0xce, 0xb2, 0x62,
- 0xa6, 0x0f, 0x68, 0x9f, 0x99,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0xd9, 0x46, 0x5b, 0xbf, 0xfd,
- 0x8a, 0xa1, 0x08, 0xd5, 0xf3, 0x0c, 0x1c, 0xd8,
- 0xa8, 0xb3, 0xe5, 0x89, 0x83, 0x9e, 0x23, 0x47,
- 0x81, 0x66, 0x77, 0x11, 0x98, 0xe5, 0xf4, 0xac,
- 0x06, 0xe9, 0x4c, 0x05, 0x8b, 0xc4, 0x16,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x1a, 0xc5, 0x28, 0xfd,
- 0x71, 0xc0, 0xe6, 0x89, 0xb8, 0x82, 0x92, 0x1b,
- 0xdd, 0x39, 0xe5, 0xbf, 0x41, 0x82, 0x1f, 0xc1,
- 0xbc, 0x85, 0xe5, 0x32, 0x1b, 0x93, 0x46, 0x15,
- 0x03, 0x01, 0x00, 0x16, 0x1a, 0x8b, 0x10, 0x42,
- 0x12, 0xb2, 0xbd, 0xd3, 0xf1, 0x74, 0x1f, 0xc2,
- 0x10, 0x08, 0xc2, 0x79, 0x99, 0x2c, 0x55, 0xef,
- 0x4a, 0xbd,
- },
+func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES-GCM",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
}
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-// -cipher ECDHE-RSA-AES128-SHA -port 10443
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc013 \
-// -minversion=0x0303 -maxversion=0x0303
-var clientTLS12Script = [][]byte{
- {
- 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, 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, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
- 0x03, 0x02, 0x01, 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 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,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 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, 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,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 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, 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, 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, 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, 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,
- },
+func TestHandshakeClientCertRSA(t *testing.T) {
+ config := *testConfig
+ cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-RSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-RSA-ECDSA",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+ config: &config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
}
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-// -port 10443 -verify 0
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc02f \
-// -maxversion=0x0303
-var clientTLS12ClientCertScript = [][]byte{
- {
- 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, 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, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
- 0x03, 0x02, 0x01, 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 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,
- 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
- 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
- 0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
- 0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
- 0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
- 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
- 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
- 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
- 0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
- 0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
- 0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
- 0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
- 0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
- 0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
- 0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
- 0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
- 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
- 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
- 0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
- 0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
- 0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
- 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
- 0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
- 0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
- 0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
- 0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
- 0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
- 0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
- 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, 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,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x03, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
- 0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
- 0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
- 0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
- 0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
- 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
- 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
- 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
- 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
- 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
- 0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
- 0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
- 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
- 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
- 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
- 0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
- 0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
- 0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
- 0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
- 0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
- 0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
- 0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
- 0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
- 0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
- 0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
- 0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
- 0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
- 0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
- 0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
- 0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
- 0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
- 0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
- 0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
- 0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
- 0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
- 0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
- 0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
- 0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
- 0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
- 0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
- 0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
- 0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
- 0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
- 0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
- 0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
- 0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
- 0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
- 0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
- 0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
- 0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
- 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
- 0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
- 0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
- 0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
- 0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
- 0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
- 0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
- 0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
- 0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
- 0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
- 0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
- 0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
- 0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
- 0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
- 0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
- 0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
- 0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
- 0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
- 0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
- 0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
- 0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
- 0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
- 0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
- 0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
- 0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
- 0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
- 0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
- 0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
- 0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
- 0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
- 0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
- 0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
- 0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
- 0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
- 0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
- 0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
- 0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
- 0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
- 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
- 0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
- 0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
- 0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
- 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
- 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
- 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
- 0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
- 0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
- 0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
- 0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
- 0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
- 0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
- 0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
- 0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
- 0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
- 0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
- 0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
- 0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
- 0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
- 0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
- 0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
- 0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
- 0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
- 0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
- 0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
- 0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
- 0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
- 0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
- 0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
- 0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
- 0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
- 0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
- 0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
- 0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
- 0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
- 0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
- 0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
- 0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
- 0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
- 0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
- 0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
- 0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
- 0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
- 0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
- 0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
- 0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
- 0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
- 0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
- 0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
- 0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
- 0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
- 0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
- 0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
- 0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
- 0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
- 0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
- 0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
- 0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
- 0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
- 0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
- 0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
- 0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
- 0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
- 0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
- 0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
- 0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
- 0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
- 0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
- 0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
- 0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
- 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
- 0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
- 0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
- 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
- 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
- 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
- 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
- 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
- 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
- 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
- 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
- 0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
- 0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
- 0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
- 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
- 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
- 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
- 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
- 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
- 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
- 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
- 0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
- 0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
- 0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
- 0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
- 0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
- 0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
- 0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
- 0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
- 0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
- 0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
- 0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
- 0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
- 0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
- 0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
- 0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
- 0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
- 0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
- 0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
- 0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
- 0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
- 0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
- 0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
- 0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
- 0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
- 0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
- 0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
- 0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
- 0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
- 0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
- 0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
- 0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
- 0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
- 0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
- 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
- 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
- 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
- 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
- 0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
- 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
- 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
- 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
- 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
- 0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
- 0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
- 0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
- 0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
- 0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
- 0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
- 0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
- 0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
- 0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
- 0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
- 0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
- 0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
- 0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
- 0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
- 0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
- 0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
- 0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
- 0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
- 0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
- 0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
- 0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
- 0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
- 0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
- 0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
- 0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
- 0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
- 0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
- 0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
- 0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
- 0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
- 0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
- 0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x16, 0x03, 0x03, 0x01, 0x08,
- 0x0f, 0x00, 0x01, 0x04, 0x04, 0x01, 0x01, 0x00,
- 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, 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, 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, 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,
- 0x02, 0x63, 0x1b, 0xaa, 0xc6, 0xc9, 0x6d, 0x72,
- 0x24, 0x10, 0x55, 0xa9, 0x8c, 0x3b, 0x23, 0xce,
- 0xd8, 0x4a,
- },
+func TestHandshakeClientCertECDSA(t *testing.T) {
+ config := *testConfig
+ cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-ECDSA-RSA",
+ command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ config: &config,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-ECDSA-ECDSA",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+ config: &config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
}
-var testClientChainCertificate = fromHex(
- "2d2d2d2d2d424547494e2050524956415445204b" +
- "45592d2d2d2d2d0a4d494945766749424144414e" +
- "42676b71686b6947397730424151454641415343" +
- "424b67776767536b41674541416f494241514367" +
- "6f2b2f4252483269343347590a4a324f7a485846" +
- "51706a515679386b71772b726b6e70784a706747" +
- "6266716d31657638566b6e48496c35776c74336b" +
- "722f367647736163416b4c4b4c313348560a776a" +
- "726d676b493369554545734c7248573470446e35" +
- "633544412f56625a364e3638416d78526a6f656a" +
- "30794c6a6951514673354c41664c4a4244467954" +
- "766a0a5a6b64587557717452506a51634749376a" +
- "75316758794c3475417a4a5153764a6747354f47" +
- "2b45672f45656b724d4d2f35734b4265514d334a" +
- "596e4b317156470a6b574e427854375637583950" +
- "6a5162416951432b4e33742b6338707741425130" +
- "766b6538736d6f6f70536d45714a3349486e646d" +
- "48352b714b306662335775630a715079434e7052" +
- "694456772f7367473070626a4744705262374636" +
- "37656d4d6b38666e5755416a426f387951423173" +
- "4542454a307a7a6636384b585a3034614a0a6952" +
- "6a7a544f495241674d424141454367674542414a" +
- "4b613676326b5a3144596146786e586d7369624c" +
- "386734426f67514c6a42307362524a6d746b6b4d" +
- "54370a685343325873537551522f446c654d7148" +
- "664555786731784a717579597643544d44585972" +
- "473667354a5051744d4432465a424a7239626c65" +
- "467138386c706a0a543766514e793571354c2b4f" +
- "682f6b62433835436e623641753641656978776d" +
- "2b6e77665a4f3766726b6278306d35516b715975" +
- "5739392f452b69502b454e570a76396a68773436" +
- "76515065563236494b79717656462b4f7362722f" +
- "6152316138707948336361566e3579594a433346" +
- "5855756c6f5a77516331714a6b4c434c4c0a375a" +
- "49744f525a78514c486d4d4a654d44722f5a4942" +
- "34675467645650636145375a4d5141714d6d3066" +
- "4c6b6d7671723149526b77642f6831455a645650" +
- "79320a742f6b6b43413039566336663749556575" +
- "6f67706d705a50303130564e376b6277394a6348" +
- "75544561564543675945417a47395679426e6d62" +
- "6858496c57764f0a71583747524f2f5231636a2b" +
- "6b564e35377876674b54756b35592b7a4d774a48" +
- "32626c57435945513251753974446c476854756b" +
- "664273385746772b6e6263460a7a6f706d535245" +
- "6c6d464d2f6141536d464733574e5a7072696a68" +
- "504b77726338376470636b31703131635a415478" +
- "5a413168566d43743457616343673634690a4d74" +
- "64507a334e2f34416147664956794d2b69624949" +
- "35332f515543675945417953693556735a356f6a" +
- "644a795077426e6c6142554231686f2b336b7068" +
- "70770a7264572b2b4d796b51494a345564534437" +
- "3052486e5a315839754359713978616671746c51" +
- "664c44395963442f436d665264706461586c5673" +
- "5249467a5a556c0a454630557149644e77337046" +
- "68634f4a6d6e5a3241434470434342476f763542" +
- "6e3068302b3137686a4b376f69315833716e4542" +
- "7857326c7462593476556a500a44394c5330666e" +
- "4a76703043675942504a527330714c4a4a464333" +
- "6669796b712f57574d38727474354b364a584b50" +
- "734b674b53644144577a7463316645434d0a7a65" +
- "2b394a6a5a376b4d77557063666a644c2b745047" +
- "3455563048326c524375635735414131396d7058" +
- "50367454494733713737655a6b416e65516f6163" +
- "41340a716c3073583051476c6a5763414e30464b" +
- "6f4759733975582b6378445a6e7265362f52392f" +
- "3930567766443237454c57546373677734633463" +
- "514b42675143420a6f5432326e745a5a59396d6e" +
- "72455a36752f492f4a332f35664e396737783733" +
- "3177746e463745745a5361575453587364597256" +
- "466b564f6362505135494a6f0a714a6a7249372b" +
- "474a4d69376f6a4c69642f4c45656f31764f3163" +
- "454158334f43723236554e38612f6c7434394f5a" +
- "69354c337348556b756c475951755671650a6737" +
- "6e6e4632437749544c34503645486443575a4461" +
- "7a4136626d7375524f2b6462536e335a6c567651" +
- "4b42674859524c5a665458536c44755264776977" +
- "746b0a513148546b6d6b57694156726c4f577864" +
- "5858456d546130303045574c46446145797a7358" +
- "7834424863357166776b5a4e746b634a56396e58" +
- "63536e647441530a35767a427a676e797a4f7962" +
- "68315878484a3966427472414f3847555878446c" +
- "6634394457616753393449763072596e616b7656" +
- "2f673039786875415763366e0a5365757230576b" +
- "5376453847666653734d485149584c456b0a2d2d" +
- "2d2d2d454e442050524956415445204b45592d2d" +
- "2d2d2d0a2d2d2d2d2d424547494e204345525449" +
- "4649434154452d2d2d2d2d0a4d494944656a4343" +
- "416d494343514330523168584b326649776a414e" +
- "42676b71686b6947397730424151554641444342" +
- "6744454c4d416b474131554542684d430a56564d" +
- "78437a414a42674e564241674d416b355a4d5245" +
- "77447759445651514844416843636d3976613278" +
- "35626a45564d424d47413155454367774d54586b" +
- "670a51304567513278705a5735304d5263774651" +
- "5944565151444441357465574e68593278705a57" +
- "35304c6d4e76625445684d423847435371475349" +
- "62334451454a0a41525953616e5a7a6147466f61" +
- "5752415a32316861577775593239744d42345844" +
- "54457a4d4455794e6a49784e4451774d466f5844" +
- "54457a4d4459794e5449780a4e4451774d466f77" +
- "6654454c4d416b474131554542684d4356564d78" +
- "4554415042674e564241674d4345356c6479425a" +
- "62334a724d52457744775944565151480a444168" +
- "43636d397661327835626a45514d413447413155" +
- "454367774854586b67544756685a6a45544d4245" +
- "47413155454177774b62586c735a57466d4c6d4e" +
- "760a625445684d42384743537147534962334451" +
- "454a41525953616e5a7a6147466f615752415a32" +
- "316861577775593239744d494942496a414e4267" +
- "6b71686b69470a397730424151454641414f4341" +
- "5138414d49494243674b43415145416f4b507677" +
- "5552396f754e786d43646a73783178554b593046" +
- "63764a4b735071354a36630a536159426d333670" +
- "7458722f465a4a78794a65634a6264354b2f2b72" +
- "7872476e414a43796939647831634936356f4a43" +
- "4e346c42424c43367831754b51352b580a4f5177" +
- "50315732656a6576414a73555936486f394d6934" +
- "346b4542624f5377487979515178636b3734325a" +
- "4856376c7172555434304842694f343774594638" +
- "690a2b4c674d7955457279594275546876684950" +
- "7848704b7a44502b624367586b444e79574a7974" +
- "616c5270466a5163552b3165312f543430477749" +
- "6b41766a64370a666e504b634141554e4c354876" +
- "4c4a714b4b5570684b6964794235335a682b6671" +
- "697448323931726e4b6a38676a61555967316350" +
- "374942744b5734786736550a572b78657533706a" +
- "4a504835316c41497761504d6b41646242415243" +
- "644d38332b76436c32644f4769596b5938307a69" +
- "45514944415141424d413047435371470a534962" +
- "3344514542425155414134494241514351752f6c" +
- "65756863667243476661307047304730386a7a33" +
- "34586a357972364161382f2b4a72467436347045" +
- "710a493458475455646e4151696f425230425946" +
- "42665761332b6538594d564a426f634763753759" +
- "6634615971734d7635766b426b715a4932435a67" +
- "5644694f37790a4d4f326b6a372f575679445551" +
- "7831536c6d2b75435a5942556a6a6a72356e5833" +
- "42535a7849734f42412b7a46425455705a506879" +
- "597142373250384e6e63460a427641714241712b" +
- "4c73364250534f6832746a72787570657a796732" +
- "55544756586b414537617a4279465a70682b7737" +
- "417a36644430784d363965364a742f6a0a336844" +
- "756b324b4e63314a752f7a63326d487374566b79" +
- "364362696e384473576763726251367673544735" +
- "3877517369496b4d6474677a4275632f6b552b34" +
- "640a506f696e4537352f766135797a38316a3073" +
- "4d59574a4b697262554a6e5a454433547a69484e" +
- "35340a2d2d2d2d2d454e44204345525449464943" +
- "4154452d2d2d2d2d0a2d2d2d2d2d424547494e20" +
- "43455254494649434154452d2d2d2d2d0a4d4949" +
- "4468444343416d7743435143723761626b536973" +
- "722b44414e42676b71686b694739773042415155" +
- "4641444342686a454c4d416b474131554542684d" +
- "430a56564d78437a414a42674e564241674d416b" +
- "355a4d524577447759445651514844416843636d" +
- "397661327835626a45684d423847413155454367" +
- "775954586b670a5132567964476c6d61574e6864" +
- "4755675158563061473979615852354d52457744" +
- "775944565151444441687465574e684c6d39795a" +
- "7a45684d423847435371470a534962334451454a" +
- "41525953616e5a7a6147466f615752415a323168" +
- "61577775593239744d4234584454457a4d445579" +
- "4e6a49784d5467304d466f584454457a0a4d4459" +
- "794e5449784d5467304d466f7767594178437a41" +
- "4a42674e5642415954416c56544d517377435159" +
- "445651514944414a4f575445524d413847413155" +
- "450a42777749516e4a7662327473655734784654" +
- "415442674e5642416f4d4445313549454e424945" +
- "4e7361575675644445584d425547413155454177" +
- "774f62586c6a0a59574e73615756756443356a62" +
- "3230784954416642676b71686b69473977304243" +
- "514557456d70326332686861476c6b5147647459" +
- "576c734c6d4e76625443430a415349774451594a" +
- "4b6f5a496876634e415145424251414467674550" +
- "4144434341516f4367674542414d345438484b77" +
- "596367594e34704250534368484d752f0a396a74" +
- "304a697157456578546f63783964315a46447a61" +
- "33386b6953476d4c4d747343684c30517277596e" +
- "4c6268376256354c566c32434d51537a5a495037" +
- "700a4834373866774a454479694231677a4e7650" +
- "4258624d796e75676167707048613730614b5941" +
- "3953624a42736a455376734a3251756946596f44" +
- "7a75564c55700a4a68384b724f3949614450514d" +
- "39434c477578754c37564b553849613076465142" +
- "566c6332646f44436b6533336663366166564f36" +
- "6b7243796c5377693362680a416931535a376e64" +
- "554d6b37427951696167416457494f6f374a5878" +
- "32754a7a6f4b4679594a364755387446714d4b67" +
- "554b425431767759684c564b4a7443690a717444" +
- "2f747634366e4c555a4f7a2f685341326b43552b" +
- "447963444a7067745948787837724b4a43764748" +
- "3049596f41326853675941502b6b784a73567330" +
- "430a417745414154414e42676b71686b69473977" +
- "30424151554641414f43415145414a536b374873" +
- "4e594d75596a794f3459384231696254745a6d54" +
- "722b535849480a5031695432384376734c4e6330" +
- "567959794f704b3546687a445666464533786365" +
- "5762614242336c6d4e6f3152305377306e706d6e" +
- "63314270592b68456249610a6838444e56653230" +
- "657a4e79362f666a6534734368756b724a6a4b66" +
- "6d66484c6b36753546724f617369495449523962" +
- "7a4b4a5a75326e79754165417a677a330a6d4579" +
- "4677705a7149675870766b6977416c74704b4269" +
- "496c755058786e7254365a6e2f6e634e68545a71" +
- "573873597a54655664576d686b576f49315a5358" +
- "6a0a6a46757739705a57764c2b58646b746d5249" +
- "476b784b637878614650364b544b495055425735" +
- "6c5057765477654c397853645878776149592f58" +
- "4a62467569530a787a6449722b346b2f44554c77" +
- "7430467832366a4b62737066644d726c49444451" +
- "464d4f413151396534764f2b6151444a32507355" +
- "513d3d0a2d2d2d2d2d454e442043455254494649" +
- "434154452d2d2d2d2d0a2d2d2d2d2d424547494e" +
- "2043455254494649434154452d2d2d2d2d0a4d49" +
- "49443454434341736d67417749424167494a414d" +
- "7769544575596f6f6a384d413047435371475349" +
- "623344514542425155414d4947474d5173774351" +
- "59440a5651514745774a56557a454c4d416b4741" +
- "31554543417743546c6b784554415042674e5642" +
- "41634d43454a796232397262486c754d53457748" +
- "7759445651514b0a4442684e655342445a584a30" +
- "61575a70593246305a5342426458526f62334a70" +
- "64486b784554415042674e5642414d4d43473135" +
- "5932457562334a6e4d5345770a4877594a4b6f5a" +
- "496876634e41516b4246684a71646e4e6f595768" +
- "705a45426e625746706243356a62323077486863" +
- "4e4d544d774e5449324d6a45774e5441780a5768" +
- "634e4d6a4d774e5449304d6a45774e544178576a" +
- "4342686a454c4d416b474131554542684d435656" +
- "4d78437a414a42674e564241674d416b355a4d52" +
- "45770a447759445651514844416843636d397661" +
- "327835626a45684d423847413155454367775954" +
- "586b675132567964476c6d61574e686447556751" +
- "585630614739790a615852354d52457744775944" +
- "565151444441687465574e684c6d39795a7a4568" +
- "4d42384743537147534962334451454a41525953" +
- "616e5a7a6147466f615752410a5a323168615777" +
- "75593239744d494942496a414e42676b71686b69" +
- "47397730424151454641414f43415138414d4949" +
- "4243674b434151454138507574674634330a3032" +
- "33754c737938444e645753315a467a5369324975" +
- "6e69443947484b69664f6434317544672f375a75" +
- "4731447071324259367a34635633686c74473067" +
- "75530a4178754a4442735144706d503468666f77" +
- "6a4141523962382b5138376454534e5462435a74" +
- "3642746f4c6174326764654f4334433544427472" +
- "684e79314d6a4f0a46416575493479506e6f7867" +
- "31676135377741597742306c48746f2b4c383872" +
- "566f53654d4348484b665944696954354e4b786c" +
- "6e59413279447356454c31520a3662774334656d" +
- "7a5770715a5152736e6f4531516e69642f6f5830" +
- "4a6837324b796c2b7870516934424e5253696172" +
- "67665549754c7858755a6c635045786c460a7145" +
- "74646757624d456a65555876303845494652502f" +
- "6f503361474a41366c346b665537383779737670" +
- "4d774c72374b663062544b4c524f6b5874625132" +
- "79760a6d31787162567262655635716177494441" +
- "5141426f314177546a416442674e564851344546" +
- "67515561783441714a2f3666514435344a30506b" +
- "497951714b45330a61396f77487759445652306a" +
- "42426777466f415561783441714a2f3666514435" +
- "344a30506b497951714b453361396f7744415944" +
- "5652305442415577417745420a2f7a414e42676b" +
- "71686b6947397730424151554641414f43415145" +
- "417a57397a5456594c387934633467494d464c73" +
- "76335478442f742b554c616d4a675648340a5836" +
- "65674536724d73426a69567a344e4b5a506f6c64" +
- "556255394a52387233316e6e73695a574a637845" +
- "7764364f6e443143766e654d7351382f34476739" +
- "77360a486d495177455a33787032667135596c58" +
- "50736d775255667054507554356f55616853586b" +
- "7975564339796f31326b753841454f2f55375132" +
- "616a6c5a6437370a79736f63582f6c546f49666e" +
- "4d3573767a2b51542f4f7836624c435145357532" +
- "78515032446c376935436242666c502b61615048" +
- "324935756c444b67337371320a7a4e5942315868" +
- "414b474f623773384a4f7a554538425143396f41" +
- "4f6b4c4b55306955577548703268345366684d57" +
- "76776d316f656f5363786f706a594964710a4a63" +
- "476865412b3636462f687571796b6239304a5078" +
- "4c4c48665050534e66544a75696377314f7a7574" +
- "77796d5a695731673d3d0a2d2d2d2d2d454e4420" +
- "43455254494649434154452d2d2d2d2d0a",
-)
+func TestClientResumption(t *testing.T) {
+ serverConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ clientConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ InsecureSkipVerify: true,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ }
-// Script of interaction with openssl implementation:
-//
-// openssl s_server -cipher ECDHE-ECDSA-AES128-SHA \
-// -key server.key -cert server.crt -port 10443
-//
-// The values for this test are obtained by building and running in client mode:
-// % go test -test.run "TestRunClient" -connect -ciphersuites=0xc009
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-//
-// -----BEGIN EC PARAMETERS-----
-// BgUrgQQAIw==
-// -----END EC PARAMETERS-----
-// -----BEGIN EC PRIVATE KEY-----
-// MIHcAgEBBEIBmIPpCa0Kyeo9M/nq5mHxeFIGlw+MqakWcvHu3Keo7xK9ZWG7JG3a
-// XfS01efjqSZJvF2DoL+Sly4A5iBn0Me9mdegBwYFK4EEACOhgYkDgYYABADEoe2+
-// mPkLSHM2fsMWVhEi8j1TwztNIT3Na3Xm9rDcmt8mwbyyh/ByMnyzZC8ckLzqaCMQ
-// fv7jJcBIOmngKG3TNwDvBGLdDaCccGKD2IHTZDGqnpcxvZawaMCbI952ZD8aXH/p
-// Eg5YWLZfcN2b2OrV1/XVzLm2nzBmW2aaIOIn5b/+Ow==
-// -----END EC PRIVATE KEY-----
-//
-// and certificate is:
-//
-// -----BEGIN CERTIFICATE-----
-// MIICADCCAWICCQC4vy1HoNLr9DAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
-// EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
-// eSBMdGQwHhcNMTIxMTIyMTUwNjMyWhcNMjIxMTIwMTUwNjMyWjBFMQswCQYDVQQG
-// EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk
-// Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAxKHtvpj5C0hz
-// Nn7DFlYRIvI9U8M7TSE9zWt15vaw3JrfJsG8sofwcjJ8s2QvHJC86mgjEH7+4yXA
-// SDpp4Cht0zcA7wRi3Q2gnHBig9iB02Qxqp6XMb2WsGjAmyPedmQ/Glx/6RIOWFi2
-// X3Ddm9jq1df11cy5tp8wZltmmiDiJ+W//jswCQYHKoZIzj0EAQOBjAAwgYgCQgGI
-// ok/r4kXFSH0brPXtmJ2uR3DAXhu2L73xtk23YUDTEaLO7gt+kn7/dp3DO36lP876
-// EOJZ7EctfKzaTpcOFaBv0AJCAU38vmcTnC0FDr0/o4wlwTMTgw2UBrvUN3r27HrJ
-// hi7d1xFpf4V8Vt77MXgr5Md4Da7Lvp5ONiQxe2oPOZUSB48q
-// -----END CERTIFICATE-----
-var ecdheECDSAAESClientScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
- 0x46, 0x03, 0x01, 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, 0x09,
- 0x01, 0x00, 0x00, 0x1b, 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,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x54, 0x02, 0x00, 0x00,
- 0x50, 0x03, 0x01, 0x50, 0xd7, 0x19, 0xc9, 0x03,
- 0xc2, 0x3a, 0xc6, 0x1f, 0x0a, 0x84, 0x9e, 0xd7,
- 0xf4, 0x7e, 0x07, 0x6d, 0xa8, 0xe4, 0xa9, 0x4f,
- 0x22, 0x50, 0xa2, 0x19, 0x24, 0x44, 0x42, 0x65,
- 0xaa, 0xba, 0x3a, 0x20, 0x90, 0x70, 0xb7, 0xe5,
- 0x57, 0xed, 0xb1, 0xb1, 0x43, 0x4b, 0xa1, 0x4e,
- 0xee, 0x7a, 0x5b, 0x88, 0xf6, 0xa6, 0x73, 0x3b,
- 0xcb, 0xa7, 0xbd, 0x57, 0x50, 0xf2, 0x72, 0x8c,
- 0xbc, 0x45, 0x73, 0xaa, 0xc0, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
- 0x02, 0x16, 0x03, 0x01, 0x02, 0x0e, 0x0b, 0x00,
- 0x02, 0x0a, 0x00, 0x02, 0x07, 0x00, 0x02, 0x04,
- 0x30, 0x82, 0x02, 0x00, 0x30, 0x82, 0x01, 0x62,
- 0x02, 0x09, 0x00, 0xb8, 0xbf, 0x2d, 0x47, 0xa0,
- 0xd2, 0xeb, 0xf4, 0x30, 0x09, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
- 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
- 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
- 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
- 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x32, 0x31, 0x31, 0x32, 0x32, 0x31,
- 0x35, 0x30, 0x36, 0x33, 0x32, 0x5a, 0x17, 0x0d,
- 0x32, 0x32, 0x31, 0x31, 0x32, 0x30, 0x31, 0x35,
- 0x30, 0x36, 0x33, 0x32, 0x5a, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9b, 0x30,
- 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
- 0x23, 0x03, 0x81, 0x86, 0x00, 0x04, 0x00, 0xc4,
- 0xa1, 0xed, 0xbe, 0x98, 0xf9, 0x0b, 0x48, 0x73,
- 0x36, 0x7e, 0xc3, 0x16, 0x56, 0x11, 0x22, 0xf2,
- 0x3d, 0x53, 0xc3, 0x3b, 0x4d, 0x21, 0x3d, 0xcd,
- 0x6b, 0x75, 0xe6, 0xf6, 0xb0, 0xdc, 0x9a, 0xdf,
- 0x26, 0xc1, 0xbc, 0xb2, 0x87, 0xf0, 0x72, 0x32,
- 0x7c, 0xb3, 0x64, 0x2f, 0x1c, 0x90, 0xbc, 0xea,
- 0x68, 0x23, 0x10, 0x7e, 0xfe, 0xe3, 0x25, 0xc0,
- 0x48, 0x3a, 0x69, 0xe0, 0x28, 0x6d, 0xd3, 0x37,
- 0x00, 0xef, 0x04, 0x62, 0xdd, 0x0d, 0xa0, 0x9c,
- 0x70, 0x62, 0x83, 0xd8, 0x81, 0xd3, 0x64, 0x31,
- 0xaa, 0x9e, 0x97, 0x31, 0xbd, 0x96, 0xb0, 0x68,
- 0xc0, 0x9b, 0x23, 0xde, 0x76, 0x64, 0x3f, 0x1a,
- 0x5c, 0x7f, 0xe9, 0x12, 0x0e, 0x58, 0x58, 0xb6,
- 0x5f, 0x70, 0xdd, 0x9b, 0xd8, 0xea, 0xd5, 0xd7,
- 0xf5, 0xd5, 0xcc, 0xb9, 0xb6, 0x9f, 0x30, 0x66,
- 0x5b, 0x66, 0x9a, 0x20, 0xe2, 0x27, 0xe5, 0xbf,
- 0xfe, 0x3b, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x04, 0x01, 0x03, 0x81, 0x8c,
- 0x00, 0x30, 0x81, 0x88, 0x02, 0x42, 0x01, 0x88,
- 0xa2, 0x4f, 0xeb, 0xe2, 0x45, 0xc5, 0x48, 0x7d,
- 0x1b, 0xac, 0xf5, 0xed, 0x98, 0x9d, 0xae, 0x47,
- 0x70, 0xc0, 0x5e, 0x1b, 0xb6, 0x2f, 0xbd, 0xf1,
- 0xb6, 0x4d, 0xb7, 0x61, 0x40, 0xd3, 0x11, 0xa2,
- 0xce, 0xee, 0x0b, 0x7e, 0x92, 0x7e, 0xff, 0x76,
- 0x9d, 0xc3, 0x3b, 0x7e, 0xa5, 0x3f, 0xce, 0xfa,
- 0x10, 0xe2, 0x59, 0xec, 0x47, 0x2d, 0x7c, 0xac,
- 0xda, 0x4e, 0x97, 0x0e, 0x15, 0xa0, 0x6f, 0xd0,
- 0x02, 0x42, 0x01, 0x4d, 0xfc, 0xbe, 0x67, 0x13,
- 0x9c, 0x2d, 0x05, 0x0e, 0xbd, 0x3f, 0xa3, 0x8c,
- 0x25, 0xc1, 0x33, 0x13, 0x83, 0x0d, 0x94, 0x06,
- 0xbb, 0xd4, 0x37, 0x7a, 0xf6, 0xec, 0x7a, 0xc9,
- 0x86, 0x2e, 0xdd, 0xd7, 0x11, 0x69, 0x7f, 0x85,
- 0x7c, 0x56, 0xde, 0xfb, 0x31, 0x78, 0x2b, 0xe4,
- 0xc7, 0x78, 0x0d, 0xae, 0xcb, 0xbe, 0x9e, 0x4e,
- 0x36, 0x24, 0x31, 0x7b, 0x6a, 0x0f, 0x39, 0x95,
- 0x12, 0x07, 0x8f, 0x2a, 0x16, 0x03, 0x01, 0x00,
- 0xd6, 0x0c, 0x00, 0x00, 0xd2, 0x03, 0x00, 0x17,
- 0x41, 0x04, 0x33, 0xed, 0xe1, 0x10, 0x3d, 0xe2,
- 0xb0, 0x81, 0x5e, 0x01, 0x1b, 0x00, 0x4a, 0x7d,
- 0xdc, 0xc5, 0x78, 0x02, 0xb1, 0x9a, 0x78, 0x92,
- 0x34, 0xd9, 0x23, 0xcc, 0x01, 0xfb, 0x0c, 0x49,
- 0x1c, 0x4a, 0x59, 0x8a, 0x80, 0x1b, 0x34, 0xf0,
- 0xe8, 0x87, 0x1b, 0x7c, 0xfb, 0x72, 0xf5, 0xea,
- 0xf9, 0xf3, 0xff, 0xa6, 0x3e, 0x4e, 0xac, 0xbc,
- 0xee, 0x14, 0x2b, 0x87, 0xd4, 0x0b, 0xda, 0x19,
- 0x60, 0x2b, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x01, 0x75, 0x46, 0x4f, 0x97, 0x9f, 0xc5,
- 0xf9, 0x4c, 0x38, 0xcf, 0x3b, 0x37, 0x1a, 0x6b,
- 0x53, 0xfc, 0x05, 0x73, 0x7d, 0x98, 0x2c, 0x5b,
- 0x76, 0xd4, 0x37, 0x1f, 0x50, 0x6d, 0xad, 0xc6,
- 0x0f, 0x8f, 0x7b, 0xcc, 0x60, 0x8e, 0x04, 0x00,
- 0x21, 0x80, 0xa8, 0xa5, 0x98, 0xf2, 0x42, 0xf2,
- 0xc3, 0xf6, 0x44, 0x50, 0xc4, 0x7a, 0xae, 0x6f,
- 0x74, 0xa0, 0x7f, 0x07, 0x7a, 0x0b, 0xbb, 0x41,
- 0x9e, 0x3c, 0x0b, 0x02, 0x42, 0x01, 0xbe, 0x64,
- 0xaa, 0x12, 0x03, 0xfb, 0xd8, 0x4f, 0x93, 0xf9,
- 0x92, 0x54, 0x0d, 0x9c, 0x9d, 0x53, 0x88, 0x19,
- 0x69, 0x94, 0xfc, 0xd6, 0xf7, 0x60, 0xcf, 0x70,
- 0x64, 0x15, 0x1b, 0x02, 0x22, 0x56, 0xb0, 0x2c,
- 0xb1, 0x72, 0x4c, 0x9e, 0x7b, 0xf0, 0x53, 0x97,
- 0x43, 0xac, 0x11, 0x62, 0xe5, 0x5a, 0xf1, 0x7e,
- 0x87, 0x8f, 0x5c, 0x43, 0x1d, 0xae, 0x56, 0x28,
- 0xdb, 0x76, 0x15, 0xd8, 0x1c, 0x73, 0xce, 0x16,
- 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
- 0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
- 0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
- 0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
- 0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
- 0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
- 0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
- 0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
- 0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
- 0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x1a, 0x45,
- 0x92, 0x3b, 0xac, 0x8d, 0x91, 0x89, 0xd3, 0x2c,
- 0xf4, 0x3c, 0x5f, 0x70, 0xf1, 0x79, 0xa5, 0x6a,
- 0xcf, 0x97, 0x8f, 0x3f, 0x73, 0x08, 0xca, 0x3f,
- 0x55, 0xb0, 0x28, 0xd1, 0x6f, 0xcd, 0x9b, 0xca,
- 0xb6, 0xb7, 0xd0, 0xa5, 0x21, 0x5b, 0x08, 0xf8,
- 0x42, 0xe2, 0xdf, 0x25, 0x6a, 0x16,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x30, 0x30, 0x83, 0xb6, 0x51, 0x8a,
- 0x85, 0x4a, 0xee, 0xe4, 0xb6, 0xae, 0xf3, 0xc1,
- 0xdc, 0xd2, 0x04, 0xb3, 0xd0, 0x25, 0x47, 0x5f,
- 0xac, 0x83, 0xa3, 0x7d, 0xcf, 0x47, 0x92, 0xed,
- 0x92, 0x6c, 0xd1, 0x6e, 0xfd, 0x63, 0xf5, 0x2d,
- 0x89, 0xd8, 0x04, 0x8c, 0x62, 0x71, 0xae, 0x5e,
- 0x32, 0x48, 0xf8,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x20, 0xcf, 0x5e, 0xba,
- 0xf4, 0x47, 0x32, 0x35, 0x9b, 0x85, 0xdc, 0xb3,
- 0xff, 0x77, 0x90, 0xd9, 0x2b, 0xbd, 0x59, 0x2a,
- 0x33, 0xe4, 0x6e, 0x9b, 0xfc, 0x1c, 0x73, 0x3f,
- 0x5e, 0x1e, 0xe3, 0xa4, 0xc2, 0x17, 0x03, 0x01,
- 0x00, 0x20, 0x05, 0xdf, 0x2d, 0x9b, 0x29, 0x7f,
- 0x97, 0xcd, 0x49, 0x04, 0x53, 0x22, 0x1a, 0xa1,
- 0xa1, 0xe6, 0x38, 0x3a, 0x56, 0x37, 0x1f, 0xd8,
- 0x3a, 0x12, 0x2c, 0xf0, 0xeb, 0x61, 0x35, 0x76,
- 0xe5, 0xf0, 0x15, 0x03, 0x01, 0x00, 0x20, 0xa5,
- 0x56, 0xb5, 0x49, 0x4b, 0xc2, 0xd4, 0x4c, 0xf6,
- 0x95, 0x15, 0x7d, 0x41, 0x1d, 0x5c, 0x00, 0x0e,
- 0x20, 0xb1, 0x0a, 0xbc, 0xc9, 0x2a, 0x09, 0x17,
- 0xb4, 0xaa, 0x1c, 0x79, 0xda, 0x79, 0x27,
- },
+ testResumeState := func(test string, didResume bool) {
+ hs, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("%s: handshake failed: %s", test, err)
+ }
+ if hs.DidResume != didResume {
+ t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
+ }
+ }
+
+ testResumeState("Handshake", false)
+ testResumeState("Resume", true)
+
+ if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
+ t.Fatalf("Failed to invalidate SessionTicketKey")
+ }
+ testResumeState("InvalidSessionTicketKey", false)
+ testResumeState("ResumeAfterInvalidSessionTicketKey", true)
+
+ clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+ testResumeState("DifferentCipherSuite", false)
+ testResumeState("DifferentCipherSuiteRecovers", true)
+
+ clientConfig.ClientSessionCache = nil
+ testResumeState("WithoutSessionCache", false)
+}
+
+func TestLRUClientSessionCache(t *testing.T) {
+ // Initialize cache of capacity 4.
+ cache := NewLRUClientSessionCache(4)
+ cs := make([]ClientSessionState, 6)
+ keys := []string{"0", "1", "2", "3", "4", "5", "6"}
+
+ // Add 4 entries to the cache and look them up.
+ for i := 0; i < 4; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 4; i++ {
+ if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
+ t.Fatalf("session cache failed lookup for added key: %s", keys[i])
+ }
+ }
+
+ // Add 2 more entries to the cache. First 2 should be evicted.
+ for i := 4; i < 6; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 2; i++ {
+ if s, ok := cache.Get(keys[i]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key: %s", keys[i])
+ }
+ }
+
+ // Touch entry 2. LRU should evict 3 next.
+ cache.Get(keys[2])
+ cache.Put(keys[0], &cs[0])
+ if s, ok := cache.Get(keys[3]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key 3")
+ }
+
+ // Update entry 0 in place.
+ cache.Put(keys[0], &cs[3])
+ if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] {
+ t.Fatalf("session cache failed update for key 0")
+ }
+
+ // Adding a nil entry is valid.
+ cache.Put(keys[0], nil)
+ if s, ok := cache.Get(keys[0]); !ok || s != nil {
+ t.Fatalf("failed to add nil entry to cache")
+ }
}
diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go
index 83952000f..7bcaa5eb9 100644
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -7,20 +7,21 @@ package tls
import "bytes"
type clientHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuites []uint16
- compressionMethods []uint8
- nextProtoNeg bool
- serverName string
- ocspStapling bool
- supportedCurves []uint16
- supportedPoints []uint8
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -38,11 +39,12 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
m.serverName == m1.serverName &&
m.ocspStapling == m1.ocspStapling &&
- eqUint16s(m.supportedCurves, m1.supportedCurves) &&
+ eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
- eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
+ eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
+ m.secureRenegotiation == m1.secureRenegotiation
}
func (m *clientHelloMsg) marshal() []byte {
@@ -80,6 +82,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -114,13 +120,13 @@ func (m *clientHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
z = z[4:]
}
if len(m.serverName) > 0 {
z[0] = byte(extensionServerName >> 8)
- z[1] = byte(extensionServerName)
+ z[1] = byte(extensionServerName & 0xff)
l := len(m.serverName) + 5
z[2] = byte(l >> 8)
z[3] = byte(l)
@@ -224,6 +230,13 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
m.raw = x
@@ -256,6 +269,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ if m.cipherSuites[i] == scsvRenegotiation {
+ m.secureRenegotiation = true
+ }
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
@@ -341,10 +357,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
numCurves := l / 2
- m.supportedCurves = make([]uint16, numCurves)
+ m.supportedCurves = make([]CurveID, numCurves)
d := data[2:]
for i := 0; i < numCurves; i++ {
- m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+ m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
d = d[2:]
}
case extensionSupportedPoints:
@@ -379,6 +395,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes[i].signature = d[1]
d = d[2:]
}
+ case extensionRenegotiationInfo + 1:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
}
data = data[length:]
}
@@ -387,16 +408,17 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- ticketSupported bool
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation bool
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -414,7 +436,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
- m.ticketSupported == m1.ticketSupported
+ m.ticketSupported == m1.ticketSupported &&
+ m.secureRenegotiation == m1.secureRenegotiation
}
func (m *serverHelloMsg) marshal() []byte {
@@ -441,6 +464,10 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
+ if m.secureRenegotiation {
+ extensionsLength += 1
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -469,7 +496,7 @@ func (m *serverHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
- z[1] = byte(extensionNextProtoNeg)
+ z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
z[3] = byte(nextProtoLen)
z = z[4:]
@@ -494,6 +521,13 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
+ if m.secureRenegotiation {
+ z[0] = byte(extensionRenegotiationInfo >> 8)
+ z[1] = byte(extensionRenegotiationInfo & 0xff)
+ z[2] = 0
+ z[3] = 1
+ z = z[5:]
+ }
m.raw = x
@@ -573,6 +607,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.ticketSupported = true
+ case extensionRenegotiationInfo:
+ if length != 1 || data[0] != 0 {
+ return false
+ }
+ m.secureRenegotiation = true
}
data = data[length:]
}
@@ -1255,6 +1294,18 @@ func eqUint16s(x, y []uint16) bool {
return true
}
+func eqCurveIDs(x, y []CurveID) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
func eqStrings(x, y []string) bool {
if len(x) != len(y) {
return false
diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
index 4f569eeb1..f46aabdfd 100644
--- a/src/pkg/crypto/tls/handshake_messages_test.go
+++ b/src/pkg/crypto/tls/handshake_messages_test.go
@@ -125,9 +125,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
}
m.ocspStapling = rand.Intn(10) > 5
m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
- m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+ m.supportedCurves = make([]CurveID, rand.Intn(5)+1)
for i := range m.supportedCurves {
- m.supportedCurves[i] = uint16(rand.Intn(30000))
+ m.supportedCurves[i] = CurveID(rand.Intn(30000))
}
if rand.Intn(10) > 5 {
m.ticketSupported = true
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index c9ccf675c..75111eba0 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -12,6 +12,7 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
+ "fmt"
"io"
)
@@ -100,11 +101,13 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
var ok bool
hs.clientHello, ok = msg.(*clientHelloMsg)
if !ok {
- return false, c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return false, unexpectedMessageError(hs.clientHello, msg)
}
c.vers, ok = config.mutualVersion(hs.clientHello.vers)
if !ok {
- return false, c.sendAlert(alertProtocolVersion)
+ c.sendAlert(alertProtocolVersion)
+ return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
}
c.haveVers = true
@@ -114,12 +117,14 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
hs.hello = new(serverHelloMsg)
supportedCurve := false
+ preferredCurves := config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
- switch curve {
- case curveP256, curveP384, curveP521:
- supportedCurve = true
- break Curves
+ for _, supported := range preferredCurves {
+ if supported == curve {
+ supportedCurve = true
+ break Curves
+ }
}
}
@@ -142,20 +147,18 @@ Curves:
}
if !foundCompression {
- return false, c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: client does not support uncompressed connections")
}
hs.hello.vers = c.vers
- t := uint32(config.time().Unix())
hs.hello.random = make([]byte, 32)
- hs.hello.random[0] = byte(t >> 24)
- hs.hello.random[1] = byte(t >> 16)
- hs.hello.random[2] = byte(t >> 8)
- hs.hello.random[3] = byte(t)
- _, err = io.ReadFull(config.rand(), hs.hello.random[4:])
+ _, err = io.ReadFull(config.rand(), hs.hello.random)
if err != nil {
- return false, c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return false, err
}
+ hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
@@ -170,7 +173,8 @@ Curves:
}
if len(config.Certificates) == 0 {
- return false, c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return false, errors.New("tls: no certificates configured")
}
hs.cert = &config.Certificates[0]
if len(hs.clientHello.serverName) > 0 {
@@ -199,7 +203,8 @@ Curves:
}
if hs.suite == nil {
- return false, c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: no cipher suite supported by both client and server")
}
return false, nil
@@ -349,7 +354,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// certificate message, even if it's empty.
if config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
}
hs.finishedHash.Write(certMsg.marshal())
@@ -376,7 +382,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// Get client key exchange
ckx, ok := msg.(*clientKeyExchangeMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(ckx, msg)
}
hs.finishedHash.Write(ckx.marshal())
@@ -393,7 +400,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
certVerify, ok := msg.(*certificateVerifyMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
}
switch key := pub.(type) {
@@ -462,7 +470,7 @@ func (hs *serverHandshakeState) readFinished() error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.error(); err != nil {
+ if err := c.in.error(); err != nil {
return err
}
@@ -473,7 +481,8 @@ func (hs *serverHandshakeState) readFinished() error {
}
nextProto, ok := msg.(*nextProtoMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(nextProto, msg)
}
hs.finishedHash.Write(nextProto.marshal())
c.clientProtocol = nextProto.proto
@@ -485,13 +494,15 @@ func (hs *serverHandshakeState) readFinished() error {
}
clientFinished, ok := msg.(*finishedMsg)
if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
}
verify := hs.finishedHash.clientSum(hs.masterSecret)
if len(verify) != len(clientFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message is incorrect")
}
hs.finishedHash.Write(clientFinished.marshal())
@@ -594,7 +605,8 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
case *ecdsa.PublicKey, *rsa.PublicKey:
pub = key
default:
- return nil, c.sendAlert(alertUnsupportedCertificate)
+ c.sendAlert(alertUnsupportedCertificate)
+ return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
}
c.peerCertificates = certs
return pub, nil
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index c08eba7f1..c3e36785b 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -12,20 +12,20 @@ import (
"crypto/x509"
"encoding/hex"
"encoding/pem"
- "flag"
+ "errors"
"fmt"
"io"
- "log"
"math/big"
"net"
"os"
- "strconv"
+ "os/exec"
+ "path/filepath"
"strings"
- "sync"
"testing"
"time"
)
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
type zeroSource struct{}
func (zeroSource) Read(b []byte) (n int, err error) {
@@ -39,22 +39,22 @@ func (zeroSource) Read(b []byte) (n int, err error) {
var testConfig *Config
func init() {
- testConfig = new(Config)
- testConfig.Time = func() time.Time { return time.Unix(0, 0) }
- testConfig.Rand = zeroSource{}
- testConfig.Certificates = make([]Certificate, 2)
+ testConfig = &Config{
+ Time: func() time.Time { return time.Unix(0, 0) },
+ Rand: zeroSource{},
+ Certificates: make([]Certificate, 2),
+ InsecureSkipVerify: true,
+ MinVersion: VersionSSL30,
+ MaxVersion: VersionTLS12,
+ }
testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate}
testConfig.Certificates[1].PrivateKey = testRSAPrivateKey
testConfig.BuildNameToCertificate()
- testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
- testConfig.InsecureSkipVerify = true
- testConfig.MinVersion = VersionSSL30
- testConfig.MaxVersion = VersionTLS10
}
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
// Create in-memory network connection,
// send message to server. Should return
// expected error.
@@ -69,20 +69,20 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
}()
err := Server(s, testConfig).Handshake()
s.Close()
- if e, ok := err.(*net.OpError); !ok || e.Err != expected {
- t.Errorf("Got error: %s; expected: %s", err, expected)
+ if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
+ t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
}
}
func TestSimpleError(t *testing.T) {
- testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
+ testClientHelloFailure(t, &serverHelloDoneMsg{}, "unexpected handshake message")
}
var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
func TestRejectBadProtocolVersion(t *testing.T) {
for _, v := range badProtocolVersions {
- testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
+ testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
}
}
@@ -92,7 +92,7 @@ func TestNoSuiteOverlap(t *testing.T) {
cipherSuites: []uint16{0xff00},
compressionMethods: []uint8{0},
}
- testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+ testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
}
func TestNoCompressionOverlap(t *testing.T) {
@@ -101,7 +101,7 @@ func TestNoCompressionOverlap(t *testing.T) {
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{0xff},
}
- testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+ testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
}
func TestTLS12OnlyCipherSuites(t *testing.T) {
@@ -121,7 +121,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
TLS_RSA_WITH_RC4_128_SHA,
},
compressionMethods: []uint8{compressionNone},
- supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedCurves: []CurveID{CurveP256, CurveP384, CurveP521},
supportedPoints: []uint8{pointFormatUncompressed},
}
@@ -178,10 +178,12 @@ func TestClose(t *testing.T) {
func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
c, s := net.Pipe()
+ done := make(chan bool)
go func() {
cli := Client(c, clientConfig)
cli.Handshake()
c.Close()
+ done <- true
}()
server := Server(s, serverConfig)
err = server.Handshake()
@@ -189,9 +191,27 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e
state = server.ConnectionState()
}
s.Close()
+ <-done
return
}
+func TestVersion(t *testing.T) {
+ serverConfig := &Config{
+ Certificates: testConfig.Certificates,
+ MaxVersion: VersionTLS11,
+ }
+ clientConfig := &Config{
+ InsecureSkipVerify: true,
+ }
+ state, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.Version != VersionTLS11 {
+ t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11)
+ }
+}
+
func TestCipherSuitePreference(t *testing.T) {
serverConfig := &Config{
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
@@ -221,2920 +241,327 @@ func TestCipherSuitePreference(t *testing.T) {
}
}
-func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config, peers []*x509.Certificate) {
- c, s := net.Pipe()
- srv := Server(s, config)
- pchan := make(chan []*x509.Certificate, 1)
- go func() {
- srv.Write([]byte("hello, world\n"))
- srv.Close()
- s.Close()
- st := srv.ConnectionState()
- pchan <- st.PeerCertificates
- }()
-
- for i, b := range serverScript {
- if i%2 == 0 {
- c.Write(b)
- continue
- }
- bb := make([]byte, len(b))
- n, err := io.ReadFull(c, bb)
- if err != nil {
- t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", name, i, err, n, len(bb), bb[:n], b)
- }
- if !bytes.Equal(b, bb) {
- t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
- }
- }
- c.Close()
-
- if peers != nil {
- gotpeers := <-pchan
- if len(peers) == len(gotpeers) {
- for i := range peers {
- if !peers[i].Equal(gotpeers[i]) {
- t.Fatalf("%s: mismatch on peer cert %d", name, i)
- }
- }
- } else {
- t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", name, len(peers), len(gotpeers))
- }
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
+
+// serverTest represents a test of the TLS server handshake against a reference
+// implementation.
+type serverTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // command, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ command []string
+ // expectedPeerCerts contains a list of PEM blocks of expected
+ // certificates from the client.
+ expectedPeerCerts []string
+ // config, if not nil, contains a custom Config to use for this test.
+ config *Config
+}
+
+var defaultClientCommand = []string{"openssl", "s_client", "-no_ticket"}
+
+// connFromCommand starts opens a listening socket and starts the reference
+// client to connect to it. It returns a recordingConn that wraps the resulting
+// connection.
+func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, err error) {
+ l, err := net.ListenTCP("tcp", &net.TCPAddr{
+ IP: net.IPv4(127, 0, 0, 1),
+ Port: 0,
+ })
+ if err != nil {
+ return nil, nil, err
}
-}
+ defer l.Close()
-func TestHandshakeServerRSARC4(t *testing.T) {
- testServerScript(t, "RSA-RC4", rsaRC4ServerScript, testConfig, nil)
-}
-
-func TestHandshakeServerRSA3DES(t *testing.T) {
- des3Config := new(Config)
- *des3Config = *testConfig
- des3Config.CipherSuites = []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA}
- testServerScript(t, "RSA-3DES", rsaDES3ServerScript, des3Config, nil)
-}
-
-func TestHandshakeServerRSAAES(t *testing.T) {
- aesConfig := new(Config)
- *aesConfig = *testConfig
- aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
- testServerScript(t, "RSA-AES", rsaAESServerScript, aesConfig, nil)
-}
+ port := l.Addr().(*net.TCPAddr).Port
-func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
- ecdsaConfig := new(Config)
- *ecdsaConfig = *testConfig
- ecdsaConfig.Certificates = make([]Certificate, 1)
- ecdsaConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- ecdsaConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
- ecdsaConfig.BuildNameToCertificate()
- ecdsaConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- testServerScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESServerScript, ecdsaConfig, nil)
-}
-
-func TestHandshakeServerSSLv3(t *testing.T) {
- testServerScript(t, "SSLv3", sslv3ServerScript, testConfig, nil)
-}
-
-// TestHandshakeServerSNI involves a client sending an SNI extension of
-// "snitest.com", which happens to match the CN of testSNICertificate. The test
-// verifies that the server correctly selects that certificate.
-func TestHandshakeServerSNI(t *testing.T) {
- testServerScript(t, "SNI", selectCertificateBySNIScript, testConfig, nil)
-}
-
-func TestResumption(t *testing.T) {
- testServerScript(t, "IssueTicket", issueSessionTicketTest, testConfig, nil)
- testServerScript(t, "Resume", serverResumeTest, testConfig, nil)
-}
-
-func TestTLS12ClientCertServer(t *testing.T) {
- config := *testConfig
- config.MaxVersion = VersionTLS12
- config.ClientAuth = RequireAnyClientCert
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
-
- testServerScript(t, "TLS12", tls12ServerScript, &config, nil)
-}
-
-type clientauthTest struct {
- name string
- clientauth ClientAuthType
- peers []*x509.Certificate
- script [][]byte
-}
-
-func TestClientAuthRSA(t *testing.T) {
- for _, cat := range clientauthRSATests {
- t.Log("running", cat.name)
- cfg := new(Config)
- *cfg = *testConfig
- cfg.ClientAuth = cat.clientauth
- testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+ var command []string
+ command = append(command, test.command...)
+ if len(command) == 0 {
+ command = defaultClientCommand
}
-}
-
-func TestClientAuthECDSA(t *testing.T) {
- for _, cat := range clientauthECDSATests {
- t.Log("running", cat.name)
- cfg := new(Config)
- *cfg = *testConfig
- cfg.Certificates = make([]Certificate, 1)
- cfg.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- cfg.Certificates[0].PrivateKey = testECDSAPrivateKey
- cfg.BuildNameToCertificate()
- cfg.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- cfg.ClientAuth = cat.clientauth
- testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+ command = append(command, "-connect")
+ command = append(command, fmt.Sprintf("127.0.0.1:%d", port))
+ cmd := exec.Command(command[0], command[1:]...)
+ cmd.Stdin = nil
+ var output bytes.Buffer
+ cmd.Stdout = &output
+ cmd.Stderr = &output
+ if err := cmd.Start(); err != nil {
+ return nil, nil, err
}
-}
-// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
-// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
-func TestCipherSuiteCertPreferance(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- config.MaxVersion = VersionTLS11
- config.PreferServerCipherSuites = true
- testServerScript(t, "CipherSuiteCertPreference", tls11ECDHEAESServerScript, &config, nil)
+ connChan := make(chan interface{})
+ go func() {
+ tcpConn, err := l.Accept()
+ if err != nil {
+ connChan <- err
+ }
+ connChan <- tcpConn
+ }()
- config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
- config.Certificates = []Certificate{
- Certificate{
- Certificate: [][]byte{testECDSACertificate},
- PrivateKey: testECDSAPrivateKey,
- },
+ var tcpConn net.Conn
+ select {
+ case connOrError := <-connChan:
+ if err, ok := connOrError.(error); ok {
+ return nil, nil, err
+ }
+ tcpConn = connOrError.(net.Conn)
+ case <-time.After(2 * time.Second):
+ output.WriteTo(os.Stdout)
+ return nil, nil, errors.New("timed out waiting for connection from child process")
}
- config.BuildNameToCertificate()
- config.PreferServerCipherSuites = true
- testServerScript(t, "CipherSuiteCertPreference2", ecdheECDSAAESServerScript, &config, nil)
-}
-
-func TestTLS11Server(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
- config.MaxVersion = VersionTLS11
- testServerScript(t, "TLS11", tls11ECDHEAESServerScript, &config, nil)
-}
-
-func TestAESGCM(t *testing.T) {
- var config = *testConfig
- config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
- config.MaxVersion = VersionTLS12
- testServerScript(t, "AES-GCM", aesGCMServerScript, &config, nil)
-}
-// recordingConn is a net.Conn that records the traffic that passes through it.
-// WriteTo can be used to produce Go code that contains the recorded traffic.
-type recordingConn struct {
- net.Conn
- lock sync.Mutex
- flows [][]byte
- currentlyReading bool
-}
-
-func (r *recordingConn) Read(b []byte) (n int, err error) {
- if n, err = r.Conn.Read(b); n == 0 {
- return
+ record := &recordingConn{
+ Conn: tcpConn,
}
- b = b[:n]
-
- r.lock.Lock()
- defer r.lock.Unlock()
- if l := len(r.flows); l == 0 || !r.currentlyReading {
- buf := make([]byte, len(b))
- copy(buf, b)
- r.flows = append(r.flows, buf)
- } else {
- r.flows[l-1] = append(r.flows[l-1], b[:n]...)
- }
- r.currentlyReading = true
- return
+ return record, cmd, nil
}
-func (r *recordingConn) Write(b []byte) (n int, err error) {
- if n, err = r.Conn.Write(b); n == 0 {
- return
- }
- b = b[:n]
-
- r.lock.Lock()
- defer r.lock.Unlock()
-
- if l := len(r.flows); l == 0 || r.currentlyReading {
- buf := make([]byte, len(b))
- copy(buf, b)
- r.flows = append(r.flows, buf)
- } else {
- r.flows[l-1] = append(r.flows[l-1], b[:n]...)
- }
- r.currentlyReading = false
- return
+func (test *serverTest) dataPath() string {
+ return filepath.Join("testdata", "Server-"+test.name)
}
-// WriteTo writes Go source code to w that contains the recorded traffic.
-func (r *recordingConn) WriteTo(w io.Writer) {
- fmt.Fprintf(w, "var changeMe = [][]byte {\n")
- for _, buf := range r.flows {
- fmt.Fprintf(w, "\t{")
- for i, b := range buf {
- if i%8 == 0 {
- fmt.Fprintf(w, "\n\t\t")
- }
- fmt.Fprintf(w, "0x%02x, ", b)
- }
- fmt.Fprintf(w, "\n\t},\n")
+func (test *serverTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
}
- fmt.Fprintf(w, "}\n")
+ defer in.Close()
+ return parseTestData(in)
}
-var serve = flag.Bool("serve", false, "run a TLS server on :10443")
-var testCipherSuites = flag.String("ciphersuites",
- "0x"+strconv.FormatInt(int64(TLS_RSA_WITH_RC4_128_SHA), 16),
- "cipher suites to accept in serving mode")
-var testMinVersion = flag.String("minversion",
- "0x"+strconv.FormatInt(int64(VersionSSL30), 16),
- "minimum version to negotiate")
-var testMaxVersion = flag.String("maxversion",
- "0x"+strconv.FormatInt(int64(VersionTLS10), 16),
- "maximum version to negotiate")
-var testClientAuth = flag.Int("clientauth", 0, "value for tls.Config.ClientAuth")
-
-func GetTestConfig() *Config {
- var config = *testConfig
-
- minVersion, err := strconv.ParseUint(*testMinVersion, 0, 64)
- if err != nil {
- panic(err)
- }
- config.MinVersion = uint16(minVersion)
- maxVersion, err := strconv.ParseUint(*testMaxVersion, 0, 64)
- if err != nil {
- panic(err)
- }
- config.MaxVersion = uint16(maxVersion)
+func (test *serverTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
- suites := strings.Split(*testCipherSuites, ",")
- config.CipherSuites = make([]uint16, len(suites))
- for i := range suites {
- suite, err := strconv.ParseUint(suites[i], 0, 64)
+ if write {
+ var err error
+ recordingConn, childProcess, err = test.connFromCommand()
if err != nil {
- panic(err)
+ t.Fatalf("Failed to start subcommand: %s", err)
}
- config.CipherSuites[i] = uint16(suite)
+ serverConn = recordingConn
+ } else {
+ clientConn, serverConn = net.Pipe()
}
-
- ecdsa := false
- for _, suite := range config.CipherSuites {
- switch suite {
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- ecdsa = true
- }
+ config := test.config
+ if config == nil {
+ config = testConfig
}
- if ecdsa {
- config.Certificates = nil
- if !*connect {
- config.Certificates = make([]Certificate, 1)
- config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
- config.Certificates[0].PrivateKey = testECDSAPrivateKey
+ server := Server(serverConn, config)
+ peerCertsChan := make(chan []*x509.Certificate, 1)
+ go func() {
+ if _, err := server.Write([]byte("hello, world\n")); err != nil {
+ t.Logf("Error from Server.Write: %s", err)
}
- config.BuildNameToCertificate()
- }
-
- config.ClientAuth = ClientAuthType(*testClientAuth)
- return &config
-}
-
-func TestRunServer(t *testing.T) {
- if !*serve {
- return
- }
-
- config := GetTestConfig()
-
- const addr = ":10443"
- l, err := net.Listen("tcp", addr)
- if err != nil {
- t.Fatal(err)
- }
- log.Printf("Now listening for connections on %s", addr)
+ server.Close()
+ serverConn.Close()
+ peerCertsChan <- server.ConnectionState().PeerCertificates
+ }()
- for {
- tcpConn, err := l.Accept()
+ if !write {
+ flows, err := test.loadData()
if err != nil {
- log.Printf("error accepting connection: %s", err)
- break
+ t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
}
-
- record := &recordingConn{
- Conn: tcpConn,
+ for i, b := range flows {
+ if i%2 == 0 {
+ clientConn.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ n, err := io.ReadFull(clientConn, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
+ }
}
+ clientConn.Close()
+ }
- conn := Server(record, config)
- if err := conn.Handshake(); err != nil {
- log.Printf("error from TLS handshake: %s", err)
- break
+ peerCerts := <-peerCertsChan
+ if len(peerCerts) == len(test.expectedPeerCerts) {
+ for i, peerCert := range peerCerts {
+ block, _ := pem.Decode([]byte(test.expectedPeerCerts[i]))
+ if !bytes.Equal(block.Bytes, peerCert.Raw) {
+ t.Fatalf("%s: mismatch on peer cert %d", test.name, i+1)
+ }
}
+ } else {
+ t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", test.name, len(test.expectedPeerCerts), len(peerCerts))
+ }
- _, err = conn.Write([]byte("hello, world\n"))
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- log.Printf("error from Write: %s", err)
- continue
+ t.Fatalf("Failed to create output file: %s", err)
}
-
- conn.Close()
-
- record.WriteTo(os.Stdout)
+ defer out.Close()
+ recordingConn.Close()
+ if len(recordingConn.flows) < 3 {
+ childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ t.Fatalf("Handshake failed")
+ }
+ recordingConn.WriteTo(out)
+ fmt.Printf("Wrote %s\n", path)
+ childProcess.Wait()
}
}
-func bigFromString(s string) *big.Int {
- ret := new(big.Int)
- ret.SetString(s, 10)
- return ret
+func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) {
+ test := *template
+ test.name = prefix + test.name
+ if len(test.command) == 0 {
+ test.command = defaultClientCommand
+ }
+ test.command = append([]string(nil), test.command...)
+ test.command = append(test.command, option)
+ test.run(t, *update)
}
-func fromHex(s string) []byte {
- b, _ := hex.DecodeString(s)
- return b
+func runServerTestSSLv3(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "SSLv3-", "-ssl3")
}
-var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
-
-var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
-
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+func runServerTestTLS10(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv10-", "-tls1")
+}
-var testRSAPrivateKey = &rsa.PrivateKey{
- PublicKey: rsa.PublicKey{
- N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
- E: 65537,
- },
- D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
- Primes: []*big.Int{
- bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
- bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
- },
+func runServerTestTLS11(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv11-", "-tls1_1")
}
-var testECDSAPrivateKey = &ecdsa.PrivateKey{
- PublicKey: ecdsa.PublicKey{
- Curve: &elliptic.CurveParams{
- P: bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"),
- N: bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449"),
- B: bigFromString("1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984"),
- Gx: bigFromString("2661740802050217063228768716723360960729859168756973147706671368418802944996427808491545080627771902352094241225065558662157113545570916814161637315895999846"),
- Gy: bigFromString("3757180025770020463545507224491183603594455134769762486694567779615544477440556316691234405012945539562144444537289428522585666729196580810124344277578376784"),
- BitSize: 521,
- },
- X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
- Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
- },
- D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
+func runServerTestTLS12(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv12-", "-tls1_2")
}
-func loadPEMCert(in string) *x509.Certificate {
- block, _ := pem.Decode([]byte(in))
- if block.Type == "CERTIFICATE" && len(block.Headers) == 0 {
- cert, err := x509.ParseCertificate(block.Bytes)
- if err == nil {
- return cert
- }
- panic("error parsing cert")
+func TestHandshakeServerRSARC4(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
}
- panic("error parsing PEM")
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS11(t, test)
+ runServerTestTLS12(t, test)
}
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in server mode:
-// % go test -test.run "TestRunServer" -serve
-// The recorded bytes are written to stdout.
-var rsaRC4ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
- 0x50, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xbd, 0x32,
- 0x13, 0xd7, 0xea, 0x33, 0x65, 0x02, 0xb8, 0x70,
- 0xb7, 0x84, 0xc4, 0x05, 0x1f, 0xa4, 0x24, 0xc4,
- 0x91, 0x69, 0x04, 0x32, 0x96, 0xfe, 0x5b, 0x49,
- 0x71, 0x60, 0x9a, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 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, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
- 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
- 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
- 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
- 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
- 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
- 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
- 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
- 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
- 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
- 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
- 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
- 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
- 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
- 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
- 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
- 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
- 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
- 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
- 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
- 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
- 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
- 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
- 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
- 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
- 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
- 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
- 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
- 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
- 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
- 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
- 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
- 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
- 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
- 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
- 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
- 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
- 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
- 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
- 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
- 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
- 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
- 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
- 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
- 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
- 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x2d, 0x09, 0x7c, 0x7f, 0xfc,
- 0x84, 0xce, 0xb3, 0x30, 0x9b, 0xf9, 0xb7, 0xc8,
- 0xc3, 0xff, 0xee, 0x6f, 0x20, 0x8a, 0xf4, 0xfb,
- 0x86, 0x55, 0x1f, 0x6a, 0xb4, 0x81, 0x50, 0x3a,
- 0x46, 0x1b, 0xd3, 0xca, 0x4b, 0x11, 0xff, 0xef,
- 0x02, 0xbc, 0x18, 0xb8, 0x4a, 0x7d, 0x43, 0x23,
- 0x96, 0x92, 0x27, 0x7c, 0xca, 0xcf, 0xe6, 0x91,
- 0xe8, 0x14, 0x97, 0x68, 0xb4, 0xe5, 0xc0, 0xc9,
- 0x23, 0xdd, 0x54, 0x07, 0xa6, 0x2e, 0x8c, 0x98,
- 0xfc, 0xc6, 0x8c, 0x04, 0x6b, 0x1b, 0x5f, 0xd5,
- 0x3d, 0x8b, 0x6c, 0x55, 0x4f, 0x7a, 0xe6, 0x6c,
- 0x74, 0x2c, 0x1e, 0x34, 0xdb, 0xfb, 0x00, 0xb1,
- 0x4e, 0x10, 0x21, 0x16, 0xe0, 0x3e, 0xc5, 0x64,
- 0x84, 0x28, 0x2b, 0x2b, 0x29, 0x47, 0x51, 0x34,
- 0x76, 0x15, 0x20, 0x71, 0x0b, 0x30, 0xa1, 0x85,
- 0xd5, 0x15, 0x18, 0x14, 0x64, 0x4b, 0x40, 0x7c,
- 0x4f, 0xb3, 0x7b, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xab, 0xee,
- 0xf5, 0x97, 0x5f, 0xc6, 0x78, 0xf3, 0xc6, 0x83,
- 0x5b, 0x55, 0x4f, 0xcb, 0x45, 0x3f, 0xfa, 0xf7,
- 0x05, 0x02, 0xc2, 0x63, 0x87, 0x18, 0xb5, 0x9a,
- 0x62, 0xe2, 0x3f, 0x88, 0x5a, 0x60, 0x61, 0x72,
- 0xfa, 0x9c,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x72, 0xa4, 0xe4, 0xaa, 0xd2,
- 0xc4, 0x39, 0x7e, 0x2a, 0xc1, 0x6f, 0x34, 0x42,
- 0x28, 0xcb, 0x9d, 0x7a, 0x09, 0xca, 0x96, 0xad,
- 0x0e, 0x11, 0x51, 0x8a, 0x06, 0xb0, 0xe9, 0xca,
- 0xeb, 0xce, 0xe2, 0xd5, 0x2e, 0xc1, 0x8d, 0x17,
- 0x03, 0x01, 0x00, 0x21, 0x2e, 0x61, 0x86, 0x17,
- 0xdb, 0xa6, 0x30, 0xe2, 0x62, 0x06, 0x2a, 0x8b,
- 0x75, 0x2c, 0x2d, 0xcf, 0xf5, 0x01, 0x11, 0x52,
- 0x81, 0x38, 0xcf, 0xd5, 0xf7, 0xdc, 0x52, 0x31,
- 0x1f, 0x97, 0x43, 0xc2, 0x71, 0x15, 0x03, 0x01,
- 0x00, 0x16, 0xe0, 0x21, 0xfe, 0x36, 0x2e, 0x68,
- 0x2c, 0xf1, 0xbe, 0x04, 0xec, 0xd4, 0xc6, 0xdd,
- 0xac, 0x6f, 0x4c, 0x85, 0x32, 0x3f, 0x87, 0x1b,
- },
+func TestHandshakeServerRSA3DES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-3DES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "DES-CBC3-SHA"},
+ }
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-var rsaDES3ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
- 0xc1, 0x03, 0x03, 0x50, 0xae, 0x5d, 0x38, 0xec,
- 0xaa, 0x2f, 0x41, 0xf9, 0xd2, 0x7b, 0xa1, 0xfd,
- 0x0f, 0xff, 0x4e, 0x54, 0x0e, 0x15, 0x57, 0xaf,
- 0x2c, 0x91, 0xb5, 0x35, 0x5b, 0x2e, 0xb0, 0xec,
- 0x20, 0xe5, 0xd2, 0x00, 0x00, 0x50, 0xc0, 0x09,
- 0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
- 0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
- 0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
- 0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
- 0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
- 0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
- 0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
- 0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
- 0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
- 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
- 0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
- 0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
- 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
- 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
- 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x51, 0x04, 0xf1, 0x7a, 0xbf,
- 0xe8, 0xa5, 0x86, 0x09, 0xa7, 0xf3, 0xcc, 0x93,
- 0x00, 0x10, 0x5b, 0xb8, 0xc1, 0x51, 0x0d, 0x5b,
- 0xcd, 0xed, 0x26, 0x01, 0x69, 0x73, 0xf4, 0x05,
- 0x8a, 0x6a, 0xc3, 0xb1, 0x9e, 0x84, 0x4e, 0x39,
- 0xcf, 0x5e, 0x55, 0xa9, 0x70, 0x19, 0x96, 0x91,
- 0xcd, 0x2c, 0x78, 0x3c, 0xa2, 0x6d, 0xb0, 0x49,
- 0x86, 0xf6, 0xd1, 0x3a, 0xde, 0x00, 0x4b, 0xa6,
- 0x25, 0xbf, 0x85, 0x39, 0xce, 0xb1, 0xcf, 0xbc,
- 0x16, 0xc7, 0x66, 0xac, 0xf8, 0xd2, 0x3b, 0xd1,
- 0xcc, 0x16, 0xac, 0x63, 0x3c, 0xbe, 0xd9, 0xb6,
- 0x6a, 0xe4, 0x13, 0x8a, 0xf4, 0x56, 0x2f, 0x92,
- 0x54, 0xd8, 0xf0, 0x84, 0x01, 0x32, 0x1a, 0xa9,
- 0x2d, 0xaf, 0x82, 0x0e, 0x00, 0xfa, 0x07, 0x88,
- 0xd9, 0x87, 0xe7, 0xdc, 0x9e, 0xe9, 0x72, 0x49,
- 0xb8, 0xfa, 0x8c, 0x7b, 0x07, 0x0b, 0x03, 0x7c,
- 0x10, 0x8c, 0x8a, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0xa8, 0x61, 0xa4,
- 0xf4, 0x5f, 0x8a, 0x1f, 0x5c, 0x92, 0x3f, 0x8c,
- 0xdb, 0xd6, 0x10, 0xcd, 0x9e, 0xe7, 0xf0, 0xc4,
- 0x3c, 0xb6, 0x1c, 0x9a, 0x56, 0x73, 0x7f, 0xa6,
- 0x14, 0x24, 0xcb, 0x96, 0x1f, 0xe0, 0xaf, 0xcd,
- 0x3c, 0x66, 0x43, 0xb7, 0x37, 0x65, 0x34, 0x47,
- 0xf8, 0x43, 0xf1, 0xcc, 0x15, 0xb8, 0xdc, 0x35,
- 0xe0, 0xa4, 0x2d, 0x78, 0x94, 0xe0, 0x02, 0xf3,
- 0x76, 0x46, 0xf7, 0x9b, 0x8d, 0x0d, 0x5d, 0x0b,
- 0xd3, 0xdd, 0x9a, 0x9e, 0x62, 0x2e, 0xc5, 0x98,
- 0x75, 0x63, 0x0c, 0xbf, 0x8e, 0x49, 0x33, 0x23,
- 0x7c, 0x00, 0xcf, 0xfb, 0xcf, 0xba, 0x0f, 0x41,
- 0x39, 0x89, 0xb9, 0xcc, 0x59, 0xd0, 0x2b, 0xb6,
- 0xec, 0x04, 0xe2, 0xc0, 0x52, 0xc7, 0xcf, 0x71,
- 0x47, 0xff, 0x70, 0x7e, 0xa9, 0xbd, 0x1c, 0xdd,
- 0x17, 0xa5, 0x6c, 0xb7, 0x10, 0x4f, 0x42, 0x18,
- 0x37, 0x69, 0xa9, 0xd2, 0xb3, 0x18, 0x84, 0x92,
- 0xa7, 0x47, 0x21, 0xf6, 0x95, 0x63, 0x29, 0xd6,
- 0xa5, 0xb6, 0xda, 0x65, 0x67, 0x69, 0xc4, 0x26,
- 0xac, 0x8b, 0x08, 0x58, 0xdd, 0x3c, 0x31, 0x20,
- 0xd5, 0x0c, 0x88, 0x72, 0x18, 0x16, 0x88, 0x1e,
- 0x4a, 0x0f, 0xe1, 0xcf, 0x95, 0x24,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xde, 0xef, 0xba, 0x3e, 0x18, 0x1c,
- 0x1e, 0x5e, 0xbc, 0x87, 0xf1, 0x87, 0x8d, 0x72,
- 0xe3, 0xbe, 0x0f, 0xdf, 0xfd, 0xd0, 0xb2, 0x89,
- 0xf8, 0x05, 0x9a, 0x52, 0x47, 0x77, 0x9e, 0xe8,
- 0xb1, 0x1d, 0x18, 0xed, 0x6a, 0x4b, 0x63, 0x1d,
- 0xf1, 0x62, 0xd2, 0x65, 0x21, 0x26, 0x73, 0xd4,
- 0x35, 0x5b, 0x95, 0x89, 0x12, 0x59, 0x23, 0x8c,
- 0xc3, 0xfc, 0xf9, 0x4d, 0x21, 0x79, 0xa0, 0xbd,
- 0xff, 0x33, 0xa2, 0x3d, 0x0b, 0x6f, 0x89, 0xc9,
- 0x23, 0xe4, 0xe7, 0x9f, 0x1d, 0x98, 0xf6, 0xed,
- 0x02, 0x8d, 0xac, 0x1a, 0xf9, 0xcb, 0xa5, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x28, 0x91, 0x56, 0x80, 0xe2, 0x6d, 0x51,
- 0x88, 0x03, 0xf8, 0x49, 0xe6, 0x6a, 0x5a, 0xfb,
- 0x2f, 0x0b, 0xb5, 0xa1, 0x0d, 0x63, 0x83, 0xae,
- 0xb9, 0xbc, 0x05, 0xf0, 0x81, 0x00, 0x61, 0x83,
- 0x38, 0xda, 0x14, 0xf6, 0xea, 0xd8, 0x78, 0x65,
- 0xc7, 0x26, 0x17, 0x03, 0x01, 0x00, 0x18, 0x81,
- 0x30, 0x8b, 0x22, 0x5a, 0xd3, 0x7f, 0xc8, 0xf2,
- 0x8a, 0x6b, 0xa3, 0xba, 0x4d, 0xe7, 0x6e, 0xd2,
- 0xfd, 0xbf, 0xf2, 0xc5, 0x28, 0xa0, 0x62, 0x17,
- 0x03, 0x01, 0x00, 0x28, 0x17, 0x83, 0x3c, 0x78,
- 0x18, 0xfa, 0x8d, 0x58, 0x5c, 0xaa, 0x05, 0x7d,
- 0x67, 0x96, 0x11, 0x60, 0x11, 0xc0, 0x1e, 0x0d,
- 0x6a, 0x6e, 0x5f, 0x1d, 0x98, 0x4b, 0xff, 0x82,
- 0xee, 0x21, 0x06, 0x29, 0xd3, 0x8b, 0x80, 0x78,
- 0x39, 0x05, 0x34, 0x9b, 0x15, 0x03, 0x01, 0x00,
- 0x18, 0xa9, 0x38, 0x18, 0x4f, 0x9d, 0x84, 0x75,
- 0x88, 0x53, 0xd6, 0x85, 0xc2, 0x15, 0x4b, 0xe3,
- 0xe3, 0x35, 0x9a, 0x74, 0xc9, 0x3e, 0x13, 0xc1,
- 0x8c,
- },
+func TestHandshakeServerRSAAES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
+ }
+ runServerTestSSLv3(t, test)
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-var rsaAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
- 0xc1, 0x03, 0x03, 0x50, 0xae, 0x5c, 0xe9, 0x5e,
- 0x31, 0x93, 0x82, 0xa5, 0x6f, 0x51, 0x82, 0xc8,
- 0x55, 0x4f, 0x1f, 0x2e, 0x90, 0x98, 0x81, 0x13,
- 0x27, 0x80, 0x68, 0xb4, 0x2d, 0xba, 0x3a, 0x76,
- 0xd8, 0xd7, 0x2c, 0x00, 0x00, 0x50, 0xc0, 0x09,
- 0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
- 0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
- 0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
- 0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
- 0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
- 0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
- 0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
- 0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
- 0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
- 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
- 0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
- 0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
- 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
- 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
- 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0x2f, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x51, 0x2e, 0xec, 0x0d, 0x86,
- 0xf3, 0x9f, 0xf2, 0x77, 0x04, 0x27, 0x2b, 0x0e,
- 0x9c, 0xab, 0x35, 0x84, 0x65, 0xff, 0x36, 0xef,
- 0xc0, 0x08, 0xc9, 0x1d, 0x9f, 0x29, 0xae, 0x8d,
- 0xc5, 0x66, 0x81, 0x31, 0x92, 0x5e, 0x3d, 0xac,
- 0xaa, 0x37, 0x28, 0x2c, 0x06, 0x91, 0xa6, 0xc2,
- 0xd0, 0x83, 0x34, 0x24, 0x1c, 0x88, 0xfc, 0x0a,
- 0xcf, 0xbf, 0xc2, 0x94, 0xe2, 0xed, 0xa7, 0x6a,
- 0xa8, 0x8d, 0x3d, 0xf7, 0x06, 0x7d, 0x69, 0xf8,
- 0x0d, 0xb2, 0xf7, 0xe4, 0x45, 0xcb, 0x0a, 0x25,
- 0xcb, 0xb2, 0x2e, 0x38, 0x9a, 0x84, 0x75, 0xe8,
- 0xe1, 0x42, 0x39, 0xa2, 0x18, 0x0e, 0x48, 0xca,
- 0x33, 0x16, 0x4e, 0xf6, 0x2f, 0xec, 0x07, 0xe7,
- 0x57, 0xe1, 0x20, 0x40, 0x40, 0x6d, 0x4e, 0x29,
- 0x04, 0x1a, 0x8c, 0x99, 0xfb, 0x19, 0x3c, 0xaa,
- 0x75, 0x64, 0xd3, 0xa6, 0xe6, 0xed, 0x3f, 0x5a,
- 0xd2, 0xc9, 0x80, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x01, 0x10, 0xe9, 0x9e,
- 0x06, 0x92, 0x18, 0xbf, 0x5e, 0xaf, 0x33, 0xc1,
- 0xbf, 0x0e, 0x12, 0x07, 0x48, 0x4f, 0x6b, 0x6c,
- 0xf5, 0x23, 0x5e, 0x87, 0xa7, 0xd3, 0x50, 0x79,
- 0x38, 0xdc, 0xe0, 0x49, 0xd3, 0x81, 0x21, 0x12,
- 0xd0, 0x3d, 0x9a, 0xfb, 0x83, 0xc1, 0x8b, 0xfc,
- 0x14, 0xd5, 0xd5, 0xa7, 0xa3, 0x34, 0x14, 0x71,
- 0xbe, 0xea, 0x37, 0x18, 0x12, 0x7f, 0x41, 0xfb,
- 0xc5, 0x51, 0x17, 0x9d, 0x96, 0x58, 0x14, 0xfb,
- 0x4f, 0xd7, 0xd3, 0x15, 0x0f, 0xec, 0x5a, 0x0d,
- 0x35, 0xbb, 0x3c, 0x81, 0x5b, 0x3f, 0xdf, 0x52,
- 0xa4, 0x4c, 0xcd, 0x13, 0xe1, 0x10, 0x37, 0x34,
- 0xbf, 0xb4, 0x80, 0x1e, 0x8d, 0xe2, 0xc3, 0x7a,
- 0x0f, 0x7b, 0x7d, 0x23, 0xeb, 0xd0, 0x99, 0x69,
- 0xad, 0x0a, 0x2d, 0xb3, 0x6c, 0xd6, 0x80, 0x11,
- 0x7f, 0x6c, 0xed, 0x1b, 0xcd, 0x08, 0x22, 0x56,
- 0x90, 0x0e, 0xa4, 0xc3, 0x29, 0x33, 0x96, 0x30,
- 0x34, 0x94, 0xa1, 0xeb, 0x9c, 0x1b, 0x5a, 0xd1,
- 0x03, 0x61, 0xf9, 0xdd, 0xf3, 0x64, 0x8a, 0xfd,
- 0x5f, 0x44, 0xdb, 0x2e, 0xa7, 0xfd, 0xe1, 0x1a,
- 0x66, 0xc5, 0x01, 0x9c, 0xc7, 0xd1, 0xc4, 0xd3,
- 0xea, 0x14, 0x3c, 0xed, 0x74, 0xbb, 0x1b, 0x97,
- 0x8f, 0xf1, 0x29, 0x39, 0x33, 0x92, 0x93, 0x4e,
- 0xf5, 0x87, 0x91, 0x61, 0x65, 0x8d, 0x27, 0x8d,
- 0x76, 0xc1, 0xfa, 0x6a, 0x99, 0x80, 0xb1, 0x9b,
- 0x29, 0x53, 0xce, 0x3e, 0xb6, 0x9a, 0xce, 0x3c,
- 0x19, 0x5e, 0x48, 0x83, 0xaa, 0xa7, 0x66, 0x98,
- 0x59, 0xf4, 0xbb, 0xf2, 0xbc, 0xd9, 0xc5, 0x9a,
- 0xc8, 0x2c, 0x63, 0x58, 0xd5, 0xd4, 0xbc, 0x03,
- 0xa9, 0x06, 0xa9, 0x80, 0x0d, 0xb3, 0x46, 0x2d,
- 0xe3, 0xc6, 0xaf, 0x1a, 0x39, 0x18, 0x7e, 0x1e,
- 0x83, 0x80, 0x46, 0x11, 0xd2, 0x13, 0x9f, 0xda,
- 0xfc, 0x2d, 0x42, 0xaa, 0x5a, 0x1d, 0x4c, 0x31,
- 0xe5, 0x58, 0x78, 0x5e, 0xe2, 0x04, 0xd6, 0x23,
- 0x7f, 0x3f, 0x06, 0xc0, 0x54, 0xf8,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xfb, 0xef, 0xba, 0xed, 0xc5, 0x36,
- 0xc8, 0x5a, 0x41, 0x3f, 0x05, 0xfa, 0xfe, 0x48,
- 0xc3, 0x91, 0x12, 0x8b, 0xe8, 0x32, 0x6a, 0x9f,
- 0xdc, 0x97, 0xe2, 0x77, 0xb9, 0x96, 0x2d, 0xd4,
- 0xe5, 0xbd, 0xa1, 0xfd, 0x94, 0xbb, 0x74, 0x63,
- 0xb1, 0x0c, 0x38, 0xbc, 0x6f, 0x69, 0xaf, 0xa3,
- 0x46, 0x9c, 0x96, 0x41, 0xde, 0x59, 0x23, 0xff,
- 0x15, 0x6b, 0x3a, 0xef, 0x91, 0x6d, 0x92, 0x44,
- 0xdc, 0x72, 0x1f, 0x40, 0x3d, 0xb5, 0x34, 0x8f,
- 0x2a, 0xac, 0x21, 0x69, 0x05, 0x6f, 0xb2, 0x60,
- 0x32, 0x5d, 0x3d, 0x97, 0xb4, 0x24, 0x99, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x68, 0x27, 0x97, 0xca, 0x63, 0x09,
- 0x22, 0xed, 0x0e, 0x61, 0x7c, 0x76, 0x31, 0x9c,
- 0xbe, 0x27, 0xc9, 0xe6, 0x09, 0xc3, 0xc3, 0xc2,
- 0xf4, 0xa2, 0x32, 0xba, 0x7c, 0xf2, 0x0f, 0xb8,
- 0x3d, 0xcb, 0xe2, 0x4c, 0xc0, 0x7d, 0x8e, 0x5b,
- 0x5a, 0xed, 0x05, 0x5c, 0x15, 0x96, 0x69, 0xc2,
- 0x6f, 0x5f, 0x17, 0x03, 0x01, 0x00, 0x20, 0x5a,
- 0xfe, 0x0b, 0xe1, 0x6f, 0xa8, 0x54, 0x19, 0x78,
- 0xca, 0xba, 0x2e, 0x1e, 0x2e, 0xe1, 0x5d, 0x17,
- 0xe5, 0x97, 0x05, 0x2c, 0x08, 0x0c, 0xff, 0xa8,
- 0x59, 0xa9, 0xde, 0x5e, 0x21, 0x34, 0x04, 0x17,
- 0x03, 0x01, 0x00, 0x30, 0x86, 0xb1, 0x3f, 0x88,
- 0x43, 0xf0, 0x07, 0xee, 0xa8, 0xf4, 0xbc, 0xe7,
- 0x5f, 0xc6, 0x8c, 0x86, 0x4c, 0xca, 0x70, 0x88,
- 0xcc, 0x6a, 0xb4, 0x3d, 0x40, 0xe8, 0x54, 0x89,
- 0x19, 0x43, 0x1f, 0x76, 0xe2, 0xac, 0xb2, 0x5b,
- 0x92, 0xf8, 0x57, 0x39, 0x2a, 0xc3, 0x6d, 0x13,
- 0x45, 0xfa, 0x36, 0x9e, 0x15, 0x03, 0x01, 0x00,
- 0x20, 0x6d, 0xed, 0x7b, 0x59, 0x28, 0x2a, 0x27,
- 0x04, 0x15, 0x07, 0x4e, 0xeb, 0x13, 0x00, 0xe3,
- 0x3a, 0x3f, 0xf8, 0xaa, 0x2b, 0x3b, 0x1a, 0x8c,
- 0x12, 0xd6, 0x4c, 0xec, 0x2a, 0xaf, 0x33, 0x60,
- 0xaf,
- },
+func TestHandshakeServerAESGCM(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ }
+ runServerTestTLS12(t, test)
}
-// Generated using:
-// $ go test -test.run TestRunServer -serve -ciphersuites=0xc00a
-// $ openssl s_client -host 127.0.0.1 -port 10443 -cipher ECDHE-ECDSA-AES256-SHA
-var ecdheECDSAAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
- 0x9c, 0x03, 0x03, 0x50, 0xd7, 0x18, 0x31, 0x49,
- 0xde, 0x19, 0x8d, 0x08, 0x5c, 0x4b, 0x60, 0x67,
- 0x0f, 0xfe, 0xd0, 0x62, 0xf9, 0x31, 0x48, 0x17,
- 0x9e, 0x50, 0xc1, 0xd8, 0x35, 0x24, 0x0e, 0xa6,
- 0x09, 0x06, 0x51, 0x00, 0x00, 0x04, 0xc0, 0x0a,
- 0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
- 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
- 0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
- 0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
- 0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
- 0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
- 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
- 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
- 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
- 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x0f, 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0xc0, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
- 0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
- 0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
- 0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
- 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
- 0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
- 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
- 0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
- 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
- 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
- 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
- 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
- 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
- 0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
- 0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
- 0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
- 0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
- 0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
- 0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
- 0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
- 0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
- 0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
- 0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
- 0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
- 0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
- 0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
- 0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
- 0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
- 0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
- 0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
- 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
- 0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
- 0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
- 0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
- 0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
- 0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
- 0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
- 0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
- 0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
- 0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
- 0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
- 0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
- 0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
- 0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
- 0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
- 0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
- 0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
- 0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
- 0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
- 0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
- 0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
- 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
- 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
- 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
- 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
- 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
- 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
- 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
- 0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
- 0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
- 0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
- 0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
- 0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
- 0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
- 0x68, 0x30, 0x22, 0x50, 0xe6, 0x98, 0x97, 0x7b,
- 0x69, 0xf7, 0x93, 0xed, 0xcd, 0x19, 0x2f, 0x44,
- 0x6c, 0x2e, 0xdf, 0x25, 0xee, 0xcc, 0x46, 0x16,
- 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x00, 0x1c, 0xc5, 0xe8, 0xb3,
- 0x42, 0xb4, 0xad, 0xca, 0x45, 0xcd, 0x42, 0x7b,
- 0xfb, 0x0c, 0xea, 0x32, 0x26, 0xd4, 0x8a, 0xef,
- 0xdf, 0xc9, 0xff, 0xd2, 0xe0, 0x36, 0xea, 0x4e,
- 0xbb, 0x3e, 0xf4, 0x9c, 0x76, 0x4f, 0x44, 0xbd,
- 0x84, 0x72, 0xdd, 0xcb, 0xe5, 0x28, 0x8d, 0x31,
- 0x72, 0x3b, 0xd3, 0xf2, 0x9a, 0x13, 0xfb, 0x8a,
- 0xa7, 0x72, 0xca, 0x21, 0x6c, 0xea, 0xbf, 0xe9,
- 0x8c, 0x0a, 0xcc, 0x8f, 0xd6, 0x00, 0x20, 0x87,
- 0xf3, 0x7d, 0x18, 0xc5, 0xfd, 0x9e, 0xdd, 0x6b,
- 0x06, 0xdc, 0x52, 0xeb, 0x14, 0xc0, 0x67, 0x5a,
- 0x06, 0xd8, 0x98, 0x19, 0x14, 0xe7, 0xd4, 0x36,
- 0x32, 0xee, 0xb7, 0xfa, 0xe2, 0x85, 0x4a, 0x16,
- 0x42, 0x0c, 0xa6, 0x21, 0xcf, 0x1f, 0xae, 0x10,
- 0x8b, 0x28, 0x32, 0x19, 0xa4, 0x0a, 0xd7, 0xce,
- 0xe6, 0xe1, 0x93, 0xfb, 0x5f, 0x08, 0x8b, 0x42,
- 0xa2, 0x20, 0xed, 0x0d, 0x62, 0xca, 0xed, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x2e, 0x33, 0xc0, 0x57, 0x6c, 0xb4,
- 0x1b, 0xd2, 0x63, 0xe8, 0x67, 0x10, 0x2d, 0x87,
- 0x71, 0x6e, 0x19, 0x60, 0xf4, 0xa4, 0x10, 0x52,
- 0x73, 0x2d, 0x09, 0x5e, 0xdb, 0x6c, 0xdc, 0xcf,
- 0x2d, 0xff, 0x03, 0x11, 0x95, 0x76, 0x90, 0xd7,
- 0x87, 0x54, 0x43, 0xed, 0xc2, 0x36, 0x69, 0x14,
- 0x72, 0x4a,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x8b, 0xde, 0xef, 0xba, 0xc5, 0x7e, 0x04,
- 0xab, 0xfd, 0x79, 0x56, 0xf3, 0xe1, 0xa5, 0x3e,
- 0x02, 0xdf, 0x69, 0x6d, 0x1f, 0x41, 0x9f, 0xbc,
- 0x93, 0xe2, 0x6c, 0xf1, 0xb1, 0x38, 0xf5, 0x2b,
- 0x8c, 0x4c, 0xf4, 0x74, 0xe1, 0x79, 0x35, 0x34,
- 0x97, 0x9b, 0xd5, 0xba, 0xfd, 0xf7, 0x2f, 0x2d,
- 0x9e, 0x84, 0x54, 0xee, 0x77, 0x59, 0x23, 0x8f,
- 0xc8, 0x84, 0xb4, 0xd6, 0xea, 0x4c, 0x44, 0x8a,
- 0xc6, 0x9c, 0xf9, 0x9b, 0x27, 0xea, 0x4f, 0x28,
- 0x72, 0x33, 0x12, 0x20, 0x7c, 0xd7, 0x3f, 0x56,
- 0xa6, 0x76, 0xc7, 0x48, 0xe4, 0x2d, 0x6f, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x30, 0x36, 0xe3, 0xd4, 0xf7, 0xb1, 0x69,
- 0x18, 0x8d, 0x09, 0xba, 0x52, 0x1e, 0xd5, 0x7d,
- 0x2c, 0x15, 0x3a, 0xd6, 0xe3, 0x99, 0x30, 0x2c,
- 0x99, 0x97, 0xbc, 0x19, 0x3c, 0x63, 0xa1, 0x25,
- 0x68, 0xbc, 0x8a, 0x16, 0x47, 0xec, 0xae, 0x13,
- 0xa4, 0x03, 0x96, 0x29, 0x11, 0x92, 0x90, 0x1a,
- 0xc8, 0xa4, 0x17, 0x03, 0x01, 0x00, 0x20, 0xc1,
- 0x10, 0x1d, 0xa6, 0xf1, 0xe2, 0x8a, 0xcc, 0x37,
- 0x7d, 0x8e, 0x05, 0x00, 0xfb, 0xd1, 0x9f, 0xc7,
- 0x11, 0xd2, 0x00, 0xb4, 0x27, 0x0a, 0x25, 0x14,
- 0xd9, 0x79, 0x1b, 0xcb, 0x4d, 0x81, 0x61, 0x17,
- 0x03, 0x01, 0x00, 0x30, 0x5c, 0x7c, 0x2d, 0xc0,
- 0x9e, 0xa6, 0xc4, 0x8e, 0xfd, 0xf4, 0xe2, 0xe5,
- 0xe4, 0xe6, 0x56, 0x9f, 0x7d, 0x4c, 0x4c, 0x2d,
- 0xb7, 0xa9, 0xac, 0xfa, 0x9f, 0x12, 0x7f, 0x2d,
- 0x30, 0x57, 0xe4, 0x8e, 0x30, 0x86, 0x65, 0x59,
- 0xcd, 0x24, 0xda, 0xe2, 0x8a, 0x7b, 0x0c, 0x5e,
- 0x86, 0x05, 0x06, 0x2a, 0x15, 0x03, 0x01, 0x00,
- 0x20, 0xd6, 0xb7, 0x70, 0xf8, 0x47, 0xbc, 0x0f,
- 0xf4, 0x66, 0x98, 0x1b, 0x1e, 0x8a, 0x8c, 0x0b,
- 0xa1, 0x4a, 0x04, 0x29, 0x60, 0x72, 0x8b, 0xc4,
- 0x73, 0xc1, 0xd6, 0x41, 0x72, 0xb7, 0x17, 0x39,
- 0xda,
- },
-}
+func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
+ config := *testConfig
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ config.Certificates[0].PrivateKey = testECDSAPrivateKey
+ config.BuildNameToCertificate()
-var sslv3ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00,
- 0x50, 0x03, 0x00, 0x50, 0x77, 0x3d, 0x42, 0xae,
- 0x84, 0xbd, 0xc5, 0x07, 0xa5, 0xc4, 0xd6, 0x16,
- 0x4e, 0xd5, 0xc5, 0xfa, 0x02, 0x7a, 0x0f, 0x1d,
- 0xc1, 0xe1, 0xaa, 0xe3, 0x3b, 0x4b, 0x6f, 0x11,
- 0xfa, 0x1a, 0xa4, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00,
- },
- {
- 0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 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, 0x00, 0x05, 0x00, 0x16,
- 0x03, 0x00, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
- 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
- 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
- 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
- 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
- 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
- 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
- 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
- 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
- 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
- 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
- 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
- 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
- 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
- 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
- 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
- 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
- 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
- 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
- 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
- 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
- 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
- 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
- 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
- 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
- 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
- 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
- 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
- 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
- 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
- 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
- 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
- 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
- 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
- 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
- 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
- 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
- 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
- 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
- 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
- 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
- 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
- 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
- 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
- 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
- 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
- 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
- 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
- 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
- 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
- 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
- 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
- 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
- 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
- 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
- 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
- 0xbd, 0xd9, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00,
- 0x80, 0x4a, 0x8d, 0xc4, 0x38, 0x7a, 0x9c, 0xd6,
- 0xe8, 0x72, 0x9e, 0xa3, 0xdf, 0x37, 0xb4, 0x6c,
- 0x58, 0x33, 0x59, 0xd9, 0xc9, 0x4b, 0x50, 0x33,
- 0x6c, 0xed, 0x73, 0x38, 0x2a, 0x46, 0x55, 0x31,
- 0xa9, 0x8e, 0x8e, 0xfc, 0x0b, 0x5d, 0x5f, 0x3c,
- 0x88, 0x28, 0x3f, 0x60, 0x51, 0x13, 0xf1, 0x59,
- 0x0c, 0xa3, 0x5e, 0xe0, 0xa3, 0x35, 0x06, 0xb1,
- 0x71, 0x59, 0x24, 0x4e, 0xed, 0x07, 0x15, 0x88,
- 0x50, 0xef, 0xc2, 0xb2, 0x2a, 0x52, 0x30, 0x6a,
- 0x7c, 0xbe, 0x2f, 0xc6, 0x8f, 0xa8, 0x83, 0xc5,
- 0x80, 0x14, 0x62, 0x74, 0x7f, 0x96, 0x9f, 0x41,
- 0x32, 0x74, 0xdd, 0x76, 0x2d, 0x7b, 0xeb, 0x7b,
- 0xea, 0xd0, 0x4f, 0x0c, 0xcf, 0x9a, 0x9c, 0xc5,
- 0x7a, 0xe4, 0xbc, 0xf8, 0xa6, 0xe1, 0x09, 0x8e,
- 0x7c, 0x53, 0x3a, 0xe3, 0x30, 0x8f, 0x76, 0xee,
- 0x58, 0xbb, 0xfd, 0x0b, 0x06, 0xb8, 0xdf, 0xb7,
- 0x31, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16,
- 0x03, 0x00, 0x00, 0x3c, 0x13, 0x91, 0xc6, 0x4a,
- 0x0c, 0x59, 0x25, 0xce, 0x54, 0xc0, 0x1d, 0xb9,
- 0x2a, 0xff, 0x4d, 0xca, 0x26, 0x0c, 0x8c, 0x04,
- 0x98, 0x7c, 0x7c, 0x38, 0xa3, 0xf5, 0xf9, 0x36,
- 0x1c, 0x04, 0x32, 0x47, 0x2d, 0x48, 0x0e, 0x96,
- 0xe8, 0x2b, 0x5e, 0x5a, 0xc6, 0x0a, 0x48, 0x41,
- 0x34, 0x5e, 0x62, 0xd5, 0x68, 0x4e, 0x44, 0x1d,
- 0xb2, 0xa1, 0x11, 0xad, 0x6e, 0x14, 0x85, 0x61,
- },
- {
- 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x00, 0x00, 0x3c, 0x88, 0xae, 0xa9, 0xd4, 0xa8,
- 0x10, 0x8d, 0x65, 0xa6, 0x3e, 0x1e, 0xed, 0xd2,
- 0xfc, 0xc4, 0x7c, 0xa8, 0x94, 0x4f, 0x11, 0xaf,
- 0xa6, 0x87, 0x09, 0x37, 0x54, 0xf7, 0x69, 0xd1,
- 0xb5, 0x25, 0x6b, 0xb5, 0xed, 0xcb, 0x25, 0x39,
- 0x73, 0xeb, 0x53, 0x6c, 0xc7, 0xb4, 0x29, 0x8f,
- 0xd6, 0x49, 0xd1, 0x95, 0x59, 0x80, 0x9a, 0x67,
- 0x5c, 0xb2, 0xe0, 0xbd, 0x1e, 0xff, 0xaa, 0x17,
- 0x03, 0x00, 0x00, 0x21, 0x65, 0x7b, 0x99, 0x09,
- 0x02, 0xc3, 0x9d, 0x54, 0xd6, 0xe7, 0x32, 0x62,
- 0xab, 0xc1, 0x09, 0x91, 0x30, 0x0a, 0xc9, 0xfa,
- 0x70, 0xec, 0x06, 0x7b, 0xa3, 0xe1, 0x5f, 0xb4,
- 0x63, 0xe6, 0x5c, 0xba, 0x1f, 0x15, 0x03, 0x00,
- 0x00, 0x16, 0x40, 0x70, 0xbe, 0xe6, 0xa6, 0xee,
- 0x8f, 0xd0, 0x87, 0xa0, 0x43, 0xa1, 0x92, 0xd7,
- 0xd0, 0x1a, 0x0c, 0x20, 0x7c, 0xbf, 0xa2, 0xb5,
- },
+ test := &serverTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
+ config: &config,
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
}
-var selectCertificateBySNIScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x6a, 0x01, 0x00, 0x00,
- 0x66, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xfe, 0xfb,
- 0x8d, 0xc2, 0x68, 0xeb, 0xf9, 0xfa, 0x54, 0x97,
- 0x86, 0x45, 0xa2, 0xa3, 0xed, 0xb1, 0x91, 0xb8,
- 0x28, 0xc0, 0x47, 0xaf, 0xfb, 0xcd, 0xdc, 0x0e,
- 0xb3, 0xea, 0xa5, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00,
- 0x0e, 0x00, 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74,
- 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 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, 0x05, 0x00, 0x16,
- 0x03, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x01, 0xfc,
- 0x00, 0x01, 0xf9, 0x00, 0x01, 0xf6, 0x30, 0x82,
- 0x01, 0xf2, 0x30, 0x82, 0x01, 0x5d, 0xa0, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0b,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x30, 0x28, 0x31, 0x10, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
- 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x31,
- 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74, 0x65, 0x73,
- 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x31,
- 0x37, 0x34, 0x30, 0x33, 0x35, 0x5a, 0x17, 0x0d,
- 0x31, 0x33, 0x30, 0x34, 0x31, 0x31, 0x31, 0x37,
- 0x34, 0x35, 0x33, 0x35, 0x5a, 0x30, 0x28, 0x31,
- 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43,
- 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
- 0x04, 0x03, 0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74,
- 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
- 0x81, 0x9d, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x03,
- 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
- 0x81, 0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5,
- 0xe5, 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe,
- 0xe6, 0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d,
- 0x8a, 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7,
- 0xa5, 0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c,
- 0xb5, 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b,
- 0x7e, 0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe,
- 0x12, 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf,
- 0xfa, 0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04,
- 0xd3, 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4,
- 0x54, 0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00,
- 0xfe, 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d,
- 0x7d, 0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb,
- 0x51, 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32,
- 0x66, 0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71,
- 0x9a, 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda,
- 0x2d, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
- 0x32, 0x30, 0x30, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
- 0x02, 0x00, 0xa0, 0x30, 0x0d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x04, 0x06, 0x04, 0x04, 0x01, 0x02,
- 0x03, 0x04, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
- 0x23, 0x04, 0x08, 0x30, 0x06, 0x80, 0x04, 0x01,
- 0x02, 0x03, 0x04, 0x30, 0x0b, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
- 0x03, 0x81, 0x81, 0x00, 0x89, 0xc6, 0x45, 0x5f,
- 0x1c, 0x1f, 0x5e, 0xf8, 0xeb, 0x1a, 0xb1, 0x74,
- 0xee, 0x24, 0x39, 0x05, 0x9f, 0x5c, 0x42, 0x59,
- 0xbb, 0x1a, 0x8d, 0x86, 0xcd, 0xb1, 0xd0, 0x56,
- 0xf5, 0x6a, 0x71, 0x7d, 0xa4, 0x0e, 0x95, 0xab,
- 0x90, 0xf5, 0x9e, 0x8d, 0xea, 0xf6, 0x27, 0xc1,
- 0x57, 0x99, 0x50, 0x94, 0xdb, 0x08, 0x02, 0x26,
- 0x6e, 0xb3, 0x4f, 0xc6, 0x84, 0x2d, 0xea, 0x8a,
- 0x4b, 0x68, 0xd9, 0xc1, 0x38, 0x91, 0x03, 0xab,
- 0x84, 0xfb, 0x9e, 0x1f, 0x85, 0xd9, 0xb5, 0xd2,
- 0x3f, 0xf2, 0x31, 0x2c, 0x86, 0x70, 0xfb, 0xb5,
- 0x40, 0x14, 0x82, 0x45, 0xa4, 0xeb, 0xaf, 0xe2,
- 0x64, 0xd9, 0x0c, 0x8a, 0x4c, 0xf4, 0xf8, 0x5b,
- 0x0f, 0xac, 0x12, 0xac, 0x2f, 0xc4, 0xa3, 0x15,
- 0x4b, 0xad, 0x52, 0x46, 0x28, 0x68, 0xaf, 0x96,
- 0xc6, 0x2c, 0x65, 0x25, 0xd6, 0x52, 0xb6, 0xe3,
- 0x18, 0x45, 0xbd, 0xcc, 0x16, 0x03, 0x01, 0x00,
- 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x69, 0xc3, 0xd4, 0x0e, 0xcc,
- 0xdc, 0xbc, 0x5e, 0xc2, 0x64, 0xa6, 0xde, 0x3c,
- 0x0c, 0x7e, 0x0c, 0x6b, 0x80, 0x0f, 0xd4, 0x8f,
- 0x02, 0x4b, 0xb2, 0xba, 0x8d, 0x01, 0xeb, 0x6b,
- 0xa1, 0x2e, 0x79, 0x37, 0xba, 0xae, 0x24, 0xc2,
- 0x26, 0x72, 0x51, 0xe1, 0x82, 0x8e, 0x51, 0x41,
- 0x1c, 0x54, 0xa4, 0x26, 0xbe, 0x13, 0xcd, 0x1b,
- 0xc6, 0xed, 0x3d, 0x1f, 0xfd, 0x72, 0x80, 0x90,
- 0xdb, 0xbf, 0xd6, 0x39, 0x94, 0x5f, 0x48, 0xfb,
- 0x25, 0x5a, 0xc9, 0x60, 0x9b, 0xd7, 0xc6, 0x20,
- 0xa8, 0x66, 0x64, 0x13, 0xf3, 0x65, 0xc8, 0xb1,
- 0xd5, 0x33, 0x21, 0x0e, 0x73, 0x41, 0xc0, 0x18,
- 0x1a, 0x37, 0xfe, 0xcf, 0x28, 0x2a, 0xcd, 0xe4,
- 0x0b, 0xac, 0xdd, 0x25, 0x5e, 0xcb, 0x17, 0x51,
- 0x69, 0xd5, 0x8c, 0xf4, 0xb6, 0x21, 0x98, 0xef,
- 0x20, 0xdb, 0x14, 0x67, 0xf3, 0x7c, 0x95, 0x6a,
- 0x48, 0x2a, 0x6a, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x36, 0x1b,
- 0x09, 0xe5, 0xb9, 0xb9, 0x4d, 0x7d, 0xae, 0x87,
- 0xb6, 0x0f, 0xaf, 0xec, 0x22, 0xba, 0x0d, 0xa5,
- 0x96, 0x5e, 0x64, 0x65, 0xe7, 0xfb, 0xe3, 0xf3,
- 0x6b, 0x72, 0xa8, 0xdb, 0xed, 0xd8, 0x69, 0x9c,
- 0x08, 0xd8,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x60, 0xf7, 0x09, 0x5f, 0xd1,
- 0xcb, 0xc9, 0xe1, 0x22, 0xb5, 0x2a, 0xcc, 0xde,
- 0x7c, 0xa7, 0xb8, 0x85, 0x00, 0xbc, 0xfd, 0x85,
- 0xe1, 0x91, 0x36, 0xbb, 0x07, 0x42, 0xad, 0x3d,
- 0x29, 0x62, 0x69, 0xc1, 0x45, 0x92, 0x6f, 0x17,
- 0x03, 0x01, 0x00, 0x21, 0x0d, 0xf9, 0xd5, 0x87,
- 0xb9, 0x57, 0x3c, 0x50, 0x19, 0xe4, 0x3a, 0x50,
- 0x45, 0xcc, 0x86, 0x89, 0xd4, 0x32, 0x79, 0x45,
- 0x7c, 0x9f, 0x96, 0xd4, 0x54, 0x56, 0x0c, 0x63,
- 0x72, 0x81, 0xc3, 0xd3, 0xe3, 0x15, 0x03, 0x01,
- 0x00, 0x16, 0x84, 0xec, 0x2e, 0xf6, 0xaf, 0x4f,
- 0xee, 0x48, 0x0f, 0xbe, 0xcd, 0x82, 0x5c, 0x56,
- 0x16, 0xe4, 0xfb, 0x89, 0xc5, 0x57, 0x3e, 0x91,
- },
+// TestHandshakeServerSNI involves a client sending an SNI extension of
+// "snitest.com", which happens to match the CN of testSNICertificate. The test
+// verifies that the server correctly selects that certificate.
+func TestHandshakeServerSNI(t *testing.T) {
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ }
+ runServerTestTLS12(t, test)
}
-var issueSessionTicketTest = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00,
- 0x56, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x49, 0x7a,
- 0xb7, 0x86, 0x5c, 0x27, 0xd2, 0x97, 0x61, 0xe3,
- 0x49, 0x41, 0x48, 0xe7, 0x0e, 0xaa, 0x7e, 0x4d,
- 0xb8, 0xdc, 0x01, 0x97, 0xfb, 0xab, 0x53, 0xb2,
- 0x5e, 0x36, 0xf6, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
- 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x68, 0x10, 0xdc, 0x80, 0xbc,
- 0xb3, 0x5a, 0x10, 0x75, 0x89, 0xcc, 0xe5, 0x9f,
- 0xbf, 0xe2, 0xce, 0xa4, 0x9f, 0x7f, 0x60, 0xc4,
- 0xfe, 0x5c, 0xb5, 0x02, 0x2d, 0xa5, 0xa9, 0x1e,
- 0x2c, 0x10, 0x79, 0x15, 0x0f, 0xed, 0x96, 0xb3,
- 0xa8, 0x5e, 0x21, 0xbc, 0x5b, 0xdc, 0x58, 0x04,
- 0x7d, 0x37, 0xdb, 0xa0, 0x31, 0xe8, 0x4f, 0x04,
- 0xbc, 0x46, 0x7c, 0xdb, 0x2e, 0x93, 0x07, 0xaf,
- 0xa6, 0x36, 0xd3, 0x39, 0x8d, 0x1d, 0x95, 0xa8,
- 0x50, 0x4b, 0xc4, 0x2b, 0xde, 0xd7, 0x04, 0x6d,
- 0x77, 0x6c, 0x4d, 0x70, 0x51, 0x88, 0x16, 0x31,
- 0x40, 0xb5, 0xba, 0x90, 0x47, 0x64, 0x0c, 0x87,
- 0xa5, 0x19, 0xf9, 0x89, 0x24, 0x3c, 0x5e, 0x4b,
- 0xaa, 0xe0, 0x60, 0x47, 0x0f, 0x2e, 0xcc, 0xc2,
- 0xd5, 0x21, 0xed, 0x72, 0xd0, 0xa9, 0xdd, 0x2a,
- 0x2b, 0xef, 0x08, 0x3a, 0x65, 0xea, 0x8b, 0x52,
- 0x77, 0x2d, 0xcc, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xe2, 0x95,
- 0x62, 0x3c, 0x18, 0xe5, 0xc7, 0x2c, 0xda, 0x16,
- 0x9b, 0x28, 0x0d, 0xf7, 0x88, 0x7b, 0x5d, 0x33,
- 0x55, 0x3b, 0x01, 0x73, 0xf2, 0xc6, 0x4e, 0x96,
- 0x01, 0x01, 0x83, 0x65, 0xd4, 0xef, 0x12, 0x13,
- 0x1d, 0x42,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
- 0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
- 0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
- 0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
- 0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
- 0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
- 0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
- 0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
- 0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
- 0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
- 0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0x3f, 0x66, 0xe4, 0x98, 0xc1, 0x3f,
- 0xc6, 0x2c, 0x81, 0xfb, 0xa9, 0x9f, 0x27, 0xe9,
- 0x63, 0x20, 0x1e, 0x0e, 0x4f, 0xfc, 0x5d, 0x12,
- 0xee, 0x77, 0x73, 0xc6, 0x96, 0x51, 0xf2, 0x26,
- 0x35, 0x3f, 0xce, 0x6a, 0xa9, 0xfd, 0x17, 0x03,
- 0x01, 0x00, 0x21, 0x8d, 0xd5, 0x67, 0x60, 0x5d,
- 0xa7, 0x93, 0xcc, 0x39, 0x78, 0x59, 0xab, 0xdb,
- 0x10, 0x96, 0xf2, 0xad, 0xa2, 0x85, 0xe2, 0x93,
- 0x43, 0x43, 0xcf, 0x82, 0xbd, 0x1f, 0xdc, 0x7a,
- 0x72, 0xd6, 0x83, 0x3b, 0x15, 0x03, 0x01, 0x00,
- 0x16, 0x89, 0x55, 0xf6, 0x42, 0x71, 0xa9, 0xe9,
- 0x05, 0x68, 0xe8, 0xce, 0x0d, 0x21, 0xe9, 0xec,
- 0xf2, 0x27, 0x67, 0xa7, 0x94, 0xf8, 0x34,
- },
-}
-var serverResumeTest = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x00,
- 0xbe, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x4f, 0x1f,
- 0x6f, 0xa5, 0x81, 0xeb, 0xb8, 0x80, 0x55, 0xa4,
- 0x76, 0xc2, 0x7f, 0x27, 0xf2, 0xe7, 0xc9, 0x7a,
- 0x01, 0x3c, 0xd8, 0xc1, 0xde, 0x99, 0x1f, 0x7c,
- 0xab, 0x35, 0x98, 0x00, 0x00, 0x28, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
- 0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
- 0x00, 0x00, 0x6c, 0x00, 0x23, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
- 0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
- 0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
- 0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
- 0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
- 0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
- 0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
- 0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
- 0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
- 0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
- 0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
- 0x26, 0x03, 0x01, 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, 0x05, 0x00, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0xc5, 0x35, 0x74, 0x19, 0x05, 0xc5,
- 0x85, 0x68, 0x48, 0xe8, 0xb5, 0xe9, 0xaf, 0x78,
- 0xbd, 0x35, 0x6f, 0xe9, 0x79, 0x34, 0x1b, 0xf0,
- 0x35, 0xd4, 0x4e, 0x55, 0x2e, 0x3c, 0xd5, 0xaf,
- 0xfc, 0xba, 0xf5, 0x1e, 0x83, 0x32,
- },
- {
- 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x27, 0x28, 0x88, 0xe1, 0x7e,
- 0x0d, 0x9c, 0x12, 0x50, 0xf6, 0x7a, 0xa7, 0x32,
- 0x21, 0x68, 0xba, 0xd8, 0x0a, 0xdc, 0x39, 0xef,
- 0x68, 0x95, 0x82, 0xae, 0xbd, 0x12, 0x79, 0xa1,
- 0x99, 0xfd, 0xd0, 0x10, 0x8e, 0x4b, 0xd8,
- },
- {
- 0x17, 0x03, 0x01, 0x00, 0x21, 0xc5, 0x7e, 0x0a,
- 0x52, 0x6a, 0xb9, 0xaa, 0x1d, 0xae, 0x9e, 0x24,
- 0x9c, 0x34, 0x1e, 0xdb, 0x50, 0x95, 0xee, 0x76,
- 0xd7, 0x28, 0x88, 0x08, 0xe3, 0x2e, 0x58, 0xf7,
- 0xdb, 0x34, 0x75, 0xa5, 0x7f, 0x9d, 0x15, 0x03,
- 0x01, 0x00, 0x16, 0x2c, 0xc1, 0x29, 0x5f, 0x12,
- 0x1d, 0x19, 0xab, 0xb3, 0xf4, 0x35, 0x1c, 0x62,
- 0x6a, 0x80, 0x29, 0x0d, 0x0e, 0xef, 0x7d, 0x6e,
- 0x50,
- },
-}
+// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
+// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
+func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
+ config := *testConfig
+ config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
+ config.PreferServerCipherSuites = true
-var clientauthRSATests = []clientauthTest{
- // Server asks for cert with empty CA list, client doesn't give it.
- // go test -run "TestRunServer" -serve -clientauth 1
- {"RequestClientCert, none given", RequestClientCert, nil, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x6c, 0xb5, 0x5a,
- 0xc2, 0xf5, 0xf0, 0x92, 0x94, 0x8a, 0x64, 0x18,
- 0xa4, 0x2b, 0x82, 0x07, 0xbc, 0xd9, 0xd9, 0xf9,
- 0x7b, 0xd2, 0xd0, 0xee, 0xa2, 0x70, 0x4e, 0x23,
- 0x88, 0x7c, 0x95, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
- 0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
- 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00,
- 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x36,
- 0xfc, 0xd8, 0xc8, 0xa2, 0x67, 0xc8, 0xc6, 0xf4,
- 0x28, 0x70, 0xe1, 0x5a, 0x02, 0x8f, 0xef, 0x42,
- 0xe0, 0xd3, 0xb8, 0xd6, 0x6b, 0xe4, 0xee, 0x5c,
- 0xcf, 0x42, 0xc4, 0xfa, 0xcd, 0x0f, 0xfe, 0xf4,
- 0x76, 0x76, 0x47, 0x73, 0xa8, 0x72, 0x8f, 0xa2,
- 0x56, 0x81, 0x83, 0xb8, 0x84, 0x72, 0x67, 0xdd,
- 0xbe, 0x05, 0x4b, 0x84, 0xd9, 0xd2, 0xb6, 0xc2,
- 0xe7, 0x20, 0xac, 0x1f, 0x46, 0x9d, 0x05, 0x47,
- 0x8e, 0x89, 0xc0, 0x42, 0x57, 0x4a, 0xa2, 0x98,
- 0xe5, 0x39, 0x4f, 0xc4, 0x27, 0x6d, 0x43, 0xa8,
- 0x83, 0x76, 0xe6, 0xad, 0xe3, 0x17, 0x68, 0x31,
- 0xcb, 0x7e, 0xfc, 0xe7, 0x4b, 0x76, 0x3d, 0x3c,
- 0xfa, 0x77, 0x65, 0xc9, 0x4c, 0x5b, 0xce, 0x5e,
- 0xf7, 0x8b, 0xa8, 0xa6, 0xdd, 0xb2, 0xef, 0x0b,
- 0x46, 0x83, 0xdf, 0x0a, 0x8c, 0x22, 0x12, 0x6e,
- 0xe1, 0x45, 0x54, 0x88, 0xd1, 0xe8, 0xd2, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0x30, 0x8c, 0x7d, 0x40, 0xfc, 0x5e,
- 0x80, 0x9c, 0xc4, 0x7c, 0x62, 0x01, 0xa1, 0x37,
- 0xcf, 0x1a, 0x75, 0x28, 0x8d, 0xeb, 0x63, 0xcc,
- 0x02, 0xa6, 0x66, 0xdf, 0x36, 0x01, 0xb3, 0x9d,
- 0x38, 0x42, 0x16, 0x91, 0xf0, 0x02,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x96, 0x9a, 0x2a,
- 0x6c, 0x8c, 0x7e, 0x38, 0x10, 0x46, 0x86, 0x1d,
- 0x19, 0x1d, 0x62, 0x29, 0x3f, 0x58, 0xfb, 0x6d,
- 0x89, 0xd2, 0x81, 0x9a, 0x1c, 0xb3, 0x58, 0xb3,
- 0x19, 0x39, 0x17, 0x47, 0x49, 0xc9, 0xfe, 0x4a,
- 0x7a, 0x32, 0xac, 0x2c, 0x43, 0xf9, 0xa9, 0xea,
- 0xec, 0x51, 0x46, 0xf1, 0xb8, 0x59, 0x23, 0x70,
- 0xce, 0x7c, 0xb9, 0x47, 0x70, 0xa3, 0xc9, 0xae,
- 0x47, 0x7b, 0x7e, 0xc7, 0xcf, 0x76, 0x12, 0x76,
- 0x18, 0x90, 0x12, 0xcd, 0xf3, 0xd4, 0x27, 0x81,
- 0xfc, 0x46, 0x03, 0x3e, 0x05, 0x87, 0x6f, 0x14,
- 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
- 0x00, 0x24, 0xc3, 0xa0, 0x29, 0xb1, 0x52, 0x82,
- 0xef, 0x85, 0xa1, 0x64, 0x0f, 0xe4, 0xa3, 0xfb,
- 0xa7, 0x1d, 0x22, 0x4c, 0xcb, 0xd6, 0x5b, 0x18,
- 0x61, 0xc7, 0x7c, 0xf2, 0x67, 0x4a, 0xc7, 0x11,
- 0x9d, 0x8e, 0x0e, 0x15, 0x22, 0xcf, 0x17, 0x03,
- 0x01, 0x00, 0x21, 0xfd, 0xbb, 0xf1, 0xa9, 0x7c,
- 0xbf, 0x92, 0xb3, 0xfa, 0x2c, 0x08, 0x6f, 0x22,
- 0x78, 0x80, 0xf2, 0x2e, 0x86, 0x26, 0x21, 0x36,
- 0x3f, 0x32, 0xdf, 0xb6, 0x47, 0xa5, 0xf8, 0x27,
- 0xc1, 0xe9, 0x53, 0x90, 0x15, 0x03, 0x01, 0x00,
- 0x16, 0xfe, 0xef, 0x2e, 0xa0, 0x5d, 0xe0, 0xce,
- 0x94, 0x20, 0x56, 0x61, 0x6e, 0xe5, 0x62, 0xce,
- 0x27, 0x57, 0x3e, 0x30, 0x32, 0x77, 0x53,
- },
- }},
-
- // Server asks for cert with empty CA list, client gives one
- // go test -run "TestRunServer" -serve -clientauth 1
- {"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientCertificate}, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x74, 0x0e, 0x95,
- 0x6f, 0x4f, 0x4a, 0xbf, 0xb7, 0xc0, 0x6c, 0xac,
- 0xd9, 0xfe, 0x7d, 0xd0, 0x51, 0x19, 0x62, 0x62,
- 0x1c, 0x6e, 0x57, 0x77, 0xd2, 0x31, 0xaf, 0x88,
- 0xb9, 0xc0, 0x1d, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0x05, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
- 0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
- 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01,
- 0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
- 0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
- 0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
- 0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
- 0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
- 0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
- 0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
- 0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
- 0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
- 0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
- 0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
- 0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
- 0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
- 0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
- 0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
- 0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
- 0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
- 0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
- 0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
- 0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
- 0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
- 0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
- 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
- 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
- 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
- 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
- 0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
- 0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
- 0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
- 0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
- 0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
- 0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
- 0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
- 0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
- 0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
- 0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
- 0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
- 0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
- 0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
- 0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
- 0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
- 0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
- 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x0a, 0x4e, 0x89, 0xdf, 0x3a,
- 0x3f, 0xf0, 0x4f, 0xef, 0x1a, 0x90, 0xd4, 0x3c,
- 0xaf, 0x10, 0x57, 0xb0, 0xa1, 0x5f, 0xcd, 0x62,
- 0x01, 0xe9, 0x0c, 0x36, 0x42, 0xfd, 0xaf, 0x23,
- 0xf9, 0x14, 0xa6, 0x72, 0x26, 0x4e, 0x01, 0xdb,
- 0xac, 0xb7, 0x4c, 0xe6, 0xa9, 0x52, 0xe2, 0xec,
- 0x26, 0x8c, 0x7a, 0x64, 0xf8, 0x0b, 0x4c, 0x2f,
- 0xa9, 0xcb, 0x75, 0xaf, 0x60, 0xd4, 0xb4, 0xe6,
- 0xe8, 0xdb, 0x78, 0x78, 0x85, 0xf6, 0x0c, 0x95,
- 0xcc, 0xb6, 0x55, 0xb9, 0xba, 0x9e, 0x91, 0xbc,
- 0x66, 0xdb, 0x1e, 0x28, 0xab, 0x73, 0xce, 0x8b,
- 0xd0, 0xd3, 0xe8, 0xbc, 0xd0, 0x21, 0x28, 0xbd,
- 0xfb, 0x74, 0x64, 0xde, 0x3b, 0x3b, 0xd3, 0x4c,
- 0x32, 0x40, 0x82, 0xba, 0x91, 0x1e, 0xe8, 0x47,
- 0xc2, 0x09, 0xb7, 0x16, 0xaa, 0x25, 0xa9, 0x3c,
- 0x6c, 0xa7, 0xf8, 0xc9, 0x54, 0x84, 0xc6, 0xf7,
- 0x56, 0x05, 0xa4, 0x16, 0x03, 0x01, 0x00, 0x86,
- 0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x4b, 0xab,
- 0xda, 0xac, 0x2a, 0xb3, 0xe6, 0x34, 0x55, 0xcd,
- 0xf2, 0x4b, 0x67, 0xe3, 0xd3, 0xff, 0xa3, 0xf4,
- 0x79, 0x82, 0x01, 0x47, 0x8a, 0xe3, 0x9f, 0x89,
- 0x70, 0xbe, 0x24, 0x24, 0xb7, 0x69, 0x60, 0xed,
- 0x55, 0xa0, 0xca, 0x72, 0xb6, 0x4a, 0xbc, 0x1d,
- 0xe2, 0x3f, 0xb5, 0x31, 0xda, 0x02, 0xf6, 0x37,
- 0x51, 0xf8, 0x4c, 0x88, 0x2e, 0xb3, 0x8a, 0xe8,
- 0x7b, 0x4a, 0x90, 0x36, 0xe4, 0xa6, 0x31, 0x95,
- 0x8b, 0xa0, 0xc6, 0x91, 0x12, 0xb9, 0x35, 0x4e,
- 0x72, 0xeb, 0x5c, 0xa2, 0xe8, 0x4c, 0x68, 0xf9,
- 0x69, 0xfa, 0x70, 0x60, 0x6c, 0x7f, 0x32, 0x99,
- 0xf1, 0xc3, 0x2d, 0xb4, 0x59, 0x58, 0x87, 0xaf,
- 0x67, 0x62, 0x90, 0xe7, 0x8d, 0xd0, 0xa3, 0x77,
- 0x33, 0xc2, 0x9b, 0xd5, 0x9c, 0xc7, 0xea, 0x25,
- 0x98, 0x76, 0x9c, 0xe0, 0x6a, 0x03, 0x3a, 0x10,
- 0xfd, 0x10, 0x3d, 0x55, 0x53, 0xa0, 0x14, 0x03,
- 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
- 0x24, 0xd5, 0x12, 0xfc, 0xb9, 0x5a, 0xe3, 0x27,
- 0x01, 0xbe, 0xc3, 0x77, 0x17, 0x1a, 0xbb, 0x4f,
- 0xae, 0xd5, 0xa7, 0xee, 0x56, 0x61, 0x0d, 0x40,
- 0xf4, 0xa4, 0xb5, 0xcc, 0x76, 0xfd, 0xbd, 0x13,
- 0x04, 0xe1, 0xb8, 0xc7, 0x36,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x67, 0x04, 0x00, 0x02,
- 0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x1f, 0xe2, 0x69,
- 0x07, 0x7f, 0x85, 0x2d, 0x4e, 0x2a, 0x2e, 0xbd,
- 0x05, 0xe9, 0xc1, 0x6c, 0x9e, 0xbf, 0x47, 0x18,
- 0x91, 0x77, 0xf7, 0xe8, 0xb6, 0x27, 0x37, 0xa6,
- 0x6b, 0x87, 0x29, 0xbb, 0x3b, 0xe5, 0x68, 0x62,
- 0x04, 0x3e, 0xad, 0x4d, 0xff, 0xad, 0xf1, 0x22,
- 0x87, 0x8d, 0xf6, 0x04, 0x3b, 0x59, 0x22, 0xf7,
- 0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
- 0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
- 0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
- 0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
- 0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
- 0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
- 0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
- 0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
- 0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
- 0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
- 0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
- 0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
- 0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
- 0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
- 0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
- 0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
- 0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
- 0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
- 0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
- 0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
- 0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
- 0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
- 0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
- 0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
- 0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
- 0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
- 0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
- 0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
- 0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
- 0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
- 0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
- 0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
- 0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
- 0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
- 0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
- 0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
- 0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
- 0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
- 0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
- 0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
- 0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
- 0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
- 0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
- 0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
- 0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
- 0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
- 0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
- 0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
- 0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
- 0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
- 0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
- 0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
- 0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
- 0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
- 0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
- 0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
- 0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
- 0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
- 0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
- 0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
- 0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
- 0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
- 0x06, 0x90, 0xb2, 0x51, 0x7a, 0xc3, 0x11, 0x41,
- 0x4b, 0xe3, 0x26, 0x94, 0x3e, 0xa2, 0xfd, 0x0a,
- 0xda, 0x50, 0xf6, 0x50, 0x78, 0x19, 0x6c, 0x52,
- 0xd1, 0x12, 0x76, 0xc2, 0x50, 0x2f, 0x0b, 0xca,
- 0x33, 0xe5, 0x79, 0x93, 0x14, 0x03, 0x01, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x2b,
- 0x51, 0x42, 0x95, 0x6b, 0xca, 0x9f, 0x42, 0x5d,
- 0xd2, 0xd9, 0x67, 0xf9, 0x49, 0x30, 0xfd, 0x2a,
- 0x46, 0xd3, 0x04, 0xf4, 0x86, 0xf9, 0x11, 0x34,
- 0x82, 0xac, 0xe2, 0xc2, 0x2d, 0xc4, 0xd0, 0xfe,
- 0xa9, 0xc9, 0x4b, 0x17, 0x03, 0x01, 0x00, 0x21,
- 0x65, 0x1c, 0xe9, 0x5c, 0xb6, 0xe2, 0x7c, 0x8e,
- 0x49, 0x12, 0x1b, 0xe6, 0x40, 0xd3, 0x97, 0x21,
- 0x76, 0x01, 0xe5, 0x80, 0x5e, 0xf3, 0x11, 0x47,
- 0x25, 0x02, 0x78, 0x8e, 0x6b, 0xae, 0xb3, 0xf3,
- 0x59, 0x15, 0x03, 0x01, 0x00, 0x16, 0x38, 0xc1,
- 0x99, 0x2e, 0xf8, 0x6f, 0x45, 0xa4, 0x10, 0x79,
- 0x5b, 0xc1, 0x47, 0x9a, 0xf6, 0x5c, 0x90, 0xeb,
- 0xa6, 0xe3, 0x1a, 0x24,
+ test := &serverTest{
+ name: "CipherSuiteCertPreferenceRSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
+
+ config = *testConfig
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
+ config.Certificates = []Certificate{
+ Certificate{
+ Certificate: [][]byte{testECDSACertificate},
+ PrivateKey: testECDSAPrivateKey,
},
- }},
-}
+ }
+ config.BuildNameToCertificate()
+ config.PreferServerCipherSuites = true
-var tls11ECDHEAESServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x46, 0x01, 0x00, 0x01,
- 0x42, 0x03, 0x03, 0x51, 0x9f, 0xa3, 0xb0, 0xb7,
- 0x1d, 0x26, 0x93, 0x36, 0xc0, 0x8d, 0x7e, 0xf8,
- 0x4f, 0x6f, 0xc9, 0x3c, 0x31, 0x1e, 0x7f, 0xb1,
- 0xf0, 0xc1, 0x0f, 0xf9, 0x0c, 0xa2, 0xd5, 0xca,
- 0x48, 0xe5, 0x35, 0x00, 0x00, 0xd0, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0xa5,
- 0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39,
- 0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88,
- 0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0x00, 0x84, 0xc0, 0x12, 0xc0, 0x08, 0xc0, 0x1c,
- 0xc0, 0x1b, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10,
- 0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a,
- 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23,
- 0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e,
- 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e,
- 0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e,
- 0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30,
- 0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97,
- 0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42,
- 0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25,
- 0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c,
- 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0x00, 0x07,
- 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x14,
- 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
- 0x00, 0x49, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
- 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
- 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
- 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
- 0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
- 0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
- 0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
- 0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x02, 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, 0xc0, 0x13, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x02,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x02, 0x01, 0x0f, 0x0c, 0x00, 0x01,
- 0x0b, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x80, 0x16, 0x83, 0x9b, 0xf9,
- 0x72, 0xdb, 0x9f, 0x55, 0x02, 0xe1, 0x04, 0xf7,
- 0xb5, 0x3f, 0x4c, 0x71, 0x13, 0x5a, 0x91, 0xe9,
- 0x1d, 0xeb, 0x9d, 0x9c, 0xfb, 0x88, 0xef, 0xca,
- 0xec, 0x7d, 0x9b, 0xdd, 0xd9, 0xee, 0x2b, 0x8e,
- 0xef, 0xf8, 0xb6, 0xc7, 0x7d, 0xfe, 0xda, 0x7f,
- 0x90, 0x2e, 0x53, 0xf1, 0x64, 0x95, 0xfc, 0x66,
- 0xfc, 0x87, 0x27, 0xb6, 0x9f, 0xc8, 0x3a, 0x95,
- 0x68, 0x17, 0xe1, 0x7d, 0xf1, 0x88, 0xe8, 0x17,
- 0x5f, 0x99, 0x90, 0x3f, 0x47, 0x47, 0x81, 0x06,
- 0xe2, 0x8e, 0x22, 0x56, 0x8f, 0xc2, 0x14, 0xe5,
- 0x62, 0xa7, 0x0d, 0x41, 0x3c, 0xc7, 0x4a, 0x0a,
- 0x74, 0x4b, 0xda, 0x00, 0x8e, 0x4f, 0x90, 0xe6,
- 0xd7, 0x68, 0xe5, 0x8b, 0xf2, 0x3f, 0x53, 0x1d,
- 0x7a, 0xe6, 0xb3, 0xe9, 0x8a, 0xc9, 0x4d, 0x19,
- 0xa6, 0xcf, 0xf9, 0xed, 0x5e, 0x26, 0xdc, 0x90,
- 0x1c, 0x41, 0xad, 0x7c, 0x16, 0x03, 0x02, 0x00,
- 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0x11, 0xf2, 0xa4, 0x2d,
- 0x1a, 0x75, 0x6c, 0xbc, 0x2d, 0x91, 0x95, 0x07,
- 0xbe, 0xd6, 0x41, 0x7a, 0xbb, 0xc2, 0x7b, 0xa6,
- 0x9b, 0xe3, 0xdc, 0x41, 0x7f, 0x1e, 0x2e, 0xcc,
- 0x6d, 0xa3, 0x85, 0x53, 0x98, 0x9f, 0x2d, 0xe6,
- 0x3c, 0xb9, 0x82, 0xa6, 0x80, 0x53, 0x9b, 0x71,
- 0xfd, 0x27, 0xe5, 0xe5, 0xdf, 0x13, 0xba, 0x56,
- 0x62, 0x30, 0x4a, 0x57, 0x27, 0xa7, 0xcc, 0x26,
- 0x54, 0xe8, 0x65, 0x6e, 0x4d, 0x00, 0xbf, 0x8a,
- 0xcc, 0x89, 0x6a, 0x6c, 0x88, 0xda, 0x79, 0x4f,
- 0xc5, 0xad, 0x6d, 0x1d, 0x7c, 0x53, 0x7b, 0x1a,
- 0x96, 0xf2, 0xf8, 0x30, 0x01, 0x0b, 0xc2, 0xf0,
- 0x78, 0x41, 0xf4, 0x0d, 0xe0, 0xbe, 0xb9, 0x36,
- 0xe0, 0xb7, 0xee, 0x16, 0xeb, 0x25, 0x67, 0x04,
- 0xc0, 0x2e, 0xd8, 0x34, 0x4a, 0x65, 0xa5, 0xf1,
- 0x95, 0x75, 0xc7, 0x39, 0xa9, 0x68, 0xa9, 0x53,
- 0x93, 0x5b, 0xca, 0x7b, 0x7f, 0xc0, 0x63, 0x14,
- 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
- 0x00, 0x40, 0x01, 0xb1, 0xae, 0x1b, 0x8a, 0x65,
- 0xf8, 0x37, 0x50, 0x39, 0x76, 0xef, 0xaa, 0xda,
- 0x84, 0xc9, 0x5f, 0x80, 0xdc, 0xfa, 0xe0, 0x46,
- 0x5a, 0xc7, 0x77, 0x9d, 0x76, 0x03, 0xa6, 0xd5,
- 0x0e, 0xbf, 0x25, 0x30, 0x5c, 0x99, 0x7d, 0xcd,
- 0x2b, 0xaa, 0x2e, 0x8c, 0xdd, 0xda, 0xaa, 0xd7,
- 0xf1, 0xf6, 0x33, 0x47, 0x51, 0x1e, 0x83, 0xa1,
- 0x83, 0x04, 0xd2, 0xb2, 0xc8, 0xbc, 0x11, 0xc5,
- 0x1a, 0x87,
- },
- {
- 0x16, 0x03, 0x02, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xeb, 0x8b, 0xc7, 0xef, 0xba, 0xe8, 0x0f, 0x69,
- 0xfe, 0xfb, 0xc3, 0x3d, 0x90, 0x5d, 0xd7, 0xb2,
- 0x51, 0x64, 0xac, 0xc3, 0xae, 0x33, 0x03, 0x42,
- 0x45, 0x2d, 0xa7, 0x57, 0xbd, 0xa3, 0x85, 0x64,
- 0xa6, 0xfe, 0x5c, 0x33, 0x04, 0x93, 0xf2, 0x7c,
- 0x06, 0x6d, 0xd7, 0xd7, 0xcf, 0x4a, 0xaf, 0xb2,
- 0xdd, 0x06, 0xdc, 0x28, 0x14, 0x59, 0x23, 0x02,
- 0xef, 0x97, 0x6a, 0xe8, 0xec, 0xca, 0x10, 0x44,
- 0xcd, 0xb8, 0x50, 0x16, 0x46, 0x5a, 0x05, 0xda,
- 0x04, 0xb3, 0x0e, 0xe9, 0xf0, 0x74, 0xc5, 0x23,
- 0xc2, 0x0e, 0xa1, 0x54, 0x66, 0x7b, 0xe8, 0x14,
- 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x6b, 0x43, 0x1c, 0x58, 0xbc, 0x85,
- 0xf7, 0xc1, 0x76, 0xbc, 0x72, 0x33, 0x41, 0x6b,
- 0xb8, 0xf8, 0xfd, 0x53, 0x21, 0xc2, 0x41, 0x1b,
- 0x72, 0x4f, 0xce, 0x97, 0xca, 0x14, 0x23, 0x4d,
- 0xbc, 0x44, 0xd6, 0xd7, 0xfc, 0xbc, 0xfd, 0xfd,
- 0x5d, 0x33, 0x42, 0x1b, 0x52, 0x40, 0x0a, 0x2b,
- 0x6c, 0x98, 0x17, 0x03, 0x02, 0x00, 0x40, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d,
- 0x31, 0xef, 0x03, 0x7d, 0xa5, 0x74, 0x92, 0x24,
- 0x34, 0xae, 0x4e, 0xc9, 0xfc, 0x59, 0xcb, 0x64,
- 0xf4, 0x45, 0xb1, 0xac, 0x02, 0xf2, 0x87, 0xe7,
- 0x2f, 0xfd, 0x01, 0xca, 0x78, 0x02, 0x2e, 0x3a,
- 0x38, 0xcd, 0xb1, 0xe0, 0xf2, 0x2e, 0xf6, 0x27,
- 0xa0, 0xac, 0x1f, 0x91, 0x43, 0xc2, 0x3d, 0x15,
- 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x9f, 0x30, 0x24, 0x56,
- 0x2c, 0xde, 0xa0, 0xe6, 0x44, 0x35, 0x30, 0x51,
- 0xec, 0xd4, 0x69, 0x2d, 0x46, 0x64, 0x04, 0x21,
- 0xfe, 0x7c, 0x4d, 0xc5, 0xd0, 0x8c, 0xf9, 0xd2,
- 0x3f, 0x88, 0x69, 0xd5,
- },
+ test = &serverTest{
+ name: "CipherSuiteCertPreferenceECDSA",
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
}
-// $ go test -run TestRunServer -serve -clientauth 1 \
-// -ciphersuites=0xc011 -minversion=0x0303 -maxversion=0x0303
-var tls12ServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
- 0x1a, 0x03, 0x03, 0x51, 0xe5, 0x76, 0x84, 0x0e,
- 0xb9, 0x17, 0xca, 0x08, 0x47, 0xd9, 0xbd, 0xd0,
- 0x94, 0xd1, 0x97, 0xca, 0x5b, 0xe7, 0x20, 0xac,
- 0x8e, 0xbb, 0xc7, 0x29, 0xe9, 0x26, 0xcf, 0x7d,
- 0xb3, 0xdc, 0x99, 0x00, 0x00, 0x82, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
- 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
- 0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
- 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
- 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
- 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
- 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
- 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
- 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
- 0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
- 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
- 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
- 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
- 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
- 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 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, 0xc0, 0x11, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
- 0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x4a, 0xf9,
- 0xf5, 0x0a, 0x61, 0x37, 0x7e, 0x4e, 0x92, 0xb5,
- 0x1c, 0x91, 0x21, 0xb2, 0xb5, 0x17, 0x00, 0xbf,
- 0x01, 0x5f, 0x30, 0xec, 0x62, 0x08, 0xd6, 0x9d,
- 0x1a, 0x08, 0x05, 0x72, 0x8b, 0xf4, 0x49, 0x85,
- 0xa7, 0xbf, 0x3f, 0x75, 0x58, 0x3e, 0x26, 0x82,
- 0xc3, 0x28, 0x07, 0xf9, 0x41, 0x7d, 0x03, 0x14,
- 0x3b, 0xc3, 0x05, 0x64, 0xff, 0x52, 0xf4, 0x75,
- 0x6a, 0x87, 0xcd, 0xdf, 0x93, 0x31, 0x0a, 0x71,
- 0x60, 0x17, 0xc6, 0x33, 0xf0, 0x79, 0xb6, 0x7b,
- 0xd0, 0x9c, 0xa0, 0x5f, 0x74, 0x14, 0x2c, 0x5a,
- 0xb4, 0x3f, 0x39, 0xf5, 0xe4, 0x9f, 0xbe, 0x6d,
- 0x21, 0xd2, 0xa9, 0x42, 0xf7, 0xdc, 0xa6, 0x65,
- 0xb7, 0x6a, 0x7e, 0x2e, 0x14, 0xd3, 0xf6, 0xf3,
- 0x4b, 0x4c, 0x5b, 0x1a, 0x70, 0x7a, 0xbc, 0xb0,
- 0x12, 0xf3, 0x6e, 0x0c, 0xcf, 0x43, 0x22, 0xae,
- 0x5b, 0xba, 0x00, 0xf8, 0xfd, 0xaf, 0x16, 0x03,
- 0x03, 0x00, 0x0f, 0x0d, 0x00, 0x00, 0x0b, 0x02,
- 0x01, 0x40, 0x00, 0x04, 0x04, 0x01, 0x04, 0x03,
- 0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e,
- 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x03, 0x01, 0xfb, 0x0b, 0x00, 0x01,
- 0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
- 0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
- 0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
- 0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
- 0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
- 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
- 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
- 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
- 0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
- 0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
- 0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
- 0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
- 0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
- 0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
- 0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
- 0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
- 0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
- 0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
- 0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
- 0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
- 0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
- 0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
- 0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
- 0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
- 0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
- 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
- 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
- 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
- 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
- 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
- 0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
- 0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
- 0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
- 0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
- 0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
- 0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
- 0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
- 0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
- 0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
- 0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
- 0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
- 0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
- 0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
- 0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
- 0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
- 0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
- 0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0x5d, 0x3a, 0x92, 0x59,
- 0x7f, 0x9a, 0x22, 0x36, 0x0e, 0x1b, 0x1d, 0x2a,
- 0x05, 0xb7, 0xa4, 0xb6, 0x5d, 0xfc, 0x51, 0x6e,
- 0x15, 0xe5, 0x89, 0x7c, 0xe2, 0xfa, 0x87, 0x38,
- 0x05, 0x79, 0x15, 0x92, 0xb4, 0x8f, 0x88, 0x8f,
- 0x9d, 0x5d, 0xa0, 0xaf, 0xf8, 0xce, 0xf9, 0x6f,
- 0x83, 0xf4, 0x08, 0x69, 0xe4, 0x91, 0xc5, 0xed,
- 0xb9, 0xc5, 0xa8, 0x1f, 0x4b, 0xec, 0xef, 0x91,
- 0xc1, 0xa3, 0x34, 0x24, 0x18, 0x00, 0x2d, 0xcd,
- 0xe6, 0x44, 0xef, 0x5a, 0x3e, 0x52, 0x63, 0x5b,
- 0x36, 0x1f, 0x7e, 0xce, 0x9e, 0xaa, 0xda, 0x8d,
- 0xb5, 0xc9, 0xea, 0xd8, 0x1b, 0xd1, 0x1c, 0x7c,
- 0x07, 0xfc, 0x3c, 0x2d, 0x70, 0x1f, 0xf9, 0x4d,
- 0xcb, 0xaa, 0xad, 0x07, 0xd5, 0x6d, 0xbd, 0xa6,
- 0x61, 0xf3, 0x2f, 0xa3, 0x9c, 0x45, 0x02, 0x4a,
- 0xac, 0x6c, 0xb6, 0x37, 0x95, 0xb1, 0x4a, 0xb5,
- 0x0a, 0x4e, 0x60, 0x67, 0xd7, 0xe0, 0x04, 0x16,
- 0x03, 0x03, 0x00, 0x88, 0x0f, 0x00, 0x00, 0x84,
- 0x04, 0x01, 0x00, 0x80, 0x08, 0x83, 0x53, 0xf0,
- 0xf8, 0x14, 0xf5, 0xc2, 0xd1, 0x8b, 0xf0, 0xa5,
- 0xc1, 0xd8, 0x1a, 0x36, 0x4b, 0x75, 0x77, 0x02,
- 0x19, 0xd8, 0x11, 0x3f, 0x5a, 0x36, 0xfc, 0xe9,
- 0x2b, 0x4b, 0xf9, 0xfe, 0xda, 0x8a, 0x0f, 0x6e,
- 0x3d, 0xd3, 0x52, 0x87, 0xf7, 0x9c, 0x78, 0x39,
- 0xa8, 0xf1, 0xd7, 0xf7, 0x4e, 0x35, 0x33, 0xf9,
- 0xc5, 0x76, 0xa8, 0x12, 0xc4, 0x91, 0x33, 0x1d,
- 0x93, 0x8c, 0xbf, 0xb1, 0x83, 0x00, 0x90, 0xc5,
- 0x52, 0x3e, 0xe0, 0x0a, 0xe8, 0x92, 0x75, 0xdf,
- 0x54, 0x5f, 0x9f, 0x95, 0x76, 0x62, 0xb5, 0x85,
- 0x69, 0xa4, 0x86, 0x85, 0x6c, 0xf3, 0x6b, 0x2a,
- 0x72, 0x7b, 0x4d, 0x42, 0x33, 0x67, 0x4a, 0xce,
- 0xb5, 0xdb, 0x9b, 0xae, 0xc0, 0xb0, 0x10, 0xeb,
- 0x3b, 0xf4, 0xc2, 0x9a, 0x64, 0x47, 0x4c, 0x1e,
- 0xa5, 0x91, 0x7f, 0x6d, 0xd1, 0x03, 0xf5, 0x4a,
- 0x90, 0x69, 0x18, 0xb1, 0x14, 0x03, 0x03, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x59,
- 0xfc, 0x7e, 0xae, 0xb3, 0xbf, 0xab, 0x4d, 0xdb,
- 0x4e, 0xab, 0xa9, 0x6d, 0x6b, 0x4c, 0x60, 0xb6,
- 0x16, 0xe0, 0xab, 0x7f, 0x52, 0x2d, 0xa1, 0xfc,
- 0xe1, 0x80, 0xd2, 0x8a, 0xa1, 0xe5, 0x8f, 0xa1,
- 0x70, 0x93, 0x23,
- },
- {
- 0x16, 0x03, 0x03, 0x02, 0x67, 0x04, 0x00, 0x02,
- 0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xea, 0x8b, 0xc5, 0xef, 0xba, 0x64, 0xb7, 0x23,
- 0x08, 0x86, 0x4f, 0x37, 0xe0, 0x8f, 0xbd, 0x75,
- 0x71, 0x2b, 0xcb, 0x20, 0x75, 0x11, 0x3b, 0xa2,
- 0x9e, 0x39, 0x3c, 0x03, 0xef, 0x6e, 0x41, 0xd7,
- 0xcf, 0x1a, 0x2c, 0xf2, 0xfe, 0xc2, 0xd3, 0x65,
- 0x59, 0x00, 0x9d, 0x03, 0xb4, 0xf2, 0x20, 0xe4,
- 0x33, 0x80, 0xcd, 0xf6, 0xe4, 0x59, 0x22, 0xf7,
- 0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
- 0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
- 0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
- 0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
- 0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
- 0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
- 0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
- 0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
- 0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
- 0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
- 0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
- 0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
- 0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
- 0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
- 0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
- 0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
- 0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
- 0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
- 0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
- 0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
- 0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
- 0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
- 0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
- 0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
- 0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
- 0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
- 0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
- 0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
- 0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
- 0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
- 0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
- 0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
- 0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
- 0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
- 0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
- 0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
- 0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
- 0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
- 0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
- 0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
- 0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
- 0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
- 0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
- 0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
- 0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
- 0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
- 0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
- 0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
- 0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
- 0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
- 0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
- 0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
- 0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
- 0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
- 0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
- 0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
- 0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
- 0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
- 0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
- 0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
- 0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
- 0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
- 0x06, 0x90, 0xb2, 0x51, 0xc0, 0x48, 0x10, 0xac,
- 0x2a, 0xec, 0xec, 0x48, 0x7a, 0x19, 0x47, 0xc4,
- 0x2a, 0xeb, 0xb3, 0xa2, 0x07, 0x22, 0x32, 0x78,
- 0xf4, 0x73, 0x5e, 0x92, 0x42, 0x15, 0xa1, 0x90,
- 0x91, 0xd0, 0xeb, 0x12, 0x14, 0x03, 0x03, 0x00,
- 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x45,
- 0x4b, 0x80, 0x42, 0x46, 0xde, 0xbb, 0xe7, 0x76,
- 0xd1, 0x33, 0x92, 0xfc, 0x46, 0x17, 0x6d, 0x21,
- 0xf6, 0x0e, 0x16, 0xca, 0x9b, 0x9b, 0x04, 0x65,
- 0x16, 0x40, 0x44, 0x64, 0xbc, 0x58, 0xfa, 0x2a,
- 0x49, 0xe9, 0xed, 0x17, 0x03, 0x03, 0x00, 0x21,
- 0x89, 0x71, 0xcd, 0x56, 0x54, 0xbf, 0x73, 0xde,
- 0xfb, 0x4b, 0x4e, 0xf1, 0x7f, 0xc6, 0x75, 0xa6,
- 0xbd, 0x6b, 0x6c, 0xd9, 0xdc, 0x0c, 0x71, 0xb4,
- 0xb9, 0xbb, 0x6e, 0xfa, 0x9e, 0xc7, 0xc7, 0x4c,
- 0x24, 0x15, 0x03, 0x03, 0x00, 0x16, 0x62, 0xea,
- 0x65, 0x69, 0x68, 0x4a, 0xce, 0xa7, 0x9e, 0xce,
- 0xc0, 0xf1, 0x5c, 0x96, 0xd9, 0x1f, 0x49, 0xac,
- 0x2d, 0x05, 0x89, 0x94,
- },
+func TestResumption(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
+
+ test := &serverTest{
+ name: "IssueTicket",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "Resume",
+ command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ }
+ runServerTestTLS12(t, test)
}
// cert.pem and key.pem were generated with generate_cert.go
// Thus, they have no ExtKeyUsage fields and trigger an error
// when verification is turned on.
-var clientCertificate = loadPEMCert(`
+const clientCertificatePEM = `
-----BEGIN CERTIFICATE-----
MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
@@ -3147,10 +574,9 @@ DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
GFGNEH5PlGffo05wc46QkYU=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
-/* corresponding key.pem for cert.pem is:
+const clientKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
@@ -3165,10 +591,9 @@ saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA
------END RSA PRIVATE KEY-----
-*/
+-----END RSA PRIVATE KEY-----`
-var clientECDSACertificate = loadPEMCert(`
+const clientECDSACertificatePEM = `
-----BEGIN CERTIFICATE-----
MIIB/DCCAV4CCQCaMIRsJjXZFzAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
@@ -3181,10 +606,9 @@ ixgnTy5w/hOWusPTQBbNZU6sER7m8TAJBgcqhkjOPQQBA4GMADCBiAJCAOAUxGBg
C3JosDJdYUoCdFzCgbkWqD8pyDbHgf9stlvZcPE4O1BIKJTLCRpS8V3ujfK58PDa
2RU6+b0DeoeiIzXsAkIBo9SKeDUcSpoj0gq+KxAxnZxfvuiRs9oa9V2jI/Umi0Vw
jWVim34BmT0Y9hCaOGGbLlfk+syxis7iI6CH8OFnUes=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
-/* corresponding key for cert is:
+const clientECDSAKeyPEM = `
-----BEGIN EC PARAMETERS-----
BgUrgQQAIw==
-----END EC PARAMETERS-----
@@ -3194,603 +618,83 @@ k+wLWoqizS3NpQyMtrU8JFdWfj+C57UNkOugBwYFK4EEACOhgYkDgYYABACVjJF1
FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
3kfDdq0Z9kUsjLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx
+U56jb0JuK7qixgnTy5w/hOWusPTQBbNZU6sER7m8Q==
------END EC PRIVATE KEY-----
-*/
-var clientauthECDSATests = []clientauthTest{
- // Server asks for cert with empty CA list, client gives one
- // go test -run "TestRunServer" -serve \
- // -clientauth 1 -ciphersuites=0xc00a
- // openssl s_client -host 127.0.0.1 -port 10443 \
- // -cipher ECDHE-ECDSA-AES256-SHA -key client.key -cert client.crt
- {"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientECDSACertificate}, [][]byte{
- {
- 0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
- 0x9c, 0x03, 0x03, 0x51, 0xe5, 0x73, 0xc5, 0xae,
- 0x51, 0x94, 0xb4, 0xf2, 0xe8, 0xf6, 0x03, 0x0e,
- 0x3b, 0x34, 0xaf, 0xf0, 0xdc, 0x1b, 0xcc, 0xd8,
- 0x0c, 0x45, 0x82, 0xd4, 0xd6, 0x76, 0x04, 0x6e,
- 0x4f, 0x7a, 0x24, 0x00, 0x00, 0x04, 0xc0, 0x0a,
- 0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
- 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
- 0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
- 0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
- 0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
- 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
- 0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
- 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
- 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
- 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
- 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
- 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
- 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
- 0x00, 0x0f, 0x00, 0x01, 0x01,
- },
- {
- 0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 0x03, 0x01, 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, 0xc0, 0x0a, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
- 0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
- 0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
- 0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
- 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
- 0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
- 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
- 0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
- 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
- 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
- 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
- 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
- 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
- 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
- 0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
- 0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
- 0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
- 0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
- 0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
- 0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
- 0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
- 0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
- 0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
- 0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
- 0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
- 0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
- 0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
- 0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
- 0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
- 0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
- 0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
- 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
- 0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
- 0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
- 0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
- 0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
- 0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
- 0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
- 0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
- 0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
- 0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
- 0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
- 0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
- 0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
- 0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
- 0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
- 0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
- 0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
- 0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
- 0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
- 0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
- 0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
- 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
- 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
- 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
- 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
- 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
- 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
- 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
- 0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
- 0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
- 0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
- 0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
- 0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
- 0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
- 0x68, 0x30, 0x21, 0xf4, 0xa8, 0xa9, 0x1b, 0xec,
- 0x44, 0x4f, 0x5d, 0x02, 0x2f, 0x60, 0x45, 0x60,
- 0xba, 0xe0, 0x4e, 0xc0, 0xd4, 0x3b, 0x01, 0x16,
- 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00, 0x05,
- 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03, 0x01,
- 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x0a, 0x0b, 0x00, 0x02,
- 0x06, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x30,
- 0x82, 0x01, 0xfc, 0x30, 0x82, 0x01, 0x5e, 0x02,
- 0x09, 0x00, 0x9a, 0x30, 0x84, 0x6c, 0x26, 0x35,
- 0xd9, 0x17, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x32, 0x31, 0x31, 0x31, 0x34, 0x31, 0x33,
- 0x32, 0x35, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x32,
- 0x32, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x32,
- 0x35, 0x35, 0x33, 0x5a, 0x30, 0x41, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x4e, 0x53,
- 0x57, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
- 0x04, 0x07, 0x13, 0x07, 0x50, 0x79, 0x72, 0x6d,
- 0x6f, 0x6e, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x4a, 0x6f,
- 0x65, 0x6c, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x30,
- 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
- 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86, 0x00,
- 0x04, 0x00, 0x95, 0x8c, 0x91, 0x75, 0x14, 0xc0,
- 0x5e, 0xc4, 0x57, 0xb4, 0xd4, 0xc3, 0x6f, 0x8d,
- 0xae, 0x68, 0x1e, 0xdd, 0x6f, 0xce, 0x86, 0xe1,
- 0x7e, 0x6e, 0xb2, 0x48, 0x3e, 0x81, 0xe5, 0x4e,
- 0xe2, 0xc6, 0x88, 0x4b, 0x64, 0xdc, 0xf5, 0x30,
- 0xbb, 0xd3, 0xff, 0x65, 0xcc, 0x5b, 0xf4, 0xdd,
- 0xb5, 0x6a, 0x3e, 0x3e, 0xd0, 0x1d, 0xde, 0x47,
- 0xc3, 0x76, 0xad, 0x19, 0xf6, 0x45, 0x2c, 0x8c,
- 0xbc, 0xd8, 0x1d, 0x01, 0x4c, 0x1f, 0x70, 0x90,
- 0x46, 0x76, 0x48, 0x8b, 0x8f, 0x83, 0xcc, 0x4a,
- 0x5c, 0x8f, 0x40, 0x76, 0xda, 0xe0, 0x89, 0xec,
- 0x1d, 0x2b, 0xc4, 0x4e, 0x30, 0x76, 0x28, 0x41,
- 0xb2, 0x62, 0xa8, 0xfb, 0x5b, 0xf1, 0xf9, 0x4e,
- 0x7a, 0x8d, 0xbd, 0x09, 0xb8, 0xae, 0xea, 0x8b,
- 0x18, 0x27, 0x4f, 0x2e, 0x70, 0xfe, 0x13, 0x96,
- 0xba, 0xc3, 0xd3, 0x40, 0x16, 0xcd, 0x65, 0x4e,
- 0xac, 0x11, 0x1e, 0xe6, 0xf1, 0x30, 0x09, 0x06,
- 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01,
- 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88, 0x02,
- 0x42, 0x00, 0xe0, 0x14, 0xc4, 0x60, 0x60, 0x0b,
- 0x72, 0x68, 0xb0, 0x32, 0x5d, 0x61, 0x4a, 0x02,
- 0x74, 0x5c, 0xc2, 0x81, 0xb9, 0x16, 0xa8, 0x3f,
- 0x29, 0xc8, 0x36, 0xc7, 0x81, 0xff, 0x6c, 0xb6,
- 0x5b, 0xd9, 0x70, 0xf1, 0x38, 0x3b, 0x50, 0x48,
- 0x28, 0x94, 0xcb, 0x09, 0x1a, 0x52, 0xf1, 0x5d,
- 0xee, 0x8d, 0xf2, 0xb9, 0xf0, 0xf0, 0xda, 0xd9,
- 0x15, 0x3a, 0xf9, 0xbd, 0x03, 0x7a, 0x87, 0xa2,
- 0x23, 0x35, 0xec, 0x02, 0x42, 0x01, 0xa3, 0xd4,
- 0x8a, 0x78, 0x35, 0x1c, 0x4a, 0x9a, 0x23, 0xd2,
- 0x0a, 0xbe, 0x2b, 0x10, 0x31, 0x9d, 0x9c, 0x5f,
- 0xbe, 0xe8, 0x91, 0xb3, 0xda, 0x1a, 0xf5, 0x5d,
- 0xa3, 0x23, 0xf5, 0x26, 0x8b, 0x45, 0x70, 0x8d,
- 0x65, 0x62, 0x9b, 0x7e, 0x01, 0x99, 0x3d, 0x18,
- 0xf6, 0x10, 0x9a, 0x38, 0x61, 0x9b, 0x2e, 0x57,
- 0xe4, 0xfa, 0xcc, 0xb1, 0x8a, 0xce, 0xe2, 0x23,
- 0xa0, 0x87, 0xf0, 0xe1, 0x67, 0x51, 0xeb, 0x16,
- 0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00, 0x86,
- 0x85, 0x04, 0x00, 0xcd, 0x1c, 0xe8, 0x66, 0x5b,
- 0xa8, 0x9d, 0x83, 0x2f, 0x7e, 0x1d, 0x0b, 0x59,
- 0x23, 0xbc, 0x30, 0xcf, 0xa3, 0xaf, 0x21, 0xdc,
- 0xf2, 0x57, 0x49, 0x56, 0x30, 0x25, 0x7c, 0x84,
- 0x5d, 0xad, 0xaa, 0x9c, 0x7b, 0x2a, 0x95, 0x58,
- 0x3d, 0x30, 0x87, 0x01, 0x3b, 0xb7, 0xea, 0xcb,
- 0xc4, 0xa3, 0xeb, 0x22, 0xbf, 0x2d, 0x61, 0x17,
- 0x8c, 0x9b, 0xe8, 0x1b, 0xb2, 0x87, 0x16, 0x78,
- 0xd5, 0xfd, 0x8b, 0xdd, 0x00, 0x0f, 0xda, 0x8e,
- 0xfd, 0x28, 0x36, 0xeb, 0xe4, 0xc5, 0x42, 0x14,
- 0xc7, 0xbd, 0x29, 0x5e, 0x9a, 0xed, 0x5e, 0xc1,
- 0xf7, 0xf4, 0xbd, 0xbd, 0x15, 0x9c, 0xe8, 0x44,
- 0x71, 0xa7, 0xb6, 0xe9, 0xfa, 0x7e, 0x97, 0xcb,
- 0x96, 0x3e, 0x53, 0x76, 0xfb, 0x11, 0x1f, 0x36,
- 0x8f, 0x30, 0xfb, 0x71, 0x3a, 0x75, 0x3a, 0x25,
- 0x7b, 0xa2, 0xc1, 0xf9, 0x3e, 0x58, 0x5f, 0x07,
- 0x16, 0xed, 0xe1, 0xf7, 0xc1, 0xb1, 0x16, 0x03,
- 0x01, 0x00, 0x90, 0x0f, 0x00, 0x00, 0x8c, 0x00,
- 0x8a, 0x30, 0x81, 0x87, 0x02, 0x42, 0x00, 0xb2,
- 0xd3, 0x91, 0xe6, 0xd5, 0x9b, 0xb2, 0xb8, 0x03,
- 0xf4, 0x85, 0x4d, 0x43, 0x79, 0x1f, 0xb6, 0x6f,
- 0x0c, 0xcd, 0x67, 0x5f, 0x5e, 0xca, 0xee, 0xb3,
- 0xe4, 0xab, 0x1e, 0x58, 0xc3, 0x04, 0xa9, 0x8a,
- 0xa7, 0xcf, 0xaa, 0x33, 0x88, 0xd5, 0x35, 0xd2,
- 0x80, 0x8f, 0xfa, 0x1b, 0x3c, 0x3d, 0xf7, 0x80,
- 0x50, 0xde, 0x80, 0x30, 0x64, 0xee, 0xc0, 0xb3,
- 0x91, 0x6e, 0x5d, 0x1e, 0xc0, 0xdc, 0x3a, 0x93,
- 0x02, 0x41, 0x4e, 0xca, 0x98, 0x41, 0x8c, 0x36,
- 0xf2, 0x12, 0xbf, 0x8e, 0x0f, 0x69, 0x8e, 0xf8,
- 0x7b, 0x9d, 0xba, 0x9c, 0x5c, 0x48, 0x79, 0xf4,
- 0xba, 0x3d, 0x06, 0xa5, 0xab, 0x47, 0xe0, 0x1a,
- 0x45, 0x28, 0x3a, 0x8f, 0xbf, 0x14, 0x24, 0x36,
- 0xd1, 0x1d, 0x29, 0xdc, 0xde, 0x72, 0x5b, 0x76,
- 0x41, 0x67, 0xe8, 0xe5, 0x71, 0x4a, 0x77, 0xe9,
- 0xed, 0x02, 0x19, 0xdd, 0xe4, 0xaa, 0xe9, 0x2d,
- 0xe7, 0x47, 0x32, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xfa, 0xc3,
- 0xf2, 0x35, 0xd0, 0x6d, 0x32, 0x78, 0x6a, 0xd6,
- 0xe6, 0x70, 0x5e, 0x00, 0x4c, 0x35, 0xf1, 0xe0,
- 0x21, 0xcf, 0xc3, 0x78, 0xcd, 0xe0, 0x2b, 0x0b,
- 0xf4, 0xeb, 0xf9, 0xc0, 0x38, 0xf2, 0x9a, 0x31,
- 0x55, 0x07, 0x2b, 0x8d, 0x68, 0x40, 0x31, 0x08,
- 0xaa, 0xe3, 0x16, 0xcf, 0x4b, 0xd4,
- },
- {
- 0x16, 0x03, 0x01, 0x02, 0x76, 0x04, 0x00, 0x02,
- 0x72, 0x00, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xe8, 0x8b, 0xde, 0xef, 0xba, 0xf9, 0xdb, 0x95,
- 0x24, 0xa5, 0x49, 0xb3, 0x23, 0xd8, 0x73, 0x88,
- 0x50, 0x42, 0xed, 0xeb, 0xa3, 0xd8, 0xab, 0x31,
- 0x9c, 0xd0, 0x00, 0x01, 0xef, 0xc0, 0xbf, 0xab,
- 0x59, 0x55, 0xb5, 0xb9, 0xef, 0xa5, 0xa6, 0xec,
- 0x69, 0xed, 0x00, 0x2f, 0x47, 0xdb, 0x75, 0x52,
- 0x0c, 0xe5, 0x86, 0xb7, 0x02, 0x59, 0x22, 0xf7,
- 0xfd, 0x8b, 0xff, 0xa4, 0x09, 0xc0, 0x1c, 0x10,
- 0x80, 0x10, 0x7f, 0x4c, 0x7a, 0x94, 0x40, 0x10,
- 0x0d, 0xda, 0x8a, 0xe5, 0x4a, 0xbc, 0xd0, 0xc0,
- 0x4b, 0xa5, 0x33, 0x97, 0xc6, 0xe7, 0x40, 0x7f,
- 0x7f, 0x8c, 0xf9, 0xf8, 0xc8, 0xb8, 0xfb, 0x8c,
- 0xdd, 0x28, 0x81, 0xae, 0xfd, 0x37, 0x20, 0x3a,
- 0x40, 0x37, 0x99, 0xc4, 0x21, 0x01, 0xc4, 0x91,
- 0xb0, 0x5e, 0x11, 0xc5, 0xa9, 0xfd, 0x9a, 0x02,
- 0x7e, 0x97, 0x6a, 0x86, 0x89, 0xb8, 0xc1, 0x32,
- 0x4c, 0x7e, 0x6d, 0x47, 0x61, 0x0e, 0xe3, 0xc2,
- 0xf0, 0x62, 0x3c, 0xc6, 0x71, 0x4f, 0xbb, 0x47,
- 0x65, 0xb1, 0xd9, 0x22, 0x79, 0x15, 0xea, 0x1f,
- 0x4b, 0x2a, 0x8a, 0xa4, 0xc8, 0x73, 0x34, 0xba,
- 0x83, 0xe4, 0x70, 0x99, 0xc9, 0xcf, 0xbe, 0x64,
- 0x99, 0xb9, 0xfa, 0xe9, 0xaf, 0x5d, 0xc7, 0x20,
- 0x26, 0xde, 0xc5, 0x06, 0x12, 0x36, 0x4f, 0x4d,
- 0xc0, 0xbb, 0x81, 0x5b, 0x5e, 0x38, 0xc3, 0x07,
- 0x21, 0x04, 0x1a, 0x53, 0x9c, 0x59, 0xac, 0x2d,
- 0xe6, 0xa5, 0x93, 0xa5, 0x19, 0xc6, 0xb0, 0xf7,
- 0x56, 0x5d, 0xdf, 0xd1, 0xf4, 0xfd, 0x44, 0x6d,
- 0xc6, 0xa2, 0x31, 0xa7, 0x35, 0x42, 0x18, 0x50,
- 0x0c, 0x4f, 0x6e, 0xe3, 0x3b, 0xa3, 0xaa, 0x1c,
- 0xbe, 0x41, 0x0d, 0xce, 0x6c, 0x62, 0xe1, 0x96,
- 0x2d, 0xbd, 0x14, 0x31, 0xe3, 0xc4, 0x5b, 0xbf,
- 0xf6, 0xde, 0xec, 0x42, 0xe8, 0xc7, 0x2a, 0x0b,
- 0xdb, 0x2d, 0x7c, 0xf0, 0x3f, 0x45, 0x32, 0x45,
- 0x09, 0x47, 0x09, 0x0f, 0x21, 0x22, 0x45, 0x06,
- 0x11, 0xb8, 0xf9, 0xe6, 0x67, 0x90, 0x4b, 0x4a,
- 0xde, 0x81, 0xfb, 0xeb, 0xe7, 0x9a, 0x08, 0x30,
- 0xcf, 0x51, 0xe1, 0xd9, 0xfa, 0x79, 0xa3, 0xcc,
- 0x65, 0x1a, 0x83, 0x86, 0xc9, 0x7a, 0x41, 0xf5,
- 0xdf, 0xa0, 0x7c, 0x44, 0x23, 0x17, 0xf3, 0x62,
- 0xe8, 0xa9, 0x31, 0x1e, 0x6b, 0x05, 0x4b, 0x4f,
- 0x9d, 0x91, 0x46, 0x92, 0xa6, 0x25, 0x32, 0xca,
- 0xa1, 0x75, 0xda, 0xe6, 0x80, 0x3e, 0x7f, 0xd1,
- 0x26, 0x57, 0x07, 0x42, 0xe4, 0x91, 0xff, 0xbd,
- 0x44, 0xae, 0x98, 0x5c, 0x1d, 0xdf, 0x11, 0xe3,
- 0xae, 0x87, 0x5e, 0xb7, 0x69, 0xad, 0x34, 0x7f,
- 0x3a, 0x07, 0x7c, 0xdf, 0xfc, 0x76, 0x17, 0x8b,
- 0x62, 0xc8, 0xe1, 0x78, 0x2a, 0xc8, 0xb9, 0x8a,
- 0xbb, 0x5c, 0xfb, 0x38, 0x74, 0x91, 0x6e, 0x12,
- 0x0c, 0x1f, 0x8e, 0xe1, 0xc2, 0x01, 0xd8, 0x9d,
- 0x23, 0x0f, 0xc4, 0x67, 0x5d, 0xe5, 0x67, 0x4b,
- 0x94, 0x6e, 0x69, 0x72, 0x90, 0x2d, 0x52, 0x78,
- 0x8e, 0x61, 0xba, 0xdf, 0x4e, 0xf5, 0xdc, 0xfb,
- 0x73, 0xbe, 0x03, 0x70, 0xd9, 0x01, 0x30, 0xf3,
- 0xa1, 0xbb, 0x9a, 0x5f, 0xec, 0x9e, 0xed, 0x8d,
- 0xdd, 0x53, 0xfd, 0x60, 0xc3, 0x2b, 0x7a, 0x00,
- 0x2c, 0xf9, 0x0a, 0x57, 0x47, 0x45, 0x43, 0xb3,
- 0x23, 0x01, 0x9c, 0xee, 0x54, 0x4d, 0x58, 0xd3,
- 0x71, 0x1c, 0xc9, 0xd3, 0x30, 0x9e, 0x14, 0xa5,
- 0xf3, 0xbf, 0x4d, 0x9b, 0xb7, 0x13, 0x21, 0xae,
- 0xd2, 0x8d, 0x6e, 0x6f, 0x1c, 0xcc, 0xb2, 0x41,
- 0xb2, 0x64, 0x56, 0x83, 0xce, 0xd1, 0x0c, 0x79,
- 0x32, 0x78, 0xef, 0xc5, 0x21, 0xb1, 0xe8, 0xc4,
- 0x42, 0xa7, 0x8d, 0xc1, 0xfa, 0xa1, 0x9c, 0x3c,
- 0x21, 0xd8, 0xe9, 0x90, 0xe2, 0x7c, 0x14, 0x26,
- 0xfe, 0x61, 0x3e, 0xf9, 0x71, 0x1d, 0x5d, 0x49,
- 0x3b, 0xb1, 0xb8, 0x42, 0xa1, 0xb8, 0x1c, 0x75,
- 0x7d, 0xee, 0xed, 0xfc, 0xe6, 0x20, 0x2b, 0x9e,
- 0x10, 0x52, 0xda, 0x56, 0x4d, 0x64, 0x6c, 0x41,
- 0xc1, 0xf7, 0x60, 0x0c, 0x10, 0x65, 0x6f, 0xd4,
- 0xe9, 0x9b, 0x0d, 0x83, 0x13, 0xc8, 0x5a, 0xa3,
- 0x56, 0x2a, 0x42, 0xc6, 0x1c, 0xfe, 0xdb, 0xba,
- 0x3d, 0x04, 0x12, 0xfd, 0x28, 0xeb, 0x78, 0xdd,
- 0xbc, 0xc8, 0x0d, 0xa1, 0xce, 0xd4, 0x54, 0xbf,
- 0xaf, 0xe1, 0x60, 0x0c, 0xa3, 0xc3, 0xc3, 0x62,
- 0x58, 0xc1, 0x79, 0xa7, 0x95, 0x41, 0x09, 0x24,
- 0xc6, 0x9a, 0x50, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x4d, 0x7b,
- 0x5f, 0x28, 0x5e, 0x68, 0x6c, 0xa3, 0x65, 0xc7,
- 0x7e, 0x49, 0x6c, 0xb3, 0x67, 0xbb, 0xd0, 0x75,
- 0xa2, 0x9e, 0x8c, 0x92, 0x4f, 0x8c, 0x33, 0x14,
- 0x7c, 0x6c, 0xf1, 0x74, 0x97, 0xc3, 0xe0, 0x10,
- 0xe9, 0x0d, 0xc2, 0x30, 0x5c, 0x23, 0xee, 0x1d,
- 0x16, 0x2e, 0xb9, 0x96, 0x2b, 0x2d, 0x17, 0x03,
- 0x01, 0x00, 0x20, 0xf2, 0xc8, 0xa7, 0x1b, 0x60,
- 0x46, 0xee, 0xe5, 0x7e, 0xc9, 0x35, 0xb3, 0xf1,
- 0x7c, 0x32, 0x0c, 0x85, 0x94, 0x59, 0x57, 0x27,
- 0xb0, 0xbd, 0x52, 0x86, 0x90, 0xf1, 0xb7, 0x4d,
- 0x1e, 0xc1, 0x16, 0x17, 0x03, 0x01, 0x00, 0x30,
- 0xff, 0x85, 0x50, 0xdf, 0x3f, 0xfc, 0xa2, 0x61,
- 0x1a, 0x12, 0xc0, 0x1e, 0x10, 0x32, 0x88, 0x50,
- 0xa0, 0x2c, 0x80, 0xda, 0x77, 0xea, 0x09, 0x47,
- 0xe0, 0x85, 0x07, 0x29, 0x45, 0x65, 0x19, 0xa3,
- 0x8d, 0x99, 0xb8, 0xbf, 0xb6, 0xbc, 0x76, 0xe2,
- 0x50, 0x24, 0x82, 0x0a, 0xfd, 0xdd, 0x35, 0x09,
- 0x15, 0x03, 0x01, 0x00, 0x20, 0xe7, 0x36, 0xf6,
- 0x61, 0xd2, 0x95, 0x3c, 0xb6, 0x65, 0x7b, 0xb2,
- 0xb8, 0xdf, 0x03, 0x53, 0xeb, 0xf7, 0x16, 0xe0,
- 0xe0, 0x15, 0x22, 0x71, 0x70, 0x62, 0x73, 0xad,
- 0xb5, 0x1a, 0x77, 0x44, 0x57,
- },
- }},
+-----END EC PRIVATE KEY-----`
+
+func TestClientAuth(t *testing.T) {
+ var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string
+
+ if *update {
+ certPath = tempFile(clientCertificatePEM)
+ defer os.Remove(certPath)
+ keyPath = tempFile(clientKeyPEM)
+ defer os.Remove(keyPath)
+ ecdsaCertPath = tempFile(clientECDSACertificatePEM)
+ defer os.Remove(ecdsaCertPath)
+ ecdsaKeyPath = tempFile(clientECDSAKeyPEM)
+ defer os.Remove(ecdsaKeyPath)
+ }
+
+ config := *testConfig
+ config.ClientAuth = RequestClientCert
+
+ test := &serverTest{
+ name: "ClientAuthRequestedNotGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
+ config: &config,
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
+ config: &config,
+ expectedPeerCerts: []string{clientCertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndECDSAGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+ config: &config,
+ expectedPeerCerts: []string{clientECDSACertificatePEM},
+ }
+ runServerTestTLS12(t, test)
}
-var aesGCMServerScript = [][]byte{
- {
- 0x16, 0x03, 0x01, 0x01, 0x1c, 0x01, 0x00, 0x01,
- 0x18, 0x03, 0x03, 0x52, 0x1e, 0x74, 0xf0, 0xb0,
- 0xc1, 0x8b, 0x16, 0xf9, 0x74, 0xfc, 0x16, 0xc4,
- 0x11, 0x18, 0x96, 0x08, 0x25, 0x38, 0x4f, 0x98,
- 0x98, 0xbe, 0xb5, 0x61, 0xdf, 0x94, 0x15, 0xcc,
- 0x9b, 0x61, 0xef, 0x00, 0x00, 0x80, 0xc0, 0x30,
- 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
- 0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
- 0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
- 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
- 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
- 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
- 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
- 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
- 0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
- 0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
- 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
- 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
- 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
- 0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
- 0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
- 0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
- 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
- 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
- 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
- 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
- 0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
- 0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
- 0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
- 0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d,
- 0x00, 0x22, 0x00, 0x20, 0x06, 0x01, 0x06, 0x02,
- 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03,
- 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
- 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f, 0x00, 0x01,
- 0x01,
- },
- {
- 0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
- 0x2c, 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, 0xc0, 0x2f, 0x00, 0x00,
- 0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
- 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
- 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
- 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
- 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
- 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
- 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
- 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
- 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
- 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
- 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
- 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
- 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
- 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
- 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
- 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
- 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
- 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
- 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
- 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
- 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
- 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
- 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
- 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
- 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
- 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
- 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
- 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
- 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
- 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
- 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
- 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
- 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
- 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
- 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
- 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
- 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
- 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
- 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
- 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
- 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
- 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
- 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
- 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
- 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
- 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
- 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
- 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
- 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
- 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
- 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
- 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
- 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
- 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
- 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
- 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
- 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
- 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
- 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
- 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
- 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
- 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
- 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
- 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
- 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
- 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
- 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
- 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
- 0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
- 0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
- 0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
- 0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
- 0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
- 0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
- 0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
- 0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
- 0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
- 0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
- 0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
- 0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
- 0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
- 0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
- 0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
- 0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
- 0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
- 0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
- 0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x0d, 0x8e,
- 0x79, 0xe6, 0x86, 0xf6, 0xb6, 0xfb, 0x6b, 0x6a,
- 0xcc, 0x55, 0xe4, 0x80, 0x4d, 0xc5, 0x0c, 0xc6,
- 0xa3, 0x9f, 0x1d, 0x39, 0xd2, 0x98, 0x57, 0x31,
- 0xa2, 0x90, 0x73, 0xe8, 0xd2, 0xcd, 0xb0, 0x93,
- 0x1a, 0x60, 0x0f, 0x38, 0x02, 0x3b, 0x1b, 0x25,
- 0x56, 0xec, 0x44, 0xab, 0xbe, 0x2e, 0x0c, 0xc0,
- 0x6e, 0x54, 0x91, 0x50, 0xd6, 0xb1, 0xa2, 0x98,
- 0x14, 0xa8, 0x35, 0x62, 0x9d, 0xca, 0xfb, 0x0f,
- 0x64, 0x2b, 0x05, 0xa0, 0xa0, 0x57, 0xef, 0xcd,
- 0x95, 0x45, 0x13, 0x5a, 0x9b, 0x3d, 0xdb, 0x42,
- 0x54, 0x7f, 0xb9, 0x17, 0x08, 0x7f, 0xb2, 0xf0,
- 0xb1, 0xc3, 0xdf, 0x67, 0x95, 0xe2, 0x73, 0xf2,
- 0x76, 0xa3, 0x97, 0xfd, 0x9c, 0x92, 0x4a, 0xdb,
- 0x95, 0x1e, 0x91, 0x95, 0xae, 0x3d, 0xae, 0x58,
- 0xb5, 0x03, 0x6f, 0x5c, 0x3a, 0x19, 0xab, 0x92,
- 0xa5, 0x09, 0x6b, 0x40, 0x61, 0xb0, 0x16, 0x03,
- 0x03, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromHex(s string) []byte {
+ b, _ := hex.DecodeString(s)
+ return b
+}
+
+var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
+
+var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
+
+var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")
+
+var testRSAPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+ E: 65537,
},
- {
- 0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
- 0x86, 0x85, 0x04, 0x01, 0xba, 0xb8, 0xad, 0x69,
- 0x20, 0x5e, 0xc1, 0x61, 0xc3, 0x0f, 0xb4, 0x30,
- 0x64, 0x66, 0x70, 0x96, 0x33, 0x3c, 0x8e, 0x12,
- 0x56, 0xbf, 0x6d, 0xb8, 0x6d, 0xc6, 0xba, 0xea,
- 0xfc, 0x38, 0xc0, 0x8b, 0x87, 0xa8, 0xf3, 0x87,
- 0xa1, 0xd5, 0xb6, 0xb0, 0x72, 0xc7, 0xd4, 0x19,
- 0x56, 0xa0, 0x91, 0xe1, 0x45, 0xc7, 0xf1, 0x7d,
- 0xb0, 0x1d, 0x78, 0x18, 0xf6, 0x3d, 0xbf, 0x1a,
- 0x23, 0x93, 0x0b, 0x19, 0xb1, 0x00, 0x56, 0xc9,
- 0x5e, 0x89, 0xd4, 0x9d, 0xd9, 0x5b, 0xe0, 0xb8,
- 0xff, 0x2f, 0x7d, 0x93, 0xae, 0x5b, 0xa5, 0x1f,
- 0x1f, 0x2b, 0x09, 0xe5, 0xf6, 0x07, 0x26, 0xa3,
- 0xed, 0xcb, 0x6a, 0x1a, 0xd6, 0x14, 0x83, 0x9b,
- 0xd3, 0x9d, 0x47, 0x1b, 0xf3, 0x72, 0x5f, 0x69,
- 0x21, 0x8f, 0xfa, 0x09, 0x38, 0x1a, 0x6b, 0x91,
- 0xcf, 0x19, 0x32, 0x54, 0x58, 0x8e, 0xee, 0xaf,
- 0xeb, 0x06, 0x9b, 0x3a, 0x34, 0x16, 0x66, 0x14,
- 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
- 0x00, 0x28, 0xc6, 0x96, 0x67, 0x62, 0xcc, 0x47,
- 0x01, 0xb5, 0xbd, 0xb7, 0x24, 0xd3, 0xb6, 0xfd,
- 0xb8, 0x46, 0xce, 0x82, 0x6d, 0x31, 0x1f, 0x15,
- 0x11, 0x8f, 0xed, 0x62, 0x71, 0x5f, 0xae, 0xb6,
- 0xa9, 0x0c, 0x24, 0x1d, 0xe8, 0x26, 0x51, 0xca,
- 0x7c, 0x42,
+ D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+ Primes: []*big.Int{
+ bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+ bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
},
- {
- 0x16, 0x03, 0x03, 0x00, 0x72, 0x04, 0x00, 0x00,
- 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
- 0xea, 0x8b, 0xfb, 0xef, 0xba, 0xc8, 0x88, 0x94,
- 0x44, 0x99, 0x5f, 0x02, 0x68, 0x3a, 0x12, 0x67,
- 0x7f, 0xb9, 0x39, 0x71, 0x84, 0xe0, 0x30, 0xe6,
- 0x90, 0x6c, 0xcf, 0x32, 0x29, 0x29, 0x5c, 0x5a,
- 0x8b, 0x7d, 0xaa, 0x11, 0x28, 0x26, 0xb5, 0xce,
- 0xd2, 0x88, 0xd5, 0xb0, 0x5f, 0x94, 0x37, 0xa2,
- 0x48, 0xd9, 0x53, 0xb2, 0xab, 0x59, 0x23, 0x3d,
- 0x81, 0x6e, 0x64, 0x89, 0xca, 0x1a, 0x84, 0x16,
- 0xdf, 0x31, 0x10, 0xde, 0x52, 0x7f, 0x50, 0xf3,
- 0xd9, 0x27, 0xa0, 0xe8, 0x34, 0x15, 0x9e, 0x11,
- 0xdd, 0xba, 0xce, 0x40, 0x17, 0xf3, 0x67, 0x14,
- 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
- 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x35, 0xcb, 0x17, 0x66, 0xee, 0xfd,
- 0x27, 0xdb, 0xb8, 0xa8, 0x8a, 0xf1, 0x56, 0x67,
- 0x89, 0x0d, 0x13, 0xac, 0xe2, 0x31, 0xb9, 0xa2,
- 0x26, 0xbb, 0x1c, 0xcf, 0xd1, 0xb2, 0x48, 0x1d,
- 0x0d, 0xb1, 0x17, 0x03, 0x03, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
- 0x89, 0x7c, 0x58, 0x6a, 0x9b, 0x00, 0x05, 0x8c,
- 0x7f, 0x28, 0x54, 0x61, 0x44, 0x10, 0xee, 0x85,
- 0x26, 0xa8, 0x04, 0xcd, 0xca, 0x85, 0x60, 0xf2,
- 0xeb, 0x22, 0xbd, 0x9e, 0x15, 0x03, 0x03, 0x00,
- 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x10, 0xe4, 0xe5, 0xf9, 0x85, 0xe3, 0xb0,
- 0xec, 0x84, 0x29, 0x91, 0x05, 0x7d, 0x86, 0xe3,
- 0x97, 0xeb, 0xb2,
+}
+
+var testECDSAPrivateKey = &ecdsa.PrivateKey{
+ PublicKey: ecdsa.PublicKey{
+ Curve: elliptic.P521(),
+ X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
+ Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
},
+ D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
}
diff --git a/src/pkg/crypto/tls/handshake_test.go b/src/pkg/crypto/tls/handshake_test.go
new file mode 100644
index 000000000..f95f274ab
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_test.go
@@ -0,0 +1,167 @@
+// 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 tls
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// TLS reference tests run a connection against a reference implementation
+// (OpenSSL) of TLS and record the bytes of the resulting connection. The Go
+// code, during a test, is configured with deterministic randomness and so the
+// reference test can be reproduced exactly in the future.
+//
+// In order to save everyone who wishes to run the tests from needing the
+// reference implementation installed, the reference connections are saved in
+// files in the testdata directory. Thus running the tests involves nothing
+// external, but creating and updating them requires the reference
+// implementation.
+//
+// Tests can be updated by running them with the -update flag. This will cause
+// the test files. Generally one should combine the -update flag with -test.run
+// to updated a specific test. Since the reference implementation will always
+// generate fresh random numbers, large parts of the reference connection will
+// always change.
+
+var update = flag.Bool("update", false, "update golden files on disk")
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+ net.Conn
+ sync.Mutex
+ flows [][]byte
+ reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+ if n, err = r.Conn.Read(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || !r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = true
+ return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+ if n, err = r.Conn.Write(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = false
+ return
+}
+
+// WriteTo writes Go source code to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+ // TLS always starts with a client to server flow.
+ clientToServer := true
+
+ for i, flow := range r.flows {
+ source, dest := "client", "server"
+ if !clientToServer {
+ source, dest = dest, source
+ }
+ fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ dumper := hex.Dumper(w)
+ dumper.Write(flow)
+ dumper.Close()
+ clientToServer = !clientToServer
+ }
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+ var currentFlow []byte
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ // If the line starts with ">>> " then it marks the beginning
+ // of a new flow.
+ if strings.HasPrefix(line, ">>> ") {
+ if len(currentFlow) > 0 || len(flows) > 0 {
+ flows = append(flows, currentFlow)
+ currentFlow = nil
+ }
+ continue
+ }
+
+ // Otherwise the line is a line of hex dump that looks like:
+ // 00000170 fc f5 06 bf (...) |.....X{&?......!|
+ // (Some bytes have been omitted from the middle section.)
+
+ if i := strings.IndexByte(line, ' '); i >= 0 {
+ line = line[i:]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ if i := strings.IndexByte(line, '|'); i >= 0 {
+ line = line[:i]
+ } else {
+ return nil, errors.New("invalid test data")
+ }
+
+ hexBytes := strings.Fields(line)
+ for _, hexByte := range hexBytes {
+ val, err := strconv.ParseUint(hexByte, 16, 8)
+ if err != nil {
+ return nil, errors.New("invalid hex byte in test data: " + err.Error())
+ }
+ currentFlow = append(currentFlow, byte(val))
+ }
+ }
+
+ if len(currentFlow) > 0 {
+ flows = append(flows, currentFlow)
+ }
+
+ return flows, nil
+}
+
+// tempFile creates a temp file containing contents and returns its path.
+func tempFile(contents string) string {
+ file, err := ioutil.TempFile("", "go-tls-test")
+ if err != nil {
+ panic("failed to create temp file: " + err.Error())
+ }
+ path := file.Name()
+ file.WriteString(contents)
+ file.Close()
+ return path
+}
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 7e820c1e7..f38b701f1 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -19,6 +19,9 @@ import (
"math/big"
)
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
// rsaKeyAgreement implements the standard TLS key agreement where the client
// encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{}
@@ -35,14 +38,14 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
if len(ckx.ciphertext) < 2 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
ciphertext := ckx.ciphertext
if version != VersionSSL30 {
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
ciphertext = ckx.ciphertext[2:]
}
@@ -61,7 +64,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
- return errors.New("unexpected ServerKeyExchange")
+ return errors.New("tls: unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -138,7 +141,7 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ..
// 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.
+// advertised 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
@@ -160,6 +163,20 @@ func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatu
return 0, errors.New("tls: client doesn't support any common hash functions")
}
+func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+ switch id {
+ case CurveP256:
+ return elliptic.P256(), true
+ case CurveP384:
+ return elliptic.P384(), true
+ case CurveP521:
+ return elliptic.P521(), true
+ default:
+ return nil, false
+ }
+
+}
+
// ecdheRSAKeyAgreement implements a TLS key agreement where the server
// generates a ephemeral EC public/private key pair and signs it. The
// pre-master secret is then calculated using ECDH. The signature may
@@ -173,23 +190,16 @@ type ecdheKeyAgreement struct {
}
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
- var curveid uint16
-
-Curve:
- for _, c := range clientHello.supportedCurves {
- switch c {
- case curveP256:
- ka.curve = elliptic.P256()
- curveid = c
- break Curve
- case curveP384:
- ka.curve = elliptic.P384()
- curveid = c
- break Curve
- case curveP521:
- ka.curve = elliptic.P521()
- curveid = c
- break Curve
+ var curveid CurveID
+ preferredCurves := config.curvePreferences()
+
+NextCandidate:
+ for _, candidate := range preferredCurves {
+ for _, c := range clientHello.supportedCurves {
+ if candidate == c {
+ curveid = c
+ break NextCandidate
+ }
}
}
@@ -197,6 +207,11 @@ Curve:
return nil, errors.New("tls: no supported elliptic curves offered")
}
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return nil, errors.New("tls: preferredCurves includes unsupported curve")
+ }
+
var x, y *big.Int
var err error
ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
@@ -271,11 +286,11 @@ Curve:
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
if x == nil {
- return nil, errors.New("bad ClientKeyExchange")
+ return nil, errClientKeyExchange
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
@@ -285,26 +300,18 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
return preMasterSecret, nil
}
-var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
-
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
if len(skx.key) < 4 {
return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return errors.New("server selected unsupported curve")
+ return errors.New("tls: server selected unsupported curve")
}
- curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
+ curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
- switch curveid {
- case curveP256:
- ka.curve = elliptic.P256()
- case curveP384:
- ka.curve = elliptic.P384()
- case curveP521:
- ka.curve = elliptic.P521()
- default:
- return errors.New("server selected unsupported curve")
+ var ok bool
+ if ka.curve, ok = curveForCurveID(curveid); !ok {
+ return errors.New("tls: server selected unsupported curve")
}
publicLen := int(skx.key[3])
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
new file mode 100644
index 000000000..00722cba9
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,129 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 03 46 |....Y...U..S...F|
+00000010 0f 84 c4 cb 55 ef 85 f6 4f d7 0e e1 4b 10 d4 bb |....U...O...K...|
+00000020 35 87 2d f3 d7 18 ec 4e 95 4b f4 20 28 82 94 d9 |5.-....N.K. (...|
+00000030 df c4 fc ee 21 23 c1 e2 76 3e 7b 09 af 2c 39 23 |....!#..v>{..,9#|
+00000040 f8 46 6c 31 88 42 f0 79 de 37 2b 00 c0 09 00 00 |.Fl1.B.y.7+.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 4f |*............A.O|
+00000280 47 16 72 98 9e 9f 2e 8e 78 e9 0f fe 95 83 7b aa |G.r.....x.....{.|
+00000290 e5 3d c0 7d cf 83 bd 22 0b fd 48 f1 a7 49 a5 7d |.=.}..."..H..I.}|
+000002a0 8e 0c 83 7f e1 2d 71 03 cc 90 09 ab f7 35 81 48 |.....-q......5.H|
+000002b0 a4 1e 7d 87 21 23 12 58 2c 47 f3 af c7 6c 71 00 |..}.!#.X,G...lq.|
+000002c0 8a 30 81 87 02 42 00 b4 03 38 60 43 d9 32 ef 64 |.0...B...8`C.2.d|
+000002d0 5a 9c 91 95 0d 10 21 53 c7 78 f8 bf 50 ed 13 5d |Z.....!S.x..P..]|
+000002e0 c3 e7 71 d6 11 04 f1 e4 9d ce 17 99 8d 1a 87 1f |..q.............|
+000002f0 cb dd f8 1b ae cd bc 4a 77 ab 7c 50 bf 73 c3 ea |.......Jw.|P.s..|
+00000300 d6 df 88 56 f6 b1 03 83 02 41 66 3d fb 4e 7e af |...V.....Af=.N~.|
+00000310 4e c1 60 fe 09 fa 7e 74 99 66 7f de b4 b2 74 89 |N.`...~t.f....t.|
+00000320 1c a4 cf 74 1a 55 a5 be 74 f9 36 21 3d ae c8 c3 |...t.U..t.6!=...|
+00000330 24 8e ad db a3 26 67 8f 98 27 e3 93 ee d9 5c fb |$....&g..'....\.|
+00000340 85 82 e2 13 c3 50 ab e9 f6 39 2b 16 03 01 00 0e |.....P...9+.....|
+00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......|
+>>> Flow 3 (client to server)
+00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
+00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
+00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
+00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
+00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 90 0f |.h.A.Vk.Z.......|
+00000260 00 00 8c 00 8a 30 81 87 02 42 00 c6 85 8e 06 b7 |.....0...B......|
+00000270 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 |.....>.f#..B.d.9|
+00000280 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 |.?.!.(.`kM=..K^w|
+00000290 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 |..Y(...'....3H..|
+000002a0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI|
+000002b0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...|
+000002c0 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......|
+000002d0 67 d0 f2 06 28 4e 51 4e fd f0 01 be 41 3c 52 42 |g...(NQN....A<RB|
+000002e0 10 44 73 88 3e 44 24 bb 2e 77 01 77 6f a8 ac 14 |.Ds.>D$..w.wo...|
+000002f0 03 01 00 01 01 16 03 01 00 30 a3 da 45 22 96 83 |.........0..E"..|
+00000300 59 90 e9 6b ec 3b 77 50 05 89 e6 0c 61 d1 1d 2b |Y..k.;wP....a..+|
+00000310 da d4 49 bf b9 c6 dd ad c3 9c 82 bd 53 62 e8 57 |..I.........Sb.W|
+00000320 a4 6a e7 9f b1 d5 39 77 88 6d |.j....9w.m|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 a4 45 dd 99 df |..........0.E...|
+00000010 66 ae f5 c7 bd 1a eb 6a ff ac a6 38 14 81 b5 07 |f......j...8....|
+00000020 86 24 80 f1 09 59 ad 33 3d 43 ed 9e 43 b1 1e 9f |.$...Y.3=C..C...|
+00000030 bd 8c b3 e0 41 83 a1 34 91 c5 a1 |....A..4...|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 ae e3 ae 7f 2d e3 a2 f7 1b 4e 69 |.... ....-....Ni|
+00000010 cb 18 c6 68 42 f8 de 61 92 4c fa d6 19 7c 8c 09 |...hB..a.L...|..|
+00000020 82 e2 f2 32 19 17 03 01 00 20 2a 77 65 1f c1 fd |...2..... *we...|
+00000030 5e 37 b7 15 f6 1f 4c 7f 5f 89 52 b4 32 27 4d 17 |^7....L._.R.2'M.|
+00000040 33 c6 e8 50 ac 70 c8 b9 2d 0a 15 03 01 00 20 e0 |3..P.p..-..... .|
+00000050 cb ce 07 80 55 a0 46 ca a7 25 4c 5f 9d 7c 73 37 |....U.F..%L_.|s7|
+00000060 de 72 6d 36 a8 e4 be fd 2a e7 f8 8d 14 80 b7 |.rm6....*......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
new file mode 100644
index 000000000..c0be82491
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -0,0 +1,125 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 ed |....Q...M..S....|
+00000010 86 9c 56 84 5a d3 7d d7 f3 4e 6f 2c 69 0d f0 59 |..V.Z.}..No,i..Y|
+00000020 a5 d1 de 2d 03 2f dd 63 c3 ab fa 20 30 d6 5a 24 |...-./.c... 0.Z$|
+00000030 5c 31 67 36 8d 4c 43 e1 64 c4 8a 2c a5 fd 39 92 |\1g6.LC.d..,..9.|
+00000040 c5 6f 58 47 a3 fe 63 14 98 92 11 90 00 05 00 00 |.oXG..c.........|
+00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 0e 0d 00 |n8P)l...........|
+00000320 00 06 03 01 02 40 00 00 0e 00 00 00 |.....@......|
+>>> Flow 3 (client to server)
+00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 3e |..........mQ...>|
+00000220 fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c 8e |.u.A6..j.*.%.gL.|
+00000230 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 1d |b/0......+.#....|
+00000240 f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 0d |.;...'..$...[.f.|
+00000250 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be c8 |j.....C.........|
+00000260 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce e6 |.9L.....K.../...|
+00000270 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 f1 |.w.o#......:..V.|
+00000280 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 35 |.T^F..;3..(....5|
+00000290 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 01 00 90 0f |..C.0oUN.p......|
+000002a0 00 00 8c 00 8a 30 81 87 02 42 00 c6 85 8e 06 b7 |.....0...B......|
+000002b0 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 |.....>.f#..B.d.9|
+000002c0 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 |.?.!.(.`kM=..K^w|
+000002d0 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 |..Y(...'....3H..|
+000002e0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI|
+000002f0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...|
+00000300 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......|
+00000310 67 d0 f2 06 28 4e 51 4e fd f0 01 47 e7 c9 d9 23 |g...(NQN...G...#|
+00000320 21 6b 87 d2 55 e3 c9 f7 eb 86 d5 1e 50 df d5 14 |!k..U.......P...|
+00000330 03 01 00 01 01 16 03 01 00 24 95 62 42 be 90 39 |.........$.bB..9|
+00000340 68 ae f5 77 47 21 14 b9 ac ee 81 2d e3 9e c7 34 |h..wG!.....-...4|
+00000350 3a 00 5c c9 12 1d c0 5a 7c e7 ef e0 cd fd |:.\....Z|.....|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 ea 98 c0 fb 86 |..........$.....|
+00000010 87 7a 2e e1 c7 68 61 3e 5b cc da 1f d6 7b ab 5a |.z...ha>[....{.Z|
+00000020 a0 ae a2 cf d0 54 44 19 12 db 75 2b 8c 73 8c |.....TD...u+.s.|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 1a f3 28 77 31 33 4c b3 7c 4b 75 61 |......(w13L.|Kua|
+00000010 38 69 6b ae c9 36 ab 2e 56 16 29 6a 9a 00 2f 15 |8ik..6..V.)j../.|
+00000020 03 01 00 16 6b ed 68 18 ed ff 44 39 9b 4a e4 a2 |....k.h...D9.J..|
+00000030 cd 79 ef 2a 3e 5a 4d b1 5d 56 |.y.*>ZM.]V|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
new file mode 100644
index 000000000..3e6dbc271
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -0,0 +1,128 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 4f |....Y...U..S...O|
+00000010 73 06 2d 72 41 36 a1 b2 d3 50 97 55 8c c5 f1 43 |s.-rA6...P.U...C|
+00000020 37 1f 1a 2a fe 51 70 0b 2f 25 9e 20 50 61 86 80 |7..*.Qp./%. Pa..|
+00000030 9a 9c 6d 6f c9 ea 5c ce 0c b7 7c ce e3 be d0 e5 |..mo..\...|.....|
+00000040 be d0 c4 80 78 c3 c7 17 0c 2d 8e c8 c0 09 00 00 |....x....-......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 b1 |*............A..|
+00000280 0f 0f 4a 18 ed 25 32 b3 a3 19 ed 4b 61 b6 eb e4 |..J..%2....Ka...|
+00000290 d3 f7 77 13 ac 9f 60 c7 8d 6d cb f1 ee 99 1a 71 |..w...`..m.....q|
+000002a0 68 aa d3 a7 70 7f 38 d0 f6 23 ab 9a f6 dd 19 4f |h...p.8..#.....O|
+000002b0 ce 10 ef d5 cf 64 85 2f 75 f6 20 06 4b f0 b9 00 |.....d./u. .K...|
+000002c0 8b 30 81 88 02 42 01 00 b9 6b 80 91 59 0a 48 3f |.0...B...k..Y.H?|
+000002d0 72 16 96 8f 21 2c 28 e4 6d 03 74 66 35 16 7d ec |r...!,(.m.tf5.}.|
+000002e0 c7 08 9b 52 b5 05 d9 38 d8 b7 51 42 a7 4a 9f 9b |...R...8..QB.J..|
+000002f0 1a 37 14 de c5 f5 16 96 83 81 58 d3 a6 1e ce 8a |.7........X.....|
+00000300 bc 19 47 30 fe c5 85 55 02 42 01 4f 61 59 68 85 |..G0...U.B.OaYh.|
+00000310 c7 64 23 22 f6 83 53 cc 58 38 25 b5 ce 74 c1 68 |.d#"..S.X8%..t.h|
+00000320 9f 32 72 33 ea c9 62 e0 26 63 92 e3 5f 34 10 0b |.2r3..b.&c.._4..|
+00000330 3c d5 83 fe 9f 67 69 ef 33 6b 19 c1 ec d6 6c 35 |<....gi.3k....l5|
+00000340 89 33 17 d3 9d 93 e2 e5 6e 89 9a a1 16 03 01 00 |.3......n.......|
+00000350 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......|
+>>> Flow 3 (client to server)
+00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
+00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
+00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
+00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
+00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
+00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
+00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
+00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
+00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
+000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
+000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
+000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
+000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
+000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
+000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
+00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
+00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
+00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
+00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
+00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
+00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
+00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
+00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
+00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
+00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
+000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
+000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
+000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
+000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
+000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
+000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
+00000200 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......|
+00000250 0f 00 00 82 00 80 20 2c 5a 08 3a 00 33 50 19 b2 |...... ,Z.:.3P..|
+00000260 0f ba 6c 76 7f 5c 92 e2 78 55 3e 32 32 bb 33 bc |..lv.\..xU>22.3.|
+00000270 ab a9 34 e0 83 cf 82 cd 9e 6b 3f 9d e6 49 61 29 |..4......k?..Ia)|
+00000280 8b b4 ed e8 12 cd a9 52 86 11 48 64 08 61 72 8d |.......R..Hd.ar.|
+00000290 d6 6a ac 42 cc e4 07 5f 08 56 9f 2f c5 35 d3 9b |.j.B..._.V./.5..|
+000002a0 e9 0d 91 82 c0 e9 bb 9f a9 8f df 96 85 08 9a 69 |...............i|
+000002b0 a4 93 b3 72 37 ba f9 b1 a4 0b b0 9f 43 6a 15 ec |...r7.......Cj..|
+000002c0 79 b8 fd 9c 1f 5f 0d 2c 56 33 c7 15 d5 4a b7 82 |y...._.,V3...J..|
+000002d0 ea 44 80 20 c5 80 14 03 01 00 01 01 16 03 01 00 |.D. ............|
+000002e0 30 c9 c0 7c d7 57 d3 00 ab 87 eb 78 56 6b a1 69 |0..|.W.....xVk.i|
+000002f0 1d fa ec ae 38 f3 ef 5d 49 19 0d 4b f0 73 63 af |....8..]I..K.sc.|
+00000300 89 b6 cb 76 cf fb b9 c1 99 98 06 0a 54 67 a0 6e |...v........Tg.n|
+00000310 e7 |.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 20 db fd ed ed |..........0 ....|
+00000010 7c d5 bf 8f 06 3b 86 1b c1 60 7d a4 74 e9 a6 c9 ||....;...`}.t...|
+00000020 f5 7c c7 f4 65 91 06 d5 53 88 d7 57 a4 22 b6 1f |.|..e...S..W."..|
+00000030 f1 02 e9 79 36 e6 a1 22 51 3a 4c |...y6.."Q:L|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 00 66 51 6a 14 ca ea e2 21 48 74 |.... .fQj....!Ht|
+00000010 c4 c1 6e b9 8b 23 af 7c 33 c9 00 f8 0b ec ab 35 |..n..#.|3......5|
+00000020 e7 42 0a d1 ae 17 03 01 00 20 00 1c 6d 60 75 5d |.B....... ..m`u]|
+00000030 b3 fb 40 2e e0 b7 0d 48 f4 87 ac d4 bf ea 01 0d |..@....H........|
+00000040 fe 10 0d 05 04 43 6b 19 ed f2 15 03 01 00 20 f8 |.....Ck....... .|
+00000050 03 ac 62 4b 1f db 2e d2 4e 00 c3 a4 57 3c 0a 62 |..bK....N...W<.b|
+00000060 05 a0 ef bd 2b 9b 9a 63 27 72 d7 d8 f1 8d 84 |....+..c'r.....|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
new file mode 100644
index 000000000..94e686004
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -0,0 +1,124 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 73 |....Q...M..S...s|
+00000010 ee 5f 70 a4 aa 0d be d7 46 a3 25 3f e3 5d ef 7b |._p.....F.%?.].{|
+00000020 73 49 7c b6 82 4d 99 2f 31 fc 8b 20 2d a3 33 7c |sI|..M./1.. -.3||
+00000030 a5 c3 85 86 ba 61 4d 05 b0 5e d3 5e 88 6e c3 4b |.....aM..^.^.n.K|
+00000040 95 d3 e9 67 f1 96 24 58 7a 6f e6 c5 00 05 00 00 |...g..$Xzo......|
+00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 0e 0d 00 |n8P)l...........|
+00000320 00 06 03 01 02 40 00 00 0e 00 00 00 |.....@......|
+>>> Flow 3 (client to server)
+00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
+00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
+00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
+00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
+00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
+00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
+00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
+00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
+00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
+000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
+000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
+000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
+000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
+000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
+000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
+00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
+00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
+00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
+00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
+00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
+00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
+00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
+00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
+00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
+00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
+000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
+000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
+000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
+000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
+000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
+000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
+00000200 16 03 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000210 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000220 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000230 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000240 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000250 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V|
+00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....|
+00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 01 00 86 |5..C.0oUN.p.....|
+00000290 0f 00 00 82 00 80 0f 4c d2 b2 f0 94 6d 61 d1 2c |.......L....ma.,|
+000002a0 db 6f 79 03 bd 40 b2 d2 1d 61 ef 83 1b 4a 0c 7b |.oy..@...a...J.{|
+000002b0 c5 73 1e 1a 81 e7 67 0a d6 aa 2d 04 04 cc 0e 4b |.s....g...-....K|
+000002c0 2e da 96 7f 15 6c 05 ee c4 53 7e 33 89 28 7d db |.....l...S~3.(}.|
+000002d0 a1 77 43 ba a3 51 a9 1c b9 f5 ec 9a 8d eb 2c 46 |.wC..Q........,F|
+000002e0 5c 33 59 6b 16 af de f4 9b 80 76 a3 22 30 5d bb |\3Yk......v."0].|
+000002f0 02 b9 77 96 8a db 36 9f 54 95 00 d8 58 e1 aa 04 |..w...6.T...X...|
+00000300 98 c9 0c 32 ae 62 81 12 0c f6 1b 76 c6 58 a7 8c |...2.b.....v.X..|
+00000310 0e d8 b7 8e ed 0f 14 03 01 00 01 01 16 03 01 00 |................|
+00000320 24 1d c0 20 02 2d da 69 54 29 8c ff af 5c 56 a8 |$.. .-.iT)...\V.|
+00000330 eb d0 09 95 29 8f 52 8c e2 7b 9f 36 3e 47 a0 33 |....).R..{.6>G.3|
+00000340 2e 63 a2 24 93 |.c.$.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 99 e8 fb 65 f4 |..........$...e.|
+00000010 95 ae 8b 71 cc 5d a4 95 a7 27 98 fd 16 3f 7a 1a |...q.]...'...?z.|
+00000020 b6 bd bf 0a 58 72 77 97 1f 8e b1 dd 4b 12 12 |....Xrw.....K..|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 1a 42 70 c0 89 78 12 5c 91 7e 88 2d |.....Bp..x.\.~.-|
+00000010 2f 8f be f2 f2 12 9d 81 ae 78 08 38 5e 6d 1b 15 |/........x.8^m..|
+00000020 03 01 00 16 1a 64 b1 6f 8a ff d3 63 6a c7 b8 95 |.....d.o...cj...|
+00000030 3d b0 87 bc 62 e9 88 5b 26 bd |=...b..[&.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..30c4c6b83
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 b2 |....Y...U..S....|
+00000010 e0 f6 f6 b5 c9 5b 28 d0 5d 58 1b 6f 4e 2b 9d 05 |.....[(.]X.oN+..|
+00000020 2a b9 b4 da 45 cf f3 10 b2 23 44 20 f8 4d 59 05 |*...E....#D .MY.|
+00000030 ad 27 f2 a0 ee 7f ec cc 20 dc e7 a2 1b 07 b3 a5 |.'...... .......|
+00000040 37 7e 61 3d d6 5c 03 cf cc f5 9b ca c0 09 00 00 |7~a=.\..........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 da |*............A..|
+00000280 5a fd 09 e5 d6 c0 70 41 5e 3a 87 eb df 0c ad 90 |Z.....pA^:......|
+00000290 22 8a 2f 90 81 0c 24 00 68 92 f3 d5 95 2f 93 43 |"./...$.h..../.C|
+000002a0 e9 58 2d 18 28 62 ee 33 5b 21 2e 49 87 21 4d 32 |.X-.(b.3[!.I.!M2|
+000002b0 32 19 b3 ba fe 2d 9a 85 12 0e a1 77 08 06 75 00 |2....-.....w..u.|
+000002c0 8a 30 81 87 02 42 01 91 14 fc 68 74 95 10 4b d4 |.0...B....ht..K.|
+000002d0 67 60 12 46 bb b0 f6 98 77 a3 41 b8 01 5c 49 54 |g`.F....w.A..\IT|
+000002e0 9e 3e 81 e7 97 a3 b9 73 6e 15 74 67 be e5 d9 eb |.>.....sn.tg....|
+000002f0 8b 87 c5 22 ab ab 58 28 4f d1 b6 80 94 1b f5 f7 |..."..X(O.......|
+00000300 12 43 ef 0a c7 3e 1a 76 02 41 7a 00 49 cb 9f 3b |.C...>.v.Az.I..;|
+00000310 91 6e 38 58 0a d3 d0 d1 ee 67 f0 b6 5d cd fa 23 |.n8X.....g..]..#|
+00000320 b6 98 43 af 9c 71 90 1e 1d 50 a2 6e 61 5b f2 92 |..C..q...P.na[..|
+00000330 b4 69 73 f2 3b 54 bf 1c 9d 05 19 97 e4 4e 41 9e |.is.;T.......NA.|
+00000340 f2 9a 76 77 9a 86 43 1f 1f 30 a2 16 03 01 00 04 |..vw..C..0......|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 01 00 30 88 60 65 b2 d7 51 1f ad 96 56 |.....0.`e..Q...V|
+00000060 4e 0a 20 eb b5 b0 1a dd 4c f6 1a cf d4 5c 47 c4 |N. .....L....\G.|
+00000070 9c 7c a0 36 dd d1 1b 96 91 99 c0 a7 2d 9a 7c 42 |.|.6........-.|B|
+00000080 51 d1 de 87 2b a4 |Q...+.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 86 6c b5 94 69 |..........0.l..i|
+00000010 2e e0 55 a2 4d a8 63 f2 5b 1f ae 34 21 c8 21 6a |..U.M.c.[..4!.!j|
+00000020 00 b6 56 ed 4e 2a b0 ff 01 2f da ce a1 c0 41 03 |..V.N*.../....A.|
+00000030 a9 1b 6e 2e e1 88 50 ba 62 14 88 |..n...P.b..|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 a6 63 0a 2f a5 dc e1 fb cb 7b 1f |.... .c./.....{.|
+00000010 f2 da 74 c3 ff e9 f5 8b 9c 5f 0c d3 f7 1f 44 e6 |..t......_....D.|
+00000020 90 13 5c 48 50 17 03 01 00 20 c7 75 b5 ff bc 09 |..\HP.... .u....|
+00000030 34 f2 45 db 0d 22 08 8e f1 35 cd b6 0f b0 eb 2a |4.E.."...5.....*|
+00000040 b7 1a d0 8e 14 a4 54 84 f9 dc 15 03 01 00 20 e0 |......T....... .|
+00000050 36 3d aa b3 a9 b4 20 23 ca 9e 8c 5d fc a8 c8 b7 |6=.... #...]....|
+00000060 f5 c2 b6 d0 5a e2 ce a5 7b 68 a0 48 86 95 6a |....Z...{h.H..j|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
new file mode 100644
index 000000000..868f0ceb0
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 21 |....Y...U..S...!|
+00000010 67 b5 2b 34 fb 62 d7 36 4f cf 68 2e 29 39 d0 28 |g.+4.b.6O.h.)9.(|
+00000020 3a 02 32 82 8f 95 de 62 d6 03 77 20 e6 98 56 cd |:.2....b..w ..V.|
+00000030 96 24 d1 b9 4d eb 51 19 bb b7 71 f4 9c 29 32 d4 |.$..M.Q...q..)2.|
+00000040 e5 c6 0a 54 e0 4a 20 29 3e bd 06 0d c0 13 00 00 |...T.J )>.......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..|
+00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............|
+00000080 a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
+00000090 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 13 |....0E1.0...U...|
+000000a0 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f |.AU1.0...U....So|
+000000b0 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 |me-State1!0...U.|
+000000c0 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 |...Internet Widg|
+000000d0 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 |its Pty Ltd0...1|
+000000e0 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 31 |00424090938Z..11|
+000000f0 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b 30 |0424090938Z0E1.0|
+00000100 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+00000110 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+00000120 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+00000130 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+00000140 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |td0..0...*.H....|
+00000150 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 bb |........0.......|
+00000160 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 |y......F...i..+.|
+00000170 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c |CZ..-.zC...R..eL|
+00000180 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 |,x.#........;~b.|
+00000190 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b |,.3...\zV.....X{|
+000001a0 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a |&?......!.J..T.Z|
+000001b0 bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 |..Bq......~.}}..|
+000001c0 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf |9....Q.|..L;2f..|
+000001d0 af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 02 |....q.....k..-y.|
+000001e0 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d |.......0..0...U.|
+000001f0 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce |.........Z..(.i.|
+00000200 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d 23 |#i..&...90u..U.#|
+00000210 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 |.n0l......Z..(.i|
+00000220 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 |.#i..&...9.I.G0E|
+00000230 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 |1.0...U....AU1.0|
+00000240 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 |...U....Some-Sta|
+00000250 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 |te1!0...U....Int|
+00000260 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 |ernet Widgits Pt|
+00000270 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca |y Ltd...........|
+00000280 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 0d |0...U....0....0.|
+00000290 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 81 |..*.H...........|
+000002a0 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 |..lE$.k.Y..R....|
+000002b0 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 |...zdu.Z.f..+...|
+000002c0 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 |f..O8.n`....A..%|
+000002d0 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 |...z$.0.........|
+000002e0 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a |1Y....x.PV\..Z-Z|
+000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....|
+00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.|
+00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...|
+00000320 d9 16 03 01 00 cb 0c 00 00 c7 03 00 17 41 04 05 |.............A..|
+00000330 45 33 f8 4b e9 96 0e 4a fd ec 54 76 21 9b 24 8a |E3.K...J..Tv!.$.|
+00000340 75 0b 80 84 c7 30 2b 22 f0 85 57 a4 a9 79 d6 f6 |u....0+"..W..y..|
+00000350 6d 80 b0 71 d9 66 c9 6c dd 76 fc 32 d0 c6 bc 52 |m..q.f.l.v.2...R|
+00000360 2f f1 c9 62 17 53 76 ec be a6 1c 93 f2 b4 5d 00 |/..b.Sv.......].|
+00000370 80 72 d9 20 52 70 7c 03 b1 33 fa 51 23 cd 05 97 |.r. Rp|..3.Q#...|
+00000380 6f d6 89 2f 8d 2e 3a 17 32 eb f2 ff 6b 39 70 5e |o../..:.2...k9p^|
+00000390 21 41 8d 69 02 c8 9a 17 19 e4 48 9b 51 c3 7f 9b |!A.i......H.Q...|
+000003a0 8d 4a 83 97 07 0e 30 f1 8b 6b e9 92 12 01 d6 96 |.J....0..k......|
+000003b0 f2 1a a2 10 7f 59 87 16 1a fb 55 67 68 fc 78 c6 |.....Y....Ugh.x.|
+000003c0 57 ac 05 dd f3 6f 77 84 eb ae b0 33 2d 19 2c ba |W....ow....3-.,.|
+000003d0 b8 ae 9f 95 69 85 95 45 5e 37 f4 17 17 9b 03 c1 |....i..E^7......|
+000003e0 50 b1 36 42 bd 60 5c 8b d8 b6 f3 c8 34 c8 9d 9d |P.6B.`\.....4...|
+000003f0 75 16 03 01 00 04 0e 00 00 00 |u.........|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 01 00 30 ca d1 1b 08 27 9b 44 e7 e9 b4 |.....0....'.D...|
+00000060 90 16 4d 30 4e 65 5c 0d 47 ba 46 86 cf c9 80 e7 |..M0Ne\.G.F.....|
+00000070 64 31 f5 a1 9e dc 39 15 d3 be 16 4f c7 90 b6 62 |d1....9....O...b|
+00000080 5d 6d 7f 41 4e 3e |]m.AN>|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 98 81 24 8e cd |..........0..$..|
+00000010 b6 48 2f 80 de 8e 24 3c cd 02 67 80 34 97 d7 92 |.H/...$<..g.4...|
+00000020 78 c2 44 3d 5d 05 eb 88 76 79 46 7a c3 fa ca 73 |x.D=]...vyFz...s|
+00000030 45 82 ad c1 81 00 ca 40 c1 2f 13 |E......@./.|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 ee 19 59 67 67 a9 8b db 99 87 50 |.... ..Ygg.....P|
+00000010 01 e2 02 c1 d5 6d 36 79 af aa ec 1b 80 0e b6 5e |.....m6y.......^|
+00000020 5f fa 03 01 cc 17 03 01 00 20 ec e2 04 b7 3b a5 |_........ ....;.|
+00000030 f2 e0 13 1f 17 48 e7 6e d3 eb f0 fa 36 ef 6e 2e |.....H.n....6.n.|
+00000040 fb ea c8 39 c4 5f 4b 28 d4 50 15 03 01 00 20 c7 |...9._K(.P.... .|
+00000050 45 ff fb c7 07 0c d8 0e 35 a3 c5 31 47 b7 03 0e |E.......5..1G...|
+00000060 14 c8 29 fd 53 70 5f 15 ac d2 1c 4c 69 fb d6 |..).Sp_....Li..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4
new file mode 100644
index 000000000..395d53bba
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 76 |....Q...M..S...v|
+00000010 e8 45 7f 57 f3 42 4b 33 0b 06 fa a6 fa c4 3d 84 |.E.W.BK3......=.|
+00000020 5a 45 dc 93 41 a5 8d 79 6e 8f 11 20 e7 c6 29 2b |ZE..A..yn.. ..)+|
+00000030 ff 4a 6e 63 67 a6 10 cb 49 19 46 1e 5e 0a d5 70 |.Jncg...I.F.^..p|
+00000040 96 88 9a 32 48 ef c3 4a 45 4c 6d e0 00 05 00 00 |...2H..JELm.....|
+00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V|
+00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....|
+00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 01 00 01 |5..C.0oUN.p.....|
+00000090 01 16 03 01 00 24 cd c0 68 dc 2e 69 cc c7 5b c5 |.....$..h..i..[.|
+000000a0 3f bd 40 cf a0 0f 41 34 ce 16 37 10 26 c8 3f d1 |?.@...A4..7.&.?.|
+000000b0 46 3b ad 7b b0 31 f3 c5 36 e7 |F;.{.1..6.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 ea 77 6f 3c 42 |..........$.wo<B|
+00000010 12 16 51 de e8 b6 f9 85 06 d9 6d 05 75 50 2b 27 |..Q.......m.uP+'|
+00000020 93 b7 6b 65 e9 14 99 48 53 3e be e4 be 03 5d |..ke...HS>....]|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 1a 9e ae ca 55 df c4 d9 47 04 55 dd |........U...G.U.|
+00000010 3b 33 e1 a6 16 6f a1 94 b1 9b 4d 0d cb 6c 3b 15 |;3...o....M..l;.|
+00000020 03 01 00 16 92 5d 76 07 e9 b7 31 29 09 c5 b1 09 |.....]v...1)....|
+00000030 2d 64 3d 85 8d f1 d1 40 54 b8 |-d=....@T.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..9f941f8ef
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 1c |....Y...U..S....|
+00000010 d1 1c 6a 5f 7a 5c 26 69 92 cd ee c3 57 ed 96 90 |..j_z\&i....W...|
+00000020 e3 c5 f1 ee 8b ee 99 5f 46 2c e6 20 c8 50 6a a4 |......._F,. .Pj.|
+00000030 4b 93 e6 da ba 6d d4 87 f6 75 a8 9d 44 db b5 43 |K....m...u..D..C|
+00000040 df 12 57 de a4 f1 bc fb b8 7a 3f 6a c0 09 00 00 |..W......z?j....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 02 00 d4 0c 00 00 d0 03 00 17 41 04 7b |*............A.{|
+00000280 c4 00 37 35 51 de c3 f2 a4 95 2c 19 21 3e a6 94 |..75Q.....,.!>..|
+00000290 7b fd 04 d7 b7 1c 56 e6 af 3c ee 36 cb 55 e6 f0 |{.....V..<.6.U..|
+000002a0 e6 24 34 6b 8a 02 66 71 f9 e2 f5 a6 c9 d7 6c dc |.$4k..fq......l.|
+000002b0 65 59 ff 1c c9 ec a9 8b 07 d6 52 2c 01 3c c3 00 |eY........R,.<..|
+000002c0 89 30 81 86 02 41 74 89 1a 31 72 e6 8b c0 4a ce |.0...At..1r...J.|
+000002d0 8f 5a 49 a7 52 2d 6d b9 8b 50 17 62 2a 99 d6 3b |.ZI.R-m..P.b*..;|
+000002e0 02 85 41 4d 34 53 b5 09 bd e3 ac 16 c1 9b e9 83 |..AM4S..........|
+000002f0 cc 83 e3 9c 23 34 67 71 72 d4 05 a2 34 f7 08 29 |....#4gqr...4..)|
+00000300 62 43 2e cc bc 08 01 02 41 59 de 5a d0 dd d7 6b |bC......AY.Z...k|
+00000310 db 9c 35 29 79 f8 96 91 56 74 1f 18 7b ee 25 83 |..5)y...Vt..{.%.|
+00000320 f2 37 0e 77 ab 38 fb 5e 04 0b 09 d9 b4 1f 3f be |.7.w.8.^......?.|
+00000330 2e e3 60 e3 96 f3 29 c1 6d 8f 56 1b fd 62 14 48 |..`...).m.V..b.H|
+00000340 e3 d9 2a ea 2f be 93 d0 8b 31 16 03 02 00 04 0e |..*./....1......|
+00000350 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
+00000060 00 00 00 00 00 00 b6 98 a2 a9 48 34 12 6b 0a 94 |..........H4.k..|
+00000070 89 fc 38 04 63 5a 6f 63 36 3e d9 35 12 64 8c 28 |..8.cZoc6>.5.d.(|
+00000080 99 a6 cf 2e 57 e3 14 6d 0a 8a ab f0 a6 58 37 7c |....W..m.....X7||
+00000090 96 04 d3 71 bc d4 |...q..|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 40 c5 01 c9 0a b0 |..........@.....|
+00000010 d8 ca 5e c1 19 dc 37 6c 2e a0 b3 11 a8 87 65 5a |..^...7l......eZ|
+00000020 09 41 b9 fe 53 c4 c9 76 97 6d 7f ac c0 be d2 07 |.A..S..v.m......|
+00000030 84 e5 5b 78 37 34 ee da 3b cb 3e 82 52 79 91 44 |..[x74..;.>.Ry.D|
+00000040 b4 e4 1c ec 3a c0 c0 9d cd ff 13 |....:......|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 46 60 13 39 2b 2f 72 95 ed 0e aa |.....F`.9+/r....|
+00000020 69 6e b4 64 3e 83 43 d0 f9 7f 37 7c 1d b9 ce 11 |in.d>.C...7|....|
+00000030 d9 41 66 60 6d 15 03 02 00 30 00 00 00 00 00 00 |.Af`m....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 b1 26 d0 5d 08 98 |...........&.]..|
+00000050 eb 28 42 74 31 58 42 95 c5 ad 1a 92 0a f5 5f ed |.(Bt1XB......._.|
+00000060 45 98 e0 90 e5 a3 b6 8b 8d 18 |E.........|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
new file mode 100644
index 000000000..fc723396a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 fe |....Y...U..S....|
+00000010 17 8b 79 ad 93 2e d3 89 66 9b 5d 9b b4 03 3e ba |..y.....f.]...>.|
+00000020 65 2a f1 55 f9 3c 33 de 2c a7 47 20 fa 4f 82 11 |e*.U.<3.,.G .O..|
+00000030 96 81 d0 70 2e 65 b3 68 2e 3a 6d d7 6c 74 22 33 |...p.e.h.:m.lt"3|
+00000040 d4 ae 6c aa c8 f0 c7 20 8b 10 21 e7 c0 13 00 00 |..l.... ..!.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 02 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..|
+00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............|
+00000080 a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
+00000090 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 13 |....0E1.0...U...|
+000000a0 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f |.AU1.0...U....So|
+000000b0 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 |me-State1!0...U.|
+000000c0 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 |...Internet Widg|
+000000d0 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 |its Pty Ltd0...1|
+000000e0 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 31 |00424090938Z..11|
+000000f0 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b 30 |0424090938Z0E1.0|
+00000100 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+00000110 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+00000120 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+00000130 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+00000140 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |td0..0...*.H....|
+00000150 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 bb |........0.......|
+00000160 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 |y......F...i..+.|
+00000170 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c |CZ..-.zC...R..eL|
+00000180 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 |,x.#........;~b.|
+00000190 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b |,.3...\zV.....X{|
+000001a0 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a |&?......!.J..T.Z|
+000001b0 bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 |..Bq......~.}}..|
+000001c0 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf |9....Q.|..L;2f..|
+000001d0 af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 02 |....q.....k..-y.|
+000001e0 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d |.......0..0...U.|
+000001f0 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce |.........Z..(.i.|
+00000200 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d 23 |#i..&...90u..U.#|
+00000210 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 |.n0l......Z..(.i|
+00000220 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 |.#i..&...9.I.G0E|
+00000230 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 |1.0...U....AU1.0|
+00000240 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 |...U....Some-Sta|
+00000250 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 |te1!0...U....Int|
+00000260 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 |ernet Widgits Pt|
+00000270 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca |y Ltd...........|
+00000280 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 0d |0...U....0....0.|
+00000290 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 81 |..*.H...........|
+000002a0 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 |..lE$.k.Y..R....|
+000002b0 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 |...zdu.Z.f..+...|
+000002c0 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 |f..O8.n`....A..%|
+000002d0 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 |...z$.0.........|
+000002e0 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a |1Y....x.PV\..Z-Z|
+000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....|
+00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.|
+00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...|
+00000320 d9 16 03 02 00 cb 0c 00 00 c7 03 00 17 41 04 26 |.............A.&|
+00000330 56 18 02 e5 66 d4 aa 24 7e ae 39 e5 ca 78 6c c1 |V...f..$~.9..xl.|
+00000340 90 02 c3 c4 ad 79 2c 47 a8 bf 54 e2 8a 22 b6 ef |.....y,G..T.."..|
+00000350 99 d4 7a 7f 8f 78 6a 78 4e 14 2a 16 0d bb 54 38 |..z..xjxN.*...T8|
+00000360 59 1f 7a 53 1b c7 73 10 89 4b de c3 66 39 7a 00 |Y.zS..s..K..f9z.|
+00000370 80 3a 88 38 c8 15 07 ab 2f 0f 0d cb 19 07 84 ac |.:.8..../.......|
+00000380 24 fd 8b d2 9d 05 45 c6 11 c3 d6 84 58 95 5a 08 |$.....E.....X.Z.|
+00000390 b9 a4 2c c0 41 4e 34 e0 b2 24 98 94 b7 67 27 50 |..,.AN4..$...g'P|
+000003a0 ba 82 35 28 a9 bf 16 ee e3 7b 49 9c 4c 81 80 69 |..5(.....{I.L..i|
+000003b0 d7 aa ed 46 ea 9a 68 c4 97 b7 11 d4 35 91 74 5e |...F..h.....5.t^|
+000003c0 54 10 34 83 cd c4 06 18 49 7d 7a 28 c9 53 06 73 |T.4.....I}z(.S.s|
+000003d0 00 7b 04 b6 d8 36 a7 4b 67 7f 81 30 94 de 40 4d |.{...6.Kg..0..@M|
+000003e0 18 f8 c4 b7 02 00 44 8e bc 72 06 24 53 15 74 72 |......D..r.$S.tr|
+000003f0 8d 16 03 02 00 04 0e 00 00 00 |..........|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
+00000060 00 00 00 00 00 00 8a 87 81 38 35 c0 4c bb f8 12 |.........85.L...|
+00000070 fa 75 04 cd 1e 3a 61 96 93 c8 fb 07 d1 6d b4 55 |.u...:a......m.U|
+00000080 0f b5 0f 07 35 0a 96 ce 5c 6f 24 62 d3 68 e4 b0 |....5...\o$b.h..|
+00000090 5d be 81 37 c2 9c |]..7..|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 40 66 36 8d f8 8c |..........@f6...|
+00000010 7f db 38 e8 39 df f8 2f cb 88 9c 14 d9 89 10 b4 |..8.9../........|
+00000020 be 59 88 d7 f3 73 62 af a3 42 66 6e 74 38 64 9f |.Y...sb..Bfnt8d.|
+00000030 16 79 09 d7 14 7e 91 8a 70 73 63 28 30 58 fe cc |.y...~..psc(0X..|
+00000040 42 45 d6 37 fb 9e 8c c1 01 af 34 |BE.7......4|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 31 0b e3 9d 2a 05 83 19 7d 10 36 |.....1...*...}.6|
+00000020 23 dc da fe 00 ab d3 aa 8f ce 28 5f 08 fd b7 59 |#.........(_...Y|
+00000030 1e 00 2e 25 5a 15 03 02 00 30 00 00 00 00 00 00 |...%Z....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 10 91 fd fa 59 07 |..............Y.|
+00000050 df 2c 92 25 15 7b 7c 83 44 89 0d 4f 65 43 99 2e |.,.%.{|.D..OeC..|
+00000060 41 5d 51 c9 09 89 ed 02 08 bc |A]Q.......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4
new file mode 100644
index 000000000..f7be3f7e9
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 51 02 00 00 4d 03 02 53 04 f1 02 d4 |....Q...M..S....|
+00000010 69 65 aa 96 3d 42 96 eb 9e 7d 8a 18 af 4c 7c 5d |ie..=B...}...L|]|
+00000020 fb 97 5f da 94 62 13 69 1f 66 06 20 aa 52 e3 08 |.._..b.i.f. .R..|
+00000030 35 0a 87 d5 ef 93 49 ab 1a 74 dd 90 bd 69 70 d1 |5.....I..t...ip.|
+00000040 e9 f1 44 17 3a dc 33 98 f5 e5 ab 93 00 05 00 00 |..D.:.3.........|
+00000050 05 ff 01 00 01 00 16 03 02 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 02 00 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V|
+00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....|
+00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 02 00 01 |5..C.0oUN.p.....|
+00000090 01 16 03 02 00 24 07 9f dc df 2d c3 a6 88 06 28 |.....$....-....(|
+000000a0 21 e0 e0 d3 31 99 fc 89 b8 82 6e 95 f4 4b 9e e2 |!...1.....n..K..|
+000000b0 d9 36 5c 14 ce d7 db e2 78 4e |.6\.....xN|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 24 81 72 75 80 d4 |..........$.ru..|
+00000010 1b 1a 32 00 89 bf 9e 79 30 b9 6b 67 e0 8e c7 eb |..2....y0.kg....|
+00000020 73 f2 e4 93 51 65 9b 5f 91 b1 b4 b1 f7 44 76 |s...Qe._.....Dv|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 1a b2 91 39 63 c0 38 3c 4d 25 fd 14 |.......9c.8<M%..|
+00000010 b9 b6 e1 23 21 b4 8d 17 9e 1f d8 33 92 69 c2 15 |...#!......3.i..|
+00000020 03 02 00 16 4b 10 25 4d 9d 09 c2 11 96 be f7 5b |....K.%M.......[|
+00000030 c2 9b 99 fd 1f 8e af 0f 2c 51 |........,Q|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
new file mode 100644
index 000000000..207327036
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 03 6f |....Y...U..S...o|
+00000010 c6 4b 55 27 fe e8 fe 4d 7c 0e d4 20 98 b8 7c 81 |.KU'...M|.. ..|.|
+00000020 3d 31 f8 35 66 2f 0a 0b f1 2c e3 20 86 4d 12 32 |=1.5f/...,. .M.2|
+00000030 73 e3 ba be 25 50 a4 a2 a1 7b f1 9a 76 7a 75 fb |s...%P...{..vzu.|
+00000040 e2 64 a2 12 ec f3 e7 9d 9a 24 6e 94 c0 09 00 00 |.d.......$n.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 a3 |*............A..|
+00000280 03 8c de d2 b0 68 c8 25 0e 85 ea d7 ae 13 0d 79 |.....h.%.......y|
+00000290 ec 59 0d b5 4d 51 96 d9 7f 64 36 fb 4c d5 6a 26 |.Y..MQ...d6.L.j&|
+000002a0 ae 0e 48 61 df 5c 2b d4 ff 09 41 15 c4 14 8e 1b |..Ha.\+...A.....|
+000002b0 84 a8 c8 cd ef 10 97 95 66 67 85 dd fd dc 2a 04 |........fg....*.|
+000002c0 03 00 8a 30 81 87 02 41 11 75 5d bc bd 08 28 d4 |...0...A.u]...(.|
+000002d0 5b 1b 45 7f 9c d3 8d 0b 91 fa f6 82 ba 59 bd 3e |[.E..........Y.>|
+000002e0 96 01 c6 1d 38 db fe 08 e7 56 89 fc 10 b0 37 6a |....8....V....7j|
+000002f0 3d d6 c9 50 16 53 f7 c2 a2 60 67 82 1f 74 b8 d5 |=..P.S...`g..t..|
+00000300 bc 02 ec 96 db 82 18 8c 87 02 42 01 0d df f7 b7 |..........B.....|
+00000310 05 3c 8c 56 f0 1d 33 18 cf c5 4c 80 7e 0b d9 f9 |.<.V..3...L.~...|
+00000320 f0 51 69 fe 5d b8 0b 64 c0 c7 0d f4 75 65 ae 07 |.Qi.]..d....ue..|
+00000330 9d cf f4 4b ad 52 f6 b8 10 26 18 bd d6 e2 0d a8 |...K.R...&......|
+00000340 80 10 50 34 15 cd 72 0b 7d a9 94 de 4c 16 03 03 |..P4..r.}...L...|
+00000350 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 02 |.0...(...@. ....|
+00000360 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000370 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e 00 |................|
+00000380 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
+00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
+00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
+00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
+00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 92 0f |.h.A.Vk.Z.......|
+00000260 00 00 8e 04 03 00 8a 30 81 87 02 42 00 c6 85 8e |.......0...B....|
+00000270 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 |.......>.f#..B.d|
+00000280 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b |.9.?.!.(.`kM=..K|
+00000290 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 |^w..Y(...'....3H|
+000002a0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A|
+000002b0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.|
+000002c0 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....|
+000002d0 88 0d 64 db 8e 4f 73 4e ea 29 0b ed a0 f5 ce 3d |..d..OsN.).....=|
+000002e0 5f cc 20 ef 0a 22 02 82 f2 14 2a b7 42 68 bd c7 |_. .."....*.Bh..|
+000002f0 4d 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |M..........@....|
+00000300 00 00 00 00 00 00 00 00 00 00 00 00 f0 cc 4f c7 |..............O.|
+00000310 b6 0f c9 38 4d 4b 97 2c 4f be 53 08 4c d6 5b 4e |...8MK.,O.S.L.[N|
+00000320 24 70 30 81 82 3a 7f 62 95 03 4d fc 54 78 ec 13 |$p0..:.b..M.Tx..|
+00000330 b2 a1 00 85 2b 04 e4 1d 7b 6e 87 60 |....+...{n.`|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 d5 2a 76 79 1c |..........@.*vy.|
+00000010 e7 d5 b1 5c 65 6b d1 45 73 53 4c 05 3a 6c 5d 81 |...\ek.EsSL.:l].|
+00000020 dd 2f f0 74 62 e4 8e f8 ed 21 99 c7 4f d6 28 40 |./.tb....!..O.(@|
+00000030 63 d9 6d e5 b0 04 73 27 7a 1d 08 19 31 10 da ef |c.m...s'z...1...|
+00000040 79 26 33 fb 45 23 be a4 7c 03 66 |y&3.E#..|.f|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 e2 53 bd c0 ef 9e e6 44 94 ea 5d |......S.....D..]|
+00000020 f5 c5 a9 4b ed eb 1c 49 9f 79 44 f9 cd d7 de 02 |...K...I.yD.....|
+00000030 51 10 ae 87 7d 15 03 03 00 30 00 00 00 00 00 00 |Q...}....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 d3 95 13 7f 5f 58 |.............._X|
+00000050 ab d6 17 ea 01 2c 2a ea 5d 7c 44 61 4a 27 97 52 |.....,*.]|DaJ'.R|
+00000060 cc 9b 86 f6 37 42 2b 94 01 49 |....7B+..I|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
new file mode 100644
index 000000000..c3b753a7b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -0,0 +1,127 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 03 b0 |....Q...M..S....|
+00000010 43 00 97 24 a7 a8 ea b2 24 fe 96 24 a1 49 64 fd |C..$....$..$.Id.|
+00000020 1c a3 30 35 2d 85 a7 40 42 86 6b 20 af 27 7f ac |..05-..@B.k .'..|
+00000030 8b 16 89 6c 78 b7 f5 29 02 58 a6 8b 61 43 c2 b0 |...lx..).X..aC..|
+00000040 e0 a8 96 c8 fa 2b 26 ad 9a 5f 2d d6 00 05 00 00 |.....+&.._-.....|
+00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 30 0d 00 |n8P)l........0..|
+00000320 00 28 03 01 02 40 00 20 06 01 06 02 06 03 05 01 |.(...@. ........|
+00000330 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+00000340 02 01 02 02 02 03 01 01 00 00 0e 00 00 00 |..............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 3e |..........mQ...>|
+00000220 fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c 8e |.u.A6..j.*.%.gL.|
+00000230 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 1d |b/0......+.#....|
+00000240 f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 0d |.;...'..$...[.f.|
+00000250 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be c8 |j.....C.........|
+00000260 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce e6 |.9L.....K.../...|
+00000270 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 f1 |.w.o#......:..V.|
+00000280 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 35 |.T^F..;3..(....5|
+00000290 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 03 00 92 0f |..C.0oUN.p......|
+000002a0 00 00 8e 04 03 00 8a 30 81 87 02 42 00 c6 85 8e |.......0...B....|
+000002b0 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 |.......>.f#..B.d|
+000002c0 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b |.9.?.!.(.`kM=..K|
+000002d0 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 |^w..Y(...'....3H|
+000002e0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A|
+000002f0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.|
+00000300 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....|
+00000310 88 5a 97 82 3e 55 6b 7c d8 db b8 cc 1b 30 84 0a |.Z..>Uk|.....0..|
+00000320 7a 97 71 e4 10 bb a4 39 8c 2a cf f5 88 c7 d1 95 |z.q....9.*......|
+00000330 73 14 03 03 00 01 01 16 03 03 00 24 9f 1e f0 72 |s..........$...r|
+00000340 92 ea dc f7 56 96 37 e4 69 db db 66 1d f6 94 c4 |....V.7.i..f....|
+00000350 18 31 4f d0 5d c5 f4 53 21 aa 98 b1 dc 08 94 94 |.1O.]..S!.......|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 ee 68 c1 87 9f |..........$.h...|
+00000010 d7 90 94 f1 3b 6d 26 0b 3d 89 7a 45 3b 52 5d 3c |....;m&.=.zE;R]<|
+00000020 dd 7c c1 4e 57 3e a9 ee 91 be cf 2b a3 98 9d |.|.NW>.....+...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1a 88 33 3e 2b 22 6b 92 d0 bb 8a 1e |......3>+"k.....|
+00000010 9b f4 9e aa 91 8b 2b 95 ea 53 c8 03 0a 93 58 15 |......+..S....X.|
+00000020 03 03 00 16 c4 67 79 ba ec cf 90 b1 f9 ac ec 64 |.....gy........d|
+00000030 72 01 08 8f 3a 98 aa 66 25 00 |r...:..f%.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
new file mode 100644
index 000000000..0037af61a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -0,0 +1,133 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 fd |....Y...U..S....|
+00000010 41 bd ef ee f3 da fc 1a 31 8c 77 f2 e9 66 54 a0 |A.......1.w..fT.|
+00000020 f4 15 b1 1c 84 0d 6d 74 87 ac 7d 20 78 17 8b 08 |......mt..} x...|
+00000030 10 20 c9 44 e4 8a 43 af 4a c7 b8 3d 99 f2 f7 af |. .D..C.J..=....|
+00000040 bb a3 21 2f 40 cc ed b6 da a8 a1 d5 c0 09 00 00 |..!/@...........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 a9 |*............A..|
+00000280 19 8b d9 9b 5c 7c 6a 7d 85 d2 70 4e 89 7e 0b 5b |....\|j}..pN.~.[|
+00000290 dd 5e a1 63 8d 15 bc 0b 0c 47 3d 4d e8 a7 56 88 |.^.c.....G=M..V.|
+000002a0 2e f6 7f e2 4d fc ed cc 03 ed a1 2d ac ae 81 a5 |....M......-....|
+000002b0 e2 6d 7f 9f a3 93 e9 10 c1 0e 48 1b f3 f4 38 04 |.m........H...8.|
+000002c0 03 00 8b 30 81 88 02 42 00 87 fe 7e 63 82 14 57 |...0...B...~c..W|
+000002d0 dc 7d e2 0f cc 97 2d ba 3c a7 56 4a 17 a8 09 6a |.}....-.<.VJ...j|
+000002e0 28 2e f2 66 1a 3f 2d 48 2b 6f 79 a1 60 cd 5e 10 |(..f.?-H+oy.`.^.|
+000002f0 0b 0a 28 f2 5f e4 3f 4f f9 c9 91 34 d9 dc bc fc |..(._.?O...4....|
+00000300 98 ea 77 0b 99 f8 a2 11 c4 bd 02 42 01 a0 b0 dc |..w........B....|
+00000310 db 5b c2 09 99 bd ee a0 b9 aa 31 b9 10 84 22 be |.[........1...".|
+00000320 5a 63 12 5a 43 00 8e c1 33 cc 91 bb c2 70 7a 63 |Zc.ZC...3....pzc|
+00000330 19 82 c0 74 48 a1 c7 3d 1f f1 6f 4a 6f 6a 8c 3f |...tH..=..oJoj.?|
+00000340 28 31 a8 0c 65 19 26 62 4b 7a 7c 4b ea 1a 16 03 |(1..e.&bKz|K....|
+00000350 03 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 |..0...(...@. ...|
+00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
+00000370 01 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e |................|
+00000380 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
+00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
+00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
+00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
+00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
+00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
+00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
+00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
+00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
+000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
+000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
+000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
+000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
+000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
+000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
+00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
+00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
+00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
+00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
+00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
+00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
+00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
+00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
+00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
+00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
+000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
+000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
+000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
+000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
+000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
+000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
+00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......|
+00000250 0f 00 00 84 04 01 00 80 38 f2 16 e5 b5 86 16 62 |........8......b|
+00000260 86 e1 7d 01 f1 a8 e1 f7 e7 85 b1 a0 17 ee 84 25 |..}............%|
+00000270 cb 3c 46 61 1a 78 7b 1e ee 32 bc d9 6c fa 6b 76 |.<Fa.x{..2..l.kv|
+00000280 67 a7 9e c8 7a 4c e8 79 0d 22 27 ad e7 98 6a 98 |g...zL.y."'...j.|
+00000290 89 88 8b a9 69 5b 6f c6 00 48 9a 21 77 a9 7c 15 |....i[o..H.!w.|.|
+000002a0 ba 47 16 74 8d 6c 67 dc 6d f1 98 b6 61 e8 bc 08 |.G.t.lg.m...a...|
+000002b0 18 53 a6 93 bf fc 27 5e b7 4d d2 eb 68 e9 23 ee |.S....'^.M..h.#.|
+000002c0 d2 70 d2 55 2c c7 99 7d c0 66 b5 1c ea 38 71 5c |.p.U,..}.f...8q\|
+000002d0 a6 57 1f 52 e4 8e e8 51 14 03 03 00 01 01 16 03 |.W.R...Q........|
+000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............|
+000002f0 00 00 00 5e e7 6e 1c a2 02 24 34 f0 a6 b6 27 ea |...^.n...$4...'.|
+00000300 69 d5 0e 2e a8 ad 5c ad 6c 06 78 68 39 92 27 f1 |i.....\.l.xh9.'.|
+00000310 e8 35 49 67 4d fb 5d 8a 31 2e 4e 3f 19 ed ea 30 |.5IgM.].1.N?...0|
+00000320 20 60 e1 | `.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 ee a8 82 bc 3f |..........@....?|
+00000010 bf ab a6 e4 30 e0 3d f1 2f 19 a2 ac 7a 81 57 f1 |....0.=./...z.W.|
+00000020 ee 67 3f 55 2b 30 fa 72 b5 10 03 ec 8d 0a 8f bb |.g?U+0.r........|
+00000030 24 f5 45 f5 4e 53 4b 93 a5 0d 42 6c 46 69 98 fb |$.E.NSK...BlFi..|
+00000040 63 c5 9f 95 65 d1 b6 f0 a4 15 bd |c...e......|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 cb 4e bc d1 a9 58 ef c8 39 a9 36 |......N...X..9.6|
+00000020 f4 35 05 96 8e a4 50 bc f4 15 06 f9 fd 41 6d 1e |.5....P......Am.|
+00000030 5e 7c 82 63 94 15 03 03 00 30 00 00 00 00 00 00 |^|.c.....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 bd 77 87 a5 5a d4 |...........w..Z.|
+00000050 b8 59 e6 6b 0f dd ea f9 ed 18 b2 9f a9 61 b4 3a |.Y.k.........a.:|
+00000060 47 15 15 3b 83 ef e1 6d db a8 |G..;...m..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
new file mode 100644
index 000000000..df3eaa440
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -0,0 +1,126 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 1d |....Q...M..S....|
+00000010 0e dc 86 e5 a9 07 71 46 15 34 af 47 15 3f 03 9c |......qF.4.G.?..|
+00000020 fc d6 fd 44 7c f4 f1 c7 8d 6f f8 20 28 ea 3c dc |...D|....o. (.<.|
+00000030 b2 4c b7 ba 20 88 c4 db a5 73 ea 93 ab 3a 85 a6 |.L.. ....s...:..|
+00000040 8f 59 49 d9 a9 31 14 d5 a6 2b 4f d1 00 05 00 00 |.YI..1...+O.....|
+00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 30 0d 00 |n8P)l........0..|
+00000320 00 28 03 01 02 40 00 20 06 01 06 02 06 03 05 01 |.(...@. ........|
+00000330 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+00000340 02 01 02 02 02 03 01 01 00 00 0e 00 00 00 |..............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
+00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
+00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
+00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
+00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
+00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
+00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
+00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
+00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
+000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
+000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
+000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
+000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
+000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
+000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
+00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
+00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
+00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
+00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
+00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
+00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
+00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
+00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
+00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
+00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
+000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
+000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
+000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
+000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
+000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
+000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
+00000200 16 03 03 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000210 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000220 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000230 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000240 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000250 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V|
+00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....|
+00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 03 00 88 |5..C.0oUN.p.....|
+00000290 0f 00 00 84 04 01 00 80 2a 1f ae 48 9f 86 16 dc |........*..H....|
+000002a0 c2 55 1f 5f 95 81 ed 56 00 5d 35 46 e5 b6 57 d5 |.U._...V.]5F..W.|
+000002b0 a6 3e 32 38 8b e2 c6 1c b9 b1 38 b2 da 66 45 ed |.>28......8..fE.|
+000002c0 58 6a 7f 43 41 93 a5 09 da b9 04 ce 3f 13 8a 19 |Xj.CA.......?...|
+000002d0 13 e9 2c 1f c5 e7 35 b4 2d ea 7c 81 90 33 c0 66 |..,...5.-.|..3.f|
+000002e0 dc 41 8b 23 08 8f 69 d4 d6 a2 5f c1 bd 26 e6 2e |.A.#..i..._..&..|
+000002f0 7f c8 7c a8 2d d4 08 95 ce 6e 58 54 04 a2 a6 63 |..|.-....nXT...c|
+00000300 54 72 67 f2 7f 61 0a 6b 58 46 d4 88 95 38 37 f2 |Trg..a.kXF...87.|
+00000310 93 95 48 56 14 a7 b9 7c 14 03 03 00 01 01 16 03 |..HV...|........|
+00000320 03 00 24 64 bb 41 3a cb a2 2f 95 53 5c 2f f7 83 |..$d.A:../.S\/..|
+00000330 a2 35 18 f6 d0 8d 6f e2 54 ed 2f 07 10 f4 36 e2 |.5....o.T./...6.|
+00000340 3d e5 30 1d e3 63 01 |=.0..c.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 0a 22 b6 bc da |..........$."...|
+00000010 34 38 53 8e 80 e2 25 7b 31 2f 70 8e 3a db e8 a3 |48S...%{1/p.:...|
+00000020 70 0e 88 22 b4 a8 be d4 a3 e3 cc 13 94 ef 47 |p.."..........G|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1a b4 9c b1 57 ea 01 03 fe 01 e7 1e |........W.......|
+00000010 c4 a7 0f 25 14 99 00 4f 88 51 c1 98 6e 99 01 15 |...%...O.Q..n...|
+00000020 03 03 00 16 2e c4 11 8b 1a fc 37 81 18 33 e4 9f |..........7..3..|
+00000030 48 a3 29 e3 ad 9b 9b ec 9f 99 |H.).......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..76445903b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 a0 |....Y...U..S....|
+00000010 5f bd a4 8d 98 93 b8 da 08 86 9f b2 be 9a a4 91 |_...............|
+00000020 2b 3c 1f 18 f0 75 7c a9 a8 a0 f7 20 4a 89 9a d2 |+<...u|.... J...|
+00000030 34 3b d9 b1 c2 fd 61 bd 97 19 22 ce b9 d1 5b a7 |4;....a..."...[.|
+00000040 83 80 9c 19 d0 f5 a0 aa 4c ac 06 20 c0 09 00 00 |........L.. ....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3c |*............A.<|
+00000280 8f 35 1e 47 5d 7b ad 13 0c e9 5c c0 97 c7 83 06 |.5.G]{....\.....|
+00000290 49 0f 6c cf e5 4d 3b ed f7 1b c6 96 8d ba 54 35 |I.l..M;.......T5|
+000002a0 7f df 35 e3 6e 28 e9 71 f2 24 b5 ab 17 2b 4b 2b |..5.n(.q.$...+K+|
+000002b0 0c 8f 9f 48 89 73 8f 09 69 84 af 7f ec 43 7a 04 |...H.s..i....Cz.|
+000002c0 03 00 8a 30 81 87 02 41 79 84 43 0c 78 fa 7e e2 |...0...Ay.C.x.~.|
+000002d0 c5 51 c1 60 88 c4 4a 59 7d 02 fa dc 19 68 33 ed |.Q.`..JY}....h3.|
+000002e0 19 ef a1 df ef 6b 21 a6 98 aa ba a9 13 70 91 0f |.....k!......p..|
+000002f0 cc 6c 5c 1e 99 53 1b 42 51 6c 06 a7 3c c4 04 22 |.l\..S.BQl..<.."|
+00000300 5d 0d c1 30 ab e3 ec b4 54 02 42 01 15 15 1a 6e |]..0....T.B....n|
+00000310 6f f1 c6 b1 10 84 2c c8 04 de 2b 52 d5 b4 f7 c9 |o.....,...+R....|
+00000320 4f 6d 0e 0e 26 45 1d 7a 28 59 2b 8b f6 92 3a 23 |Om..&E.z(Y+...:#|
+00000330 7a 39 9c d5 4e cc 5d c5 45 92 9c d0 5f 33 12 e3 |z9..N.].E..._3..|
+00000340 2b 29 39 52 bb 16 aa e1 72 9e b5 fe 99 16 03 03 |+)9R....r.......|
+00000350 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
+00000060 00 00 00 00 00 00 20 a3 f8 5a e2 ea f3 09 19 3e |...... ..Z.....>|
+00000070 4a 54 69 70 06 5b 17 35 0f ed e7 30 3b 6f eb a1 |JTip.[.5...0;o..|
+00000080 cb 9c 35 81 10 2e 34 f7 12 a5 e4 63 20 b2 65 31 |..5...4....c .e1|
+00000090 19 da 30 43 39 59 |..0C9Y|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 8d 4d 31 07 df |..........@.M1..|
+00000010 ab 41 f5 19 9c 1a 57 fc 33 ab 5f e6 bd 45 b9 fa |.A....W.3._..E..|
+00000020 7f db c0 df 72 f2 3b ef aa d4 5e 34 e6 3d 44 7c |....r.;...^4.=D||
+00000030 12 05 c7 57 da 54 b1 e3 66 f0 0a ab cd 15 a5 bf |...W.T..f.......|
+00000040 c5 c2 07 a9 d9 a7 2e 5e 29 da da |.......^)..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 dc 03 7b 29 2c 49 64 58 2d dc f7 |.......{),IdX-..|
+00000020 26 a1 3b ec 2d e8 30 c4 6c a3 ff e2 bc b5 a4 a6 |&.;.-.0.l.......|
+00000030 93 ce 14 bd da 15 03 03 00 30 00 00 00 00 00 00 |.........0......|
+00000040 00 00 00 00 00 00 00 00 00 00 a6 77 10 30 15 eb |...........w.0..|
+00000050 ed cf 73 5b 74 5d 09 52 4a 5b e2 f0 e4 67 f8 7a |..s[t].RJ[...g.z|
+00000060 5e 5e fc ba 7f 80 0a d2 f4 fb |^^........|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
new file mode 100644
index 000000000..fb5af17f0
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 48 |....Y...U..S...H|
+00000010 03 36 01 05 56 6f f0 54 d2 c3 d3 41 c2 e2 69 7b |.6..Vo.T...A..i{|
+00000020 50 f8 03 ef 3f 5d 7c e6 9c cb fe 20 82 a0 81 fd |P...?]|.... ....|
+00000030 72 4b b8 e6 29 76 3b 0f 1d 0a b7 82 9d 0b cf a0 |rK..)v;.........|
+00000040 65 b1 56 53 c9 d5 58 7b f0 b6 2d cf c0 2b 00 00 |e.VS..X{..-..+..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 86 |*............A..|
+00000280 36 b4 78 76 87 70 ed ae 0d 34 70 3d 16 e5 a4 db |6.xv.p...4p=....|
+00000290 ae 28 58 4c 01 5a 56 73 a7 0d 34 59 a7 04 75 69 |.(XL.ZVs..4Y..ui|
+000002a0 f2 55 24 40 b0 33 c6 93 ff ae e0 14 f5 4b ce a8 |.U$@.3.......K..|
+000002b0 e2 e6 9a 67 1d 66 fb 8f fd 56 59 e7 73 f2 2c 04 |...g.f...VY.s.,.|
+000002c0 03 00 8a 30 81 87 02 41 73 ab a8 3c 64 17 69 9f |...0...As..<d.i.|
+000002d0 4d b2 9b 55 12 60 33 94 cf f3 83 40 2b 7b 1b af |M..U.`3....@+{..|
+000002e0 5c f4 cd 02 66 fb 83 04 35 fd ab 74 98 1a 7d f6 |\...f...5..t..}.|
+000002f0 9e 50 98 c3 98 e8 56 9c f2 2a b0 30 9d 05 14 58 |.P....V..*.0...X|
+00000300 68 6a 88 04 49 07 78 bf 3a 02 42 01 be b2 05 9e |hj..I.x.:.B.....|
+00000310 67 da 1e e9 5a 36 98 52 21 9f 43 75 43 ba bb 9a |g...Z6.R!.CuC...|
+00000320 e6 e2 65 f4 e0 44 45 08 5a 1e 54 06 dd 5f 60 2e |..e..DE.Z.T.._`.|
+00000330 7d e7 55 08 d3 7b 4e 0a c7 da d4 27 34 d4 bd b0 |}.U..{N....'4...|
+00000340 12 2f 41 7a ed 71 32 ef ee 12 74 66 00 16 03 03 |./Az.q2...tf....|
+00000350 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 87 7a |.....(.........z|
+00000060 82 d7 46 25 1d a6 bb c2 a8 a8 4e a5 d1 f8 02 db |..F%......N.....|
+00000070 33 33 ca 78 b6 d3 bd 77 8a 33 23 a7 95 fb |33.x...w.3#...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 ce a1 9d 01 c0 |..........(.....|
+00000010 31 e5 d5 57 16 e1 a6 b3 8b 25 58 0f fa 2a de 3e |1..W.....%X..*.>|
+00000020 0c d9 06 11 a6 b0 d7 b0 33 ad 31 73 5b 26 b4 d2 |........3.1s[&..|
+00000030 12 56 c8 |.V.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d5 04 4c |...............L|
+00000010 7b 35 b4 d7 90 ae fe 00 d2 f2 4b 76 f1 36 5e 24 |{5........Kv.6^$|
+00000020 4a aa 94 15 03 03 00 1a 00 00 00 00 00 00 00 02 |J...............|
+00000030 d3 1c 41 37 ab f6 17 79 f0 01 a4 19 a5 75 7a 8e |..A7...y.....uz.|
+00000040 a3 b2 |..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
new file mode 100644
index 000000000..5336bbbad
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 41 |....Y...U..S...A|
+00000010 95 cc 56 30 65 46 24 75 d5 9e 3c a7 5b 6c 99 fe |..V0eF$u..<.[l..|
+00000020 86 35 23 42 3a 8f 4d 4c b9 98 7d 20 a7 46 43 72 |.5#B:.ML..} .FCr|
+00000030 66 bb b6 ad ff ad cf 63 37 fe 6b b4 78 94 08 49 |f......c7.k.x..I|
+00000040 54 06 ed f4 85 73 38 4a c6 fe b6 98 c0 13 00 00 |T....s8J........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..|
+00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............|
+00000080 a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
+00000090 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 13 |....0E1.0...U...|
+000000a0 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f |.AU1.0...U....So|
+000000b0 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 |me-State1!0...U.|
+000000c0 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 |...Internet Widg|
+000000d0 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 |its Pty Ltd0...1|
+000000e0 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 31 |00424090938Z..11|
+000000f0 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b 30 |0424090938Z0E1.0|
+00000100 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+00000110 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+00000120 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+00000130 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+00000140 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |td0..0...*.H....|
+00000150 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 bb |........0.......|
+00000160 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 |y......F...i..+.|
+00000170 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c |CZ..-.zC...R..eL|
+00000180 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 |,x.#........;~b.|
+00000190 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b |,.3...\zV.....X{|
+000001a0 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a |&?......!.J..T.Z|
+000001b0 bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 |..Bq......~.}}..|
+000001c0 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf |9....Q.|..L;2f..|
+000001d0 af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 02 |....q.....k..-y.|
+000001e0 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d |.......0..0...U.|
+000001f0 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce |.........Z..(.i.|
+00000200 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d 23 |#i..&...90u..U.#|
+00000210 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 |.n0l......Z..(.i|
+00000220 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 |.#i..&...9.I.G0E|
+00000230 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 |1.0...U....AU1.0|
+00000240 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 |...U....Some-Sta|
+00000250 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 |te1!0...U....Int|
+00000260 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 |ernet Widgits Pt|
+00000270 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca |y Ltd...........|
+00000280 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 0d |0...U....0....0.|
+00000290 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 81 |..*.H...........|
+000002a0 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 |..lE$.k.Y..R....|
+000002b0 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 |...zdu.Z.f..+...|
+000002c0 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 |f..O8.n`....A..%|
+000002d0 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 |...z$.0.........|
+000002e0 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a |1Y....x.PV\..Z-Z|
+000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....|
+00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.|
+00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...|
+00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 48 |.............A.H|
+00000330 68 d8 8a 10 b4 bf eb 8d d1 98 b0 a6 f4 47 5d 91 |h............G].|
+00000340 61 da 50 d9 85 7b 5d 90 02 2c 38 c9 af 81 d3 55 |a.P..{]..,8....U|
+00000350 07 62 b1 62 58 7f 39 94 d7 91 96 a8 1f 47 60 a5 |.b.bX.9......G`.|
+00000360 c0 04 f2 fb cb 15 75 a6 16 3f 94 53 7c ff dd 04 |......u..?.S|...|
+00000370 01 00 80 b9 82 fa 0b f8 8c 94 2c 6e 05 81 7d 80 |..........,n..}.|
+00000380 5d 9a 77 78 af c8 33 5d 89 7e 2e 3c e5 72 66 a8 |].wx..3].~.<.rf.|
+00000390 f1 5c 02 04 02 70 76 7b 45 ff 0d 29 a0 cb 0d db |.\...pv{E..)....|
+000003a0 7a 4c c4 13 19 cd 47 b2 f1 c9 43 4f 95 d2 f1 c6 |zL....G...CO....|
+000003b0 bc ae 31 4a 9d de 80 b2 a4 b7 b6 dd 8c 03 3e 2a |..1J..........>*|
+000003c0 46 5e d1 e7 5b c5 9e 06 58 f3 55 b2 77 09 f3 98 |F^..[...X.U.w...|
+000003d0 d5 7f 5a 74 64 7e 48 22 8f 7d a8 68 b6 1d 90 df |..Ztd~H".}.h....|
+000003e0 2c 91 d7 c5 07 3d d1 6f e9 c1 91 03 3c 23 5a 56 |,....=.o....<#ZV|
+000003f0 3b b2 c2 16 03 03 00 04 0e 00 00 00 |;...........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
+00000060 00 00 00 00 00 00 59 e6 92 05 27 ec 09 2c b0 a5 |......Y...'..,..|
+00000070 2a fb 7e f1 03 53 16 63 68 a1 86 13 bb da 98 27 |*.~..S.ch......'|
+00000080 6d 42 08 35 6a ec 58 61 2a 4d 44 ec ae c5 b9 d2 |mB.5j.Xa*MD.....|
+00000090 76 57 1f 75 9f 8d |vW.u..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 6e 03 d0 e6 98 |..........@n....|
+00000010 1f f5 39 7b 06 9f 95 f0 7a 88 35 7c 55 db c3 2f |..9{....z.5|U../|
+00000020 00 ef 5b d3 62 87 a2 94 da 2f f6 4a 89 c9 a8 3d |..[.b..../.J...=|
+00000030 3a 92 db 77 35 92 01 4b f5 c5 6b 95 09 9f cd 79 |:..w5..K..k....y|
+00000040 3c af 37 5b 27 bf 93 3e 04 55 71 |<.7['..>.Uq|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 bc c9 d0 8e 80 14 de 32 18 49 e8 |............2.I.|
+00000020 20 dc 5e 6c e4 6d 14 00 df 51 71 fb 86 95 16 4c | .^l.m...Qq....L|
+00000030 04 8e 71 e1 48 15 03 03 00 30 00 00 00 00 00 00 |..q.H....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 b7 6d 30 72 61 53 |...........m0raS|
+00000050 d8 0a d4 1d ae e5 d4 22 46 c9 d5 4e 4a 86 f5 ac |......."F..NJ...|
+00000060 72 98 c6 db 38 29 97 2c 84 0b |r...8).,..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4
new file mode 100644
index 000000000..0377f052a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../|
+00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............|
+00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............|
+00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................|
+00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................|
+00000070 03 02 01 02 03 ff 01 00 01 00 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 9d |....Q...M..S....|
+00000010 2e 4e d9 17 4a 35 fa 9d 94 f6 45 0a f6 6b 5d 1c |.N..J5....E..k].|
+00000020 1e 15 19 8d 6d 94 cc 90 d9 39 94 20 8b 4b de 76 |....m....9. .K.v|
+00000030 d5 64 5d b7 19 df e7 eb 7e a0 22 c4 09 38 a0 12 |.d].....~."..8..|
+00000040 d5 59 10 c8 31 06 dc fc e4 9d d1 80 00 05 00 00 |.Y..1...........|
+00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000090 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000a0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000b0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000c0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000d0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000e0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000f0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+00000100 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000110 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000120 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000130 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000140 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000150 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000160 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000170 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000180 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000190 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+000001a0 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+000001b0 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001c0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001d0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001e0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001f0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+00000200 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+00000210 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000220 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000230 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000240 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000250 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000260 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000270 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000280 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000290 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+000002a0 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+000002b0 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002c0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002d0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000320 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 6d 51 f3 7f f9 |...........mQ...|
+00000010 3e fb 75 82 41 36 83 e8 6a ee 2a 2e 25 90 67 4c |>.u.A6..j.*.%.gL|
+00000020 8e 62 2f 30 81 17 e0 85 09 0c 2b b7 23 d7 b0 e2 |.b/0......+.#...|
+00000030 1d f7 3b d7 f5 a1 27 b6 ee 24 b6 1b cc 5b ea 66 |..;...'..$...[.f|
+00000040 0d 6a f4 e5 85 f9 da 43 b4 0e 86 85 e1 f5 aa be |.j.....C........|
+00000050 c8 ce 39 4c 9c 86 00 08 c2 4b e2 c6 ec 2f f7 ce |..9L.....K.../..|
+00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V|
+00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....|
+00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 03 00 01 |5..C.0oUN.p.....|
+00000090 01 16 03 03 00 24 37 14 b2 97 7b b5 f0 9a 38 05 |.....$7...{...8.|
+000000a0 22 35 69 9c 95 2f 86 4b 37 98 22 db 4e 9a 46 9c |"5i../.K7.".N.F.|
+000000b0 b9 81 74 72 58 18 53 0c 5c 3c |..trX.S.\<|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 3c b3 e7 77 5a |..........$<..wZ|
+00000010 7c 36 5a 74 74 26 8d 5b 5a 09 96 60 e8 24 45 2f ||6Ztt&.[Z..`.$E/|
+00000020 c2 39 14 5e db 58 12 49 ad a8 b6 ea ef 58 16 |.9.^.X.I.....X.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1a 6d 29 d7 ba 2f 85 02 b6 f0 82 64 |.....m)../.....d|
+00000010 6c 55 ae ab f6 fd 14 ff b8 38 f0 f8 a6 ea cc 15 |lU.......8......|
+00000020 03 03 00 16 10 c5 d9 41 7b e2 89 67 dc 29 8e f8 |.......A{..g.)..|
+00000030 b5 ab 32 91 44 2c 27 84 49 f7 |..2.D,'.I.|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES
new file mode 100644
index 000000000..a6c7a4196
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 d8 |..../...+..R.WY.|
+00000010 86 d6 07 ae e0 8d 63 b7 1e cb aa c6 67 32 c8 dd |......c.....g2..|
+00000020 68 03 d8 3d 37 18 72 c3 c0 f1 9d 00 00 04 00 0a |h..=7.r.........|
+00000030 00 ff 01 00 |....|
+>>> Flow 2 (server to client)
+00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 00 00 84 10 00 00 80 75 e0 c9 76 d6 e9 34 |.........u..v..4|
+00000010 1d e3 31 9e db 3b 03 41 93 e8 db 73 7c e9 3f 6a |..1..;.A...s|.?j|
+00000020 d8 2a 7b 25 83 4f 45 de 3f 78 3f b6 53 a7 b4 6c |.*{%.OE.?x?.S..l|
+00000030 e3 87 c4 c3 70 55 71 79 55 dc 74 98 84 21 19 13 |....pUqyU.t..!..|
+00000040 be d5 8e 0a ff 2f 9f 7a 6b d4 6c ef 78 d1 cb 65 |...../.zk.l.x..e|
+00000050 32 4c 0c c5 29 b9 60 94 c6 79 56 a2 aa 2d d9 ad |2L..).`..yV..-..|
+00000060 51 2c 54 1b 28 23 33 54 cd 48 cb 80 13 45 3d 4a |Q,T.(#3T.H...E=J|
+00000070 8e 2f f2 da bd 68 3e 1b eb 73 f9 2d 35 6b b1 40 |./...h>..s.-5k.@|
+00000080 2e 6d 9d 1c e9 c1 02 80 37 14 03 00 00 01 01 16 |.m......7.......|
+00000090 03 00 00 40 f7 c3 dd a4 64 3d 81 24 de a2 81 7d |...@....d=.$...}|
+000000a0 e4 df 78 46 e7 ba 93 6c 36 43 05 96 fc 75 ef ec |..xF...l6C...u..|
+000000b0 a5 46 6d 47 a5 be 74 ad 15 93 d9 87 4f 1d e2 b3 |.FmG..t.....O...|
+000000c0 03 ff 2e 89 6e 50 f4 d6 a6 e2 b3 54 cb 74 07 f7 |....nP.....T.t..|
+000000d0 ca 1b 8c 0a |....|
+>>> Flow 4 (server to client)
+00000000 14 03 00 00 01 01 16 03 00 00 40 6d 3d d8 d5 cf |..........@m=...|
+00000010 05 7d 98 8c 28 28 e2 43 ab ad 4a fa ae bf ec c3 |.}..((.C..J.....|
+00000020 9c 0a 13 4d 28 a4 45 c4 b9 f2 bc c5 12 a2 68 91 |...M(.E.......h.|
+00000030 77 fa 72 f8 9e 4e b7 1f b4 02 02 e3 5d 57 b0 8b |w.r..N......]W..|
+00000040 d8 90 0c 9d e6 df 5b 90 92 a1 0d 17 03 00 00 18 |......[.........|
+00000050 91 48 8a e1 d6 bf 79 1c d5 0a 70 d5 94 20 25 78 |.H....y...p.. %x|
+00000060 d8 84 c8 6e 54 f0 99 01 17 03 00 00 28 74 19 90 |...nT.......(t..|
+00000070 41 44 53 27 bb fb 1f fd 71 34 20 61 a0 eb a4 7c |ADS'....q4 a...||
+00000080 fe 36 f8 4b d7 b0 27 d3 b9 36 e1 67 af 2d 0e 23 |.6.K..'..6.g.-.#|
+00000090 2b 76 a7 2f c3 15 03 00 00 18 db fc e9 fd 87 5f |+v./..........._|
+000000a0 92 a8 3d 4b 35 f5 c6 48 2c b4 42 50 c3 81 28 f0 |..=K5..H,.BP..(.|
+000000b0 2b 41 |+A|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES
new file mode 100644
index 000000000..4885b267d
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 30 |..../...+..R.WY0|
+00000010 e1 ee 8c 60 5b 40 dd 95 bd b4 84 87 2f 01 15 e7 |...`[@....../...|
+00000020 50 88 4c 82 6b 6d 93 8a 57 d0 27 00 00 04 00 2f |P.L.km..W.'..../|
+00000030 00 ff 01 00 |....|
+>>> Flow 2 (server to client)
+00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 00 00 84 10 00 00 80 74 50 05 6f f5 83 c9 |.........tP.o...|
+00000010 f5 0c 5a 65 c7 4e c6 f3 87 96 d7 5d 3e 88 27 32 |..Ze.N.....]>.'2|
+00000020 89 12 ba ec db ef c0 85 70 84 ed b6 83 03 8f 44 |........p......D|
+00000030 f5 6f fa fa d0 1f 95 30 d1 ae a7 71 cf ee e9 b1 |.o.....0...q....|
+00000040 80 7b 34 a9 ea 1b 5e e5 71 40 3f e8 7d 30 d1 8b |.{4...^.q@?.}0..|
+00000050 11 f1 68 1f c8 25 f0 77 c5 af b3 92 6e d9 81 cc |..h..%.w....n...|
+00000060 f8 fd 82 95 cc 1f 4a b1 05 15 7a b3 a1 22 33 09 |......J...z.."3.|
+00000070 e7 a5 c2 89 7f 03 e0 91 b6 61 a3 a0 4e 17 0d 7a |.........a..N..z|
+00000080 13 01 c4 b6 50 c7 d9 81 15 14 03 00 00 01 01 16 |....P...........|
+00000090 03 00 00 40 56 da 56 ab e6 26 98 58 53 1f 36 b5 |...@V.V..&.XS.6.|
+000000a0 03 14 bd 42 29 ee 9c 7c e4 48 26 82 68 ae fd fe |...B)..|.H&.h...|
+000000b0 5e a4 43 22 75 95 7b c8 77 88 fd d6 d4 9b c9 b5 |^.C"u.{.w.......|
+000000c0 ee 3e a6 e8 c5 04 90 63 3f ac be 56 67 da 30 d4 |.>.....c?..Vg.0.|
+000000d0 64 fb a8 a0 |d...|
+>>> Flow 4 (server to client)
+00000000 14 03 00 00 01 01 16 03 00 00 40 96 af fb 79 96 |..........@...y.|
+00000010 92 97 2d d0 67 46 1e 08 b5 35 65 ef dc bc 8e 57 |..-.gF...5e....W|
+00000020 53 b7 36 58 74 d7 88 b1 55 fc eb fa 2e f3 17 b7 |S.6Xt...U.......|
+00000030 62 58 a0 9d 99 e1 85 d4 33 e0 b4 1f 1d 94 f2 88 |bX......3.......|
+00000040 d5 9a 34 5b 74 cd d2 ff 87 bd 52 17 03 00 00 20 |..4[t.....R.... |
+00000050 c6 61 c2 28 ac d2 0c 08 7f f1 c2 62 af 37 7e 78 |.a.(.......b.7~x|
+00000060 e8 e2 a1 54 f2 3a 80 97 f8 47 64 f2 cd 94 dd 0b |...T.:...Gd.....|
+00000070 17 03 00 00 30 b8 40 8f a3 18 ff 03 84 d4 1c 28 |....0.@........(|
+00000080 82 ce d8 9a 81 3a dd 23 7c 65 d8 ca f7 f1 46 1b |.....:.#|e....F.|
+00000090 70 f0 d7 d9 54 a7 71 e6 4d d4 25 61 5a e4 30 d3 |p...T.q.M.%aZ.0.|
+000000a0 4a 42 ae 26 a5 15 03 00 00 20 c4 e8 ed 40 57 00 |JB.&..... ...@W.|
+000000b0 dc a5 0e 82 90 47 92 08 dd 7e 50 6b 30 66 5e 90 |.....G...~Pk0f^.|
+000000c0 73 7c 81 93 8d 24 b1 06 e7 39 |s|...$...9|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4
new file mode 100644
index 000000000..1314b659b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 79 |..../...+..R.WYy|
+00000010 b9 3b ef df 53 fb 09 f6 01 e5 18 0a fc 3d 65 bb |.;..S........=e.|
+00000020 cf 9c 4c 77 b1 e8 6b 4f 5f c7 94 00 00 04 00 05 |..Lw..kO_.......|
+00000030 00 ff 01 00 |....|
+>>> Flow 2 (server to client)
+00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 00 00 84 10 00 00 80 4d 66 7a f3 f8 ab 86 |.........Mfz....|
+00000010 43 4c 5f 7c 52 ca e7 3f ba 62 b3 82 88 16 7d ca |CL_|R..?.b....}.|
+00000020 3a 66 15 c0 36 55 2c ab bf 30 6b cd 9c d8 b9 48 |:f..6U,..0k....H|
+00000030 03 c9 d0 98 ab 0b a6 5b 39 c8 fe 82 8e bb f0 16 |.......[9.......|
+00000040 6f 96 62 81 f2 dc 52 02 c9 de e4 47 73 21 6e 1e |o.b...R....Gs!n.|
+00000050 3a 11 89 7a e2 6b 9e 04 64 72 15 ba 2d 10 a2 69 |:..z.k..dr..-..i|
+00000060 07 e6 ba 17 cf 54 d6 4e 5f 99 e8 59 8b 54 ce 8e |.....T.N_..Y.T..|
+00000070 6b 58 ba 83 68 46 4a 5f 43 3e 9b e1 32 a2 19 42 |kX..hFJ_C>..2..B|
+00000080 46 0f e4 47 1a 3b 16 5f e1 14 03 00 00 01 01 16 |F..G.;._........|
+00000090 03 00 00 3c 78 7e ee da 0d 38 0b 1a d6 d4 8e d5 |...<x~...8......|
+000000a0 6a c5 3a 0f 85 e7 37 a6 3c 8d 1e 4b da 02 94 bf |j.:...7.<..K....|
+000000b0 ae 2c 50 3b 4e 1c 0c 3c 4f cc d5 1c da 33 13 43 |.,P;N..<O....3.C|
+000000c0 37 64 44 ac 26 43 28 0b d0 c2 04 09 b5 0f 23 1d |7dD.&C(.......#.|
+>>> Flow 4 (server to client)
+00000000 14 03 00 00 01 01 16 03 00 00 3c 23 29 64 62 23 |..........<#)db#|
+00000010 19 20 f8 2e 15 07 ee c8 f4 ab f0 3e 66 c3 ed 7b |. .........>f..{|
+00000020 7c a7 c2 7e c3 25 3c 8f f3 04 dc 37 e8 fc 0a 1d ||..~.%<....7....|
+00000030 fa 7a 09 d4 21 11 e3 24 21 4b 37 d1 85 cc 40 bf |.z..!..$!K7...@.|
+00000040 bd bd f8 59 6b cd 73 17 03 00 00 21 47 1d ac 54 |...Yk.s....!G..T|
+00000050 bd 58 a6 c0 04 e2 0c 6b 66 64 5a 85 09 0e 47 fc |.X.....kfdZ...G.|
+00000060 0b 57 ee f1 24 b6 89 57 46 be 6b 0d f2 15 03 00 |.W..$..WF.k.....|
+00000070 00 16 b4 f7 34 99 19 43 b6 b3 5a 8b c3 d2 67 2f |....4..C..Z...g/|
+00000080 3b 19 1c 31 d4 f9 bd 96 |;..1....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..9b8cb4d9b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 76 01 00 00 72 03 01 53 04 f0 f9 4b |....v...r..S...K|
+00000010 30 a8 68 d0 79 13 14 69 ee 3b 5d 05 cb 71 63 43 |0.h.y..i.;]..qcC|
+00000020 4a 55 6b 05 25 53 19 ba e0 2f b1 00 00 04 c0 0a |JUk.%S.../......|
+00000030 00 ff 01 00 00 45 00 0b 00 04 03 00 01 02 00 0a |.....E..........|
+00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............|
+00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................|
+00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................|
+00000070 00 0f 00 10 00 11 00 0f 00 01 01 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 01 02 0e 0b 00 02 0a 00 |................|
+00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...|
+00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.|
+00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....|
+00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12|
+000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221|
+000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.|
+000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U|
+000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!|
+000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne|
+00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt|
+00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...|
+00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........|
+00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.|
+00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..|
+00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.|
+00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...|
+00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...|
+00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..|
+00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........|
+000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0|
+000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.|
+000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...|
+000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.|
+000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;|
+000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.|
+00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.|
+00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
+00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
+00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 d6 0c 00 |{j.9....*.......|
+00000250 00 d2 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
+00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
+00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
+00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
+00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 c6 |A.Vk.Z...0...B..|
+000002a0 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 |.........>.f#..B|
+000002b0 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba |.d.9.?.!.(.`kM=.|
+000002c0 a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de |.K^w..Y(...'....|
+000002d0 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 |3H...jB..~~1...f|
+000002e0 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b 49 5e |.B..}.5.......I^|
+000002f0 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 14 62 |._.....+...c...b|
+00000300 db 1e c9 2b 30 f8 41 9b a6 e6 bc de 0e 68 30 21 |...+0.A......h0!|
+00000310 d8 ef 2f 05 42 da f2 e0 2c 06 33 1d 0d 9a 1a 75 |../.B...,.3....u|
+00000320 59 a7 3a bc 16 03 01 00 04 0e 00 00 00 |Y.:..........|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 46 10 00 00 42 41 04 08 28 cf bd 3c |....F...BA..(..<|
+00000010 3c cc 98 9e 73 3f 92 a7 cb 22 83 3b c7 61 46 0e |<...s?...".;.aF.|
+00000020 4d 7c 30 b5 06 85 2f 01 be b5 40 e2 64 1e 45 c1 |M|0.../...@.d.E.|
+00000030 9d 73 95 d5 65 92 0b 9b e7 6f c6 91 ab b6 fa be |.s..e....o......|
+00000040 61 83 a7 f2 eb f5 65 31 fe 24 7b 14 03 01 00 01 |a.....e1.${.....|
+00000050 01 16 03 01 00 30 15 d1 c4 ca 0b 01 84 13 5a ba |.....0........Z.|
+00000060 89 04 87 73 7c bb d8 89 7e 10 27 ba 6f 5d dc d3 |...s|...~.'.o]..|
+00000070 b5 ef 32 86 58 cc fb eb 5c 32 9e 95 ef 01 1c ac |..2.X...\2......|
+00000080 dc 8e df 7f fe 0a |......|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 e8 48 86 81 3c |..........0.H..<|
+00000010 f5 25 5c 94 a9 06 c4 5c 71 62 b1 43 76 ec 2c 44 |.%\....\qb.Cv.,D|
+00000020 95 b5 8c 95 d2 ff 82 92 b6 fc 52 75 03 c6 a1 f0 |..........Ru....|
+00000030 99 6d b1 ed ec 68 6c d7 9f 18 50 17 03 01 00 20 |.m...hl...P.... |
+00000040 32 d9 26 8a 81 b8 9d a5 7b fd d5 4e 7a db 2e 29 |2.&.....{..Nz..)|
+00000050 58 9a 4f 6a 27 18 bc dc c2 49 b8 65 cb 8e 16 5a |X.Oj'....I.e...Z|
+00000060 17 03 01 00 30 c4 56 0a ad 9a 82 cb 3e 32 f1 7c |....0.V.....>2.||
+00000070 95 6e dd cd e9 4d f0 e5 2d c9 a3 f7 de bb d7 fd |.n...M..-.......|
+00000080 84 bb df 34 8c 64 1f 03 58 64 19 4a 5b 7a a8 81 |...4.d..Xd.J[z..|
+00000090 52 bb 51 0a 43 15 03 01 00 20 89 18 7a 40 ec 49 |R.Q.C.... ..z@.I|
+000000a0 52 d5 d3 20 ac 07 eb e9 4a 78 23 cf e7 21 32 74 |R.. ....Jx#..!2t|
+000000b0 ec 40 8d a8 f4 33 1c ae 93 cf |.@...3....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES
new file mode 100644
index 000000000..c0e6241c0
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 13 |....6...2..R.WY.|
+00000010 8b e6 5b a3 1d cb 94 ef 48 e4 59 7e 20 6d 07 67 |..[.....H.Y~ m.g|
+00000020 1e 28 6d 31 a2 e7 96 b3 7d 32 cc 00 00 04 00 0a |.(m1....}2......|
+00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 2e af d2 61 f6 |..............a.|
+00000010 e2 b8 24 da 28 17 55 99 fd 11 bd 7a ab 98 dd f2 |..$.(.U....z....|
+00000020 f6 5f e0 11 6b 12 61 6f 86 48 b2 6e db f0 dd d5 |._..k.ao.H.n....|
+00000030 07 88 e5 95 f4 2d 6b 0c d0 09 1a 5e 5f 50 1f dc |.....-k....^_P..|
+00000040 f2 e7 02 7d 5e a0 70 29 80 ef 87 aa cc 95 3f 2e |...}^.p)......?.|
+00000050 24 d1 40 b6 62 53 1d 25 31 87 1e 2f 77 d3 e1 1c |$.@.bS.%1../w...|
+00000060 c4 99 89 bc 99 09 e9 ad 1f ce 09 e6 36 1c 3e 97 |............6.>.|
+00000070 be 62 69 a0 4e 14 20 9c 82 2a 3e fc 7e 9b c4 7a |.bi.N. ..*>.~..z|
+00000080 5a f7 ad 1a 03 17 2a f8 7a 5f 44 14 03 01 00 01 |Z.....*.z_D.....|
+00000090 01 16 03 01 00 28 49 6b da 73 07 ad 85 9a 0e fb |.....(Ik.s......|
+000000a0 dd e0 69 ef c9 22 2d 86 91 51 26 63 d0 24 7d 16 |..i.."-..Q&c.$}.|
+000000b0 3c db 9b 00 c9 7e 64 e2 69 02 85 7d f7 47 |<....~d.i..}.G|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 28 dc 60 83 43 6c |..........(.`.Cl|
+00000010 37 79 ab 6e 92 1f 66 d0 b1 12 ce c1 64 9d 2b 68 |7y.n..f.....d.+h|
+00000020 c7 1a e5 1f 8c 80 08 d2 86 3e a1 2c e3 7e f4 64 |.........>.,.~.d|
+00000030 e7 96 b2 17 03 01 00 18 8d b5 7c 03 78 cf dc 09 |..........|.x...|
+00000040 95 06 4b a6 82 f9 30 d2 6b 26 cb 0a 9a 9d 47 9f |..K...0.k&....G.|
+00000050 17 03 01 00 28 30 a9 55 dd b9 4d 6a 76 00 39 96 |....(0.U..Mjv.9.|
+00000060 a3 94 6a df e5 af 1e a2 eb bb e4 ac 95 2c f7 93 |..j..........,..|
+00000070 ef d1 b5 13 d8 e2 06 1a ad 5c 00 dd 0c 15 03 01 |.........\......|
+00000080 00 18 a5 62 e4 8b 51 1d 28 46 bc 8a c8 50 a3 32 |...b..Q.(F...P.2|
+00000090 6b 7b f1 b6 19 43 63 1f 7d 38 |k{...Cc.}8|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES
new file mode 100644
index 000000000..1670997b0
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -0,0 +1,82 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 5d |....6...2..R.WY]|
+00000010 0d 77 24 3e b3 32 3d ba 0f b0 aa 1d e3 13 06 f6 |.w$>.2=.........|
+00000020 0f be 3c 92 ba 93 bd a6 6d 69 53 00 00 04 00 2f |..<.....miS..../|
+00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 20 e6 80 f7 48 |........... ...H|
+00000010 7e 7d 08 08 54 e1 b4 e3 98 27 5f 90 9d 3b e3 c2 |~}..T....'_..;..|
+00000020 c8 8b dc 9e ff 75 fa fc 60 e1 9e 67 7c c4 08 27 |.....u..`..g|..'|
+00000030 cc 6f 15 6c bc 7c 96 de 83 8f 98 6d 4a c7 b7 20 |.o.l.|.....mJ.. |
+00000040 8c 19 47 5a ff 76 92 0a df df 66 d2 b6 9d 2d 06 |..GZ.v....f...-.|
+00000050 fb ac 07 cf 38 08 f1 fd 0d fe 07 d7 69 3e 8a 79 |....8.......i>.y|
+00000060 dc 2d ab bb f7 18 3c 51 14 6e c6 70 95 a2 59 b1 |.-....<Q.n.p..Y.|
+00000070 39 04 9f ae f3 5f fb a7 2b d3 5a c0 96 d9 4d 2a |9...._..+.Z...M*|
+00000080 2a 6c 6d 39 ee fc ce 76 1a 92 1b 14 03 01 00 01 |*lm9...v........|
+00000090 01 16 03 01 00 30 10 20 90 7b 0e e6 c2 05 81 c3 |.....0. .{......|
+000000a0 bc da 84 67 dd 5f 97 e2 74 c4 35 4e bf d2 1b 90 |...g._..t.5N....|
+000000b0 2f e0 af dd 6b f5 52 db 36 cd 3e e1 e6 bd 99 30 |/...k.R.6.>....0|
+000000c0 ed c6 bc c2 38 b6 |....8.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 5d 0c a2 18 13 |..........0]....|
+00000010 40 a1 84 ce c5 d8 4e fc a4 8a 14 b5 94 18 b1 86 |@.....N.........|
+00000020 da 6a 7d 26 08 d6 a0 f8 78 5b 42 7e f8 83 54 56 |.j}&....x[B~..TV|
+00000030 36 a4 91 37 67 5a d7 68 37 c4 4f 17 03 01 00 20 |6..7gZ.h7.O.... |
+00000040 fd aa 5e cf 4b 12 c5 be a4 a2 65 5d 6e 65 46 5f |..^.K.....e]neF_|
+00000050 d2 fe 46 e7 77 2d 9c 1e 0b 39 40 48 c2 2f be 21 |..F.w-...9@H./.!|
+00000060 17 03 01 00 30 03 af 9e 6b d6 76 ed 9e 1d 8b 8b |....0...k.v.....|
+00000070 2e 2a 5d da c4 73 95 ac 0e 6f 69 cb 63 df 50 27 |.*]..s...oi.c.P'|
+00000080 30 de 2e 55 86 85 ad 3e 33 22 49 72 f2 e2 9f 8f |0..U...>3"Ir....|
+00000090 ba cf 4e 30 34 15 03 01 00 20 4c 4c 97 61 70 ea |..N04.... LL.ap.|
+000000a0 ae fc a2 e9 c6 c2 b6 2e 4d 85 f6 ae 2b 56 46 82 |........M...+VF.|
+000000b0 9d d8 a5 82 17 fa 3e 62 67 7e |......>bg~|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4
new file mode 100644
index 000000000..d653561f9
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 cf |....6...2..R.WY.|
+00000010 00 a1 49 a4 37 69 74 d8 a7 93 ea 8d e7 50 b7 b3 |..I.7it......P..|
+00000020 8c ec e5 56 fb dc 5f 1a 2e ab 18 00 00 04 00 05 |...V.._.........|
+00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 b1 96 7b 6f f5 |.............{o.|
+00000010 a0 cb 0d 60 9b 64 d3 f5 17 76 47 7b bc a5 0e 96 |...`.d...vG{....|
+00000020 53 af 68 0c 96 22 f7 28 0c 24 37 9c 51 69 ed b2 |S.h..".(.$7.Qi..|
+00000030 47 14 ba 33 c5 79 6b 96 f2 ab 3c 02 5c 37 a4 97 |G..3.yk...<.\7..|
+00000040 23 fc 7f d3 95 2d 85 99 1a 10 1b 38 e5 f1 83 55 |#....-.....8...U|
+00000050 4a ab 60 f8 89 0a 6a c4 eb 45 f5 b0 f4 f8 09 31 |J.`...j..E.....1|
+00000060 6e f0 25 30 fd 5e 68 61 bc cb 0d 9e 05 73 0a f4 |n.%0.^ha.....s..|
+00000070 a5 2e d9 d5 4e 08 f6 3b 8d 2d 21 f5 79 b6 97 55 |....N..;.-!.y..U|
+00000080 b9 99 03 49 ea 96 36 49 21 56 bf 14 03 01 00 01 |...I..6I!V......|
+00000090 01 16 03 01 00 24 f0 4f 30 06 c3 25 01 93 34 ab |.....$.O0..%..4.|
+000000a0 93 8f 59 26 83 6e 8a fd 5a a6 cf af ad b1 a2 83 |..Y&.n..Z.......|
+000000b0 28 ff c2 66 5f ac e5 a5 a5 03 |(..f_.....|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 9d b4 ea d8 be |..........$.....|
+00000010 b5 9f 00 fd b5 99 04 12 6b 7a 3f b8 52 d7 52 a9 |........kz?.R.R.|
+00000020 e9 bd 5b 63 ad b0 53 ac 46 80 be 48 6e dd ee 17 |..[c..S.F..Hn...|
+00000030 03 01 00 21 07 ac c4 fb 21 e4 b8 6b 64 3b b5 27 |...!....!..kd;.'|
+00000040 29 67 a1 10 2e d2 71 d5 59 5e fc 1d 84 31 15 6e |)g....q.Y^...1.n|
+00000050 4d 4b dc a9 3a 15 03 01 00 16 25 22 a5 78 23 5a |MK..:.....%".x#Z|
+00000060 69 6f 99 a1 b3 1c 8d bf f3 bd 1b c8 1c 57 15 75 |io...........W.u|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4
new file mode 100644
index 000000000..9237db078
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 36 01 00 00 32 03 02 52 cc 57 59 bd |....6...2..R.WY.|
+00000010 cd 9d 1e 17 38 43 a5 e3 e7 30 e4 2b 2a ef f7 5b |....8C...0.+*..[|
+00000020 81 91 0c 0b 52 f8 2d 2c 61 d3 13 00 00 04 00 05 |....R.-,a.......|
+00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 31 02 00 00 2d 03 02 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 02 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 02 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 86 10 00 00 82 00 80 71 2b 19 25 86 |...........q+.%.|
+00000010 a0 ff ba d5 1c a6 0c 8b 6b 0a b8 e9 42 93 2f 55 |........k...B./U|
+00000020 a8 ee 62 fa ed bc 6d e2 9d e3 76 a6 73 d7 99 58 |..b...m...v.s..X|
+00000030 cc 0b 14 42 96 7c b6 c7 8f 21 16 cf 71 9b 2b b9 |...B.|...!..q.+.|
+00000040 e0 34 57 76 22 d5 87 8a ce 1f ea 26 6e 1e e6 ca |.4Wv"......&n...|
+00000050 55 3b 20 cd cf 42 26 b1 51 3e 8c 1d a2 ae c4 63 |U; ..B&.Q>.....c|
+00000060 f5 ce 27 3c 1e c3 e0 e3 b1 16 c1 8a 62 bd 21 7f |..'<........b.!.|
+00000070 38 b5 b7 3a 3c bb 03 37 e1 a5 ff f1 29 e2 21 0a |8..:<..7....).!.|
+00000080 8c 20 02 e0 c0 82 97 9d 18 6d f8 14 03 02 00 01 |. .......m......|
+00000090 01 16 03 02 00 24 bc 19 16 6e fd 0b db 9e d5 1d |.....$...n......|
+000000a0 65 b6 57 1c 58 b5 6a ac f7 4f f0 cd a1 a9 0c c0 |e.W.X.j..O......|
+000000b0 df e6 eb d5 00 f7 fd 43 bb 27 |.......C.'|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 24 cf 4f e4 27 b0 |..........$.O.'.|
+00000010 3d 17 34 b1 3c 37 6e c5 2b 3d 4a c3 46 50 44 b4 |=.4.<7n.+=J.FPD.|
+00000020 de 77 18 10 4f 60 b3 4e dc 06 fd 25 ec 05 15 17 |.w..O`.N...%....|
+00000030 03 02 00 21 a5 c9 32 f2 21 fb 94 7e 0d 15 65 fd |...!..2.!..~..e.|
+00000040 3e fe e4 c1 a5 e9 88 72 b2 f1 26 39 a6 48 59 97 |>......r..&9.HY.|
+00000050 65 e3 f0 cb 46 15 03 02 00 16 4b 02 ec cd ca 30 |e...F.....K....0|
+00000060 42 cf 3d a0 4a fa 8e 79 bb ed b0 59 40 9b 2c 1a |B.=.J..y...Y@.,.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
new file mode 100644
index 000000000..0ab8b8d74
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f 5f |...........S..?_|
+00000010 f4 ef 1f b3 41 0b 54 e4 4d 56 0a 31 22 b8 5c 73 |....A.T.MV.1".\s|
+00000020 a3 cb b5 b2 9d 43 f1 83 bc d3 bd 00 00 32 c0 30 |.....C.......2.0|
+00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..|
+00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2|
+00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5|
+00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4|
+00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............|
+00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................|
+00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................|
+000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......|
+000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 16 |................|
+00000030 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 |..............0.|
+00000040 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb |..0..b.....-G...|
+00000050 f4 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b |.0...*.H.=..0E1.|
+00000060 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000070 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000080 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+00000090 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000a0 4c 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 |Ltd0...121122150|
+000000b0 36 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 |632Z..2211201506|
+000000c0 33 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |32Z0E1.0...U....|
+000000d0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000e0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+000000f0 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000100 74 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 |ts Pty Ltd0..0..|
+00000110 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 |.*.H.=....+...#.|
+00000120 81 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e |............Hs6~|
+00000130 c3 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 |..V.".=S.;M!=.ku|
+00000140 e6 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 |......&.....r2|.|
+00000150 64 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a |d/....h#.~..%.H:|
+00000160 69 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 |i.(m.7...b....pb|
+00000170 83 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b |....d1...1...h..|
+00000180 23 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 |#.vd?.\....XX._p|
+00000190 dd 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 |............0f[f|
+000001a0 9a 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce |. .'...;0...*.H.|
+000001b0 3d 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f |=......0...B...O|
+000001c0 eb e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 |..E.H}.......Gp.|
+000001d0 5e 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee |^../...M.a@.....|
+000001e0 0b 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 |.~.~.v..;~.?....|
+000001f0 59 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 |Y.G-|..N....o..B|
+00000200 01 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 |.M..g..-...?..%.|
+00000210 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e |3.......7z..z...|
+00000220 dd d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 |...i..|V..1x+..x|
+00000230 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 |.....N6$1{j.9...|
+00000240 8f 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 |.*............A.|
+00000250 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.|
+00000260 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^|
+00000270 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B|
+00000280 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.|
+00000290 04 03 00 8b 30 81 88 02 42 00 c6 85 8e 06 b7 04 |....0...B.......|
+000002a0 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 05 |....>.f#..B.d.9.|
+000002b0 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 ef |?.!.(.`kM=..K^w.|
+000002c0 e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 85 |.Y(...'....3H...|
+000002d0 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 42 00 ad 7d |jB..~~1...f.B..}|
+000002e0 06 35 ab ec 8d ac d4 ba 1b 49 5e 05 5f f0 97 93 |.5.......I^._...|
+000002f0 82 b8 2b 8d 91 98 63 8e b4 14 62 db 1e c9 2b 64 |..+...c...b...+d|
+00000300 e9 e6 bf 15 5b 67 c2 40 90 c6 1f b7 92 db 4b f6 |....[g.@......K.|
+00000310 f4 db ae 82 f1 4f 02 75 52 40 38 10 ff 35 f0 16 |.....O.uR@8..5..|
+00000320 03 03 00 04 0e 00 00 00 |........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 d8 94 c4 05 26 |....F...BA.....&|
+00000010 76 29 2d 0e ec 47 b6 50 d5 a3 da 2a ba 02 11 37 |v)-..G.P...*...7|
+00000020 3d ef e6 2a db d0 47 47 a7 9a 5f 43 2d 98 78 26 |=..*..GG.._C-.x&|
+00000030 81 e2 f1 ba fe f7 66 c6 61 cb c1 b7 60 62 34 a5 |......f.a...`b4.|
+00000040 78 67 50 3d 9a 0e 4a 8c 8f d7 10 14 03 03 00 01 |xgP=..J.........|
+00000050 01 16 03 03 00 40 5e 46 b0 5d 30 f6 da 8f 9e 67 |.....@^F.]0....g|
+00000060 f5 3e bd fe c9 b8 53 b2 10 d5 7c 0e 34 e3 93 6d |.>....S...|.4..m|
+00000070 0e 8e 8a 2b df fb 9a 0f a5 23 55 e7 0a 4b e2 d3 |...+.....#U..K..|
+00000080 db 15 e8 52 74 26 78 b3 b0 56 65 63 ac ae 1e c0 |...Rt&x..Vec....|
+00000090 0b f4 92 56 a9 04 |...V..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 16 a9 63 0a 99 |.............c..|
+00000020 21 8a fc 5c b3 ee 05 71 4e 75 c0 d9 40 54 0d 3e |!..\...qNu..@T.>|
+00000030 4e 5d 44 b7 4b 5d a9 e7 5a 30 ed b6 d5 08 50 b1 |N]D.K]..Z0....P.|
+00000040 e8 8c 54 eb 1b 39 7a f9 3b ac 2e 17 03 03 00 40 |..T..9z.;......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 96 03 20 2b 20 c4 c1 9a 76 7b f3 96 bd 33 ed e6 |.. + ...v{...3..|
+00000070 38 48 ea 53 d5 e0 62 b5 7e 1a 36 a8 dd 9f 2d 4b |8H.S..b.~.6...-K|
+00000080 06 0d ae f6 bc 99 14 b3 93 14 27 63 e2 a0 c8 76 |..........'c...v|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 48 af e1 e4 11 e1 b7 03 19 b0 e3 |.....H..........|
+000000b0 e6 a9 66 d8 ac af aa 03 f6 0d 51 df 9a 27 78 3a |..f.......Q..'x:|
+000000c0 56 5a 03 1a 4c |VZ..L|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
new file mode 100644
index 000000000..88abb15a7
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -0,0 +1,101 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f cc |...........S..?.|
+00000010 41 74 00 07 cb ae 3b 30 79 48 51 60 41 a3 8c ab |At....;0yHQ`A...|
+00000020 dc 76 f9 74 52 1e c5 fb a9 69 c2 00 00 32 c0 30 |.v.tR....i...2.0|
+00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..|
+00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2|
+00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5|
+00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4|
+00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............|
+00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................|
+00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................|
+000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......|
+000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 16 |................|
+00000030 03 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 |..............0.|
+00000040 02 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 |..0.............|
+00000050 bb a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d |......0...*.H...|
+00000060 01 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 |.....0E1.0...U..|
+00000070 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 |..AU1.0...U....S|
+00000080 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 |ome-State1!0...U|
+00000090 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 |....Internet Wid|
+000000a0 67 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d |gits Pty Ltd0...|
+000000b0 31 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 |100424090938Z..1|
+000000c0 31 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b |10424090938Z0E1.|
+000000d0 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+000000e0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+000000f0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+00000100 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+00000110 4c 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |Ltd0..0...*.H...|
+00000120 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
+00000130 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b |.y......F...i..+|
+00000140 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 |.CZ..-.zC...R..e|
+00000150 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 |L,x.#........;~b|
+00000160 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 |.,.3...\zV.....X|
+00000170 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f |{&?......!.J..T.|
+00000180 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 |Z..Bq......~.}}.|
+00000190 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 |.9....Q.|..L;2f.|
+000001a0 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 |.....q.....k..-y|
+000001b0 02 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 |........0..0...U|
+000001c0 1d 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 |..........Z..(.i|
+000001d0 ce 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d |.#i..&...90u..U.|
+000001e0 23 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db |#.n0l......Z..(.|
+000001f0 69 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 |i.#i..&...9.I.G0|
+00000200 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 |E1.0...U....AU1.|
+00000210 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 |0...U....Some-St|
+00000220 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e |ate1!0...U....In|
+00000230 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 |ternet Widgits P|
+00000240 74 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 |ty Ltd..........|
+00000250 ca 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 |.0...U....0....0|
+00000260 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 |...*.H..........|
+00000270 81 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 |...lE$.k.Y..R...|
+00000280 14 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae |....zdu.Z.f..+..|
+00000290 12 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 |.f..O8.n`....A..|
+000002a0 25 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 |%...z$.0........|
+000002b0 d7 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d |.1Y....x.PV\..Z-|
+000002c0 5a 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd |Z_3....u....R...|
+000002d0 98 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 |... _..........W|
+000002e0 e9 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 |.p.&mq..&n8P)l..|
+000002f0 bd d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 |..............A.|
+00000300 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.|
+00000310 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^|
+00000320 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B|
+00000330 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.|
+00000340 04 01 00 80 9d 84 09 35 73 fb f6 ea 94 7b 49 fb |.......5s....{I.|
+00000350 c2 70 b1 11 64 5b 93 9f d9 8c f5 56 98 f6 d3 66 |.p..d[.....V...f|
+00000360 a6 1d 18 56 88 87 71 3f b0 38 9d 44 1f ad 2c 0d |...V..q?.8.D..,.|
+00000370 3a a7 e8 d4 3e 33 3c 41 20 f3 3f 5c e5 fb e3 23 |:...>3<A .?\...#|
+00000380 12 48 ff d2 c4 30 7c 8a 51 3f 9f 19 6e 34 d7 60 |.H...0|.Q?..n4.`|
+00000390 7d 12 8a aa 90 0f 50 d9 0b 9a b2 d7 66 b1 c6 84 |}.....P.....f...|
+000003a0 af 5c e2 5e 16 3e 36 61 73 84 64 89 b3 c1 6d 50 |.\.^.>6as.d...mP|
+000003b0 33 55 c7 e1 c5 a5 4c 32 5c 95 dc 07 43 60 49 11 |3U....L2\...C`I.|
+000003c0 e9 98 cc ba 16 03 03 00 04 0e 00 00 00 |.............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 28 02 84 d5 b4 |....F...BA.(....|
+00000010 58 07 47 d5 a0 d6 0b 1d 37 91 e6 34 a4 ad 0b ad |X.G.....7..4....|
+00000020 22 01 82 77 a7 32 86 78 83 3a da 75 2f e5 68 7a |"..w.2.x.:.u/.hz|
+00000030 de e4 05 e0 02 47 40 4e 38 d2 2c c3 7b da 53 73 |.....G@N8.,.{.Ss|
+00000040 19 cb 8b 73 34 72 4d 33 71 39 c8 14 03 03 00 01 |...s4rM3q9......|
+00000050 01 16 03 03 00 40 10 63 43 76 83 bd 36 e4 1e 4d |.....@.cCv..6..M|
+00000060 7e 13 b0 ac aa c8 ec 90 31 df 84 46 49 68 39 5a |~.......1..FIh9Z|
+00000070 05 8b 73 32 86 15 3a 18 57 d8 e2 2c 2d 05 89 93 |..s2..:.W..,-...|
+00000080 37 b8 dd 73 33 92 ff a7 b2 53 27 94 b7 25 56 64 |7..s3....S'..%Vd|
+00000090 a1 d3 2c f7 6b 71 |..,.kq|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 21 5c 31 b1 4b |...........!\1.K|
+00000020 96 96 30 8f 79 35 3a 3a 2d 26 67 d0 70 48 be 30 |..0.y5::-&g.pH.0|
+00000030 f8 3e e8 c1 cb 1d d5 89 f6 9c 72 bb 1c f9 4d 90 |.>........r...M.|
+00000040 9c d7 c6 fa 40 76 a5 61 46 61 24 17 03 03 00 40 |....@v.aFa$....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 94 8a 14 04 06 b9 30 a0 67 fd b2 4c 84 f4 10 93 |......0.g..L....|
+00000070 7d d4 2b 23 f0 e9 62 93 c2 20 a2 f2 7c 07 21 4b |}.+#..b.. ..|.!K|
+00000080 94 ba 7b 7d cb 77 da 85 93 bd 53 ee ca db 9b 3e |..{}.w....S....>|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 17 3f 53 8d b3 35 b4 84 ed bb 12 |......?S..5.....|
+000000b0 cf 73 25 25 7c c3 d3 bb 1f 5a 6b 73 9a 8a b1 a2 |.s%%|....Zks....|
+000000c0 ba 99 f8 0e 43 |....C|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 000000000..547f79834
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -0,0 +1,122 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 65 |....\...X..R.WYe|
+00000010 ae b3 ec a4 7a 05 f7 ec 39 22 7d 8c 91 96 6b e0 |....z...9"}...k.|
+00000020 69 81 ff 88 28 17 60 ac 94 19 ff 00 00 04 00 05 |i...(.`.........|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........|
+00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........|
+00000310 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 86 10 00 00 82 00 80 47 5a 2f b8 78 46 |..........GZ/.xF|
+00000220 9f 3c fc ab 8b 35 c9 77 da c3 96 78 31 7c 2b 4f |.<...5.w...x1|+O|
+00000230 56 be 0f 33 bd 17 bc 1c 86 5a ae b3 0f 8b 18 2f |V..3.....Z...../|
+00000240 48 0d e0 0a 20 d3 53 96 88 d2 8a 7d b6 58 13 44 |H... .S....}.X.D|
+00000250 a5 e8 19 6d 02 df a6 1b 79 c5 54 c2 ef 4d 41 4f |...m....y.T..MAO|
+00000260 04 1c eb 37 55 b7 2b f4 7c 6d 37 9c f1 89 a0 2c |...7U.+.|m7....,|
+00000270 0f ba 10 09 e4 a1 ee 0a 7e 9a fd 2c 32 63 1c 55 |........~..,2c.U|
+00000280 85 38 de d0 7b 5f 46 03 1f cc 4d 69 51 97 d8 d7 |.8..{_F...MiQ...|
+00000290 88 6f ba 43 04 b0 42 09 61 5e 16 03 03 00 92 0f |.o.C..B.a^......|
+000002a0 00 00 8e 04 03 00 8a 30 81 87 02 41 14 3d 4c 71 |.......0...A.=Lq|
+000002b0 c2 32 4a 20 ee b7 69 17 55 e8 99 55 11 76 51 7a |.2J ..i.U..U.vQz|
+000002c0 74 55 e7 e8 c3 3b b3 70 db 1c 8e f6 8a d4 99 40 |tU...;.p.......@|
+000002d0 6e da 04 fd 7a 47 41 d6 ae c0 63 ad fd 91 a8 58 |n...zGA...c....X|
+000002e0 24 b9 ac 2f 7a 4c bf 5b 24 12 cb 3a f3 02 42 00 |$../zL.[$..:..B.|
+000002f0 90 f9 48 97 0e d4 33 99 09 9f 1d a8 97 16 60 82 |..H...3.......`.|
+00000300 85 cc 5a 5d 79 f7 2f 03 2a c0 b8 12 61 ac 9f 88 |..Z]y./.*...a...|
+00000310 1d 0d 9e 0a ee 28 a8 5a e2 42 b7 94 e2 e6 0e 13 |.....(.Z.B......|
+00000320 c8 64 dc 4e d3 6b 10 d6 83 41 9c dc d4 53 c3 08 |.d.N.k...A...S..|
+00000330 19 14 03 03 00 01 01 16 03 03 00 24 ef bd e3 23 |...........$...#|
+00000340 10 23 ae 6e b5 12 eb 9c 21 78 db 36 fd bf 7f ee |.#.n....!x.6....|
+00000350 6f c8 00 2d b6 35 cc 2f 38 73 ae a4 34 cf 0d df |o..-.5./8s..4...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 a7 50 0f 50 b4 |..........$.P.P.|
+00000010 1c c3 4d f3 7a 64 df 65 ac 35 22 13 46 cc ec 36 |..M.zd.e.5".F..6|
+00000020 e6 d2 f3 67 94 6a 18 85 9f 4a 3c 44 a3 58 b0 17 |...g.j...J<D.X..|
+00000030 03 03 00 21 51 0a 41 8c fd 50 e3 54 8b 6a 1f 83 |...!Q.A..P.T.j..|
+00000040 a5 37 98 e1 5b 1e ec 03 1d c7 0e 28 6d 79 3f 34 |.7..[......(my?4|
+00000050 de 1c 38 6d 7e 15 03 03 00 16 06 fc b1 7d ad 70 |..8m~........}.p|
+00000060 1a de d4 b7 b5 e7 a2 6d 1b 9a b0 31 0c cc 7b 70 |.......m...1..{p|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
new file mode 100644
index 000000000..04a5b117c
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -0,0 +1,121 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 6b |....\...X..R.WYk|
+00000010 11 07 04 39 77 20 c2 b4 3f cb 0a c9 53 fe 5b 3e |...9w ..?...S.[>|
+00000020 5f 58 2c 7e 30 69 e1 8e 6c 9d c8 00 00 04 00 05 |_X,~0i..l.......|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........|
+00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........|
+00000310 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
+00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
+00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
+00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
+00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
+00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
+00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
+00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
+00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
+000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
+000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
+000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
+000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
+000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
+000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
+00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
+00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
+00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
+00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000|
+00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
+00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
+00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
+00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
+00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
+00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
+000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
+000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
+000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
+000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
+000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
+000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
+00000200 16 03 03 00 86 10 00 00 82 00 80 44 89 7d aa 26 |...........D.}.&|
+00000210 30 ce 6b db 25 70 b0 1e 16 fa 5b 3a dd 4a 4b bd |0.k.%p....[:.JK.|
+00000220 ec ee 50 9d 21 ba 52 b5 51 4f a8 65 d8 2e 41 e2 |..P.!.R.QO.e..A.|
+00000230 e1 dc f3 1a df 58 4f 87 7a d3 e1 e1 1c 13 b2 0b |.....XO.z.......|
+00000240 b7 43 b7 92 f2 df 19 bb 79 71 e0 71 44 ab 19 2f |.C......yq.qD../|
+00000250 37 11 ac 62 50 b6 f1 53 fe aa b4 bc 29 8e 0b 4c |7..bP..S....)..L|
+00000260 0b 12 8d d5 84 a9 fa a9 ea 16 aa c3 0d da 32 c8 |..............2.|
+00000270 e0 4c 9f 99 f8 69 cd a8 c3 b1 76 42 67 f3 ff 15 |.L...i....vBg...|
+00000280 52 95 43 66 da 49 43 25 9d e5 eb 16 03 03 00 88 |R.Cf.IC%........|
+00000290 0f 00 00 84 04 01 00 80 01 d5 0e 1c 75 97 89 52 |............u..R|
+000002a0 1a f0 cc ef 93 6e 71 b2 b1 38 8c 50 11 f7 a3 02 |.....nq..8.P....|
+000002b0 71 c4 d5 6f 8d 01 83 06 2e ea 5a 10 8a 0d d0 fc |q..o......Z.....|
+000002c0 b6 a2 63 af 4f 99 b5 eb ab fd 01 c2 fb 26 fc fd |..c.O........&..|
+000002d0 ad 2c b3 63 b3 87 a6 f5 14 ea 7d e7 fe a8 e7 7e |.,.c......}....~|
+000002e0 20 ab b9 f6 c3 58 bd c0 f3 96 eb 83 dc 42 6c 0d | ....X.......Bl.|
+000002f0 5e e8 09 55 c7 b8 24 05 dd e1 7c af 9f 2c 22 6c |^..U..$...|..,"l|
+00000300 fa b8 94 13 3b f1 09 e1 38 59 fc a1 8c cb aa ca |....;...8Y......|
+00000310 f8 e0 2a 9c 36 f9 c3 2b 14 03 03 00 01 01 16 03 |..*.6..+........|
+00000320 03 00 24 d0 12 7c cc d2 3e 37 1f f4 7d b4 c0 fc |..$..|..>7..}...|
+00000330 19 f6 c8 ea 62 12 e0 0d af 62 d4 69 f7 96 5a c0 |....b....b.i..Z.|
+00000340 97 d3 bb b0 a3 f7 3f |......?|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 cd 20 85 1e 74 |..........$. ..t|
+00000010 18 b2 71 48 d5 10 61 c6 b0 18 26 83 c2 7f f1 b1 |..qH..a...&.....|
+00000020 2f b5 35 d0 47 a8 99 9a 9a a5 62 64 fb f9 29 17 |/.5.G.....bd..).|
+00000030 03 03 00 21 22 7b ed 61 e3 9b 6d 98 b9 23 98 e3 |...!"{.a..m..#..|
+00000040 55 11 b8 0f 7e 2b e1 c1 d4 f1 83 79 c3 f8 03 f0 |U...~+.....y....|
+00000050 02 5c 61 24 d7 15 03 03 00 16 14 2b a3 5a 56 f0 |.\a$.......+.ZV.|
+00000060 92 da d0 e6 32 91 d8 30 7a b4 d0 a2 93 f5 01 ea |....2..0z.......|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
new file mode 100644
index 000000000..562fe1aaa
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 1b |....\...X..R.WY.|
+00000010 08 fe f7 8a bf 07 84 2b 60 a6 13 2d 15 13 f8 b6 |.......+`..-....|
+00000020 d4 b6 3b f2 7a 98 ff 32 a0 68 7c 00 00 04 00 05 |..;.z..2.h|.....|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........|
+00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........|
+00000310 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................|
+00000010 86 10 00 00 82 00 80 6b 51 48 d3 18 7d 30 e0 0c |.......kQH..}0..|
+00000020 20 8d f3 e4 39 47 30 0e a5 85 79 f9 8b 11 50 9e | ...9G0...y...P.|
+00000030 81 71 5c 26 c6 bb cb aa d5 00 d1 89 79 b1 77 2d |.q\&........y.w-|
+00000040 eb 9b 86 7c 52 c6 f7 b7 10 b0 b6 94 22 51 b8 12 |...|R......."Q..|
+00000050 3c 09 35 8e 1b cc f4 3b b7 b8 78 ab 89 59 41 49 |<.5....;..x..YAI|
+00000060 21 31 eb f0 f8 94 63 3d e6 96 8f b6 63 95 05 dd |!1....c=....c...|
+00000070 46 b3 00 8a d6 83 75 99 1b 5a 48 0a 23 b5 10 c1 |F.....u..ZH.#...|
+00000080 95 b5 bc 15 72 b5 f5 a0 62 e2 1d c0 ff d2 87 a5 |....r...b.......|
+00000090 97 5c 33 49 a7 26 35 14 03 03 00 01 01 16 03 03 |.\3I.&5.........|
+000000a0 00 24 61 38 1f 9d fb d9 65 2e 02 07 fb be f9 85 |.$a8....e.......|
+000000b0 8d 15 34 c0 d1 0e 4e 10 3c 25 60 2f ac 04 21 66 |..4...N.<%`/..!f|
+000000c0 04 9d 9a 60 31 72 |...`1r|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 fe 0e 3e 84 af |..........$..>..|
+00000010 e5 6b 10 ed 41 9c 2b e0 ba e0 2b 53 61 36 1b 40 |.k..A.+...+Sa6.@|
+00000020 35 de 3a c7 c3 5c df 74 67 f7 05 74 84 f5 e1 17 |5.:..\.tg..t....|
+00000030 03 03 00 21 d3 8d 81 85 b7 1f 30 bd 89 33 f9 81 |...!......0..3..|
+00000040 89 f7 af d1 be b0 c1 46 e3 df 32 f6 dc 2f 4d 82 |.......F..2../M.|
+00000050 0a 84 9f 5b 03 15 03 03 00 16 13 af 37 91 82 67 |...[........7..g|
+00000060 b0 7c 5e 0e ec 8e cc 31 a0 ea a5 72 a4 2b 0b 73 |.|^....1...r.+.s|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 000000000..aacbb8670
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f0 f9 09 |...........S....|
+00000010 13 56 01 37 84 b1 32 59 4c 73 b1 8e bb 02 1a 32 |.V.7..2YLs.....2|
+00000020 db ab 8c e6 ed ad 7f 52 9a 59 39 00 00 04 c0 0a |.......R.Y9.....|
+00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........|
+00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............|
+00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................|
+00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................|
+00000070 00 0f 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 |.........". ....|
+00000080 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000090 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+000000a0 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 0e 0b 00 02 0a 00 |................|
+00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...|
+00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.|
+00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....|
+00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12|
+000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221|
+000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.|
+000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U|
+000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!|
+000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne|
+00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt|
+00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...|
+00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........|
+00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.|
+00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..|
+00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.|
+00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...|
+00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...|
+00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..|
+00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........|
+000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0|
+000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.|
+000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...|
+000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.|
+000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;|
+000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.|
+00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.|
+00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
+00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
+00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......|
+00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
+00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
+00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
+00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
+00000290 41 03 56 6b dc 5a 89 04 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B|
+000002a0 00 c6 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 |...........>.f#.|
+000002b0 b4 42 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d |.B.d.9.?.!.(.`kM|
+000002c0 3d ba a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff |=..K^w..Y(...'..|
+000002d0 a8 de 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 |..3H...jB..~~1..|
+000002e0 bd 66 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b |.f.B..}.5.......|
+000002f0 49 5e 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 |I^._.....+...c..|
+00000300 14 62 db 1e c9 2c 13 ae b7 d3 17 38 23 2f f6 7f |.b...,.....8#/..|
+00000310 0c 4d d3 33 d2 79 d1 77 ee cb b1 c2 fc 34 b8 69 |.M.3.y.w.....4.i|
+00000320 f9 10 8b 61 89 85 16 03 03 00 04 0e 00 00 00 |...a...........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 dd 22 68 a1 4e |....F...BA.."h.N|
+00000010 04 1b 47 f9 c5 7d 04 1d d8 fe 84 fa be 31 2e a7 |..G..}.......1..|
+00000020 f8 e5 b8 14 92 44 99 11 0e 34 97 fc e5 b1 91 cf |.....D...4......|
+00000030 a4 d1 3f b4 71 94 c6 06 16 f0 98 c0 3e 05 f9 2f |..?.q.......>../|
+00000040 0a 97 78 3d ef dc fa a2 d7 ee 7d 14 03 03 00 01 |..x=......}.....|
+00000050 01 16 03 03 00 40 90 bf 7f e9 c9 6e d1 80 f5 12 |.....@.....n....|
+00000060 6d c5 b7 c5 15 4b 18 a5 d3 18 1e f8 8c 4d 7e 6d |m....K.......M~m|
+00000070 03 60 29 7c 45 7c b2 ca 8c 07 71 70 aa 23 fa 6e |.`)|E|....qp.#.n|
+00000080 d9 0b 0a 32 4c 9e e5 00 f9 19 9b b6 8d dc d3 67 |...2L..........g|
+00000090 3d 0f bb b8 4b 9e |=...K.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 a1 6e e5 d1 ca |............n...|
+00000020 03 f4 77 dc ec ee 5d f0 22 5e 7f 55 1a 8d ad 45 |..w...]."^.U...E|
+00000030 09 f1 3b b2 61 36 dc 3d 2a 1e 1f e5 a7 84 76 a9 |..;.a6.=*.....v.|
+00000040 41 5b 86 03 ac 22 18 20 9b a9 29 17 03 03 00 40 |A[...". ..)....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 f5 cb 28 1e b5 bc 82 7f 82 38 54 14 e8 b9 6d 3b |..(......8T...m;|
+00000070 bc 99 d6 0e f9 00 96 99 a8 92 2e 86 9d 62 4e 90 |.............bN.|
+00000080 27 52 58 45 20 93 90 a1 f3 a8 89 2b e7 21 24 16 |'RXE ......+.!$.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 a8 2a ab 8f b0 ce 49 8b fd a5 c9 |......*....I....|
+000000b0 11 b2 04 83 18 f3 1d 6c 82 34 1d df dd 2f 45 3b |.......l.4.../E;|
+000000c0 27 8a 0f 16 69 |'...i|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket
new file mode 100644
index 000000000..e3e62f224
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 60 01 00 00 5c 03 03 52 cc 57 59 7e |....`...\..R.WY~|
+00000010 43 5c 3b fd 50 ab 61 3f 64 a4 f9 bd ba 8c 28 e1 |C\;.P.a?d.....(.|
+00000020 f9 a1 45 7e 48 9e 62 af 25 de 0e 00 00 04 00 05 |..E~H.b.%.......|
+00000030 00 ff 01 00 00 2f 00 23 00 00 00 0d 00 22 00 20 |...../.#.....". |
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................|
+00000060 00 0f 00 01 01 |.....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............|
+00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..|
+00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................|
+00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........|
+00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1|
+00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S|
+00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I|
+000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits |
+000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042|
+000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424|
+000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U|
+000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...|
+000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..|
+00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W|
+00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.|
+00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...|
+00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..|
+00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#|
+00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.|
+00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..|
+00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq|
+00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...|
+000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......|
+000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....|
+000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....|
+000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..|
+000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l|
+000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.|
+00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.|
+00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U|
+00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!|
+00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne|
+00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt|
+00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...|
+00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.|
+00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE|
+00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z|
+00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O|
+000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z|
+000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..|
+000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..|
+000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _|
+000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m|
+000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......|
+00000300 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 6e 2e 79 82 3a |...........n.y.:|
+00000010 c4 68 72 f5 a2 42 3d 71 f9 ec 22 8c 0b fa f0 82 |.hr..B=q..".....|
+00000020 82 c0 cb fc 52 0a 51 03 04 8c eb 4a 4e 4f b6 49 |....R.Q....JNO.I|
+00000030 ef 94 65 21 3c f7 9d 46 85 6e 35 d5 17 6b ff a3 |..e!<..F.n5..k..|
+00000040 5e 4d c1 36 1a 2f 68 f5 06 d4 2d 73 4f 1c 3b 7b |^M.6./h...-sO.;{|
+00000050 c1 fa 4e 7e 7c f9 6c 13 a6 f4 3a 43 e9 aa be 22 |..N~|.l...:C..."|
+00000060 85 6f 2f 7c 5b b0 08 e2 86 b2 ae cb a9 12 d8 32 |.o/|[..........2|
+00000070 80 1d e4 2e 5d c3 66 d1 19 e5 89 33 2a 88 24 40 |....].f....3*.$@|
+00000080 2a 6d 6b b5 f1 92 4b 66 06 b8 49 14 03 03 00 01 |*mk...Kf..I.....|
+00000090 01 16 03 03 00 24 16 49 e2 a0 67 31 cf 0d 72 cb |.....$.I..g1..r.|
+000000a0 ac 16 2c 80 37 71 69 f7 5f c4 d3 00 19 b7 4b fb |..,.7qi._.....K.|
+000000b0 e5 e9 74 8e 30 b3 1c c5 ae e6 |..t.0.....|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e|
+00000020 ea 4b d1 ef ba 06 38 1e e1 88 82 3a cd 03 ac 3b |.K....8....:...;|
+00000030 39 0a e0 19 fd af 6c 57 30 df 31 6e f7 92 38 4b |9.....lW0.1n..8K|
+00000040 5d 77 90 39 ff 32 51 f5 ed 12 d7 b0 7c 4d 6c c5 |]w.9.2Q.....|Ml.|
+00000050 76 e4 72 48 3e 59 23 fe 0d 15 df f4 ba ea b9 67 |v.rH>Y#........g|
+00000060 16 23 8f 7d 15 b6 11 f1 ab d7 d4 cd a3 21 82 92 |.#.}.........!..|
+00000070 2a 12 cf 95 f3 60 b2 14 03 03 00 01 01 16 03 03 |*....`..........|
+00000080 00 24 89 ad 87 04 4f 08 dc 2a 71 37 fb f1 95 d1 |.$....O..*q7....|
+00000090 2e 3c c2 6e 0f 38 5d e4 0e c3 f7 27 d0 46 a3 c1 |.<.n.8]....'.F..|
+000000a0 a8 3b 06 ed 96 ec 17 03 03 00 21 30 d4 9f 0b 49 |.;........!0...I|
+000000b0 9f a2 a8 a1 2c 0a 79 93 56 2d 8a ee 85 ed 62 42 |....,.y.V-....bB|
+000000c0 8c 18 fe 7a 09 3a 24 c4 5e ed 7d 2a 15 03 03 00 |...z.:$.^.}*....|
+000000d0 16 a0 24 0a 8b 90 4c fc 99 ba 67 bb 04 1e 59 69 |..$...L...g...Yi|
+000000e0 c2 98 49 b5 00 0b e0 |..I....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES
new file mode 100644
index 000000000..5995b3314
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 68 |....\...X..R.WYh|
+00000010 11 72 a6 ec 6b 0a 47 1d 10 06 ec 75 af 07 38 a0 |.r..k.G....u..8.|
+00000020 30 9e 91 12 e1 9b 19 46 0d d4 45 00 00 04 00 0a |0......F..E.....|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 7a c0 73 ec cb |...........z.s..|
+00000010 cf c2 a8 86 c0 7e 03 63 57 a1 ce 42 37 6d 78 54 |.....~.cW..B7mxT|
+00000020 29 f5 3e cc 57 c7 0d d9 69 e1 52 5c 3b 6b c4 c7 |).>.W...i.R\;k..|
+00000030 20 6d 59 ee c0 07 81 74 74 9f 62 41 64 f0 4d c8 | mY....tt.bAd.M.|
+00000040 9b aa 1a b9 da 56 07 f5 6c 1c 59 8c d3 f9 08 d9 |.....V..l.Y.....|
+00000050 08 f4 16 93 5d 9a e5 6f fb 9f ba 3d 3c d6 81 ad |....]..o...=<...|
+00000060 02 12 a7 28 b6 81 6a 77 c3 e9 d7 c7 54 d6 77 83 |...(..jw....T.w.|
+00000070 77 de 71 fb b3 f3 2d c4 a5 b1 e5 de aa 0e 21 bd |w.q...-.......!.|
+00000080 91 a2 dc 7f f7 6f 90 82 54 b1 e7 14 03 03 00 01 |.....o..T.......|
+00000090 01 16 03 03 00 30 8f ee bf fb c8 5c 54 f5 29 23 |.....0.....\T.)#|
+000000a0 d4 55 f6 98 a1 6e d5 43 e7 81 b2 36 f2 98 d8 1b |.U...n.C...6....|
+000000b0 0d 76 cb 14 ba 32 d7 36 30 e6 ab 42 80 95 f6 8a |.v...2.60..B....|
+000000c0 60 64 a0 6b 90 81 |`d.k..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....|
+00000010 00 00 00 2c 21 52 34 63 ac e3 a3 66 45 00 41 0c |...,!R4c...fE.A.|
+00000020 93 5d 6a 74 5a 25 dc 69 1d 76 73 0c f4 42 6a 18 |.]jtZ%.i.vs..Bj.|
+00000030 5b 62 23 e7 fe 41 cf d4 9b 86 35 17 03 03 00 30 |[b#..A....5....0|
+00000040 00 00 00 00 00 00 00 00 7d 5d ce 43 85 5c 6b 89 |........}].C.\k.|
+00000050 c9 a5 0e 22 69 8e b9 4a 77 4c c0 4e cc 79 d9 7e |..."i..JwL.N.y.~|
+00000060 a3 c8 d3 db 5c 53 f8 92 4d c4 5a 88 72 58 05 11 |....\S..M.Z.rX..|
+00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 1d 63 8b |.... .........c.|
+00000080 a7 74 fb 76 1d 47 31 93 1f ec 8c e2 18 8e 21 dd |.t.v.G1.......!.|
+00000090 87 97 9f 1c ca |.....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES
new file mode 100644
index 000000000..a152a96a8
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 d0 |....\...X..R.WY.|
+00000010 38 05 36 7e e3 1e 93 2a 5a bf dc c2 f8 0a 03 6f |8.6~...*Z......o|
+00000020 1a fc 21 74 e5 8b 2a c3 9e 2c 26 00 00 04 00 2f |..!t..*..,&..../|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 4b b4 28 bc 78 |...........K.(.x|
+00000010 41 34 f3 49 e8 74 07 74 42 ae 2e 55 9e 9a ce e5 |A4.I.t.tB..U....|
+00000020 4a 1b e7 55 c7 64 c4 9c b3 dd 20 d6 f8 8e 67 b3 |J..U.d.... ...g.|
+00000030 7a 5c 3b 34 e4 1a f6 bd 65 fc 21 cd 9a de 64 77 |z\;4....e.!...dw|
+00000040 09 a5 92 e5 a4 f5 18 7b 23 5b 8b c1 95 23 97 6f |.......{#[...#.o|
+00000050 76 55 04 34 22 7d 43 71 db cd eb f8 36 36 44 4b |vU.4"}Cq....66DK|
+00000060 ae e3 cc ec 64 88 7b e1 ea d6 ab 49 35 94 a5 04 |....d.{....I5...|
+00000070 1e 83 c5 cf 21 bb ca 33 5f d4 bf 1d d3 4d 07 59 |....!..3_....M.Y|
+00000080 b4 39 b2 4b 7b 05 43 70 0d ba 7a 14 03 03 00 01 |.9.K{.Cp..z.....|
+00000090 01 16 03 03 00 40 74 4b 7d b2 53 49 ea 86 90 c3 |.....@tK}.SI....|
+000000a0 64 6b 64 31 1a 2a 3f 1a 37 1e 56 b8 dd 12 6d 56 |dkd1.*?.7.V...mV|
+000000b0 2a 61 92 5b 39 e7 e1 be 71 70 4b 9b b3 f0 71 e7 |*a.[9...qpK...q.|
+000000c0 47 2e 2e 17 c3 0a 66 9f 69 74 30 2d f0 a0 7f 84 |G.....f.it0-....|
+000000d0 25 db c1 81 ee cf |%.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 f3 4d 5a fc 21 |............MZ.!|
+00000020 30 b5 a1 86 9d e2 ea 38 ac 54 57 fa 5a 54 97 b8 |0......8.TW.ZT..|
+00000030 bb 4d 64 09 ef ce a1 75 0c 50 8d ff 5c c2 e9 47 |.Md....u.P..\..G|
+00000040 95 93 53 c0 bd dc c5 9c e0 59 17 17 03 03 00 40 |..S......Y.....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 69 c5 48 6e 45 cf 98 1b 2c 23 40 d1 ab a3 c2 e2 |i.HnE...,#@.....|
+00000070 10 7b b1 c8 21 3c f0 eb 96 bd 4f 78 b2 4a 7b 18 |.{..!<....Ox.J{.|
+00000080 4c b1 a6 67 bf 06 40 01 d0 8d 91 be 17 d8 0c 71 |L..g..@........q|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 20 84 80 3d 70 fe ae ee d7 2f e9 |..... ..=p..../.|
+000000b0 bf 65 30 bf 0b dd 98 ea bb ba 12 14 98 53 7f d5 |.e0..........S..|
+000000c0 56 ce 06 3c d0 |V..<.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
new file mode 100644
index 000000000..0ddfe022f
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f1 30 73 |...........S..0s|
+00000010 a1 ea 8c d2 90 1c c6 d6 0d 3c af 58 21 65 90 25 |.........<.X!e.%|
+00000020 5e fa f4 27 22 65 c9 68 90 b9 04 00 00 04 c0 2f |^..'"e.h......./|
+00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........|
+00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............|
+00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................|
+00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................|
+00000070 00 0f 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 |.........". ....|
+00000080 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000090 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+000000a0 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 cd 0c 00 |n8P)l...........|
+00000300 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
+00000310 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
+00000320 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
+00000330 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
+00000340 41 03 56 6b dc 5a 89 04 01 00 80 a2 54 61 84 29 |A.Vk.Z......Ta.)|
+00000350 3e 97 4b 97 9a 9f 5c c0 49 6d 86 d2 79 8e 95 a1 |>.K...\.Im..y...|
+00000360 0a 5a 36 73 34 bb 05 73 35 47 e1 2b 5d f3 ef 36 |.Z6s4..s5G.+]..6|
+00000370 a8 32 e2 7e ef aa 3f 1f b3 64 60 d4 06 2e 98 e3 |.2.~..?..d`.....|
+00000380 11 e2 60 3c d6 20 17 63 b2 6f a0 cd 21 01 2b 4e |..`<. .c.o..!.+N|
+00000390 b2 a8 55 04 39 37 5c 6c 71 66 4d a3 eb 1b 83 67 |..U.97\lqfM....g|
+000003a0 6b 15 a0 56 9a f1 a2 79 92 29 ce 58 3c 10 4d 65 |k..V...y.).X<.Me|
+000003b0 1f 22 e3 ea d8 74 aa 01 7e ca f3 89 23 41 4d bd |."...t..~...#AM.|
+000003c0 df 77 4e 59 54 97 74 ad 07 ea c0 16 03 03 00 04 |.wNYT.t.........|
+000003d0 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 45 65 ce f7 b9 |....F...BA.Ee...|
+00000010 52 e3 fb 13 db 91 f2 65 43 84 57 f5 1a 19 a0 e6 |R......eC.W.....|
+00000020 89 2d bb 2c 83 6b 62 f6 6f 1f 26 ae 59 67 bd dc |.-.,.kb.o.&.Yg..|
+00000030 c4 9e 0b dc 7d 6e f8 6b 95 8c 61 47 3d cd d1 df |....}n.k..aG=...|
+00000040 82 45 30 81 c3 a3 49 5d 85 59 70 14 03 03 00 01 |.E0...I].Yp.....|
+00000050 01 16 03 03 00 28 3f aa 85 33 f9 c6 95 a0 56 ff |.....(?..3....V.|
+00000060 1c f1 5a ba 6e 41 50 0c ab 92 e1 e2 8e 89 1c f1 |..Z.nAP.........|
+00000070 fa 54 1b f1 f5 00 01 12 6d c4 96 78 b6 87 |.T......m..x..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 94 5c be 46 05 d6 d0 b0 3a 56 dc 2c 10 |....\.F....:V.,.|
+00000020 0f 6f 5d 33 33 7f a5 4e 74 84 bf 63 87 c4 f4 49 |.o]33..Nt..c...I|
+00000030 bc 6b ab 17 03 03 00 25 00 00 00 00 00 00 00 01 |.k.....%........|
+00000040 7e 4f f9 ae ae fe 6b a0 4a f8 0f 0b b4 b6 65 b6 |~O....k.J.....e.|
+00000050 be 24 5f 94 6d d1 db 54 11 07 b9 ce 01 15 03 03 |.$_.m..T........|
+00000060 00 1a 00 00 00 00 00 00 00 02 a8 1c d6 62 ac fd |.............b..|
+00000070 77 ba 23 92 5d 34 f1 17 c7 e1 1c 99 |w.#.]4......|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4
new file mode 100644
index 000000000..b703a8f76
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 c9 |....\...X..R.WY.|
+00000010 c3 13 fc 18 8a ee c2 0e 88 ff fb 4a 16 f2 eb eb |...........J....|
+00000020 d4 f8 b3 5b cd bb 25 0e 0b cb 48 00 00 04 00 05 |...[..%...H.....|
+00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................|
+00000060 01 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
+00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................|
+00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......|
+00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.|
+00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..|
+00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State|
+00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter|
+000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty |
+000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090|
+000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909|
+000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....|
+000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som|
+000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..|
+00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi|
+00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..|
+00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F|
+00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC|
+00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....|
+00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z|
+00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......|
+00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....|
+00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.||
+000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...|
+000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0|
+000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........|
+000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...|
+000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....|
+000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..|
+00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.|
+00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
+00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
+00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
+00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...|
+00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...|
+00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...|
+00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.|
+00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z|
+00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`|
+000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.|
+000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.|
+000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.|
+000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....|
+000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&|
+000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........|
+00000300 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 35 b3 60 ba 14 |...........5.`..|
+00000010 5f 19 24 a0 24 de 4e 85 a9 64 78 3a 51 24 64 70 |_.$.$.N..dx:Q$dp|
+00000020 88 55 6d c3 11 b8 d3 9f bc 7a 33 f8 3c 48 93 2f |.Um......z3.<H./|
+00000030 66 69 11 33 39 37 7a 36 a3 1c ef b0 81 71 7d 25 |fi.397z6.....q}%|
+00000040 35 da 2c 42 e2 ab d3 b7 07 8b 4a 0d 6d 77 bd ae |5.,B......J.mw..|
+00000050 02 51 7c a5 0d a6 03 4c 3c d0 ce 89 2c 83 6c de |.Q|....L<...,.l.|
+00000060 40 15 cc 72 c7 95 c8 6d ee 05 86 da 3e c6 7c d4 |@..r...m....>.|.|
+00000070 44 82 f4 24 03 22 40 00 64 27 53 15 41 8c 01 e9 |D..$."@.d'S.A...|
+00000080 39 32 fa 8e 2d f9 b4 89 34 15 d6 14 03 03 00 01 |92..-...4.......|
+00000090 01 16 03 03 00 24 f5 61 8b 24 bf b4 82 3a cf 49 |.....$.a.$...:.I|
+000000a0 99 a0 b1 1b a7 a7 a3 92 7c 84 85 e0 64 a3 3d bd |........|...d.=.|
+000000b0 38 98 7d 97 a8 b9 2a 35 a9 09 |8.}...*5..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 c9 0b 84 e6 39 |..........$....9|
+00000010 f2 e0 f3 ac 9f 0f 17 92 5f 6d de 94 18 c4 60 d9 |........_m....`.|
+00000020 66 c3 0d 1a ae c2 8f 46 8f 7f f0 58 0e 4a 9b 17 |f......F...X.J..|
+00000030 03 03 00 21 8b 73 a1 6a 7e d9 7e 4f 1d cc b2 7d |...!.s.j~.~O...}|
+00000040 3c 83 3f 52 f8 08 77 01 4c 65 11 6d 50 25 9a cc |<.?R..w.Le.mP%..|
+00000050 e3 54 27 72 59 15 03 03 00 16 3d c8 ab 14 51 fa |.T'rY.....=...Q.|
+00000060 97 f1 ef 5f b4 4f 44 58 d4 93 3b ae e5 61 1f a3 |..._.ODX..;..a..|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume b/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume
new file mode 100644
index 000000000..c495d4adc
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume
@@ -0,0 +1,36 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e8 01 00 00 e4 03 03 52 cc 57 59 c3 |...........R.WY.|
+00000010 8b df 97 05 d8 5f 16 22 b4 b1 e7 cb 7d 2f 9b 58 |....._."....}/.X|
+00000020 a3 f4 d7 2c a4 c1 9d 49 ed 4b ba 20 90 da 90 3e |...,...I.K. ...>|
+00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...|
+00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 04 00 05 |.S...N`fq.......|
+00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......|
+00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...|
+00000070 06 38 1e e1 88 82 3a cd 03 ac 3b 39 0a e0 19 fd |.8....:...;9....|
+00000080 af 6c 57 30 df 31 6e f7 92 38 4b 5d 77 90 39 ff |.lW0.1n..8K]w.9.|
+00000090 32 51 f5 ed 12 d7 b0 7c 4d 6c c5 76 e4 72 48 3e |2Q.....|Ml.v.rH>|
+000000a0 59 23 fe 0d 15 df f4 ba ea b9 67 16 23 8f 7d 15 |Y#........g.#.}.|
+000000b0 b6 11 f1 ab d7 d4 cd a3 21 82 92 2a 12 cf 95 f3 |........!..*....|
+000000c0 60 b2 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |`....". ........|
+000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 90 da 90 3e |........... ...>|
+00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...|
+00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 05 00 00 |.S...N`fq.......|
+00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
+00000060 24 11 12 ff 28 10 14 4c e5 0e ad a7 fa f3 92 fb |$...(..L........|
+00000070 13 7d ae f2 b2 4a 6b a1 9e 67 cf a8 f7 8c 6f a0 |.}...Jk..g....o.|
+00000080 6c 30 0e 18 55 |l0..U|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 16 03 03 00 24 0d 46 41 8b 24 |..........$.FA.$|
+00000010 36 01 a9 fd 8b ec fc e6 b1 83 96 df 0d 3e 53 54 |6............>ST|
+00000020 58 b8 43 f2 a6 25 5e 1a ae 19 9e d2 28 44 92 |X.C..%^.....(D.|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 21 c4 fb f6 53 bb 3e 04 cc 0b a0 03 |....!...S.>.....|
+00000010 fa 49 96 da b5 8d b2 f2 e5 d8 f3 5c 27 57 4f 9c |.I.........\'WO.|
+00000020 30 00 34 fc 52 92 15 03 03 00 16 a3 02 7a 50 d2 |0.4.R........zP.|
+00000030 c6 b3 fc 69 8f e4 94 ae ab 22 ad 05 1d 15 69 b9 |...i....."....i.|
+00000040 a5 |.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI b/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI
new file mode 100644
index 000000000..61b17a11d
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 70 01 00 00 6c 03 03 52 cc 57 59 2d |....p...l..R.WY-|
+00000010 77 aa 75 35 fa ff 2a a2 bf 91 5e e3 7f 38 7d 7a |w.u5..*...^..8}z|
+00000020 e3 93 d3 e8 8b 09 bb 06 c8 6d 91 00 00 04 00 2f |.........m...../|
+00000030 00 ff 01 00 00 3f 00 00 00 10 00 0e 00 00 0b 73 |.....?.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 22 00 20 |nitest.com...". |
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................|
+00000070 00 0f 00 01 01 |.....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
+00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
+00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
+00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
+00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
+00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
+00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
+000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
+000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
+000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
+000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
+000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
+000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
+00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
+00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
+00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
+00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
+00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
+00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
+00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
+00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
+00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
+00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
+000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
+000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
+000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
+000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
+000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
+000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
+00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
+00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
+00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
+00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
+00000240 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 0d f2 bf 75 a9 |..............u.|
+00000010 aa db f3 25 55 d4 20 59 63 54 d1 70 82 f9 61 c5 |...%U. YcT.p..a.|
+00000020 b7 ae 3f 75 71 75 9d c5 01 a1 ed b1 07 66 9f 3f |..?uqu.......f.?|
+00000030 cf c6 e6 ad 44 03 fd 18 6f 53 24 ce 76 01 bd fe |....D...oS$.v...|
+00000040 e2 51 f7 df 8a 23 3a 21 c4 00 15 ff d0 e0 ff c8 |.Q...#:!........|
+00000050 8b 89 33 c6 8e e0 ce 97 ef b4 c6 f9 b0 ea 38 89 |..3...........8.|
+00000060 79 98 34 9e f7 bc c6 fd d2 5d 56 84 5c d2 9a ce |y.4......]V.\...|
+00000070 ae de 09 bc 24 25 fc 09 0c bc 0e 91 0d 6b 36 ae |....$%.......k6.|
+00000080 ce 6b cd 14 ec b6 3c fa d6 df fc 14 03 03 00 01 |.k....<.........|
+00000090 01 16 03 03 00 40 ad 21 13 2b 33 7a 4a 0d fb 0f |.....@.!.+3zJ...|
+000000a0 eb d2 b6 85 29 1f 59 79 ba 86 53 5c 68 b4 c7 e3 |....).Yy..S\h...|
+000000b0 8a 6c 5c 18 04 4d e4 76 19 30 ba 92 b4 79 8c 64 |.l\..M.v.0...y.d|
+000000c0 00 a0 2e 13 96 45 9f e7 a9 e4 23 9e 9f 89 23 26 |.....E....#...#&|
+000000d0 36 20 82 fc 75 fe |6 ..u.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 b7 87 61 10 03 |.............a..|
+00000020 b8 a4 42 d4 8b 49 bc 40 80 70 92 c8 25 b0 c6 7f |..B..I.@.p..%...|
+00000030 b3 87 76 50 5a 59 b3 3c d8 3e 23 24 aa 1a f3 36 |..vPZY.<.>#$...6|
+00000040 c9 2c 87 c1 22 d2 94 f8 2c fd ef 17 03 03 00 40 |.,.."...,......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 e5 7f bd 3e ff 9f d4 1b 91 02 f8 69 6f 70 9d 51 |...>.......iop.Q|
+00000070 a5 ec ef 5b 10 3f 4e 3f 44 e5 9a 39 68 7c 3a b9 |...[.?N?D..9h|:.|
+00000080 69 38 31 ec 9c 45 bf 19 d1 5c 5e 2e 06 00 ca 19 |i81..E...\^.....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 63 5e 79 2c f2 05 dc 2b d7 5b ac |.....c^y,...+.[.|
+000000b0 9d fc 75 94 03 16 ca 1f b2 75 58 2d f1 2f f1 1e |..u......uX-./..|
+000000c0 d2 f6 84 8f 2e |.....|
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 6c67506fc..d50e12029 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -15,6 +15,7 @@ import (
"io/ioutil"
"net"
"strings"
+ "time"
)
// Server returns a new TLS server side connection
@@ -27,9 +28,8 @@ func Server(conn net.Conn, config *Config) *Conn {
// Client returns a new TLS client side connection
// using conn as the underlying transport.
-// Client interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
@@ -77,24 +77,51 @@ func Listen(network, laddr string, config *Config) (net.Listener, error) {
return NewListener(l, config), nil
}
-// Dial connects to the given network address using net.Dial
-// and then initiates a TLS handshake, returning the resulting
-// TLS connection.
-// Dial interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
-func Dial(network, addr string, config *Config) (*Conn, error) {
- raddr := addr
- c, err := net.Dial(network, raddr)
+type timeoutError struct{}
+
+func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ // We want the Timeout and Deadline values from dialer to cover the
+ // whole process: TCP connection and TLS handshake. This means that we
+ // also need to start our own timers now.
+ timeout := dialer.Timeout
+
+ if !dialer.Deadline.IsZero() {
+ deadlineTimeout := dialer.Deadline.Sub(time.Now())
+ if timeout == 0 || deadlineTimeout < timeout {
+ timeout = deadlineTimeout
+ }
+ }
+
+ var errChannel chan error
+
+ if timeout != 0 {
+ errChannel = make(chan error, 2)
+ time.AfterFunc(timeout, func() {
+ errChannel <- timeoutError{}
+ })
+ }
+
+ rawConn, err := dialer.Dial(network, addr)
if err != nil {
return nil, err
}
- colonPos := strings.LastIndex(raddr, ":")
+ colonPos := strings.LastIndex(addr, ":")
if colonPos == -1 {
- colonPos = len(raddr)
+ colonPos = len(addr)
}
- hostname := raddr[:colonPos]
+ hostname := addr[:colonPos]
if config == nil {
config = defaultConfig()
@@ -107,14 +134,37 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
c.ServerName = hostname
config = &c
}
- conn := Client(c, config)
- if err = conn.Handshake(); err != nil {
- c.Close()
+
+ conn := Client(rawConn, config)
+
+ if timeout == 0 {
+ err = conn.Handshake()
+ } else {
+ go func() {
+ errChannel <- conn.Handshake()
+ }()
+
+ err = <-errChannel
+ }
+
+ if err != nil {
+ rawConn.Close()
return nil, err
}
+
return conn, nil
}
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+ return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
// LoadX509KeyPair reads and parses a public/private key pair from a pair of
// files. The files must contain PEM encoded data.
func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
diff --git a/src/pkg/crypto/tls/tls_test.go b/src/pkg/crypto/tls/tls_test.go
index 38229014c..f8c94ff35 100644
--- a/src/pkg/crypto/tls/tls_test.go
+++ b/src/pkg/crypto/tls/tls_test.go
@@ -5,7 +5,12 @@
package tls
import (
+ "fmt"
+ "io"
+ "net"
+ "strings"
"testing"
+ "time"
)
var rsaCertPEM = `-----BEGIN CERTIFICATE-----
@@ -105,3 +110,128 @@ func TestX509MixedKeyPair(t *testing.T) {
t.Error("Load of ECDSA certificate succeeded with RSA private key")
}
}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ listener := newLocalListener(t)
+
+ addr := listener.Addr().String()
+ defer listener.Close()
+
+ complete := make(chan bool)
+ defer close(complete)
+
+ go func() {
+ conn, err := listener.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ <-complete
+ conn.Close()
+ }()
+
+ dialer := &net.Dialer{
+ Timeout: 10 * time.Millisecond,
+ }
+
+ var err error
+ if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil {
+ t.Fatal("DialWithTimeout completed successfully")
+ }
+
+ if !strings.Contains(err.Error(), "timed out") {
+ t.Errorf("resulting error not a timeout: %s", err)
+ }
+}
+
+// tests that Conn.Read returns (non-zero, io.EOF) instead of
+// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
+// behind the application data in the buffer.
+func TestConnReadNonzeroAndEOF(t *testing.T) {
+ // This test is racy: it assumes that after a write to a
+ // localhost TCP connection, the peer TCP connection can
+ // immediately read it. Because it's racy, we skip this test
+ // in short mode, and then retry it several times with an
+ // increasing sleep in between our final write (via srv.Close
+ // below) and the following read.
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ var err error
+ for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 {
+ if err = testConnReadNonzeroAndEOF(t, delay); err == nil {
+ return
+ }
+ }
+ t.Error(err)
+}
+
+func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ srvCh := make(chan *Conn, 1)
+ var serr error
+ go func() {
+ sconn, err := ln.Accept()
+ if err != nil {
+ serr = err
+ srvCh <- nil
+ return
+ }
+ serverConfig := *testConfig
+ srv := Server(sconn, &serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ srvCh <- nil
+ return
+ }
+ srvCh <- srv
+ }()
+
+ clientConfig := *testConfig
+ conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ srv := <-srvCh
+ if srv == nil {
+ return serr
+ }
+
+ buf := make([]byte, 6)
+
+ srv.Write([]byte("foobar"))
+ n, err := conn.Read(buf)
+ if n != 6 || err != nil || string(buf) != "foobar" {
+ return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
+ }
+
+ srv.Write([]byte("abcdef"))
+ srv.Close()
+ time.Sleep(delay)
+ n, err = conn.Read(buf)
+ if n != 6 || string(buf) != "abcdef" {
+ return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf)
+ }
+ if err != io.EOF {
+ return fmt.Errorf("Second Read error = %v; want io.EOF", err)
+ }
+ return nil
+}
diff --git a/src/pkg/crypto/x509/example_test.go b/src/pkg/crypto/x509/example_test.go
new file mode 100644
index 000000000..29e7c2139
--- /dev/null
+++ b/src/pkg/crypto/x509/example_test.go
@@ -0,0 +1,91 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509_test
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+)
+
+func ExampleCertificate_Verify() {
+ // Verifying with a custom list of root certificates.
+
+ const rootPEM = `
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----`
+
+ const certPEM = `
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
+WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
+bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
+5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
+7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
+BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
+BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
+LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
+cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
+BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
+AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
+L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
+gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
+TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
+0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
+RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
+yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
+-----END CERTIFICATE-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ block, _ := pem.Decode([]byte(certPEM))
+ if block == nil {
+ panic("failed to parse certificate PEM")
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ panic("failed to parse certificate: " + err.Error())
+ }
+
+ opts := x509.VerifyOptions{
+ DNSName: "mail.google.com",
+ Roots: roots,
+ }
+
+ if _, err := cert.Verify(opts); err != nil {
+ panic("failed to verify certificate: " + err.Error())
+ }
+}
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
index 5034946f7..58c1e54d1 100644
--- a/src/pkg/crypto/x509/pkix/pkix.go
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -30,6 +30,13 @@ type AttributeTypeAndValue struct {
Value interface{}
}
+// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
+// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
+type AttributeTypeAndValueSET struct {
+ Type asn1.ObjectIdentifier
+ Value [][]AttributeTypeAndValue `asn1:"set"`
+}
+
// Extension represents the ASN.1 structure of the same name. See RFC
// 5280, section 4.2.
type Extension struct {
diff --git a/src/pkg/crypto/x509/root_cgo_darwin.go b/src/pkg/crypto/x509/root_cgo_darwin.go
new file mode 100644
index 000000000..bdcc2c170
--- /dev/null
+++ b/src/pkg/crypto/x509/root_cgo_darwin.go
@@ -0,0 +1,79 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cgo
+
+package x509
+
+/*
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+//
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
+ if (pemRoots == NULL) {
+ return -1;
+ }
+
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+ if (err != noErr) {
+ return -1;
+ }
+
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ int i, ncerts = CFArrayGetCount(certs);
+ for (i = 0; i < ncerts; i++) {
+ CFDataRef data = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+ if (cert == NULL) {
+ continue;
+ }
+
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+
+ CFRelease(certs);
+
+ *pemRoots = combinedData;
+ return 0;
+}
+*/
+import "C"
+import "unsafe"
+
+func initSystemRoots() {
+ roots := NewCertPool()
+
+ var data C.CFDataRef = nil
+ err := C.FetchPEMRoots(&data)
+ if err == -1 {
+ return
+ }
+
+ defer C.CFRelease(C.CFTypeRef(data))
+ buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
+ roots.AppendCertsFromPEM(buf)
+ systemRoots = roots
+}
diff --git a/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
index ad3bfb4b4..2a61d36ea 100644
--- a/src/pkg/crypto/x509/root_darwin.go
+++ b/src/pkg/crypto/x509/root_darwin.go
@@ -1,81 +1,23 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// 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 x509
-/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
-#cgo LDFLAGS: -framework CoreFoundation -framework Security
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-
-// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-//
-// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
-// we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots) {
- if (pemRoots == NULL) {
- return -1;
- }
-
- CFArrayRef certs = NULL;
- OSStatus err = SecTrustCopyAnchorCertificates(&certs);
- if (err != noErr) {
- return -1;
- }
-
- CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- int i, ncerts = CFArrayGetCount(certs);
- for (i = 0; i < ncerts; i++) {
- CFDataRef data = NULL;
- SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
- if (cert == NULL) {
- continue;
- }
-
- // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
- // Once we support weak imports via cgo we should prefer that, and fall back to this
- // for older systems.
- err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
-
- if (data != NULL) {
- CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
- }
- }
-
- CFRelease(certs);
-
- *pemRoots = combinedData;
- return 0;
-}
-*/
-import "C"
-import "unsafe"
+import "os/exec"
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
-func initSystemRoots() {
- roots := NewCertPool()
-
- var data C.CFDataRef = nil
- err := C.FetchPEMRoots(&data)
- if err == -1 {
- return
+func execSecurityRoots() (*CertPool, error) {
+ cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
+ data, err := cmd.Output()
+ if err != nil {
+ return nil, err
}
- defer C.CFRelease(C.CFTypeRef(data))
- buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
- roots.AppendCertsFromPEM(buf)
- systemRoots = roots
+ roots := NewCertPool()
+ roots.AppendCertsFromPEM(data)
+ return roots, nil
}
diff --git a/src/pkg/crypto/x509/root_darwin_test.go b/src/pkg/crypto/x509/root_darwin_test.go
new file mode 100644
index 000000000..87ea4e344
--- /dev/null
+++ b/src/pkg/crypto/x509/root_darwin_test.go
@@ -0,0 +1,50 @@
+package x509
+
+import "testing"
+
+func TestSystemRoots(t *testing.T) {
+ sysRoots := systemRootsPool() // actual system roots
+ execRoots, err := execSecurityRoots() // non-cgo roots
+
+ if err != nil {
+ t.Fatalf("failed to read system roots: %v", err)
+ }
+
+ for _, tt := range []*CertPool{sysRoots, execRoots} {
+ if tt == nil {
+ t.Fatal("no system roots")
+ }
+ // On Mavericks, there are 212 bundled certs; require only
+ // 150 here, since this is just a sanity check, and the
+ // exact number will vary over time.
+ if want, have := 150, len(tt.certs); have < want {
+ t.Fatalf("want at least %d system roots, have %d", want, have)
+ }
+ }
+
+ // Check that the two cert pools are roughly the same;
+ // |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check.
+
+ isect := make(map[string]bool, len(sysRoots.certs))
+ for _, c := range sysRoots.certs {
+ isect[string(c.Raw)] = true
+ }
+
+ have := 0
+ for _, c := range execRoots.certs {
+ if isect[string(c.Raw)] {
+ have++
+ }
+ }
+
+ var want int
+ if nsys, nexec := len(sysRoots.certs), len(execRoots.certs); nsys > nexec {
+ want = nsys / 2
+ } else {
+ want = nexec / 2
+ }
+
+ if have < want {
+ t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+ }
+}
diff --git a/src/pkg/crypto/x509/root_nocgo_darwin.go b/src/pkg/crypto/x509/root_nocgo_darwin.go
new file mode 100644
index 000000000..d00e25766
--- /dev/null
+++ b/src/pkg/crypto/x509/root_nocgo_darwin.go
@@ -0,0 +1,11 @@
+// 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.
+
+// +build !cgo
+
+package x509
+
+func initSystemRoots() {
+ systemRoots, _ = execSecurityRoots()
+}
diff --git a/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go
deleted file mode 100644
index 4c742ccc3..000000000
--- a/src/pkg/crypto/x509/root_stub.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin,!cgo
-
-package x509
-
-func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
- return nil, nil
-}
-
-func initSystemRoots() {
-}
diff --git a/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go
index 324f855b1..11ad3c440 100644
--- a/src/pkg/crypto/x509/root_unix.go
+++ b/src/pkg/crypto/x509/root_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly freebsd linux openbsd netbsd
+// +build dragonfly freebsd linux nacl netbsd openbsd solaris
package x509
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 8327463ca..5fd8e3717 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -425,6 +425,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
// by each certificate. If we cross out all the usages, then the chain
// is unacceptable.
+NextCert:
for i := len(chain) - 1; i >= 0; i-- {
cert := chain[i]
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
@@ -435,7 +436,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
for _, usage := range cert.ExtKeyUsage {
if usage == ExtKeyUsageAny {
// The certificate is explicitly good for any usage.
- continue
+ continue NextCert
}
}
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index ba6c13d45..96b9d9b42 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -31,8 +31,8 @@ type verifyTest struct {
var verifyTests = []verifyTest{
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ currentTime: 1395785200,
dnsName: "www.google.com",
testSystemRootsError: true,
@@ -42,39 +42,39 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
},
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "WwW.GooGLE.coM",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
},
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.example.com",
errorCallback: expectHostnameError,
},
{
leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
currentTime: 1,
dnsName: "www.example.com",
@@ -82,8 +82,8 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
// Skip when using systemVerify, since Windows
@@ -93,14 +93,22 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeaf,
- intermediates: []string{verisignRoot, thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{geoTrustRoot, giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
expectedChains: [][]string{
- {"Google", "Thawte", "VeriSign"},
+ {"Google", "Google Internet Authority", "GeoTrust"},
+ // TODO(agl): this is ok, but it would be nice if the
+ // chain building didn't visit the same SPKI
+ // twice.
+ {"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"},
},
+ // CAPI doesn't build the chain with the duplicated GeoTrust
+ // entry so the results don't match. Thus we skip this test
+ // until that's fixed.
+ systemSkip: true,
},
{
leaf: dnssecExpLeaf,
@@ -128,9 +136,9 @@ var verifyTests = []verifyTest{
},
{
leaf: googleLeafWithInvalidHash,
- intermediates: []string{thawteIntermediate},
- roots: []string{verisignRoot},
- currentTime: 1302726541,
+ intermediates: []string{giag2Intermediate},
+ roots: []string{geoTrustRoot},
+ currentTime: 1395785200,
dnsName: "www.google.com",
// The specific error message may not occur when using system
@@ -201,6 +209,24 @@ var verifyTests = []verifyTest{
},
},
},
+ {
+ // Check that SHA-384 intermediates (which are popping up)
+ // work.
+ leaf: moipLeafCert,
+ intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
+ roots: []string{addTrustRoot},
+ currentTime: 1397502195,
+ dnsName: "api.moip.com.br",
+
+ expectedChains: [][]string{
+ {
+ "api.moip.com.br",
+ "COMODO RSA Extended Validation Secure Server CA",
+ "COMODO RSA Certification Authority",
+ "AddTrust External CA Root",
+ },
+ },
+ },
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -385,84 +411,111 @@ func nameToKey(name *pkix.Name) string {
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
-const verisignRoot = `-----BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
-lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
-AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+const geoTrustRoot = `-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
`
-const thawteIntermediate = `-----BEGIN CERTIFICATE-----
-MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi
-bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw
-MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
-d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD
-QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx
-PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g
-5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo
-3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG
-A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX
-BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov
-L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG
-AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF
-BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB
-BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc
-q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR
-bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv
+const giag2Intermediate = `-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
-----END CERTIFICATE-----
`
const googleLeaf = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
// algorithm in the certificate contains a nonsense OID.
const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BATIFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAVAF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
@@ -936,3 +989,135 @@ AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----`
+
+var moipLeafCert = `-----BEGIN CERTIFICATE-----
+MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw
+gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD
+VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl
+ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE
+BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE
+AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv
+bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g
+UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln
+YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50
+b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW
+MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe
+s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3
+UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi
++NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw
+KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI
+pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME
+GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj
+LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB
+MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG
+A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT
+QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH
+AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P
+RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB
+BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku
+bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD
+ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+
+pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC
+1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6
+z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW
+H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ
+jhuy8PqqZS9OuLilTeLu4a8z2JI=
+-----END CERTIFICATE-----`
+
+var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE-----
+MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
+MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
+VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
+CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
+vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
+xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
+WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
+iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
+BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
+ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
+A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
+b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
+BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
+L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
+cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
+AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
+jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
+1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
+teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
+fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
+KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
+ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
+XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
+tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
+jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
+pLwltum95OmYdBbxN4SBB7SC
+-----END CERTIFICATE-----`
+
+const comodoRSAAuthority = `-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
+gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
+VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
+AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
+2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
+ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
+4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
+m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
+vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
+8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
+IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
+KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
+GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
+s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
+JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
+AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
+MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
+bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
+Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
+zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
+Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
+Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
+B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
+PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
+pu/xO28QOG8=
+-----END CERTIFICATE-----`
+
+const addTrustRoot = `-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----`
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 57f68ba7e..c347fb384 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -13,6 +13,8 @@ import (
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
@@ -241,32 +243,31 @@ var (
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
)
+var signatureAlgorithmDetails = []struct {
+ algo SignatureAlgorithm
+ oid asn1.ObjectIdentifier
+ pubKeyAlgo PublicKeyAlgorithm
+ hash crypto.Hash
+}{
+ {MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+ {MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
+ {SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+ {SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+ {SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+ {DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+ {DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+ {ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+ {ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+ {ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+ {ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+}
+
func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
- switch {
- case oid.Equal(oidSignatureMD2WithRSA):
- return MD2WithRSA
- case oid.Equal(oidSignatureMD5WithRSA):
- return MD5WithRSA
- case oid.Equal(oidSignatureSHA1WithRSA):
- return SHA1WithRSA
- case oid.Equal(oidSignatureSHA256WithRSA):
- return SHA256WithRSA
- case oid.Equal(oidSignatureSHA384WithRSA):
- return SHA384WithRSA
- case oid.Equal(oidSignatureSHA512WithRSA):
- return SHA512WithRSA
- case oid.Equal(oidSignatureDSAWithSHA1):
- return DSAWithSHA1
- case oid.Equal(oidSignatureDSAWithSHA256):
- return DSAWithSHA256
- case oid.Equal(oidSignatureECDSAWithSHA1):
- return ECDSAWithSHA1
- case oid.Equal(oidSignatureECDSAWithSHA256):
- return ECDSAWithSHA256
- case oid.Equal(oidSignatureECDSAWithSHA384):
- return ECDSAWithSHA384
- case oid.Equal(oidSignatureECDSAWithSHA512):
- return ECDSAWithSHA512
+ for _, details := range signatureAlgorithmDetails {
+ if oid.Equal(details.oid) {
+ return details.algo
+ }
}
return UnknownSignatureAlgorithm
}
@@ -790,6 +791,58 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
}
}
+func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
+ // RFC 5280, 4.2.1.6
+
+ // SubjectAltName ::= GeneralNames
+ //
+ // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ //
+ // GeneralName ::= CHOICE {
+ // otherName [0] OtherName,
+ // rfc822Name [1] IA5String,
+ // dNSName [2] IA5String,
+ // x400Address [3] ORAddress,
+ // directoryName [4] Name,
+ // ediPartyName [5] EDIPartyName,
+ // uniformResourceIdentifier [6] IA5String,
+ // iPAddress [7] OCTET STRING,
+ // registeredID [8] OBJECT IDENTIFIER }
+ var seq asn1.RawValue
+ if _, err = asn1.Unmarshal(value, &seq); err != nil {
+ return
+ }
+ if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+ err = asn1.StructuralError{Msg: "bad SAN sequence"}
+ return
+ }
+
+ rest := seq.Bytes
+ for len(rest) > 0 {
+ var v asn1.RawValue
+ rest, err = asn1.Unmarshal(rest, &v)
+ if err != nil {
+ return
+ }
+ switch v.Tag {
+ case 1:
+ emailAddresses = append(emailAddresses, string(v.Bytes))
+ case 2:
+ dnsNames = append(dnsNames, string(v.Bytes))
+ case 7:
+ switch len(v.Bytes) {
+ case net.IPv4len, net.IPv6len:
+ ipAddresses = append(ipAddresses, v.Bytes)
+ default:
+ err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+ return
+ }
+ }
+ }
+
+ return
+}
+
func parseCertificate(in *certificate) (*Certificate, error) {
out := new(Certificate)
out.Raw = in.Raw
@@ -863,58 +916,12 @@ func parseCertificate(in *certificate) (*Certificate, error) {
continue
}
case 17:
- // RFC 5280, 4.2.1.6
-
- // SubjectAltName ::= GeneralNames
- //
- // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
- //
- // GeneralName ::= CHOICE {
- // otherName [0] OtherName,
- // rfc822Name [1] IA5String,
- // dNSName [2] IA5String,
- // x400Address [3] ORAddress,
- // directoryName [4] Name,
- // ediPartyName [5] EDIPartyName,
- // uniformResourceIdentifier [6] IA5String,
- // iPAddress [7] OCTET STRING,
- // registeredID [8] OBJECT IDENTIFIER }
- var seq asn1.RawValue
- _, err := asn1.Unmarshal(e.Value, &seq)
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
if err != nil {
return nil, err
}
- if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
- return nil, asn1.StructuralError{Msg: "bad SAN sequence"}
- }
- parsedName := false
-
- rest := seq.Bytes
- for len(rest) > 0 {
- var v asn1.RawValue
- rest, err = asn1.Unmarshal(rest, &v)
- if err != nil {
- return nil, err
- }
- switch v.Tag {
- case 1:
- out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
- parsedName = true
- case 2:
- out.DNSNames = append(out.DNSNames, string(v.Bytes))
- parsedName = true
- case 7:
- switch len(v.Bytes) {
- case net.IPv4len, net.IPv6len:
- out.IPAddresses = append(out.IPAddresses, v.Bytes)
- default:
- return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
- }
- }
- }
-
- if parsedName {
+ if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 {
continue
}
// If we didn't parse any of the names then we
@@ -1151,6 +1158,27 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo
return false
}
+// marshalSANs marshals a list of addresses into a the contents of an X.509
+// SubjectAlternativeName extension.
+func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBytes []byte, err error) {
+ var rawValues []asn1.RawValue
+ for _, name := range dnsNames {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
+ }
+ for _, email := range emailAddresses {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
+ }
+ for _, rawIP := range ipAddresses {
+ // If possible, we always want to encode IPv4 addresses in 4 bytes.
+ ip := rawIP.To4()
+ if ip == nil {
+ ip = rawIP
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
+ }
+ return asn1.Marshal(rawValues)
+}
+
func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
@@ -1252,22 +1280,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectAltName
- var rawValues []asn1.RawValue
- for _, name := range template.DNSNames {
- rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
- }
- for _, email := range template.EmailAddresses {
- rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
- }
- for _, rawIP := range template.IPAddresses {
- // If possible, we always want to encode IPv4 addresses in 4 bytes.
- ip := rawIP.To4()
- if ip == nil {
- ip = rawIP
- }
- rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
- }
- ret[n].Value, err = asn1.Marshal(rawValues)
+ ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
if err != nil {
return
}
@@ -1342,11 +1355,76 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
return asn1.Marshal(cert.Subject.ToRDNSequence())
}
+// signingParamsForPrivateKey returns the parameters to use for signing with
+// priv. If requestedSigAlgo is not zero then it overrides the default
+// signature algorithm.
+func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+ var pubType PublicKeyAlgorithm
+
+ switch priv := priv.(type) {
+ case *rsa.PrivateKey:
+ pubType = RSA
+ sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+ hashFunc = crypto.SHA256
+
+ case *ecdsa.PrivateKey:
+ pubType = ECDSA
+
+ switch priv.Curve {
+ case elliptic.P224(), elliptic.P256():
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+ case elliptic.P384():
+ hashFunc = crypto.SHA384
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+ case elliptic.P521():
+ hashFunc = crypto.SHA512
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+ default:
+ err = errors.New("x509: unknown elliptic curve")
+ }
+
+ default:
+ err = errors.New("x509: only RSA and ECDSA private keys supported")
+ }
+
+ if err != nil {
+ return
+ }
+
+ if requestedSigAlgo == 0 {
+ return
+ }
+
+ found := false
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == requestedSigAlgo {
+ if details.pubKeyAlgo != pubType {
+ err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+ return
+ }
+ sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+ if hashFunc == 0 {
+ err = errors.New("x509: cannot sign with hash function requested")
+ return
+ }
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ err = errors.New("x509: unknown SignatureAlgorithm")
+ }
+
+ return
+}
+
// CreateCertificate creates a new certificate based on a template. The
// following members of template are used: SerialNumber, Subject, NotBefore,
// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+// PermittedDNSDomains, SignatureAlgorithm.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the
@@ -1355,38 +1433,16 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
// The returned slice is the certificate in DER encoding.
//
// The only supported key types are RSA and ECDSA (*rsa.PublicKey or
-// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PublicKey for priv).
+// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv).
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
- var publicKeyBytes []byte
- var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
- if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
+ hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+ if err != nil {
return nil, err
}
- var signatureAlgorithm pkix.AlgorithmIdentifier
- var hashFunc crypto.Hash
-
- switch priv := priv.(type) {
- case *rsa.PrivateKey:
- signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA
- hashFunc = crypto.SHA1
- case *ecdsa.PrivateKey:
- switch priv.Curve {
- case elliptic.P224(), elliptic.P256():
- hashFunc = crypto.SHA256
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA256
- case elliptic.P384():
- hashFunc = crypto.SHA384
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA384
- case elliptic.P521():
- hashFunc = crypto.SHA512
- signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA512
- default:
- return nil, errors.New("x509: unknown elliptic curve")
- }
- default:
- return nil, errors.New("x509: only RSA and ECDSA private keys supported")
+ publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+ if err != nil {
+ return nil, err
}
if err != nil {
@@ -1535,3 +1591,313 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
+
+// CertificateRequest represents a PKCS #10, certificate signature request.
+type CertificateRequest struct {
+ Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
+ RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
+ RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+ RawSubject []byte // DER encoded Subject.
+
+ Version int
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey interface{}
+
+ Subject pkix.Name
+
+ // Attributes is a collection of attributes providing
+ // additional information about the subject of the certificate.
+ // See RFC 2986 section 4.1.
+ Attributes []pkix.AttributeTypeAndValueSET
+
+ // Extensions contains raw X.509 extensions. When parsing CSRs, this
+ // can be used to extract extensions that are not parsed by this
+ // package.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains extensions to be copied, raw, into any
+ // marshaled CSR. Values override any extensions that would otherwise
+ // be produced based on the other fields but are overridden by any
+ // extensions specified in Attributes.
+ //
+ // The ExtraExtensions field is not populated when parsing CSRs, see
+ // Extensions.
+ ExtraExtensions []pkix.Extension
+
+ // Subject Alternate Name values.
+ DNSNames []string
+ EmailAddresses []string
+ IPAddresses []net.IP
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificate
+// signature requests (see RFC 2986):
+
+type tbsCertificateRequest struct {
+ Raw asn1.RawContent
+ Version int
+ Subject asn1.RawValue
+ PublicKey publicKeyInfo
+ Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
+}
+
+type certificateRequest struct {
+ Raw asn1.RawContent
+ TBSCSR tbsCertificateRequest
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
+// extensions in a CSR.
+var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
+
+// CreateCertificateRequest creates a new certificate based on a template. The
+// following members of template are used: Subject, Attributes,
+// SignatureAlgorithm, Extension, DNSNames, EmailAddresses, and IPAddresses.
+// The private key is the private key of the signer.
+//
+// The returned slice is the certificate request in DER encoding.
+//
+// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
+// (*ecdsa.PrivateKey).
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
+ hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ var publicKeyBytes []byte
+ var publicKeyAlgorithm pkix.AlgorithmIdentifier
+
+ switch priv := priv.(type) {
+ case *rsa.PrivateKey:
+ publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
+ case *ecdsa.PrivateKey:
+ publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
+ default:
+ panic("internal error")
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ var extensions []pkix.Extension
+
+ if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
+ !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+ sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
+ if err != nil {
+ return nil, err
+ }
+
+ extensions = append(extensions, pkix.Extension{
+ Id: oidExtensionSubjectAltName,
+ Value: sanBytes,
+ })
+ }
+
+ extensions = append(extensions, template.ExtraExtensions...)
+
+ var attributes []pkix.AttributeTypeAndValueSET
+ attributes = append(attributes, template.Attributes...)
+
+ if len(extensions) > 0 {
+ // specifiedExtensions contains all the extensions that we
+ // found specified via template.Attributes.
+ specifiedExtensions := make(map[string]bool)
+
+ for _, atvSet := range template.Attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) {
+ continue
+ }
+
+ for _, atvs := range atvSet.Value {
+ for _, atv := range atvs {
+ specifiedExtensions[atv.Type.String()] = true
+ }
+ }
+ }
+
+ atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
+ for _, e := range extensions {
+ if specifiedExtensions[e.Id.String()] {
+ // Attributes already contained a value for
+ // this extension and it takes priority.
+ continue
+ }
+
+ atvs = append(atvs, pkix.AttributeTypeAndValue{
+ // There is no place for the critical flag in a CSR.
+ Type: e.Id,
+ Value: e.Value,
+ })
+ }
+
+ // Append the extensions to an existing attribute if possible.
+ appended := false
+ for _, atvSet := range attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
+ continue
+ }
+
+ atvSet.Value[0] = append(atvSet.Value[0], atvs...)
+ appended = true
+ break
+ }
+
+ // Otherwise, add a new attribute for the extensions.
+ if !appended {
+ attributes = append(attributes, pkix.AttributeTypeAndValueSET{
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ atvs,
+ },
+ })
+ }
+ }
+
+ asn1Subject := template.RawSubject
+ if len(asn1Subject) == 0 {
+ asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
+ if err != nil {
+ return
+ }
+ }
+
+ tbsCSR := tbsCertificateRequest{
+ Version: 0, // PKCS #10, RFC 2986
+ Subject: asn1.RawValue{FullBytes: asn1Subject},
+ PublicKey: publicKeyInfo{
+ Algorithm: publicKeyAlgorithm,
+ PublicKey: asn1.BitString{
+ Bytes: publicKeyBytes,
+ BitLength: len(publicKeyBytes) * 8,
+ },
+ },
+ Attributes: attributes,
+ }
+
+ tbsCSRContents, err := asn1.Marshal(tbsCSR)
+ if err != nil {
+ return
+ }
+ tbsCSR.Raw = tbsCSRContents
+
+ h := hashFunc.New()
+ h.Write(tbsCSRContents)
+ digest := h.Sum(nil)
+
+ var signature []byte
+ switch priv := priv.(type) {
+ case *rsa.PrivateKey:
+ signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
+ case *ecdsa.PrivateKey:
+ var r, s *big.Int
+ if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
+ signature, err = asn1.Marshal(ecdsaSignature{r, s})
+ }
+ default:
+ panic("internal error")
+ }
+
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(certificateRequest{
+ TBSCSR: tbsCSR,
+ SignatureAlgorithm: sigAlgo,
+ SignatureValue: asn1.BitString{
+ Bytes: signature,
+ BitLength: len(signature) * 8,
+ },
+ })
+}
+
+// ParseCertificateRequest parses a single certificate request from the
+// given ASN.1 DER data.
+func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
+ var csr certificateRequest
+
+ rest, err := asn1.Unmarshal(asn1Data, &csr)
+ if err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
+ }
+
+ return parseCertificateRequest(&csr)
+}
+
+func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
+ out := &CertificateRequest{
+ Raw: in.Raw,
+ RawTBSCertificateRequest: in.TBSCSR.Raw,
+ RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw,
+ RawSubject: in.TBSCSR.Subject.FullBytes,
+
+ Signature: in.SignatureValue.RightAlign(),
+ SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm),
+
+ PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
+
+ Version: in.TBSCSR.Version,
+ Attributes: in.TBSCSR.Attributes,
+ }
+
+ var err error
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
+ if err != nil {
+ return nil, err
+ }
+
+ var subject pkix.RDNSequence
+ if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+ return nil, err
+ }
+
+ out.Subject.FillFromRDNSequence(&subject)
+
+ var extensions []pkix.AttributeTypeAndValue
+
+ for _, atvSet := range in.TBSCSR.Attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) {
+ continue
+ }
+
+ for _, atvs := range atvSet.Value {
+ extensions = append(extensions, atvs...)
+ }
+ }
+
+ out.Extensions = make([]pkix.Extension, 0, len(extensions))
+
+ for _, e := range extensions {
+ value, ok := e.Value.([]byte)
+ if !ok {
+ return nil, errors.New("x509: extension attribute contained non-OCTET STRING data")
+ }
+
+ out.Extensions = append(out.Extensions, pkix.Extension{
+ Id: e.Type,
+ Value: value,
+ })
+
+ if len(e.Type) == 4 && e.Type[0] == 2 && e.Type[1] == 5 && e.Type[2] == 29 {
+ switch e.Type[3] {
+ case 17:
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(value)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+
+ return out, nil
+}
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index f1097e992..2fd54c78f 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -20,7 +20,9 @@ import (
"encoding/pem"
"math/big"
"net"
+ "os/exec"
"reflect"
+ "runtime"
"testing"
"time"
)
@@ -305,11 +307,12 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
name string
pub, priv interface{}
checkSig bool
+ sigAlgo SignatureAlgorithm
}{
- {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true},
- {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false},
- {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false},
- {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true},
+ {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
+ {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+ {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+ {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
}
testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -327,6 +330,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(100000, 0),
+ SignatureAlgorithm: test.sigAlgo,
+
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: KeyUsageCertSign,
@@ -390,6 +395,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
}
+ if cert.SignatureAlgorithm != test.sigAlgo {
+ t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %v, want %v", test.name, cert.SignatureAlgorithm, test.sigAlgo)
+ }
+
if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) {
t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage)
}
@@ -671,11 +680,11 @@ func TestCRLCreation(t *testing.T) {
func fromBase64(in string) []byte {
out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
- _, err := base64.StdEncoding.Decode(out, []byte(in))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
if err != nil {
panic("failed to base64 decode")
}
- return out
+ return out[:n]
}
func TestParseDERCRL(t *testing.T) {
@@ -718,6 +727,226 @@ func TestParsePEMCRL(t *testing.T) {
// Can't check the signature here without a package cycle.
}
+func TestImports(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
+ t.Errorf("failed to run x509_test_import.go: %s", err)
+ }
+}
+
const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
+
+func TestCreateCertificateRequest(t *testing.T) {
+ random := rand.Reader
+
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse private key: %s", err)
+ }
+
+ ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa384Priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa521Priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ tests := []struct {
+ name string
+ priv interface{}
+ sigAlgo SignatureAlgorithm
+ }{
+ {"RSA", rsaPriv, SHA1WithRSA},
+ {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
+ {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
+ {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
+ }
+
+ for _, test := range tests {
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ SignatureAlgorithm: test.sigAlgo,
+ DNSNames: []string{"test.example.com"},
+ EmailAddresses: []string{"gopher@golang.org"},
+ IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
+ }
+
+ derBytes, err := CreateCertificateRequest(random, &template, test.priv)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+ continue
+ }
+
+ out, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+ continue
+ }
+
+ if out.Subject.CommonName != template.Subject.CommonName {
+ t.Errorf("%s: output subject common name and template subject common name don't match", test.name)
+ } else if len(out.Subject.Organization) != len(template.Subject.Organization) {
+ t.Errorf("%s: output subject organisation and template subject organisation don't match", test.name)
+ } else if len(out.DNSNames) != len(template.DNSNames) {
+ t.Errorf("%s: output DNS names and template DNS names don't match", test.name)
+ } else if len(out.EmailAddresses) != len(template.EmailAddresses) {
+ t.Errorf("%s: output email addresses and template email addresses don't match", test.name)
+ } else if len(out.IPAddresses) != len(template.IPAddresses) {
+ t.Errorf("%s: output IP addresses and template IP addresses names don't match", test.name)
+ }
+ }
+}
+
+func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ derBytes, err := CreateCertificateRequest(rand.Reader, template, rsaPriv)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ csr, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return csr
+}
+
+func TestCertificateRequestOverrides(t *testing.T) {
+ sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ DNSNames: []string{"test.example.com"},
+
+ // An explicit extension should override the DNSNames from the
+ // template.
+ ExtraExtensions: []pkix.Extension{
+ pkix.Extension{
+ Id: oidExtensionSubjectAltName,
+ Value: sanContents,
+ },
+ },
+ }
+
+ csr := marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo.example.com" {
+ t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
+ }
+
+ // If there is already an attribute with X.509 extensions then the
+ // extra extensions should be added to it rather than creating a CSR
+ // with two extension attributes.
+
+ template.Attributes = []pkix.AttributeTypeAndValueSET{
+ pkix.AttributeTypeAndValueSET{
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ []pkix.AttributeTypeAndValue{
+ pkix.AttributeTypeAndValue{
+ Type: oidExtensionAuthorityInfoAccess,
+ Value: []byte("foo"),
+ },
+ },
+ },
+ },
+ }
+
+ csr = marshalAndParseCSR(t, &template)
+ if l := len(csr.Attributes); l != 1 {
+ t.Errorf("incorrect number of attributes: %d\n", l)
+ }
+
+ if !csr.Attributes[0].Type.Equal(oidExtensionRequest) ||
+ len(csr.Attributes[0].Value) != 1 ||
+ len(csr.Attributes[0].Value[0]) != 2 {
+ t.Errorf("bad attributes: %#v\n", csr.Attributes)
+ }
+
+ sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Extensions in Attributes should override those in ExtraExtensions.
+ template.Attributes[0].Value[0] = append(template.Attributes[0].Value[0], pkix.AttributeTypeAndValue{
+ Type: oidExtensionSubjectAltName,
+ Value: sanContents2,
+ })
+
+ csr = marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo2.example.com" {
+ t.Errorf("Attributes did not override ExtraExtensions. Got %v\n", csr.DNSNames)
+ }
+}
+
+func TestParseCertificateRequest(t *testing.T) {
+ csrBytes := fromBase64(csrBase64)
+ csr, err := ParseCertificateRequest(csrBytes)
+ if err != nil {
+ t.Fatalf("failed to parse CSR: %s", err)
+ }
+
+ if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" {
+ t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
+ }
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
+ t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
+ }
+
+ if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
+ t.Errorf("incorrect Subject name: %v", csr.Subject)
+ }
+
+ found := false
+ for _, e := range csr.Extensions {
+ if e.Id.Equal(oidExtensionBasicConstraints) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("basic constraints extension not found in CSR")
+ }
+}
+
+// This CSR was generated with OpenSSL:
+// openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
+//
+// The openssl.cnf needs to include this section:
+// [ v3_req ]
+// basicConstraints = CA:FALSE
+// keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+// subjectAltName = email:gopher@golang.org,DNS:test.example.com
+const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHqGjd0bhuAX9cpPOKgnEmqn0CAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAC9+QpKfdabxwCWwf4IEe1cKjdXLS1ScSuw27a3kZzQiPV78WJMa6dB8dqhdH5BRwGZ/qsgLrO6ZHlNeIv2Ib41Ccq71ecHW/nXc94A1BzJ/bVdI9LZcmTUvR1/m1jCpN7UqQ0ml1u9VihK7Pe762hEYxuWDQzYEU0l15S/bXmqeq3eF1A59XT/2jwe5+NV0Wwf4UQlkTXsAQMsJ+KzrQafd8Qv2A49o048uRvmjeJDrXLawGVianZ7D5A6Fpd1rZh6XcjqBpmgLw41DRQWENOdzhy+HyphKRv1MlY8OLkNqpGMhu8DdgJVGoT16DGiickoEa7Z3UCPVNgdTkT9jq7U="
diff --git a/src/pkg/crypto/x509/x509_test_import.go b/src/pkg/crypto/x509/x509_test_import.go
new file mode 100644
index 000000000..3fda7da18
--- /dev/null
+++ b/src/pkg/crypto/x509/x509_test_import.go
@@ -0,0 +1,53 @@
+// 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.
+
+// +build ignore
+
+// This file is run by the x509 tests to ensure that a program with minimal
+// imports can sign certificates without errors resulting from missing hash
+// functions.
+package main
+
+import (
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "math/big"
+ "time"
+)
+
+func main() {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ panic("Failed to parse private key: " + err.Error())
+ }
+
+ template := x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "test",
+ Organization: []string{"Σ Acme Co"},
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+ KeyUsage: x509.KeyUsageCertSign,
+ }
+
+ if _, err = x509.CreateCertificate(rand.Reader, &template, &template, &rsaPriv.PublicKey, rsaPriv); err != nil {
+ panic("failed to create certificate with basic imports: " + err.Error())
+ }
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
index c04adde1f..c0b38a249 100644
--- a/src/pkg/database/sql/convert.go
+++ b/src/pkg/database/sql/convert.go
@@ -160,27 +160,19 @@ func convertAssign(dest, src interface{}) error {
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
- *d = fmt.Sprintf("%v", src)
+ *d = asString(src)
return nil
}
case *[]byte:
sv = reflect.ValueOf(src)
- switch sv.Kind() {
- case reflect.Bool,
- reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
- reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
- reflect.Float32, reflect.Float64:
- *d = []byte(fmt.Sprintf("%v", src))
+ if b, ok := asBytes(nil, sv); ok {
+ *d = b
return nil
}
case *RawBytes:
sv = reflect.ValueOf(src)
- switch sv.Kind() {
- case reflect.Bool,
- reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
- reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
- reflect.Float32, reflect.Float64:
- *d = RawBytes(fmt.Sprintf("%v", src))
+ if b, ok := asBytes([]byte(*d)[:0], sv); ok {
+ *d = RawBytes(b)
return nil
}
case *bool:
@@ -271,5 +263,37 @@ func asString(src interface{}) string {
case []byte:
return string(v)
}
+ rv := reflect.ValueOf(src)
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(rv.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(rv.Uint(), 10)
+ case reflect.Float64:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+ case reflect.Float32:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+ case reflect.Bool:
+ return strconv.FormatBool(rv.Bool())
+ }
return fmt.Sprintf("%v", src)
}
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.AppendInt(buf, rv.Int(), 10), true
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.AppendUint(buf, rv.Uint(), 10), true
+ case reflect.Float32:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+ case reflect.Float64:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+ case reflect.Bool:
+ return strconv.AppendBool(buf, rv.Bool()), true
+ case reflect.String:
+ s := rv.String()
+ return append(buf, s...), true
+ }
+ return
+}
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
index a39c2c54f..6e2483012 100644
--- a/src/pkg/database/sql/convert_test.go
+++ b/src/pkg/database/sql/convert_test.go
@@ -8,6 +8,7 @@ import (
"database/sql/driver"
"fmt"
"reflect"
+ "runtime"
"testing"
"time"
)
@@ -279,3 +280,58 @@ func TestValueConverters(t *testing.T) {
}
}
}
+
+// Tests that assigning to RawBytes doesn't allocate (and also works).
+func TestRawBytesAllocs(t *testing.T) {
+ buf := make(RawBytes, 10)
+ test := func(name string, in interface{}, want string) {
+ if err := convertAssign(&buf, in); err != nil {
+ t.Fatalf("%s: convertAssign = %v", name, err)
+ }
+ match := len(buf) == len(want)
+ if match {
+ for i, b := range buf {
+ if want[i] != b {
+ match = false
+ break
+ }
+ }
+ }
+ if !match {
+ t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want))
+ }
+ }
+ n := testing.AllocsPerRun(100, func() {
+ test("uint64", uint64(12345678), "12345678")
+ test("uint32", uint32(1234), "1234")
+ test("uint16", uint16(12), "12")
+ test("uint8", uint8(1), "1")
+ test("uint", uint(123), "123")
+ test("int", int(123), "123")
+ test("int8", int8(1), "1")
+ test("int16", int16(12), "12")
+ test("int32", int32(1234), "1234")
+ test("int64", int64(12345678), "12345678")
+ test("float32", float32(1.5), "1.5")
+ test("float64", float64(64), "64")
+ test("bool", false, "false")
+ })
+
+ // The numbers below are only valid for 64-bit interface word sizes,
+ // and gc. With 32-bit words there are more convT2E allocs, and
+ // with gccgo, only pointers currently go in interface data.
+ // So only care on amd64 gc for now.
+ measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
+
+ if n > 0.5 && measureAllocs {
+ t.Fatalf("allocs = %v; want 0", n)
+ }
+
+ // This one involves a convT2E allocation, string -> interface{}
+ n = testing.AllocsPerRun(100, func() {
+ test("string", "foo", "foo")
+ })
+ if n > 1.5 && measureAllocs {
+ t.Fatalf("allocs = %v; want max 1", n)
+ }
+}
diff --git a/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
index 0828e63c6..eca25f29a 100644
--- a/src/pkg/database/sql/driver/driver.go
+++ b/src/pkg/database/sql/driver/driver.go
@@ -134,7 +134,7 @@ type Stmt interface {
// as an INSERT or UPDATE.
Exec(args []Value) (Result, error)
- // Exec executes a query that may return rows, such as a
+ // Query executes a query that may return rows, such as a
// SELECT.
Query(args []Value) (Rows, error)
}
diff --git a/src/pkg/database/sql/example_test.go b/src/pkg/database/sql/example_test.go
index d47eed50c..dcb74e069 100644
--- a/src/pkg/database/sql/example_test.go
+++ b/src/pkg/database/sql/example_test.go
@@ -18,6 +18,7 @@ func ExampleDB_Query() {
if err != nil {
log.Fatal(err)
}
+ defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
index a8adfdd94..c7db0dd77 100644
--- a/src/pkg/database/sql/fakedb_test.go
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -23,7 +23,7 @@ var _ = log.Printf
// interface, just for testing.
//
// It speaks a query language that's semantically similar to but
-// syntantically different and simpler than SQL. The syntax is as
+// syntactically different and simpler than SQL. The syntax is as
// follows:
//
// WIPE
@@ -433,11 +433,19 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
return stmt, nil
}
+// hook to simulate broken connections
+var hookPrepareBadConn func() bool
+
func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
c.numPrepare++
if c.db == nil {
panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
}
+
+ if hookPrepareBadConn != nil && hookPrepareBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
parts := strings.Split(query, "|")
if len(parts) < 1 {
return nil, errf("empty query")
@@ -489,10 +497,18 @@ func (s *fakeStmt) Close() error {
var errClosed = errors.New("fakedb: statement has been closed")
+// hook to simulate broken connections
+var hookExecBadConn func() bool
+
func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
if s.closed {
return nil, errClosed
}
+
+ if hookExecBadConn != nil && hookExecBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
err := checkSubsetTypes(args)
if err != nil {
return nil, err
@@ -565,10 +581,18 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
return driver.RowsAffected(1), nil
}
+// hook to simulate broken connections
+var hookQueryBadConn func() bool
+
func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if s.closed {
return nil, errClosed
}
+
+ if hookQueryBadConn != nil && hookQueryBadConn() {
+ return nil, driver.ErrBadConn
+ }
+
err := checkSubsetTypes(args)
if err != nil {
return nil, err
@@ -686,7 +710,13 @@ func (rc *rowsCursor) Columns() []string {
return rc.cols
}
+var rowsCursorNextHook func(dest []driver.Value) error
+
func (rc *rowsCursor) Next(dest []driver.Value) error {
+ if rowsCursorNextHook != nil {
+ return rowsCursorNextHook(dest)
+ }
+
if rc.closed {
return errors.New("fakedb: cursor is closed")
}
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
index 84a096513..765b80c60 100644
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -181,7 +181,8 @@ type Scanner interface {
// defers this error until a Scan.
var ErrNoRows = errors.New("sql: no rows in result set")
-// DB is a database handle. It's safe for concurrent use by multiple
+// DB is a database handle representing a pool of zero or more
+// underlying connections. It's safe for concurrent use by multiple
// goroutines.
//
// The sql package creates and frees connections automatically; it
@@ -256,7 +257,7 @@ func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
// stmt closes if the conn is about to close anyway? For now
// do the safe thing, in case stmts need to be closed.
//
- // TODO(bradfitz): after Go 1.1, closing driver.Stmts
+ // TODO(bradfitz): after Go 1.2, closing driver.Stmts
// should be moved to driverStmt, using unique
// *driverStmts everywhere (including from
// *Stmt.connStmt, instead of returning a
@@ -405,7 +406,7 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
// This value should be larger than the maximum typical value
// used for db.maxOpen. If maxOpen is significantly larger than
// connectionRequestQueueSize then it is possible for ALL calls into the *DB
-// to block until the connectionOpener can satify the backlog of requests.
+// to block until the connectionOpener can satisfy the backlog of requests.
var connectionRequestQueueSize = 1000000
// Open opens a database specified by its database driver name and a
@@ -420,6 +421,11 @@ var connectionRequestQueueSize = 1000000
// Open may just validate its arguments without creating a connection
// to the database. To verify that the data source name is valid, call
// Ping.
+//
+// The returned DB is safe for concurrent use by multiple goroutines
+// and maintains its own pool of idle connections. Thus, the Open
+// function should be called just once. It is rarely necessary to
+// close a DB.
func Open(driverName, dataSourceName string) (*DB, error) {
driveri, ok := drivers[driverName]
if !ok {
@@ -452,6 +458,9 @@ func (db *DB) Ping() error {
}
// Close closes the database, releasing any open resources.
+//
+// It is rare to Close a DB, as the DB handle is meant to be
+// long-lived and shared between many goroutines.
func (db *DB) Close() error {
db.mu.Lock()
if db.closed { // Make DB.Close idempotent
@@ -569,7 +578,7 @@ func (db *DB) maybeOpenNewConnections() {
}
}
-// Runs in a seperate goroutine, opens new connections when requested.
+// Runs in a separate goroutine, opens new connections when requested.
func (db *DB) connectionOpener() {
for _ = range db.openerCh {
db.openNewConnection()
@@ -652,13 +661,16 @@ func (db *DB) conn() (*driverConn, error) {
return conn, nil
}
+ db.numOpen++ // optimistically
db.mu.Unlock()
ci, err := db.driver.Open(db.dsn)
if err != nil {
+ db.mu.Lock()
+ db.numOpen-- // correct for earlier optimism
+ db.mu.Unlock()
return nil, err
}
db.mu.Lock()
- db.numOpen++
dc := &driverConn{
db: db,
ci: ci,
@@ -774,11 +786,11 @@ func (db *DB) putConn(dc *driverConn, err error) {
// Satisfy a connRequest or put the driverConn in the idle pool and return true
// or return false.
// putConnDBLocked will satisfy a connRequest if there is one, or it will
-// return the *driverConn to the freeConn list if err != nil and the idle
-// connection limit would not be reached.
+// return the *driverConn to the freeConn list if err == nil and the idle
+// connection limit will not be exceeded.
// If err != nil, the value of dc is ignored.
// If err == nil, then dc must not equal nil.
-// If a connRequest was fullfilled or the *driverConn was placed in the
+// If a connRequest was fulfilled or the *driverConn was placed in the
// freeConn list, then true is returned, otherwise false is returned.
func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
if db.connRequests.Len() > 0 {
@@ -791,20 +803,24 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
req <- dc
}
return true
- } else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
+ } else if err == nil && !db.closed && db.maxIdleConnsLocked() > db.freeConn.Len() {
dc.listElem = db.freeConn.PushFront(dc)
return true
}
return false
}
+// maxBadConnRetries is the number of maximum retries if the driver returns
+// driver.ErrBadConn to signal a broken connection.
+const maxBadConnRetries = 10
+
// Prepare creates a prepared statement for later queries or executions.
// Multiple queries or executions may be run concurrently from the
// returned statement.
func (db *DB) Prepare(query string) (*Stmt, error) {
var stmt *Stmt
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
stmt, err = db.prepare(query)
if err != driver.ErrBadConn {
break
@@ -846,7 +862,7 @@ func (db *DB) prepare(query string) (*Stmt, error) {
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
var res Result
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
res, err = db.exec(query, args)
if err != driver.ErrBadConn {
break
@@ -895,7 +911,7 @@ func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
var rows *Rows
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
rows, err = db.query(query, args)
if err != driver.ErrBadConn {
break
@@ -983,7 +999,7 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
func (db *DB) Begin() (*Tx, error) {
var tx *Tx
var err error
- for i := 0; i < 10; i++ {
+ for i := 0; i < maxBadConnRetries; i++ {
tx, err = db.begin()
if err != driver.ErrBadConn {
break
@@ -1245,13 +1261,24 @@ type Stmt struct {
func (s *Stmt) Exec(args ...interface{}) (Result, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- dc, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
- defer releaseConn(nil)
- return resultFromStatement(driverStmt{dc, si}, args...)
+ var res Result
+ for i := 0; i < maxBadConnRetries; i++ {
+ dc, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ if err == driver.ErrBadConn {
+ continue
+ }
+ return nil, err
+ }
+
+ res, err = resultFromStatement(driverStmt{dc, si}, args...)
+ releaseConn(err)
+ if err != driver.ErrBadConn {
+ return res, err
+ }
+ }
+ return nil, driver.ErrBadConn
}
func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
@@ -1329,26 +1356,21 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
// Make a new conn if all are busy.
// TODO(bradfitz): or wait for one? make configurable later?
if !match {
- for i := 0; ; i++ {
- dc, err := s.db.conn()
- if err != nil {
- return nil, nil, nil, err
- }
- dc.Lock()
- si, err := dc.prepareLocked(s.query)
- dc.Unlock()
- if err == driver.ErrBadConn && i < 10 {
- continue
- }
- if err != nil {
- return nil, nil, nil, err
- }
- s.mu.Lock()
- cs = connStmt{dc, si}
- s.css = append(s.css, cs)
- s.mu.Unlock()
- break
+ dc, err := s.db.conn()
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ dc.Lock()
+ si, err := dc.prepareLocked(s.query)
+ dc.Unlock()
+ if err != nil {
+ s.db.putConn(dc, err)
+ return nil, nil, nil, err
}
+ s.mu.Lock()
+ cs = connStmt{dc, si}
+ s.css = append(s.css, cs)
+ s.mu.Unlock()
}
conn := cs.dc
@@ -1361,31 +1383,39 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- dc, releaseConn, si, err := s.connStmt()
- if err != nil {
- return nil, err
- }
+ var rowsi driver.Rows
+ for i := 0; i < maxBadConnRetries; i++ {
+ dc, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ if err == driver.ErrBadConn {
+ continue
+ }
+ return nil, err
+ }
- ds := driverStmt{dc, si}
- rowsi, err := rowsiFromStatement(ds, args...)
- if err != nil {
- releaseConn(err)
- return nil, err
- }
+ rowsi, err = rowsiFromStatement(driverStmt{dc, si}, args...)
+ if err == nil {
+ // Note: ownership of ci passes to the *Rows, to be freed
+ // with releaseConn.
+ rows := &Rows{
+ dc: dc,
+ rowsi: rowsi,
+ // releaseConn set below
+ }
+ s.db.addDep(s, rows)
+ rows.releaseConn = func(err error) {
+ releaseConn(err)
+ s.db.removeDep(s, rows)
+ }
+ return rows, nil
+ }
- // Note: ownership of ci passes to the *Rows, to be freed
- // with releaseConn.
- rows := &Rows{
- dc: dc,
- rowsi: rowsi,
- // releaseConn set below
- }
- s.db.addDep(s, rows)
- rows.releaseConn = func(err error) {
releaseConn(err)
- s.db.removeDep(s, rows)
+ if err != driver.ErrBadConn {
+ return nil, err
+ }
}
- return rows, nil
+ return nil, driver.ErrBadConn
}
func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
@@ -1476,6 +1506,7 @@ func (s *Stmt) finalClose() error {
//
// rows, err := db.Query("SELECT ...")
// ...
+// defer rows.Close()
// for rows.Next() {
// var id int
// var name string
@@ -1495,10 +1526,12 @@ type Rows struct {
closeStmt driver.Stmt // if non-nil, statement to Close on close
}
-// Next prepares the next result row for reading with the Scan method.
-// It returns true on success, false if there is no next result row.
-// Every call to Scan, even the first one, must be preceded by a call
-// to Next.
+// Next prepares the next result row for reading with the Scan method. It
+// returns true on success, or false if there is no next result row or an error
+// happened while preparing it. Err should be consulted to distinguish between
+// the two cases.
+//
+// Every call to Scan, even the first one, must be preceded by a call to Next.
func (rs *Rows) Next() bool {
if rs.closed {
return false
@@ -1625,12 +1658,19 @@ func (r *Row) Scan(dest ...interface{}) error {
}
if !r.rows.Next() {
+ if err := r.rows.Err(); err != nil {
+ return err
+ }
return ErrNoRows
}
err := r.rows.Scan(dest...)
if err != nil {
return err
}
+ // Make sure the query can be processed to completion with no errors.
+ if err := r.rows.Close(); err != nil {
+ return err
+ }
return nil
}
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index 787a5c9f7..7971f1491 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -348,7 +348,6 @@ func TestStatementQueryRow(t *testing.T) {
t.Errorf("%d: age=%d, want %d", n, age, tt.want)
}
}
-
}
// golang.org/issue/3734
@@ -462,7 +461,7 @@ func TestTxStmt(t *testing.T) {
}
// Issue: http://golang.org/issue/2784
-// This test didn't fail before because we got luckly with the fakedb driver.
+// This test didn't fail before because we got lucky with the fakedb driver.
// It was failing, and now not, in github.com/bradfitz/go-sql-test
func TestTxQuery(t *testing.T) {
db := newTestDB(t, "")
@@ -660,6 +659,35 @@ func TestQueryRowClosingStmt(t *testing.T) {
}
}
+// Test issue 6651
+func TestIssue6651(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ var v string
+
+ want := "error in rows.Next"
+ rowsCursorNextHook = func(dest []driver.Value) error {
+ return fmt.Errorf(want)
+ }
+ defer func() { rowsCursorNextHook = nil }()
+ err := db.QueryRow("SELECT|people|name|").Scan(&v)
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err, want)
+ }
+ rowsCursorNextHook = nil
+
+ want = "error in rows.Close"
+ rowsCloseHook = func(rows *Rows, err *error) {
+ *err = fmt.Errorf(want)
+ }
+ defer func() { rowsCloseHook = nil }()
+ err = db.QueryRow("SELECT|people|name|").Scan(&v)
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err, want)
+ }
+}
+
type nullTestRow struct {
nullParam interface{}
notNullParam interface{}
@@ -1249,6 +1277,111 @@ func TestStmtCloseOrder(t *testing.T) {
}
}
+// golang.org/issue/5781
+func TestErrBadConnReconnect(t *testing.T) {
+ db := newTestDB(t, "foo")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+
+ simulateBadConn := func(name string, hook *func() bool, op func() error) {
+ broken, retried := false, false
+ numOpen := db.numOpen
+
+ // simulate a broken connection on the first try
+ *hook = func() bool {
+ if !broken {
+ broken = true
+ return true
+ }
+ retried = true
+ return false
+ }
+
+ if err := op(); err != nil {
+ t.Errorf(name+": %v", err)
+ return
+ }
+
+ if !broken || !retried {
+ t.Error(name + ": Failed to simulate broken connection")
+ }
+ *hook = nil
+
+ if numOpen != db.numOpen {
+ t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
+ numOpen = db.numOpen
+ }
+ }
+
+ // db.Exec
+ dbExec := func() error {
+ _, err := db.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
+ return err
+ }
+ simulateBadConn("db.Exec prepare", &hookPrepareBadConn, dbExec)
+ simulateBadConn("db.Exec exec", &hookExecBadConn, dbExec)
+
+ // db.Query
+ dbQuery := func() error {
+ rows, err := db.Query("SELECT|t1|age,name|")
+ if err == nil {
+ err = rows.Close()
+ }
+ return err
+ }
+ simulateBadConn("db.Query prepare", &hookPrepareBadConn, dbQuery)
+ simulateBadConn("db.Query query", &hookQueryBadConn, dbQuery)
+
+ // db.Prepare
+ simulateBadConn("db.Prepare", &hookPrepareBadConn, func() error {
+ stmt, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+ if err != nil {
+ return err
+ }
+ stmt.Close()
+ return nil
+ })
+
+ // stmt.Exec
+ stmt1, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+ if err != nil {
+ t.Fatalf("prepare: %v", err)
+ }
+ defer stmt1.Close()
+ // make sure we must prepare the stmt first
+ for _, cs := range stmt1.css {
+ cs.dc.inUse = true
+ }
+
+ stmtExec := func() error {
+ _, err := stmt1.Exec("Gopher", 3, false)
+ return err
+ }
+ simulateBadConn("stmt.Exec prepare", &hookPrepareBadConn, stmtExec)
+ simulateBadConn("stmt.Exec exec", &hookExecBadConn, stmtExec)
+
+ // stmt.Query
+ stmt2, err := db.Prepare("SELECT|t1|age,name|")
+ if err != nil {
+ t.Fatalf("prepare: %v", err)
+ }
+ defer stmt2.Close()
+ // make sure we must prepare the stmt first
+ for _, cs := range stmt2.css {
+ cs.dc.inUse = true
+ }
+
+ stmtQuery := func() error {
+ rows, err := stmt2.Query()
+ if err == nil {
+ err = rows.Close()
+ }
+ return err
+ }
+ simulateBadConn("stmt.Query prepare", &hookPrepareBadConn, stmtQuery)
+ simulateBadConn("stmt.Query exec", &hookQueryBadConn, stmtQuery)
+}
+
type concurrentTest interface {
init(t testing.TB, db *DB)
finish(t testing.TB)
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
index 9d32a0af2..93c68881a 100644
--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/debug/dwarf/const.go
@@ -207,10 +207,15 @@ const (
formRef8 format = 0x14
formRefUdata format = 0x15
formIndirect format = 0x16
+ // The following are new in DWARF 4.
formSecOffset format = 0x17
formExprloc format = 0x18
formFlagPresent format = 0x19
formRefSig8 format = 0x20
+ // Extensions for multi-file compression (.dwz)
+ // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+ formGnuRefAlt format = 0x1f20
+ formGnuStrpAlt format = 0x1f21
)
// A Tag is the classification (the type) of an Entry.
@@ -264,15 +269,22 @@ const (
TagVariantPart Tag = 0x33
TagVariable Tag = 0x34
TagVolatileType Tag = 0x35
- TagDwarfProcedure Tag = 0x36
- TagRestrictType Tag = 0x37
- TagInterfaceType Tag = 0x38
- TagNamespace Tag = 0x39
- TagImportedModule Tag = 0x3A
- TagUnspecifiedType Tag = 0x3B
- TagPartialUnit Tag = 0x3C
- TagImportedUnit Tag = 0x3D
- TagMutableType Tag = 0x3E
+ // The following are new in DWARF 3.
+ TagDwarfProcedure Tag = 0x36
+ TagRestrictType Tag = 0x37
+ TagInterfaceType Tag = 0x38
+ TagNamespace Tag = 0x39
+ TagImportedModule Tag = 0x3A
+ TagUnspecifiedType Tag = 0x3B
+ TagPartialUnit Tag = 0x3C
+ TagImportedUnit Tag = 0x3D
+ TagMutableType Tag = 0x3E // Later removed from DWARF.
+ TagCondition Tag = 0x3F
+ TagSharedType Tag = 0x40
+ // The following are new in DWARF 4.
+ TagTypeUnit Tag = 0x41
+ TagRvalueReferenceType Tag = 0x42
+ TagTemplateAlias Tag = 0x43
)
var tagNames = [...]string{
@@ -332,6 +344,11 @@ var tagNames = [...]string{
TagPartialUnit: "PartialUnit",
TagImportedUnit: "ImportedUnit",
TagMutableType: "MutableType",
+ TagCondition: "Condition",
+ TagSharedType: "SharedType",
+ TagTypeUnit: "TypeUnit",
+ TagRvalueReferenceType: "RvalueReferenceType",
+ TagTemplateAlias: "TemplateAlias",
}
func (t Tag) String() string {
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index c0c288992..665c6840d 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -241,10 +241,10 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// 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:
+ case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
is64, known := b.format.dwarf64()
if !known {
- b.error("unknown size for DW_FORM_sec_offset")
+ b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
} else if is64 {
val = int64(b.uint64())
} else {
@@ -387,3 +387,15 @@ func (r *Reader) SkipChildren() {
}
}
}
+
+// clone returns a copy of the reader. This is used by the typeReader
+// interface.
+func (r *Reader) clone() typeReader {
+ return r.d.Reader()
+}
+
+// offset returns the current buffer offset. This is used by the
+// typeReader interface.
+func (r *Reader) offset() Offset {
+ return r.b.off
+}
diff --git a/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
index 37a518b6d..c1b3f37ac 100644
--- a/src/pkg/debug/dwarf/open.go
+++ b/src/pkg/debug/dwarf/open.go
@@ -24,9 +24,9 @@ type Data struct {
// parsed data
abbrevCache map[uint32]abbrevTable
- addrsize int
order binary.ByteOrder
typeCache map[Offset]Type
+ typeSigs map[uint64]*typeUnit
unit []unit
}
@@ -50,6 +50,7 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
str: str,
abbrevCache: make(map[uint32]abbrevTable),
typeCache: make(map[Offset]Type),
+ typeSigs: make(map[uint64]*typeUnit),
}
// Sniff .debug_info to figure out byte order.
@@ -76,3 +77,11 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
d.unit = u
return d, nil
}
+
+// AddTypes will add one .debug_types section to the DWARF data. A
+// typical object with DWARF version 4 debug info will have multiple
+// .debug_types sections. The name is used for error reporting only,
+// and serves to distinguish one .debug_types section from another.
+func (d *Data) AddTypes(name string, types []byte) error {
+ return d.parseTypes(name, types)
+}
diff --git a/src/pkg/debug/dwarf/testdata/typedef.elf4 b/src/pkg/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 000000000..3d5a5a1b1
--- /dev/null
+++ b/src/pkg/debug/dwarf/testdata/typedef.elf4
Binary files differ
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index 1fbae6c14..68866d0b7 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -251,23 +251,37 @@ func (t *TypedefType) String() string { return t.Name }
func (t *TypedefType) Size() int64 { return t.Type.Size() }
+// typeReader is used to read from either the info section or the
+// types section.
+type typeReader interface {
+ Seek(Offset)
+ Next() (*Entry, error)
+ clone() typeReader
+ offset() Offset
+}
+
+// Type reads the type at off in the DWARF ``info'' section.
func (d *Data) Type(off Offset) (Type, error) {
- if t, ok := d.typeCache[off]; ok {
+ return d.readType("info", d.Reader(), off, d.typeCache)
+}
+
+// readType reads a type from r at off of name using and updating a
+// type cache.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+ if t, ok := typeCache[off]; ok {
return t, nil
}
-
- r := d.Reader()
r.Seek(off)
e, err := r.Next()
if err != nil {
return nil, err
}
if e == nil || e.Offset != off {
- return nil, DecodeError{"info", off, "no type at offset"}
+ return nil, DecodeError{name, off, "no type at offset"}
}
// Parse type from Entry.
- // Must always set d.typeCache[off] before calling
+ // Must always set typeCache[off] before calling
// d.Type recursively, to handle circular types correctly.
var typ Type
@@ -290,7 +304,7 @@ func (d *Data) Type(off Offset) (Type, error) {
return nil
}
if kid == nil {
- err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+ err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
return nil
}
if kid.Tag == 0 {
@@ -313,15 +327,21 @@ func (d *Data) Type(off Offset) (Type, error) {
// Get Type referred to by Entry's AttrType field.
// Set err if error happens. Not having a type is an error.
typeOf := func(e *Entry) Type {
- toff, ok := e.Val(AttrType).(Offset)
- if !ok {
+ tval := e.Val(AttrType)
+ var t Type
+ switch toff := tval.(type) {
+ case Offset:
+ if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+ return nil
+ }
+ case uint64:
+ if t, err = d.sigToType(toff); err != nil {
+ return nil
+ }
+ default:
// It appears that no Type means "void".
return new(VoidType)
}
- var t Type
- if t, err = d.Type(toff); err != nil {
- return nil
- }
return t
}
@@ -337,7 +357,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// dimensions are in left to right order.
t := new(ArrayType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
@@ -363,7 +383,7 @@ func (d *Data) Type(off Offset) (Type, error) {
}
ndim++
case TagEnumerationType:
- err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+ err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
goto Error
}
}
@@ -383,12 +403,12 @@ func (d *Data) Type(off Offset) (Type, error) {
name, _ := e.Val(AttrName).(string)
enc, ok := e.Val(AttrEncoding).(int64)
if !ok {
- err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+ err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
goto Error
}
switch enc {
default:
- err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+ err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
goto Error
case encAddress:
@@ -408,7 +428,7 @@ func (d *Data) Type(off Offset) (Type, error) {
case encUnsignedChar:
typ = new(UcharType)
}
- d.typeCache[off] = typ
+ typeCache[off] = typ
t := typ.(interface {
Basic() *BasicType
}).Basic()
@@ -433,7 +453,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// There is much more to handle C++, all ignored for now.
t := new(StructType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
switch e.Tag {
case TagClassType:
t.Kind = "class"
@@ -453,12 +473,13 @@ func (d *Data) Type(off Offset) (Type, error) {
if f.Type = typeOf(kid); err != nil {
goto Error
}
- if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ switch loc := kid.Val(AttrDataMemberLoc).(type) {
+ case []byte:
// TODO: Should have original compilation
// unit here, not unknownFormat.
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
- err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+ err = DecodeError{name, kid.Offset, "unexpected opcode"}
goto Error
}
f.ByteOffset = int64(b.uint())
@@ -466,6 +487,8 @@ func (d *Data) Type(off Offset) (Type, error) {
err = b.err
goto Error
}
+ case int64:
+ f.ByteOffset = loc
}
haveBitOffset := false
@@ -502,7 +525,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: subtype
t := new(QualType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
@@ -526,7 +549,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrConstValue: value of constant
t := new(EnumType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.EnumName, _ = e.Val(AttrName).(string)
t.Val = make([]*EnumValue, 0, 8)
for kid := next(); kid != nil; kid = next() {
@@ -552,7 +575,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrAddrClass: address class [ignored]
t := new(PtrType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if e.Val(AttrType) == nil {
t.Type = &VoidType{}
break
@@ -571,7 +594,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// TagUnspecifiedParameter: final ...
t := new(FuncType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.ReturnType = typeOf(e); err != nil {
goto Error
}
@@ -598,7 +621,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: type definition [required]
t := new(TypedefType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.Name, _ = e.Val(AttrName).(string)
t.Type = typeOf(e)
}
@@ -620,7 +643,7 @@ Error:
// If the parse fails, take the type out of the cache
// so that the next call with this offset doesn't hit
// the cache and return success.
- delete(d.typeCache, off)
+ delete(typeCache, off)
return nil, err
}
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
index b5b255f6f..2cb85e74b 100644
--- a/src/pkg/debug/dwarf/type_test.go
+++ b/src/pkg/debug/dwarf/type_test.go
@@ -73,6 +73,8 @@ func TestTypedefsMachO(t *testing.T) {
testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
}
+func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
+
func testTypedefs(t *testing.T, d *Data, kind string) {
r := d.Reader()
seen := make(map[string]bool)
diff --git a/src/pkg/debug/dwarf/typeunit.go b/src/pkg/debug/dwarf/typeunit.go
new file mode 100644
index 000000000..3fd1c9973
--- /dev/null
+++ b/src/pkg/debug/dwarf/typeunit.go
@@ -0,0 +1,166 @@
+// 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.
+
+package dwarf
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Parse the type units stored in a DWARF4 .debug_types section. Each
+// type unit defines a single primary type and an 8-byte signature.
+// Other sections may then use formRefSig8 to refer to the type.
+
+// The typeUnit format is a single type with a signature. It holds
+// the same data as a compilation unit.
+type typeUnit struct {
+ unit
+ toff Offset // Offset to signature type within data.
+ name string // Name of .debug_type section.
+ cache Type // Cache the type, nil to start.
+}
+
+// Parse a .debug_types section.
+func (d *Data) parseTypes(name string, types []byte) error {
+ b := makeBuf(d, unknownFormat{}, name, 0, types)
+ for len(b.data) > 0 {
+ base := b.off
+ dwarf64 := false
+ n := b.uint32()
+ if n == 0xffffffff {
+ n64 := b.uint64()
+ if n64 != uint64(uint32(n64)) {
+ b.error("type unit length overflow")
+ return b.err
+ }
+ n = uint32(n64)
+ dwarf64 = true
+ }
+ hdroff := b.off
+ vers := b.uint16()
+ if vers != 4 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+ return b.err
+ }
+ var ao uint32
+ if !dwarf64 {
+ ao = b.uint32()
+ } else {
+ ao64 := b.uint64()
+ if ao64 != uint64(uint32(ao64)) {
+ b.error("type unit abbrev offset overflow")
+ return b.err
+ }
+ ao = uint32(ao64)
+ }
+ atable, err := d.parseAbbrev(ao)
+ if err != nil {
+ return err
+ }
+ asize := b.uint8()
+ sig := b.uint64()
+
+ var toff uint32
+ if !dwarf64 {
+ toff = b.uint32()
+ } else {
+ to64 := b.uint64()
+ if to64 != uint64(uint32(to64)) {
+ b.error("type unit type offset overflow")
+ return b.err
+ }
+ toff = uint32(to64)
+ }
+
+ boff := b.off
+ d.typeSigs[sig] = &typeUnit{
+ unit: unit{
+ base: base,
+ off: boff,
+ data: b.bytes(int(Offset(n) - (b.off - hdroff))),
+ atable: atable,
+ asize: int(asize),
+ vers: int(vers),
+ is64: dwarf64,
+ },
+ toff: Offset(toff),
+ name: name,
+ }
+ if b.err != nil {
+ return b.err
+ }
+ }
+ return nil
+}
+
+// Return the type for a type signature.
+func (d *Data) sigToType(sig uint64) (Type, error) {
+ tu := d.typeSigs[sig]
+ if tu == nil {
+ return nil, fmt.Errorf("no type unit with signature %v", sig)
+ }
+ if tu.cache != nil {
+ return tu.cache, nil
+ }
+
+ b := makeBuf(d, tu, tu.name, tu.off, tu.data)
+ r := &typeUnitReader{d: d, tu: tu, b: b}
+ t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+ if err != nil {
+ return nil, err
+ }
+
+ tu.cache = t
+ return t, nil
+}
+
+// typeUnitReader is a typeReader for a tagTypeUnit.
+type typeUnitReader struct {
+ d *Data
+ tu *typeUnit
+ b buf
+ err error
+}
+
+// Seek to a new position in the type unit.
+func (tur *typeUnitReader) Seek(off Offset) {
+ tur.err = nil
+ doff := off - tur.tu.off
+ if doff < 0 || doff >= Offset(len(tur.tu.data)) {
+ tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
+ return
+ }
+ tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
+}
+
+// Next reads the next Entry from the type unit.
+func (tur *typeUnitReader) Next() (*Entry, error) {
+ if tur.err != nil {
+ return nil, tur.err
+ }
+ if len(tur.tu.data) == 0 {
+ return nil, nil
+ }
+ e := tur.b.entry(tur.tu.atable, tur.tu.base)
+ if tur.b.err != nil {
+ tur.err = tur.b.err
+ return nil, tur.err
+ }
+ return e, nil
+}
+
+// clone returns a new reader for the type unit.
+func (tur *typeUnitReader) clone() typeReader {
+ return &typeUnitReader{
+ d: tur.d,
+ tu: tur.tu,
+ b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
+ }
+}
+
+// offset returns the current offset.
+func (tur *typeUnitReader) offset() Offset {
+ return tur.b.off
+}
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
index 270cd2e33..0fbc8e082 100644
--- a/src/pkg/debug/dwarf/unit.go
+++ b/src/pkg/debug/dwarf/unit.go
@@ -66,7 +66,7 @@ func (d *Data) parseUnits() ([]unit, error) {
n = uint32(b.uint64())
}
vers := b.uint16()
- if vers != 2 && vers != 3 {
+ if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index 03e42b034..d622dae2a 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -517,7 +517,7 @@ const (
DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */
DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */
DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
- DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+ DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */
DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */
DT_FLAGS DynTag = 30 /* Object specific flag values. */
DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING
diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go
index 67b961b5c..e3c51bb71 100644
--- a/src/pkg/debug/elf/elf_test.go
+++ b/src/pkg/debug/elf/elf_test.go
@@ -43,7 +43,7 @@ func TestNames(t *testing.T) {
for i, tt := range nameTests {
s := fmt.Sprint(tt.val)
if s != tt.str {
- t.Errorf("#%d: want %q have %q", i, s, tt.str)
+ t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
}
}
}
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index a55c37ea9..423932fe0 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -76,6 +76,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -412,7 +415,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym32Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
}
@@ -455,7 +458,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym64Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
}
@@ -519,13 +522,17 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
return f.applyRelocationsAMD64(dst, rels)
}
+ if f.Class == ELFCLASS32 && f.Machine == EM_386 {
+ return f.applyRelocations386(dst, rels)
+ }
return errors.New("not implemented")
}
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
- if len(rels)%Sym64Size != 0 {
- return errors.New("length of relocation section is not a multiple of Sym64Size")
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -533,7 +540,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
return err
}
- b := bytes.NewBuffer(rels)
+ b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
@@ -567,6 +574,43 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocations386(dst []byte, rels []byte) error {
+ // 8 is the size of Rel32.
+ if len(rels)%8 != 0 {
+ return errors.New("length of relocation section is not a multiple of 8")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rel Rel32
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rel)
+ symNo := rel.Info >> 8
+ t := R_386(rel.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+
+ if t == R_386_32 {
+ if rel.Off+4 >= uint32(len(dst)) {
+ continue
+ }
+ val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
+ val += uint32(sym.Value)
+ f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+ }
+ }
+
+ return nil
+}
+
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
@@ -600,8 +644,58 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
}
+ // When using clang we need to process relocations even for 386.
+ rel := f.Section(".rel.debug_info")
+ if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 {
+ data, err := rel.Data()
+ if err != nil {
+ return nil, err
+ }
+ err = f.applyRelocations(dat[1], data)
+ if err != nil {
+ return nil, err
+ }
+ }
+
abbrev, info, str := dat[0], dat[1], dat[2]
- return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+ d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+ if err != nil {
+ return nil, err
+ }
+
+ // Look for DWARF4 .debug_types sections.
+ for i, s := range f.Sections {
+ if s.Name == ".debug_types" {
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+
+ for _, r := range f.Sections {
+ if r.Type != SHT_RELA && r.Type != SHT_REL {
+ continue
+ }
+ if int(r.Info) != i {
+ continue
+ }
+ rd, err := r.Data()
+ if err != nil {
+ return nil, err
+ }
+ err = f.applyRelocations(b, rd)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return d, nil
}
// Symbols returns the symbol table for f.
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 38b5f9e70..7f88a54bc 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -261,6 +261,12 @@ var relocationTests = []relocationTest{
},
},
{
+ "testdata/go-relocation-test-clang-x86.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
+ },
+ },
+ {
"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
[]relocationTestEntry{
{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj
new file mode 100644
index 000000000..e909cf4e6
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/hello.c b/src/pkg/debug/elf/testdata/hello.c
new file mode 100644
index 000000000..34d9ee792
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+ printf("hello, world\n");
+}
diff --git a/src/pkg/debug/gosym/pclntab.go b/src/pkg/debug/gosym/pclntab.go
index 3e6a8046b..6620aefb0 100644
--- a/src/pkg/debug/gosym/pclntab.go
+++ b/src/pkg/debug/gosym/pclntab.go
@@ -196,6 +196,33 @@ func (t *LineTable) go12Init() {
t.go12 = 1 // so far so good
}
+// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
+func (t *LineTable) go12Funcs() []Func {
+ // Assume it is malformed and return nil on error.
+ defer func() {
+ recover()
+ }()
+
+ n := len(t.functab) / int(t.ptrsize) / 2
+ funcs := make([]Func, n)
+ for i := range funcs {
+ f := &funcs[i]
+ f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
+ f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+ info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
+ f.LineTable = t
+ f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
+ f.Sym = &Sym{
+ Value: f.Entry,
+ Type: 'T',
+ Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
+ GoType: 0,
+ Func: f,
+ }
+ }
+ return funcs
+}
+
// findFunc returns the func corresponding to the given program counter.
func (t *LineTable) findFunc(pc uint64) []byte {
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
diff --git a/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
index 9ab05bac2..3864e3cb4 100644
--- a/src/pkg/debug/gosym/symtab.go
+++ b/src/pkg/debug/gosym/symtab.go
@@ -129,6 +129,9 @@ var (
)
func walksymtab(data []byte, fn func(sym) error) error {
+ if len(data) == 0 { // missing symtab is okay
+ return nil
+ }
var order binary.ByteOrder = binary.BigEndian
newTable := false
switch {
@@ -455,6 +458,10 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
i = end - 1 // loop will i++
}
}
+
+ if t.go12line != nil && nf == 0 {
+ t.Funcs = t.go12line.go12Funcs()
+ }
if obj != nil {
obj.Funcs = t.Funcs[lastf:]
}
diff --git a/src/pkg/debug/macho/fat.go b/src/pkg/debug/macho/fat.go
new file mode 100644
index 000000000..93b831526
--- /dev/null
+++ b/src/pkg/debug/macho/fat.go
@@ -0,0 +1,146 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package macho
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FatFile is a Mach-O universal binary that contains at least one architecture.
+type FatFile struct {
+ Magic uint32
+ Arches []FatArch
+ closer io.Closer
+}
+
+// A FatArchHeader represents a fat header for a specific image architecture.
+type FatArchHeader struct {
+ Cpu Cpu
+ SubCpu uint32
+ Offset uint32
+ Size uint32
+ Align uint32
+}
+
+const fatArchHeaderSize = 5 * 4
+
+// A FatArch is a Mach-O File inside a FatFile.
+type FatArch struct {
+ FatArchHeader
+ *File
+}
+
+// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
+// universal binary but may be a thin binary, based on its magic number.
+var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
+
+// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
+// universal binary. The Mach-O binary is expected to start at position 0 in
+// the ReaderAt.
+func NewFatFile(r io.ReaderAt) (*FatFile, error) {
+ var ff FatFile
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read the fat_header struct, which is always in big endian.
+ // Start with the magic number.
+ err := binary.Read(sr, binary.BigEndian, &ff.Magic)
+ if err != nil {
+ return nil, &FormatError{0, "error reading magic number", nil}
+ } else if ff.Magic != MagicFat {
+ // See if this is a Mach-O file via its magic number. The magic
+ // must be converted to little endian first though.
+ var buf [4]byte
+ binary.BigEndian.PutUint32(buf[:], ff.Magic)
+ leMagic := binary.LittleEndian.Uint32(buf[:])
+ if leMagic == Magic32 || leMagic == Magic64 {
+ return nil, ErrNotFat
+ } else {
+ return nil, &FormatError{0, "invalid magic number", nil}
+ }
+ }
+ offset := int64(4)
+
+ // Read the number of FatArchHeaders that come after the fat_header.
+ var narch uint32
+ err = binary.Read(sr, binary.BigEndian, &narch)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_header", nil}
+ }
+ offset += 4
+
+ if narch < 1 {
+ return nil, &FormatError{offset, "file contains no images", nil}
+ }
+
+ // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
+ // there are not duplicate architectures.
+ seenArches := make(map[uint64]bool, narch)
+ // Make sure that all images are for the same MH_ type.
+ var machoType Type
+
+ // Following the fat_header comes narch fat_arch structs that index
+ // Mach-O images further in the file.
+ ff.Arches = make([]FatArch, narch)
+ for i := uint32(0); i < narch; i++ {
+ fa := &ff.Arches[i]
+ err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_arch header", nil}
+ }
+ offset += fatArchHeaderSize
+
+ fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
+ fa.File, err = NewFile(fr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make sure the architecture for this image is not duplicate.
+ seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
+ if o, k := seenArches[seenArch]; o || k {
+ return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
+ }
+ seenArches[seenArch] = true
+
+ // Make sure the Mach-O type matches that of the first image.
+ if i == 0 {
+ machoType = fa.Type
+ } else {
+ if fa.Type != machoType {
+ return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
+ }
+ }
+ }
+
+ return &ff, nil
+}
+
+// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
+// universal binary.
+func OpenFat(name string) (ff *FatFile, err error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err = NewFatFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return
+}
+
+func (ff *FatFile) Close() error {
+ var err error
+ if ff.closer != nil {
+ err = ff.closer.Close()
+ ff.closer = nil
+ }
+ return err
+}
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index f5f0dedb7..eefb74444 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/debug/macho/file.go
@@ -11,7 +11,6 @@ import (
"bytes"
"debug/dwarf"
"encoding/binary"
- "errors"
"fmt"
"io"
"os"
@@ -74,6 +73,9 @@ type Segment struct {
func (s *Segment) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -109,6 +111,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -246,7 +251,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDylib:
var hdr DylibCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -263,7 +268,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSymtab:
var hdr SymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -290,7 +295,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDysymtab:
var hdr DysymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -299,7 +304,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
return nil, err
}
x := make([]uint32, hdr.Nindirectsyms)
- if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
return nil, err
}
st := new(Dysymtab)
@@ -311,7 +316,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment:
var seg32 Segment32
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg32); err != nil {
return nil, err
}
@@ -349,7 +354,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment64:
var seg64 Segment64
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg64); err != nil {
return nil, err
}
@@ -396,7 +401,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
- b := bytes.NewBuffer(symdat)
+ b := bytes.NewReader(symdat)
for i := range symtab {
var n Nlist64
if f.Magic == Magic64 {
@@ -475,7 +480,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
name = "__debug_" + name
s := f.Section(name)
if s == nil {
- return nil, errors.New("missing Mach-O section " + name)
+ continue
}
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
index 640225b32..4797780ce 100644
--- a/src/pkg/debug/macho/file_test.go
+++ b/src/pkg/debug/macho/file_test.go
@@ -165,3 +165,46 @@ func TestOpenFailure(t *testing.T) {
t.Errorf("open %s: succeeded unexpectedly", filename)
}
}
+
+func TestOpenFat(t *testing.T) {
+ ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if ff.Magic != MagicFat {
+ t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
+ }
+ if len(ff.Arches) != 2 {
+ t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
+ }
+
+ for i := range ff.Arches {
+ arch := &ff.Arches[i]
+ ftArch := &fileTests[i]
+
+ if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
+ t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
+ }
+
+ if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
+ t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
+ }
+ }
+}
+
+func TestOpenFatFailure(t *testing.T) {
+ filename := "file.go" // not a Mach-O file
+ if _, err := OpenFat(filename); err == nil {
+ t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
+ }
+
+ filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
+ ff, err := OpenFat(filename)
+ if err != ErrNotFat {
+ t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err)
+ }
+ if ff != nil {
+ t.Errorf("OpenFat %s: got %v, want nil", filename, ff)
+ }
+}
diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
index bc14226c5..d9678c8ed 100644
--- a/src/pkg/debug/macho/macho.go
+++ b/src/pkg/debug/macho/macho.go
@@ -26,29 +26,40 @@ const (
)
const (
- Magic32 uint32 = 0xfeedface
- Magic64 uint32 = 0xfeedfacf
+ Magic32 uint32 = 0xfeedface
+ Magic64 uint32 = 0xfeedfacf
+ MagicFat uint32 = 0xcafebabe
)
-// A Type is a Mach-O file type, either an object or an executable.
+// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
type Type uint32
const (
- TypeObj Type = 1
- TypeExec Type = 2
+ TypeObj Type = 1
+ TypeExec Type = 2
+ TypeDylib Type = 6
+ TypeBundle Type = 8
)
// A Cpu is a Mach-O cpu type.
type Cpu uint32
+const cpuArch64 = 0x01000000
+
const (
Cpu386 Cpu = 7
- CpuAmd64 Cpu = Cpu386 + 1<<24
+ CpuAmd64 Cpu = Cpu386 | cpuArch64
+ CpuArm Cpu = 12
+ CpuPpc Cpu = 18
+ CpuPpc64 Cpu = CpuPpc | cpuArch64
)
var cpuStrings = []intName{
{uint32(Cpu386), "Cpu386"},
{uint32(CpuAmd64), "CpuAmd64"},
+ {uint32(CpuArm), "CpuArm"},
+ {uint32(CpuPpc), "CpuPpc"},
+ {uint32(CpuPpc64), "CpuPpc64"},
}
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
diff --git a/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
new file mode 100644
index 000000000..7efd19300
--- /dev/null
+++ b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
Binary files differ
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index f521566ef..ce6f1408f 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -13,13 +13,15 @@ import (
"io"
"os"
"strconv"
+ "unsafe"
)
// A File represents an open PE file.
type File struct {
FileHeader
- Sections []*Section
- Symbols []*Symbol
+ OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
+ Sections []*Section
+ Symbols []*Symbol
closer io.Closer
}
@@ -72,6 +74,9 @@ type ImportDirectory struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -193,10 +198,33 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
}
- // Process sections.
+ // Read optional header.
sr.Seek(base, os.SEEK_SET)
- binary.Read(sr, binary.LittleEndian, &f.FileHeader)
- sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
+ if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+ return nil, err
+ }
+ var oh32 OptionalHeader32
+ var oh64 OptionalHeader64
+ switch uintptr(f.FileHeader.SizeOfOptionalHeader) {
+ case unsafe.Sizeof(oh32):
+ if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
+ return nil, err
+ }
+ if oh32.Magic != 0x10b { // PE32
+ return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
+ }
+ f.OptionalHeader = &oh32
+ case unsafe.Sizeof(oh64):
+ if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
+ return nil, err
+ }
+ if oh64.Magic != 0x20b { // PE32+
+ return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
+ }
+ f.OptionalHeader = &oh64
+ }
+
+ // Process sections.
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
sh := new(SectionHeader32)
@@ -213,15 +241,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
s := new(Section)
s.SectionHeader = SectionHeader{
Name: name,
- VirtualSize: uint32(sh.VirtualSize),
- VirtualAddress: uint32(sh.VirtualAddress),
- Size: uint32(sh.SizeOfRawData),
- Offset: uint32(sh.PointerToRawData),
- PointerToRelocations: uint32(sh.PointerToRelocations),
- PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
- NumberOfRelocations: uint16(sh.NumberOfRelocations),
- NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
- Characteristics: uint32(sh.Characteristics),
+ VirtualSize: sh.VirtualSize,
+ VirtualAddress: sh.VirtualAddress,
+ Size: sh.SizeOfRawData,
+ Offset: sh.PointerToRawData,
+ PointerToRelocations: sh.PointerToRelocations,
+ PointerToLineNumbers: sh.PointerToLineNumbers,
+ NumberOfRelocations: sh.NumberOfRelocations,
+ NumberOfLineNumbers: sh.NumberOfLineNumbers,
+ Characteristics: sh.Characteristics,
}
s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
s.ReaderAt = s.sr
diff --git a/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go
index c0f9fcb95..ddbb27174 100644
--- a/src/pkg/debug/pe/file_test.go
+++ b/src/pkg/debug/pe/file_test.go
@@ -12,6 +12,7 @@ import (
type fileTest struct {
file string
hdr FileHeader
+ opthdr interface{}
sections []*SectionHeader
symbols []*Symbol
}
@@ -20,6 +21,7 @@ var fileTests = []fileTest{
{
"testdata/gcc-386-mingw-obj",
FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+ nil,
[]*SectionHeader{
{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
@@ -56,27 +58,130 @@ var fileTests = []fileTest{
{
"testdata/gcc-386-mingw-exec",
FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+ &OptionalHeader32{
+ 0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+ [16]DataDirectory{
+ {0x0, 0x0},
+ {0x5000, 0x3c8},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x7000, 0x18},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ },
+ },
+ []*SectionHeader{
+ {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
+ {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
+ {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
+ {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+ },
+ []*Symbol{},
+ },
+ {
+ "testdata/gcc-amd64-mingw-obj",
+ FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
+ nil,
+ []*SectionHeader{
+ {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
+ {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+ {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
+ {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
+ {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
+ },
+ []*Symbol{
+ {".file", 0x0, -2, 0x0, 0x67},
+ {"main", 0x0, 1, 0x20, 0x2},
+ {".text", 0x0, 1, 0x0, 0x3},
+ {".data", 0x0, 2, 0x0, 0x3},
+ {".bss", 0x0, 3, 0x0, 0x3},
+ {".rdata", 0x0, 4, 0x0, 0x3},
+ {".xdata", 0x0, 5, 0x0, 0x3},
+ {".pdata", 0x0, 6, 0x0, 0x3},
+ {"__main", 0x0, 0, 0x20, 0x2},
+ {"puts", 0x0, 0, 0x20, 0x2},
+ },
+ },
+ {
+ "testdata/gcc-amd64-mingw-exec",
+ FileHeader{0x8664, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f},
+ &OptionalHeader64{
+ 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+ [16]DataDirectory{
+ {0x0, 0x0},
+ {0xe000, 0x990},
+ {0x0, 0x0},
+ {0xa000, 0x498},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x10000, 0x28},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0xe254, 0x218},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ {0x0, 0x0},
+ },
+ },
[]*SectionHeader{
- {Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
- {Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
- {Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
- {Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- {Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- {Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
- {Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {".text", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020},
+ {".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+ {".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040},
+ {".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+ {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
+ {".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+ {".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
+ {".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
},
[]*Symbol{},
},
}
+func isOptHdrEq(a, b interface{}) bool {
+ switch va := a.(type) {
+ case *OptionalHeader32:
+ vb, ok := b.(*OptionalHeader32)
+ if !ok {
+ return false
+ }
+ return *vb == *va
+ case *OptionalHeader64:
+ vb, ok := b.(*OptionalHeader64)
+ if !ok {
+ return false
+ }
+ return *vb == *va
+ case nil:
+ return b == nil
+ }
+ return false
+}
+
func TestOpen(t *testing.T) {
for i := range fileTests {
tt := &fileTests[i]
@@ -90,6 +195,10 @@ func TestOpen(t *testing.T) {
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
continue
}
+ if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
+ continue
+ }
for i, sh := range f.Sections {
if i >= len(tt.sections) {
diff --git a/src/pkg/debug/pe/pe.go b/src/pkg/debug/pe/pe.go
index 0606217b3..8e90b1b51 100644
--- a/src/pkg/debug/pe/pe.go
+++ b/src/pkg/debug/pe/pe.go
@@ -14,6 +14,78 @@ type FileHeader struct {
Characteristics uint16
}
+type DataDirectory struct {
+ VirtualAddress uint32
+ Size uint32
+}
+
+type OptionalHeader32 struct {
+ Magic uint16
+ MajorLinkerVersion uint8
+ MinorLinkerVersion uint8
+ SizeOfCode uint32
+ SizeOfInitializedData uint32
+ SizeOfUninitializedData uint32
+ AddressOfEntryPoint uint32
+ BaseOfCode uint32
+ BaseOfData uint32
+ ImageBase uint32
+ SectionAlignment uint32
+ FileAlignment uint32
+ MajorOperatingSystemVersion uint16
+ MinorOperatingSystemVersion uint16
+ MajorImageVersion uint16
+ MinorImageVersion uint16
+ MajorSubsystemVersion uint16
+ MinorSubsystemVersion uint16
+ Win32VersionValue uint32
+ SizeOfImage uint32
+ SizeOfHeaders uint32
+ CheckSum uint32
+ Subsystem uint16
+ DllCharacteristics uint16
+ SizeOfStackReserve uint32
+ SizeOfStackCommit uint32
+ SizeOfHeapReserve uint32
+ SizeOfHeapCommit uint32
+ LoaderFlags uint32
+ NumberOfRvaAndSizes uint32
+ DataDirectory [16]DataDirectory
+}
+
+type OptionalHeader64 struct {
+ Magic uint16
+ MajorLinkerVersion uint8
+ MinorLinkerVersion uint8
+ SizeOfCode uint32
+ SizeOfInitializedData uint32
+ SizeOfUninitializedData uint32
+ AddressOfEntryPoint uint32
+ BaseOfCode uint32
+ ImageBase uint64
+ SectionAlignment uint32
+ FileAlignment uint32
+ MajorOperatingSystemVersion uint16
+ MinorOperatingSystemVersion uint16
+ MajorImageVersion uint16
+ MinorImageVersion uint16
+ MajorSubsystemVersion uint16
+ MinorSubsystemVersion uint16
+ Win32VersionValue uint32
+ SizeOfImage uint32
+ SizeOfHeaders uint32
+ CheckSum uint32
+ Subsystem uint16
+ DllCharacteristics uint16
+ SizeOfStackReserve uint64
+ SizeOfStackCommit uint64
+ SizeOfHeapReserve uint64
+ SizeOfHeapCommit uint64
+ LoaderFlags uint32
+ NumberOfRvaAndSizes uint32
+ DataDirectory [16]DataDirectory
+}
+
type SectionHeader32 struct {
Name [8]uint8
VirtualSize uint32
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
new file mode 100644
index 000000000..78d4e5fed
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
Binary files differ
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
new file mode 100644
index 000000000..48ae7921f
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
Binary files differ
diff --git a/src/pkg/debug/plan9obj/file.go b/src/pkg/debug/plan9obj/file.go
new file mode 100644
index 000000000..60a585719
--- /dev/null
+++ b/src/pkg/debug/plan9obj/file.go
@@ -0,0 +1,325 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package plan9obj implements access to Plan 9 a.out object files.
+package plan9obj
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FileHeader represents a Plan 9 a.out file header.
+type FileHeader struct {
+ Magic uint32
+ Bss uint32
+ Entry uint64
+ PtrSize int
+}
+
+// A File represents an open Plan 9 a.out file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ closer io.Closer
+}
+
+// A SectionHeader represents a single Plan 9 a.out section header.
+// This structure doesn't exist on-disk, but eases navigation
+// through the object file.
+type SectionHeader struct {
+ Name string
+ Size uint32
+ Offset uint32
+}
+
+// A Section represents a single section in a Plan 9 a.out file.
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Plan 9 a.out section.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Plan 9 a.out section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in a Plan 9 a.out symbol table section.
+type Sym struct {
+ Value uint64
+ Type rune
+ Name string
+}
+
+/*
+ * Plan 9 a.out reader
+ */
+
+// formatError is returned by some operations if the data does
+// not have the correct format for an object file.
+type formatError struct {
+ off int
+ msg string
+ val interface{}
+}
+
+func (e *formatError) Error() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
+func Open(name string) (*File, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+ var err error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+func parseMagic(magic []byte) (uint32, error) {
+ m := binary.BigEndian.Uint32(magic)
+ switch m {
+ case Magic386, MagicAMD64, MagicARM:
+ return m, nil
+ }
+ return 0, &formatError{0, "bad magic number", magic}
+}
+
+// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
+// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read and decode Plan 9 magic
+ var magic [4]byte
+ if _, err := r.ReadAt(magic[:], 0); err != nil {
+ return nil, err
+ }
+ _, err := parseMagic(magic[:])
+ if err != nil {
+ return nil, err
+ }
+
+ ph := new(prog)
+ if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
+ return nil, err
+ }
+
+ f := &File{FileHeader: FileHeader{
+ Magic: ph.Magic,
+ Bss: ph.Bss,
+ Entry: uint64(ph.Entry),
+ PtrSize: 4,
+ }}
+
+ hdrSize := 4 * 8
+
+ if ph.Magic&Magic64 != 0 {
+ if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
+ return nil, err
+ }
+ f.PtrSize = 8
+ hdrSize += 8
+ }
+
+ var sects = []struct {
+ name string
+ size uint32
+ }{
+ {"text", ph.Text},
+ {"data", ph.Data},
+ {"syms", ph.Syms},
+ {"spsz", ph.Spsz},
+ {"pcsz", ph.Pcsz},
+ }
+
+ f.Sections = make([]*Section, 5)
+
+ off := uint32(hdrSize)
+
+ for i, sect := range sects {
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: sect.name,
+ Size: sect.size,
+ Offset: off,
+ }
+ off += sect.size
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ return f, nil
+}
+
+func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
+ var order binary.ByteOrder = binary.BigEndian
+ var s sym
+ p := data
+ for len(p) >= 4 {
+ // Symbol type, value.
+ if len(p) < ptrsz {
+ return &formatError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width value
+ if ptrsz == 8 {
+ s.value = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.value = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+
+ var typ byte
+ typ = p[0] & 0x7F
+ s.typ = typ
+ p = p[1:]
+
+ // Name.
+ var i int
+ var nnul int
+ for i = 0; i < len(p); i++ {
+ if p[i] == 0 {
+ nnul = 1
+ break
+ }
+ }
+ switch typ {
+ case 'z', 'Z':
+ p = p[i+nnul:]
+ for i = 0; i+2 <= len(p); i += 2 {
+ if p[i] == 0 && p[i+1] == 0 {
+ nnul = 2
+ break
+ }
+ }
+ }
+ if len(p) < i+nnul {
+ return &formatError{len(data), "unexpected EOF", nil}
+ }
+ s.name = p[0:i]
+ i += nnul
+ p = p[i:]
+
+ fn(s)
+ }
+ return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
+ var n int
+ err := walksymtab(symtab, ptrsz, func(s sym) error {
+ n++
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ fname := make(map[uint16]string)
+ syms := make([]Sym, 0, n)
+ err = walksymtab(symtab, ptrsz, func(s sym) error {
+ n := len(syms)
+ syms = syms[0 : n+1]
+ ts := &syms[n]
+ ts.Type = rune(s.typ)
+ ts.Value = s.value
+ switch s.typ {
+ default:
+ ts.Name = string(s.name[:])
+ case 'z', 'Z':
+ for i := 0; i < len(s.name); i += 2 {
+ eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+ elt, ok := fname[eltIdx]
+ if !ok {
+ return &formatError{-1, "bad filename code", eltIdx}
+ }
+ if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+ ts.Name += "/"
+ }
+ ts.Name += elt
+ }
+ }
+ switch s.typ {
+ case 'f':
+ fname[uint16(s.value)] = ts.Name
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return syms, nil
+}
+
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Sym, error) {
+ symtabSection := f.Section("syms")
+ if symtabSection == nil {
+ return nil, errors.New("no symbol section")
+ }
+
+ symtab, err := symtabSection.Data()
+ if err != nil {
+ return nil, errors.New("cannot load symbol section")
+ }
+
+ return newTable(symtab, f.PtrSize)
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
diff --git a/src/pkg/debug/plan9obj/file_test.go b/src/pkg/debug/plan9obj/file_test.go
new file mode 100644
index 000000000..96186d815
--- /dev/null
+++ b/src/pkg/debug/plan9obj/file_test.go
@@ -0,0 +1,81 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plan9obj
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/386-plan9-exec",
+ FileHeader{Magic386, 0x324, 0x14, 4},
+ []*SectionHeader{
+ {"text", 0x4c5f, 0x20},
+ {"data", 0x94c, 0x4c7f},
+ {"syms", 0x2c2b, 0x55cb},
+ {"spsz", 0x0, 0x81f6},
+ {"pcsz", 0xf7a, 0x81f6},
+ },
+ },
+ {
+ "testdata/amd64-plan9-exec",
+ FileHeader{MagicAMD64, 0x618, 0x13, 8},
+ []*SectionHeader{
+ {"text", 0x4213, 0x28},
+ {"data", 0xa80, 0x423b},
+ {"syms", 0x2c8c, 0x4cbb},
+ {"spsz", 0x0, 0x7947},
+ {"pcsz", 0xca0, 0x7947},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a Plan 9 a.out file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/src/pkg/debug/plan9obj/plan9obj.go b/src/pkg/debug/plan9obj/plan9obj.go
new file mode 100644
index 000000000..af9858562
--- /dev/null
+++ b/src/pkg/debug/plan9obj/plan9obj.go
@@ -0,0 +1,36 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * Plan 9 a.out constants and data structures
+ */
+
+package plan9obj
+
+// Plan 9 Program header.
+type prog struct {
+ Magic uint32 /* magic number */
+ Text uint32 /* size of text segment */
+ Data uint32 /* size of initialized data */
+ Bss uint32 /* size of uninitialized data */
+ Syms uint32 /* size of symbol table */
+ Entry uint32 /* entry point */
+ Spsz uint32 /* size of pc/sp offset table */
+ Pcsz uint32 /* size of pc/line number table */
+}
+
+// Plan 9 symbol table entries.
+type sym struct {
+ value uint64
+ typ byte
+ name []byte
+}
+
+const (
+ Magic64 = 0x8000 // 64-bit expanded header
+
+ Magic386 = (4*11+0)*11 + 7
+ MagicAMD64 = (4*26+0)*26 + 7 + Magic64
+ MagicARM = (4*20+0)*20 + 7
+)
diff --git a/src/pkg/debug/plan9obj/testdata/386-plan9-exec b/src/pkg/debug/plan9obj/testdata/386-plan9-exec
new file mode 100755
index 000000000..748e83f8e
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/386-plan9-exec
Binary files differ
diff --git a/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec
new file mode 100755
index 000000000..3e257dd8f
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec
Binary files differ
diff --git a/src/pkg/debug/plan9obj/testdata/hello.c b/src/pkg/debug/plan9obj/testdata/hello.c
new file mode 100644
index 000000000..c0d633e29
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+ print("hello, world\n");
+}
diff --git a/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
index e2afc5871..60da304b5 100644
--- a/src/pkg/encoding/ascii85/ascii85.go
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -281,6 +281,18 @@ func (d *decoder) Read(p []byte) (n int, err error) {
d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
continue // copy out and return
}
+ if ndst == 0 && d.err == nil {
+ // Special case: input buffer is mostly filled with non-data bytes.
+ // Filter out such bytes to make room for more input.
+ off := 0
+ for i := 0; i < d.nbuf; i++ {
+ if d.buf[i] > ' ' {
+ d.buf[off] = d.buf[i]
+ off++
+ }
+ }
+ d.nbuf = off
+ }
}
// Out of input, out of decoded output. Check errors.
diff --git a/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
index 42cf7e80e..aad199b4f 100644
--- a/src/pkg/encoding/ascii85/ascii85_test.go
+++ b/src/pkg/encoding/ascii85/ascii85_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io"
"io/ioutil"
+ "strings"
"testing"
)
@@ -16,6 +17,11 @@ type testpair struct {
}
var pairs = []testpair{
+ // Encode returns 0 when len(src) is 0
+ {
+ "",
+ "",
+ },
// Wikipedia example
{
"Man is distinguished, not only by his reason, but by this singular passion from " +
@@ -110,7 +116,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(strings.NewReader(p.encoded))
dbuf, err := ioutil.ReadAll(decoder)
if err != nil {
t.Fatal("Read failed", err)
@@ -125,7 +131,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -191,3 +197,14 @@ func TestBig(t *testing.T) {
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}
+
+func TestDecoderInternalWhitespace(t *testing.T) {
+ s := strings.Repeat(" ", 2048) + "z"
+ decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s)))
+ if err != nil {
+ t.Errorf("Decode gave error %v", err)
+ }
+ if want := []byte("\000\000\000\000"); !bytes.Equal(want, decoded) {
+ t.Errorf("Decode failed: got %v, want %v", decoded, want)
+ }
+}
diff --git a/src/pkg/encoding/asn1/asn1.go b/src/pkg/encoding/asn1/asn1.go
index 992356c26..ec7f91c1b 100644
--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -23,6 +23,7 @@ import (
"fmt"
"math/big"
"reflect"
+ "strconv"
"time"
)
@@ -197,6 +198,19 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
return true
}
+func (oi ObjectIdentifier) String() string {
+ var s string
+
+ for i, v := range oi {
+ if i > 0 {
+ s += "."
+ }
+ s += strconv.Itoa(v)
+ }
+
+ return s
+}
+
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
// returns it. An object identifier is a sequence of variable length integers
// that are assigned in a hierarchy.
@@ -451,11 +465,17 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
if err != nil {
return
}
- // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
- // that a sequence of them can be parsed into a []string.
- if t.tag == tagGeneralString {
+ switch t.tag {
+ case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ // We pretend that various other string types are
+ // PRINTABLE STRINGs so that a sequence of them can be
+ // parsed into a []string.
t.tag = tagPrintableString
+ case tagGeneralizedTime, tagUTCTime:
+ // Likewise, both time types are treated the same.
+ t.tag = tagUTCTime
}
+
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
err = StructuralError{"sequence tag mismatch"}
return
@@ -632,6 +652,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
universalTag = tagGeneralizedTime
}
+ if params.set {
+ universalTag = tagSet
+ }
+
expectedClass := classUniversal
expectedTag := universalTag
@@ -852,13 +876,20 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
//
// The following tags on struct fields have special meaning to Unmarshal:
//
-// optional marks the field as ASN.1 OPTIONAL
-// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
-// default:x sets the default value for optional integer fields
+// application specifies that a APPLICATION tag is used
+// default:x sets the default value for optional integer fields
+// explicit specifies that an additional, explicit tag wraps the implicit one
+// optional marks the field as ASN.1 OPTIONAL
+// set causes a SET, rather than a SEQUENCE type to be expected
+// tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
//
// If the type of the first field of a structure is RawContent then the raw
// ASN1 contents of the struct will be stored in it.
//
+// If the type name of a slice element ends with "SET" then it's treated as if
+// the "set" tag was set on it. This can be used with nested slices where a
+// struct tag cannot be given.
+//
// Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error.
func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
diff --git a/src/pkg/encoding/asn1/asn1_test.go b/src/pkg/encoding/asn1/asn1_test.go
index f68804ebf..b553f78e0 100644
--- a/src/pkg/encoding/asn1/asn1_test.go
+++ b/src/pkg/encoding/asn1/asn1_test.go
@@ -6,6 +6,7 @@ package asn1
import (
"bytes"
+ "fmt"
"math/big"
"reflect"
"testing"
@@ -171,6 +172,12 @@ func TestBitStringAt(t *testing.T) {
if bs.At(9) != 1 {
t.Error("#4: Failed")
}
+ if bs.At(-1) != 0 {
+ t.Error("#5: Failed")
+ }
+ if bs.At(17) != 0 {
+ t.Error("#6: Failed")
+ }
}
type bitStringRightAlignTest struct {
@@ -225,6 +232,10 @@ func TestObjectIdentifier(t *testing.T) {
}
}
}
+
+ if s := ObjectIdentifier([]int{1, 2, 3, 4}).String(); s != "1.2.3.4" {
+ t.Errorf("bad ObjectIdentifier.String(). Got %s, want 1.2.3.4", s)
+ }
}
type timeTest struct {
@@ -238,6 +249,7 @@ var utcTestData = []timeTest{
{"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
{"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
{"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
+ {"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC)},
{"a10506234540Z", false, time.Time{}},
{"91a506234540Z", false, time.Time{}},
{"9105a6234540Z", false, time.Time{}},
@@ -389,6 +401,10 @@ type TestBigInt struct {
X *big.Int
}
+type TestSet struct {
+ Ints []int `asn1:"set"`
+}
+
var unmarshalTestData = []struct {
in []byte
out interface{}
@@ -408,6 +424,7 @@ var unmarshalTestData = []struct {
{[]byte{0x01, 0x01, 0xff}, newBool(true)},
{[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
{[]byte{0x30, 0x05, 0x02, 0x03, 0x12, 0x34, 0x56}, &TestBigInt{big.NewInt(0x123456)}},
+ {[]byte{0x30, 0x0b, 0x31, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &TestSet{Ints: []int{1, 2, 3}}},
}
func TestUnmarshal(t *testing.T) {
@@ -509,6 +526,38 @@ func TestRawStructs(t *testing.T) {
}
}
+type oiEqualTest struct {
+ first ObjectIdentifier
+ second ObjectIdentifier
+ same bool
+}
+
+var oiEqualTests = []oiEqualTest{
+ {
+ ObjectIdentifier{1, 2, 3},
+ ObjectIdentifier{1, 2, 3},
+ true,
+ },
+ {
+ ObjectIdentifier{1},
+ ObjectIdentifier{1, 2, 3},
+ false,
+ },
+ {
+ ObjectIdentifier{1, 2, 3},
+ ObjectIdentifier{10, 11, 12},
+ false,
+ },
+}
+
+func TestObjectIdentifierEqual(t *testing.T) {
+ for _, o := range oiEqualTests {
+ if s := o.first.Equal(o.second); s != o.same {
+ t.Errorf("ObjectIdentifier.Equal: got: %t want: %t", s, o.same)
+ }
+ }
+}
+
var derEncodedSelfSignedCert = Certificate{
TBSCertificate: TBSCertificate{
Version: 0,
@@ -737,3 +786,29 @@ var derEncodedPaypalNULCertBytes = []byte{
0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
0x96, 0x07, 0xa8, 0xbb,
}
+
+var stringSliceTestData = [][]string{
+ {"foo", "bar"},
+ {"foo", "\\bar"},
+ {"foo", "\"bar\""},
+ {"foo", "åäö"},
+}
+
+func TestStringSlice(t *testing.T) {
+ for _, test := range stringSliceTestData {
+ bs, err := Marshal(test)
+ if err != nil {
+ t.Error(err)
+ }
+
+ var res []string
+ _, err = Unmarshal(bs, &res)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if fmt.Sprintf("%v", res) != fmt.Sprintf("%v", test) {
+ t.Errorf("incorrect marshal/unmarshal; %v != %v", res, test)
+ }
+ }
+}
diff --git a/src/pkg/encoding/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index ed17e41a5..e26fe59b3 100644
--- a/src/pkg/encoding/asn1/marshal.go
+++ b/src/pkg/encoding/asn1/marshal.go
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
return out.WriteByte(byte('0' + v%10))
}
+func marshalFourDigits(out *forkableWriter, v int) (err error) {
+ var bytes [4]byte
+ for i := range bytes {
+ bytes[3-i] = '0' + byte(v%10)
+ v /= 10
+ }
+ _, err = out.Write(bytes[:])
+ return
+}
+
+func outsideUTCRange(t time.Time) bool {
+ year := t.Year()
+ return year < 1950 || year >= 2050
+}
+
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
- year, month, day := t.Date()
+ year := t.Year()
switch {
case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
return
}
+ return marshalTimeCommon(out, t)
+}
+
+func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+ year := t.Year()
+ if year < 0 || year > 9999 {
+ return StructuralError{"cannot represent time as GeneralizedTime"}
+ }
+ if err = marshalFourDigits(out, year); err != nil {
+ return
+ }
+
+ return marshalTimeCommon(out, t)
+}
+
+func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+ _, month, day := t.Date()
+
err = marshalTwoDigits(out, int(month))
if err != nil {
return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() {
case timeType:
- return marshalUTCTime(out, value.Interface().(time.Time))
+ t := value.Interface().(time.Time)
+ if outsideUTCRange(t) {
+ return marshalGeneralizedTime(out, t)
+ } else {
+ return marshalUTCTime(out, t)
+ }
case bitStringType:
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
@@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return StructuralError{"explicit string type given to non-string member"}
}
- if tag == tagPrintableString {
+ switch tag {
+ case tagPrintableString:
if params.stringType == 0 {
// This is a string without an explicit string type. We'll use
// a PrintableString if the character set in the string is
@@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
} else {
tag = params.stringType
}
+ case tagUTCTime:
+ if outsideUTCRange(v.Interface().(time.Time)) {
+ tag = tagGeneralizedTime
+ }
}
if params.set {
@@ -568,6 +611,14 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
}
// Marshal returns the ASN.1 encoding of val.
+//
+// In addition to the struct tags recognised by Unmarshal, the following can be
+// used:
+//
+// ia5: causes strings to be marshaled as ASN.1, IA5 strings
+// omitempty: causes empty slices to be skipped
+// printable: causes strings to be marshaled as ASN.1, PrintableString strings.
+// utf8: causes strings to be marshaled as ASN.1, UTF8 strings
func Marshal(val interface{}) ([]byte, error) {
var out bytes.Buffer
v := reflect.ValueOf(val)
diff --git a/src/pkg/encoding/asn1/marshal_test.go b/src/pkg/encoding/asn1/marshal_test.go
index 763c86da2..a15acbed0 100644
--- a/src/pkg/encoding/asn1/marshal_test.go
+++ b/src/pkg/encoding/asn1/marshal_test.go
@@ -67,6 +67,14 @@ type marshalTest struct {
out string // hex encoded
}
+func farFuture() time.Time {
+ t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
var marshalTests = []marshalTest{
{10, "02010a"},
{127, "02017f"},
@@ -83,6 +91,7 @@ var marshalTests = []marshalTest{
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
+ {farFuture(), "180f32313030303430353132303130315a"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
index fe17b7322..d770de391 100644
--- a/src/pkg/encoding/base32/base32.go
+++ b/src/pkg/encoding/base32/base32.go
@@ -179,13 +179,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 8 * 5
if nn > len(p) {
nn = len(p)
+ nn -= nn % 5
}
- nn -= nn % 5
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -268,7 +266,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
// the five valid padding lengths, and Section 9 "Illustrations and
- // Examples" for an illustration for how the the 1st, 3rd and 6th base32
+ // Examples" for an illustration for how the 1st, 3rd and 6th base32
// src bytes do not yield enough information to decode a dst byte.
if dlen == 1 || dlen == 3 || dlen == 6 {
return n, false, CorruptInputError(olen - len(src) - 1)
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 63298d1c9..f56b996fa 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -108,7 +108,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
if err != nil && err != io.EOF {
@@ -125,7 +125,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -267,13 +267,13 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
====`
encodedShort := strings.Replace(encoded, "\n", "", -1)
- dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
- dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
index 85e398fd0..e38c26d0e 100644
--- a/src/pkg/encoding/base64/base64.go
+++ b/src/pkg/encoding/base64/base64.go
@@ -159,13 +159,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 4 * 3
if nn > len(p) {
nn = len(p)
+ nn -= nn % 3
}
- nn -= nn % 3
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -226,21 +224,33 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
var dbuf [4]byte
dlen := 4
- for j := 0; j < 4; {
+ for j := range dbuf {
if len(src) == 0 {
return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '=' && j >= 2 && len(src) < 4 {
+ if in == '=' {
// We've reached the end and there's padding
- if len(src)+j < 4-1 {
- // not enough padding
- return n, false, CorruptInputError(olen)
- }
- if len(src) > 0 && src[0] != '=' {
+ switch j {
+ case 0, 1:
// incorrect padding
return n, false, CorruptInputError(olen - len(src) - 1)
+ case 2:
+ // "==" is expected, the first "=" is already consumed.
+ if len(src) == 0 {
+ // not enough padding
+ return n, false, CorruptInputError(olen)
+ }
+ if src[0] != '=' {
+ // incorrect padding
+ return n, false, CorruptInputError(olen - len(src) - 1)
+ }
+ src = src[1:]
+ }
+ if len(src) > 0 {
+ // trailing garbage
+ err = CorruptInputError(olen - len(src))
}
dlen, end = j, true
break
@@ -249,7 +259,6 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(olen - len(src) - 1)
}
- j++
}
// Pack 4x 6-bit source blocks into 3 byte destination
@@ -268,7 +277,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
n += dlen - 1
}
- return n, end, nil
+ return n, end, err
}
// Decode decodes src using the encoding enc. It writes at most
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index 579591a88..a075194e0 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "reflect"
"strings"
"testing"
"time"
@@ -113,7 +114,7 @@ func TestDecode(t *testing.T) {
func TestDecoder(t *testing.T) {
for _, p := range pairs {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
if err != nil && err != io.EOF {
@@ -130,7 +131,7 @@ func TestDecoder(t *testing.T) {
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
buf := make([]byte, len(bigtest.decoded)+12)
var total int
for total = 0; total < len(bigtest.decoded); {
@@ -149,9 +150,13 @@ func TestDecodeCorrupt(t *testing.T) {
}{
{"", -1},
{"!!!!", 0},
+ {"====", 0},
{"x===", 1},
+ {"=AAA", 0},
+ {"A=AA", 1},
{"AA=A", 2},
- {"AAA=AAAA", 3},
+ {"AA==A", 4},
+ {"AAA=AAAA", 4},
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
@@ -161,6 +166,7 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAA=", -1},
{"AAAA", -1},
{"AAAAAA=", 7},
+ {"YWJjZA=====", 8},
}
for _, tc := range testCases {
dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
@@ -308,13 +314,13 @@ bqbPb06551Y4
`
encodedShort := strings.Replace(encoded, "\n", "", -1)
- dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
res1, err := ioutil.ReadAll(dec)
if err != nil {
t.Errorf("ReadAll failed: %v", err)
}
- dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
var res2 []byte
res2, err = ioutil.ReadAll(dec)
if err != nil {
@@ -325,3 +331,14 @@ bqbPb06551Y4
t.Error("Decoded results not equal")
}
}
+
+func TestDecoderIssue7733(t *testing.T) {
+ s, err := StdEncoding.DecodeString("YWJjZA=====")
+ want := CorruptInputError(8)
+ if !reflect.DeepEqual(want, err) {
+ t.Errorf("Error = %v; want CorruptInputError(8)", err)
+ }
+ if string(s) != "abcd" {
+ t.Errorf("DecodeString = %q; want abcd", s)
+ }
+}
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index f3466b9af..a5694876a 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -133,6 +133,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index fdfee7d87..c80c90383 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -111,7 +111,7 @@ func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, wan
func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
var s2 Struct
- err := Read(bytes.NewBuffer(b), order, &s2)
+ err := Read(bytes.NewReader(b), order, &s2)
checkResult(t, "Read", order, err, s2, s1)
}
@@ -131,7 +131,7 @@ func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
func TestReadSlice(t *testing.T) {
slice := make([]int32, 2)
- err := Read(bytes.NewBuffer(src), BigEndian, slice)
+ err := Read(bytes.NewReader(src), BigEndian, slice)
checkResult(t, "ReadSlice", BigEndian, err, slice, res)
}
@@ -265,6 +265,30 @@ func TestBlankFields(t *testing.T) {
}
}
+// An attempt to read into a struct with an unexported field will
+// panic. This is probably not the best choice, but at this point
+// anything else would be an API change.
+
+type Unexported struct {
+ a int32
+}
+
+func TestUnexportedRead(t *testing.T) {
+ var buf bytes.Buffer
+ u1 := Unexported{a: 1}
+ if err := Write(&buf, LittleEndian, &u1); err != nil {
+ t.Fatal(err)
+ }
+
+ defer func() {
+ if recover() == nil {
+ t.Fatal("did not panic")
+ }
+ }()
+ var u2 Unexported
+ Read(&buf, LittleEndian, &u2)
+}
+
type byteSliceReader struct {
remain []byte
}
diff --git a/src/pkg/encoding/binary/varint_test.go b/src/pkg/encoding/binary/varint_test.go
index 9476bd5fb..ca411ecbd 100644
--- a/src/pkg/encoding/binary/varint_test.go
+++ b/src/pkg/encoding/binary/varint_test.go
@@ -35,7 +35,7 @@ func testVarint(t *testing.T, x int64) {
t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
}
- y, err := ReadVarint(bytes.NewBuffer(buf))
+ y, err := ReadVarint(bytes.NewReader(buf))
if err != nil {
t.Errorf("ReadVarint(%d): %s", x, err)
}
@@ -55,7 +55,7 @@ func testUvarint(t *testing.T, x uint64) {
t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
}
- y, err := ReadUvarint(bytes.NewBuffer(buf))
+ y, err := ReadUvarint(bytes.NewReader(buf))
if err != nil {
t.Errorf("ReadUvarint(%d): %s", x, err)
}
@@ -114,7 +114,7 @@ func TestBufferTooSmall(t *testing.T) {
t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
}
- x, err := ReadUvarint(bytes.NewBuffer(buf))
+ x, err := ReadUvarint(bytes.NewReader(buf))
if x != 0 || err != io.EOF {
t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
}
@@ -127,7 +127,7 @@ func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) {
t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
}
- x, err := ReadUvarint(bytes.NewBuffer(buf))
+ x, err := ReadUvarint(bytes.NewReader(buf))
if x != 0 || err != err0 {
t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
}
diff --git a/src/pkg/encoding/csv/reader.go b/src/pkg/encoding/csv/reader.go
index b328dcc37..d9432954a 100644
--- a/src/pkg/encoding/csv/reader.go
+++ b/src/pkg/encoding/csv/reader.go
@@ -193,12 +193,6 @@ func (r *Reader) readRune() (rune, error) {
return r1, err
}
-// unreadRune puts the last rune read from r back.
-func (r *Reader) unreadRune() {
- r.r.UnreadRune()
- r.column--
-}
-
// skip reads runes up to and including the rune delim or until error.
func (r *Reader) skip(delim rune) error {
for {
diff --git a/src/pkg/encoding/csv/writer_test.go b/src/pkg/encoding/csv/writer_test.go
index 03ca6b093..22b740c07 100644
--- a/src/pkg/encoding/csv/writer_test.go
+++ b/src/pkg/encoding/csv/writer_test.go
@@ -26,6 +26,8 @@ var writeTests = []struct {
{Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+ {Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true},
+ {Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false},
}
func TestWrite(t *testing.T) {
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index b40f78360..fa57f3761 100644
--- a/src/pkg/encoding/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -1364,11 +1364,7 @@ type DT struct {
S []string
}
-func TestDebugStruct(t *testing.T) {
- if debugFunc == nil {
- return
- }
- Register(OnTheFly{})
+func newDT() DT {
var dt DT
dt.A = 17
dt.B = "hello"
@@ -1379,6 +1375,15 @@ func TestDebugStruct(t *testing.T) {
dt.M = map[string]int{"one": 1, "two": 2}
dt.T = [3]int{11, 22, 33}
dt.S = []string{"hi", "joe"}
+ return dt
+}
+
+func TestDebugStruct(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ Register(OnTheFly{})
+ dt := newDT()
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(dt)
if err != nil {
@@ -1458,3 +1463,44 @@ func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
}
}
}
+
+// TestFuzzOneByte tries to decode corrupted input sequences
+// and checks that no panic occurs.
+func TestFuzzOneByte(t *testing.T) {
+ buf := new(bytes.Buffer)
+ Register(OnTheFly{})
+ dt := newDT()
+ if err := NewEncoder(buf).Encode(dt); err != nil {
+ t.Fatal(err)
+ }
+ s := buf.String()
+
+ indices := make([]int, 0, len(s))
+ for i := 0; i < len(s); i++ {
+ switch i {
+ case 14, 167, 231, 265: // a slice length, corruptions are not handled yet.
+ continue
+ }
+ indices = append(indices, i)
+ }
+ if testing.Short() {
+ indices = []int{1, 111, 178} // known fixed panics
+ }
+ for _, i := range indices {
+ for j := 0; j < 256; j += 3 {
+ b := []byte(s)
+ b[i] ^= byte(j)
+ var e DT
+ func() {
+ defer func() {
+ if p := recover(); p != nil {
+ t.Errorf("crash for b[%d] ^= 0x%x", i, j)
+ panic(p)
+ }
+ }()
+ err := NewDecoder(bytes.NewReader(b)).Decode(&e)
+ _ = err
+ }()
+ }
+ }
+}
diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index 3e76f4c90..d8513148e 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -654,21 +654,20 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores the slice header through p.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
nr := state.decodeUint()
n := int(nr)
if indir > 0 {
- up := unsafe.Pointer(p)
- if *(*unsafe.Pointer)(up) == nil {
+ if *(*unsafe.Pointer)(p) == nil {
// Allocate the slice header.
- *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]unsafe.Pointer))
}
- p = *(*uintptr)(up)
+ p = *(*unsafe.Pointer)(p)
}
// Allocate storage for the slice elements, that is, the underlying array,
// if the existing slice does not have the capacity.
// Always write a header at p.
- hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
+ hdrp := (*reflect.SliceHeader)(p)
if hdrp.Cap < n {
hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
hdrp.Cap = n
@@ -686,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
// but first it checks that the assignment will succeed.
func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
if !value.Type().AssignableTo(ivalue.Type()) {
- errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+ errorf("%s is not assignable to type %s", value.Type(), ivalue.Type())
}
ivalue.Set(value)
}
@@ -702,6 +701,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
errorf("invalid type name length %d", nr)
}
+ if nr > uint64(state.b.Len()) {
+ errorf("invalid type name length %d: exceeds input size", nr)
+ }
b := make([]byte, nr)
state.b.Read(b)
name := string(b)
@@ -887,7 +889,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
- state.dec.decodeSlice(t, state, uintptr(p), *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ state.dec.decodeSlice(t, state, p, *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
}
case reflect.Struct:
@@ -1238,7 +1240,8 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
}
engine := *enginePtr
if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
- if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
+ if engine.numInstr == 0 && st.NumField() > 0 &&
+ dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 {
name := base.Name()
errorf("type mismatch: no fields matched compiling decoder for %s", name)
}
diff --git a/src/pkg/encoding/gob/decoder.go b/src/pkg/encoding/gob/decoder.go
index 04f706ca5..3a769ec12 100644
--- a/src/pkg/encoding/gob/decoder.go
+++ b/src/pkg/encoding/gob/decoder.go
@@ -183,11 +183,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
return -1
}
-// Decode reads the next value from the connection and stores
+// Decode reads the next value from the input stream and stores
// it in the data represented by the empty interface value.
// If e is nil, the value will be discarded. Otherwise,
// the value underlying e must be a pointer to the
// correct type for the next data item received.
+// If the input is at EOF, Decode returns io.EOF and
+// does not modify e.
func (dec *Decoder) Decode(e interface{}) error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
@@ -202,10 +204,12 @@ func (dec *Decoder) Decode(e interface{}) error {
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection.
+// DecodeValue reads the next value from the input stream.
// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
// Otherwise, it stores the value into v. In that case, v must represent
// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+// If the input is at EOF, DecodeValue returns io.EOF and
+// does not modify e.
func (dec *Decoder) DecodeValue(v reflect.Value) error {
if v.IsValid() {
if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/src/pkg/encoding/gob/encode.go b/src/pkg/encoding/gob/encode.go
index d158b6442..7831c02d1 100644
--- a/src/pkg/encoding/gob/encode.go
+++ b/src/pkg/encoding/gob/encode.go
@@ -491,7 +491,7 @@ func isZero(val reflect.Value) bool {
return !val.Bool()
case reflect.Complex64, reflect.Complex128:
return val.Complex() == 0
- case reflect.Chan, reflect.Func, reflect.Ptr:
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
return val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int() == 0
diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go
index 4ecf51d12..6445ce100 100644
--- a/src/pkg/encoding/gob/encoder_test.go
+++ b/src/pkg/encoding/gob/encoder_test.go
@@ -129,6 +129,8 @@ func TestBadData(t *testing.T) {
corruptDataCheck("", io.EOF, t)
corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
corruptDataCheck("\x03now is the time for all good men", errBadType, t)
+ // issue 6323.
+ corruptDataCheck("\x04\x24foo", errRange, t)
}
// Types not supported at top level by the Encoder.
@@ -630,7 +632,7 @@ func TestSliceReusesMemory(t *testing.T) {
// Used to crash: negative count in recvMessage.
func TestBadCount(t *testing.T) {
b := []byte{0xfb, 0xa5, 0x82, 0x2f, 0xca, 0x1}
- if err := NewDecoder(bytes.NewBuffer(b)).Decode(nil); err == nil {
+ if err := NewDecoder(bytes.NewReader(b)).Decode(nil); err == nil {
t.Error("expected error from bad count")
} else if err.Error() != errBadCount.Error() {
t.Error("expected bad count error; got", err)
diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go
index 0193e2b67..157b7723a 100644
--- a/src/pkg/encoding/gob/gobencdec_test.go
+++ b/src/pkg/encoding/gob/gobencdec_test.go
@@ -705,13 +705,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
}
// Another bug: this caused a crash with the new Go1 Time type.
-// We throw in a gob-encoding array, to test another case of isZero
-
+// We throw in a gob-encoding array, to test another case of isZero,
+// and a struct containing an nil interface, to test a third.
type isZeroBug struct {
T time.Time
S string
I int
A isZeroBugArray
+ F isZeroBugInterface
}
type isZeroBugArray [2]uint8
@@ -731,8 +732,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error {
return nil
}
+type isZeroBugInterface struct {
+ I interface{}
+}
+
+func (i isZeroBugInterface) GobEncode() (b []byte, e error) {
+ return []byte{}, nil
+}
+
+func (i *isZeroBugInterface) GobDecode(data []byte) error {
+ return nil
+}
+
func TestGobEncodeIsZero(t *testing.T) {
- x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+ x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(x)
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index 167d00e03..d1fc7024a 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/encoding/hex/hex.go
@@ -146,6 +146,9 @@ func (h *dumper) Write(data []byte) (n int, err error) {
h.buf[12] = ' '
h.buf[13] = ' '
_, err = h.w.Write(h.buf[4:])
+ if err != nil {
+ return
+ }
}
Encode(h.buf[:], data[i:i+1])
h.buf[2] = ' '
diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
index 356f590f0..b969636cd 100644
--- a/src/pkg/encoding/hex/hex_test.go
+++ b/src/pkg/encoding/hex/hex_test.go
@@ -38,7 +38,10 @@ func TestEncode(t *testing.T) {
}
func TestDecode(t *testing.T) {
- for i, test := range encDecTests {
+ // Case for decoding uppercase hex characters, since
+ // Encode always uses lowercase.
+ decTests := append(encDecTests, encDecTest{"F8F9FAFBFCFDFEFF", []byte{0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}})
+ for i, test := range decTests {
dst := make([]byte, DecodedLen(len(test.enc)))
n, err := Decode(dst, []byte(test.enc))
if err != nil {
@@ -79,6 +82,7 @@ type errTest struct {
var errTests = []errTest{
{"0", "encoding/hex: odd length hex string"},
{"0g", "encoding/hex: invalid byte: U+0067 'g'"},
+ {"00gg", "encoding/hex: invalid byte: U+0067 'g'"},
{"0\x01", "encoding/hex: invalid byte: U+0001"},
}
diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go
index 458fb39ec..af1c908ad 100644
--- a/src/pkg/encoding/json/decode.go
+++ b/src/pkg/encoding/json/decode.go
@@ -8,6 +8,7 @@
package json
import (
+ "bytes"
"encoding"
"encoding/base64"
"errors"
@@ -15,7 +16,6 @@ import (
"reflect"
"runtime"
"strconv"
- "strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
@@ -54,6 +54,11 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
+// The JSON null value unmarshals into an interface, map, pointer, or slice
+// by setting that Go value to nil. Because null is often used in JSON to mean
+// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+// on the value and produces no error.
+//
// When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement
@@ -500,11 +505,11 @@ func (d *decodeState) object(v reflect.Value) {
d.error(errPhase)
}
- // Read string key.
+ // Read key.
start := d.off - 1
op = d.scanWhile(scanContinue)
item := d.data[start : d.off-1]
- key, ok := unquote(item)
+ key, ok := unquoteBytes(item)
if !ok {
d.error(errPhase)
}
@@ -526,11 +531,11 @@ func (d *decodeState) object(v reflect.Value) {
fields := cachedTypeFields(v.Type())
for i := range fields {
ff := &fields[i]
- if ff.name == key {
+ if bytes.Equal(ff.nameBytes, key) {
f = ff
break
}
- if f == nil && strings.EqualFold(ff.name, key) {
+ if f == nil && ff.equalFold(ff.nameBytes, key) {
f = ff
}
}
@@ -561,6 +566,7 @@ func (d *decodeState) object(v reflect.Value) {
if destring {
d.value(reflect.ValueOf(&d.tempstr))
d.literalStore([]byte(d.tempstr), subv, true)
+ d.tempstr = "" // Zero scratch space for successive values.
} else {
d.value(subv)
}
diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index 22c5f89f7..238a87fd6 100644
--- a/src/pkg/encoding/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -1060,6 +1060,21 @@ func TestEmptyString(t *testing.T) {
}
}
+// Test that the returned error is non-nil when trying to unmarshal null string into int, for successive ,string option
+// Issue 7046
+func TestNullString(t *testing.T) {
+ type T struct {
+ A int `json:",string"`
+ B int `json:",string"`
+ }
+ data := []byte(`{"A": "1", "B": null}`)
+ var s T
+ err := Unmarshal(data, &s)
+ if err == nil {
+ t.Fatalf("expected error; got %v", s)
+ }
+}
+
func intp(x int) *int {
p := new(int)
*p = x
@@ -1110,8 +1125,8 @@ func TestInterfaceSet(t *testing.T) {
// Issue 2540
func TestUnmarshalNulls(t *testing.T) {
jsonData := []byte(`{
- "Bool" : null,
- "Int" : null,
+ "Bool" : null,
+ "Int" : null,
"Int8" : null,
"Int16" : null,
"Int32" : null,
@@ -1316,3 +1331,26 @@ func TestPrefilled(t *testing.T) {
}
}
}
+
+var invalidUnmarshalTests = []struct {
+ v interface{}
+ want string
+}{
+ {nil, "json: Unmarshal(nil)"},
+ {struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+ {(*int)(nil), "json: Unmarshal(nil *int)"},
+}
+
+func TestInvalidUnmarshal(t *testing.T) {
+ buf := []byte(`{"a":"1"}`)
+ for _, tt := range invalidUnmarshalTests {
+ err := Unmarshal(buf, tt.v)
+ if err == nil {
+ t.Errorf("Unmarshal expecting error, got nil")
+ continue
+ }
+ if got := err.Error(); got != tt.want {
+ t.Errorf("Unmarshal = %q; want %q", got, tt.want)
+ }
+ }
+}
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index 7d6c71d7a..741ddd89c 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -44,6 +44,7 @@ import (
// if an invalid UTF-8 sequence is encountered.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
+// Ampersand "&" is also escaped to "\u0026" for the same reason.
//
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string, and a nil slice
@@ -241,24 +242,15 @@ type encodeState struct {
scratch [64]byte
}
-// TODO(bradfitz): use a sync.Cache here
-var encodeStatePool = make(chan *encodeState, 8)
+var encodeStatePool sync.Pool
func newEncodeState() *encodeState {
- select {
- case e := <-encodeStatePool:
+ if v := encodeStatePool.Get(); v != nil {
+ e := v.(*encodeState)
e.Reset()
return e
- default:
- return new(encodeState)
- }
-}
-
-func putEncodeState(e *encodeState) {
- select {
- case encodeStatePool <- e:
- default:
}
+ return new(encodeState)
}
func (e *encodeState) marshal(v interface{}) (err error) {
@@ -813,7 +805,7 @@ func (e *encodeState) string(s string) (int, error) {
e.WriteByte('r')
default:
// This encodes bytes < 0x20 except for \n and \r,
- // as well as < and >. The latter are escaped because they
+ // as well as <, > and &. The latter are escaped because they
// can lead to security holes when user-controlled strings
// are rendered into JSON and served to some browsers.
e.WriteString(`\u00`)
@@ -936,6 +928,9 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
// A field represents a single field found in a struct.
type field struct {
name string
+ nameBytes []byte // []byte(name)
+ equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
+
tag bool
index []int
typ reflect.Type
@@ -943,6 +938,12 @@ type field struct {
quoted bool
}
+func fillField(f field) field {
+ f.nameBytes = []byte(f.name)
+ f.equalFold = foldFunc(f.nameBytes)
+ return f
+}
+
// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from json tag", then
// breaking ties with index sequence.
@@ -1042,8 +1043,14 @@ func typeFields(t reflect.Type) []field {
if name == "" {
name = sf.Name
}
- fields = append(fields, field{name, tagged, index, ft,
- opts.Contains("omitempty"), opts.Contains("string")})
+ fields = append(fields, fillField(field{
+ name: name,
+ tag: tagged,
+ index: index,
+ typ: ft,
+ omitEmpty: opts.Contains("omitempty"),
+ quoted: opts.Contains("string"),
+ }))
if count[f.typ] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
@@ -1057,7 +1064,7 @@ func typeFields(t reflect.Type) []field {
// Record new anonymous struct to explore in next round.
nextCount[ft]++
if nextCount[ft] == 1 {
- next = append(next, field{name: ft.Name(), index: index, typ: ft})
+ next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
}
}
}
diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
index 9395db7cb..2e89a78eb 100644
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/encoding/json/encode_test.go
@@ -25,13 +25,30 @@ type Optionals struct {
Mr map[string]interface{} `json:"mr"`
Mo map[string]interface{} `json:",omitempty"`
+
+ Fr float64 `json:"fr"`
+ Fo float64 `json:"fo,omitempty"`
+
+ Br bool `json:"br"`
+ Bo bool `json:"bo,omitempty"`
+
+ Ur uint `json:"ur"`
+ Uo uint `json:"uo,omitempty"`
+
+ Str struct{} `json:"str"`
+ Sto struct{} `json:"sto,omitempty"`
}
var optionalsExpected = `{
"sr": "",
"omitempty": 0,
"slr": null,
- "mr": {}
+ "mr": {},
+ "fr": 0,
+ "br": false,
+ "ur": 0,
+ "str": {},
+ "sto": {}
}`
func TestOmitEmpty(t *testing.T) {
@@ -76,7 +93,7 @@ func TestStringTag(t *testing.T) {
// Verify that it round-trips.
var s2 StringTag
- err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
+ err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
@@ -425,3 +442,13 @@ func TestIssue6458(t *testing.T) {
t.Errorf("Marshal(x) = %#q; want %#q", b, want)
}
}
+
+func TestHTMLEscape(t *testing.T) {
+ var b, want bytes.Buffer
+ m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
+ want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
+ HTMLEscape(&b, []byte(m))
+ if !bytes.Equal(b.Bytes(), want.Bytes()) {
+ t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
+ }
+}
diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go
index ea0bc149c..ca4e5ae68 100644
--- a/src/pkg/encoding/json/example_test.go
+++ b/src/pkg/encoding/json/example_test.go
@@ -5,6 +5,7 @@
package json_test
import (
+ "bytes"
"encoding/json"
"fmt"
"io"
@@ -127,3 +128,34 @@ func ExampleRawMessage() {
// YCbCr &{255 0 -10}
// RGB &{98 218 255}
}
+
+func ExampleIndent() {
+ type Road struct {
+ Name string
+ Number int
+ }
+ roads := []Road{
+ {"Diamond Fork", 29},
+ {"Sheep Creek", 51},
+ }
+
+ b, err := json.Marshal(roads)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var out bytes.Buffer
+ json.Indent(&out, b, "=", "\t")
+ out.WriteTo(os.Stdout)
+ // Output:
+ // [
+ // = {
+ // = "Name": "Diamond Fork",
+ // = "Number": 29
+ // = },
+ // = {
+ // = "Name": "Sheep Creek",
+ // = "Number": 51
+ // = }
+ // =]
+}
diff --git a/src/pkg/encoding/json/fold.go b/src/pkg/encoding/json/fold.go
new file mode 100644
index 000000000..d6f77c93e
--- /dev/null
+++ b/src/pkg/encoding/json/fold.go
@@ -0,0 +1,143 @@
+// 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 json
+
+import (
+ "bytes"
+ "unicode/utf8"
+)
+
+const (
+ caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
+ kelvin = '\u212a'
+ smallLongEss = '\u017f'
+)
+
+// foldFunc returns one of four different case folding equivalence
+// functions, from most general (and slow) to fastest:
+//
+// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
+// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
+// 3) asciiEqualFold, no special, but includes non-letters (including _)
+// 4) simpleLetterEqualFold, no specials, no non-letters.
+//
+// The letters S and K are special because they map to 3 runes, not just 2:
+// * S maps to s and to U+017F 'ſ' Latin small letter long s
+// * k maps to K and to U+212A 'K' Kelvin sign
+// See http://play.golang.org/p/tTxjOc0OGo
+//
+// The returned function is specialized for matching against s and
+// should only be given s. It's not curried for performance reasons.
+func foldFunc(s []byte) func(s, t []byte) bool {
+ nonLetter := false
+ special := false // special letter
+ for _, b := range s {
+ if b >= utf8.RuneSelf {
+ return bytes.EqualFold
+ }
+ upper := b & caseMask
+ if upper < 'A' || upper > 'Z' {
+ nonLetter = true
+ } else if upper == 'K' || upper == 'S' {
+ // See above for why these letters are special.
+ special = true
+ }
+ }
+ if special {
+ return equalFoldRight
+ }
+ if nonLetter {
+ return asciiEqualFold
+ }
+ return simpleLetterEqualFold
+}
+
+// equalFoldRight is a specialization of bytes.EqualFold when s is
+// known to be all ASCII (including punctuation), but contains an 's',
+// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
+// See comments on foldFunc.
+func equalFoldRight(s, t []byte) bool {
+ for _, sb := range s {
+ if len(t) == 0 {
+ return false
+ }
+ tb := t[0]
+ if tb < utf8.RuneSelf {
+ if sb != tb {
+ sbUpper := sb & caseMask
+ if 'A' <= sbUpper && sbUpper <= 'Z' {
+ if sbUpper != tb&caseMask {
+ return false
+ }
+ } else {
+ return false
+ }
+ }
+ t = t[1:]
+ continue
+ }
+ // sb is ASCII and t is not. t must be either kelvin
+ // sign or long s; sb must be s, S, k, or K.
+ tr, size := utf8.DecodeRune(t)
+ switch sb {
+ case 's', 'S':
+ if tr != smallLongEss {
+ return false
+ }
+ case 'k', 'K':
+ if tr != kelvin {
+ return false
+ }
+ default:
+ return false
+ }
+ t = t[size:]
+
+ }
+ if len(t) > 0 {
+ return false
+ }
+ return true
+}
+
+// asciiEqualFold is a specialization of bytes.EqualFold for use when
+// s is all ASCII (but may contain non-letters) and contains no
+// special-folding letters.
+// See comments on foldFunc.
+func asciiEqualFold(s, t []byte) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i, sb := range s {
+ tb := t[i]
+ if sb == tb {
+ continue
+ }
+ if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
+ if sb&caseMask != tb&caseMask {
+ return false
+ }
+ } else {
+ return false
+ }
+ }
+ return true
+}
+
+// simpleLetterEqualFold is a specialization of bytes.EqualFold for
+// use when s is all ASCII letters (no underscores, etc) and also
+// doesn't contain 'k', 'K', 's', or 'S'.
+// See comments on foldFunc.
+func simpleLetterEqualFold(s, t []byte) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i, b := range s {
+ if b&caseMask != t[i]&caseMask {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/encoding/json/fold_test.go b/src/pkg/encoding/json/fold_test.go
new file mode 100644
index 000000000..9fb94646a
--- /dev/null
+++ b/src/pkg/encoding/json/fold_test.go
@@ -0,0 +1,116 @@
+// 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 json
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+ "unicode/utf8"
+)
+
+var foldTests = []struct {
+ fn func(s, t []byte) bool
+ s, t string
+ want bool
+}{
+ {equalFoldRight, "", "", true},
+ {equalFoldRight, "a", "a", true},
+ {equalFoldRight, "", "a", false},
+ {equalFoldRight, "a", "", false},
+ {equalFoldRight, "a", "A", true},
+ {equalFoldRight, "AB", "ab", true},
+ {equalFoldRight, "AB", "ac", false},
+ {equalFoldRight, "sbkKc", "ſbKKc", true},
+ {equalFoldRight, "SbKkc", "ſbKKc", true},
+ {equalFoldRight, "SbKkc", "ſbKK", false},
+ {equalFoldRight, "e", "é", false},
+ {equalFoldRight, "s", "S", true},
+
+ {simpleLetterEqualFold, "", "", true},
+ {simpleLetterEqualFold, "abc", "abc", true},
+ {simpleLetterEqualFold, "abc", "ABC", true},
+ {simpleLetterEqualFold, "abc", "ABCD", false},
+ {simpleLetterEqualFold, "abc", "xxx", false},
+
+ {asciiEqualFold, "a_B", "A_b", true},
+ {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
+}
+
+func TestFold(t *testing.T) {
+ for i, tt := range foldTests {
+ if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
+ t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
+ }
+ truth := strings.EqualFold(tt.s, tt.t)
+ if truth != tt.want {
+ t.Errorf("strings.EqualFold doesn't agree with case %d", i)
+ }
+ }
+}
+
+func TestFoldAgainstUnicode(t *testing.T) {
+ const bufSize = 5
+ buf1 := make([]byte, 0, bufSize)
+ buf2 := make([]byte, 0, bufSize)
+ var runes []rune
+ for i := 0x20; i <= 0x7f; i++ {
+ runes = append(runes, rune(i))
+ }
+ runes = append(runes, kelvin, smallLongEss)
+
+ funcs := []struct {
+ name string
+ fold func(s, t []byte) bool
+ letter bool // must be ASCII letter
+ simple bool // must be simple ASCII letter (not 'S' or 'K')
+ }{
+ {
+ name: "equalFoldRight",
+ fold: equalFoldRight,
+ },
+ {
+ name: "asciiEqualFold",
+ fold: asciiEqualFold,
+ simple: true,
+ },
+ {
+ name: "simpleLetterEqualFold",
+ fold: simpleLetterEqualFold,
+ simple: true,
+ letter: true,
+ },
+ }
+
+ for _, ff := range funcs {
+ for _, r := range runes {
+ if r >= utf8.RuneSelf {
+ continue
+ }
+ if ff.letter && !isASCIILetter(byte(r)) {
+ continue
+ }
+ if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
+ continue
+ }
+ for _, r2 := range runes {
+ buf1 := append(buf1[:0], 'x')
+ buf2 := append(buf2[:0], 'x')
+ buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
+ buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
+ buf1 = append(buf1, 'x')
+ buf2 = append(buf2, 'x')
+ want := bytes.EqualFold(buf1, buf2)
+ if got := ff.fold(buf1, buf2); got != want {
+ t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
+ }
+ }
+ }
+ }
+}
+
+func isASCIILetter(b byte) bool {
+ return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
+}
diff --git a/src/pkg/encoding/json/indent.go b/src/pkg/encoding/json/indent.go
index 11ef709cc..e1bacafd6 100644
--- a/src/pkg/encoding/json/indent.go
+++ b/src/pkg/encoding/json/indent.go
@@ -69,8 +69,9 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
// Each element in a JSON object or array begins on a new,
// indented line beginning with prefix followed by one or more
// copies of indent according to the indentation nesting.
-// The data appended to dst has no trailing newline, to make it easier
-// to embed inside other formatted JSON data.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, and has no trailing newline, to make it
+// easier to embed inside other formatted JSON data.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
origLen := dst.Len()
var scan scanner
diff --git a/src/pkg/encoding/json/scanner_test.go b/src/pkg/encoding/json/scanner_test.go
index 90e45ff03..788034290 100644
--- a/src/pkg/encoding/json/scanner_test.go
+++ b/src/pkg/encoding/json/scanner_test.go
@@ -239,23 +239,16 @@ func trim(b []byte) []byte {
var jsonBig []byte
-const (
- big = 10000
- small = 100
-)
-
func initBig() {
- n := big
+ n := 10000
if testing.Short() {
- n = small
+ n = 100
}
- if len(jsonBig) != n {
- b, err := Marshal(genValue(n))
- if err != nil {
- panic(err)
- }
- jsonBig = b
+ b, err := Marshal(genValue(n))
+ if err != nil {
+ panic(err)
}
+ jsonBig = b
}
func genValue(n int) interface{} {
@@ -296,6 +289,9 @@ func genArray(n int) []interface{} {
if f > n {
f = n
}
+ if f < 1 {
+ f = 1
+ }
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
diff --git a/src/pkg/encoding/json/stream.go b/src/pkg/encoding/json/stream.go
index 1928abadb..1cb289fd8 100644
--- a/src/pkg/encoding/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -148,7 +148,8 @@ func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}
-// Encode writes the JSON encoding of v to the stream.
+// Encode writes the JSON encoding of v to the stream,
+// followed by a newline character.
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
@@ -173,7 +174,7 @@ func (enc *Encoder) Encode(v interface{}) error {
if _, err = enc.w.Write(e.Bytes()); err != nil {
enc.err = err
}
- putEncodeState(e)
+ encodeStatePool.Put(e)
return err
}
diff --git a/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go
index d9522e0b3..8c6342013 100644
--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
// EncodeToken does not call Flush, because usually it is part of a larger operation
// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
// during those), and those will call Flush when finished.
-//
// Callers that create an Encoder and then invoke EncodeToken directly, without
// using Encode or EncodeElement, need to call Flush when finished to ensure
// that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
func (enc *Encoder) EncodeToken(t Token) error {
p := &enc.p
switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
p.WriteString("-->")
return p.cachedWriteError()
case ProcInst:
- if t.Target == "xml" || !isNameString(t.Target) {
+ // First token to be encoded which is also a ProcInst with target of xml
+ // is the xml declaration. The only ProcInst where target of xml is allowed.
+ if t.Target == "xml" && p.Buffered() != 0 {
+ return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+ }
+ if !isNameString(t.Target) {
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
}
if bytes.Contains(t.Inst, endProcInst) {
diff --git a/src/pkg/encoding/xml/marshal_test.go b/src/pkg/encoding/xml/marshal_test.go
index d34118a3d..14f73a75d 100644
--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -314,6 +314,31 @@ type MarshalerStruct struct {
Foo MyMarshalerAttrTest `xml:",attr"`
}
+type InnerStruct struct {
+ XMLName Name `xml:"testns outer"`
+}
+
+type OuterStruct struct {
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedStruct struct {
+ InnerStruct
+ XMLName Name `xml:"outerns test"`
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedOrderedStruct struct {
+ XMLName Name `xml:"outerns test"`
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterOuterStruct struct {
+ OuterStruct
+}
+
func ifaceptr(x interface{}) interface{} {
return &x
}
@@ -883,6 +908,22 @@ var marshalTests = []struct {
ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
Value: &MarshalerStruct{},
},
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterStruct{IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
+ },
}
func TestMarshal(t *testing.T) {
@@ -1149,3 +1190,77 @@ func TestStructPointerMarshal(t *testing.T) {
t.Fatal(err)
}
}
+
+var encodeTokenTests = []struct {
+ tok Token
+ want string
+ ok bool
+}{
+ {StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
+ {StartElement{Name{"space", ""}, nil}, "", false},
+ {EndElement{Name{"space", ""}}, "", false},
+ {CharData("foo"), "foo", true},
+ {Comment("foo"), "<!--foo-->", true},
+ {Comment("foo-->"), "", false},
+ {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
+ {ProcInst{"", []byte("Instruction")}, "", false},
+ {ProcInst{"Target", []byte("Instruction?>")}, "", false},
+ {Directive("foo"), "<!foo>", true},
+ {Directive("foo>"), "", false},
+}
+
+func TestEncodeToken(t *testing.T) {
+ for _, tt := range encodeTokenTests {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ err := enc.EncodeToken(tt.tok)
+ switch {
+ case !tt.ok && err == nil:
+ t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
+ case tt.ok && err != nil:
+ t.Fatalf("enc.EncodeToken: %v", err)
+ case !tt.ok && err != nil:
+ // expected error, got one
+ }
+ if err := enc.Flush(); err != nil {
+ t.Fatalf("enc.EncodeToken: %v", err)
+ }
+ if got := buf.String(); got != tt.want {
+ t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+ }
+ }
+}
+
+func TestProcInstEncodeToken(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
+ }
+
+ if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
+ }
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
+ t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
+ }
+}
+
+func TestDecodeEncode(t *testing.T) {
+ var in, out bytes.Buffer
+ in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
+<?Target Instruction?>
+<root>
+</root>
+`)
+ dec := NewDecoder(&in)
+ enc := NewEncoder(&out)
+ for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
+ err = enc.EncodeToken(tok)
+ if err != nil {
+ t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
+ }
+ }
+}
diff --git a/src/pkg/encoding/xml/read.go b/src/pkg/encoding/xml/read.go
index 8890508f8..75b9f2ba1 100644
--- a/src/pkg/encoding/xml/read.go
+++ b/src/pkg/encoding/xml/read.go
@@ -112,7 +112,7 @@ import (
// to a freshly allocated value and then mapping the element to that value.
//
func Unmarshal(data []byte, v interface{}) error {
- return NewDecoder(bytes.NewBuffer(data)).Decode(v)
+ return NewDecoder(bytes.NewReader(data)).Decode(v)
}
// Decode works like xml.Unmarshal, except it reads the decoder
@@ -284,6 +284,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
}
+ // Load value from interface, but only if the result will be
+ // usefully addressable.
+ if val.Kind() == reflect.Interface && !val.IsNil() {
+ e := val.Elem()
+ if e.Kind() == reflect.Ptr && !e.IsNil() {
+ val = e
+ }
+ }
+
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
diff --git a/src/pkg/encoding/xml/read_test.go b/src/pkg/encoding/xml/read_test.go
index 1404c900f..01f55d0dd 100644
--- a/src/pkg/encoding/xml/read_test.go
+++ b/src/pkg/encoding/xml/read_test.go
@@ -685,3 +685,30 @@ func TestUnmarshaler(t *testing.T) {
t.Errorf("m=%#+v\n", m)
}
}
+
+type Pea struct {
+ Cotelydon string
+}
+
+type Pod struct {
+ Pea interface{} `xml:"Pea"`
+}
+
+// https://code.google.com/p/go/issues/detail?id=6836
+func TestUnmarshalIntoInterface(t *testing.T) {
+ pod := new(Pod)
+ pod.Pea = new(Pea)
+ xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
+ err := Unmarshal([]byte(xml), pod)
+ if err != nil {
+ t.Fatalf("failed to unmarshal %q: %v", xml, err)
+ }
+ pea, ok := pod.Pea.(*Pea)
+ if !ok {
+ t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+ }
+ have, want := pea.Cotelydon, "Green stuff"
+ if have != want {
+ t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
+ }
+}
diff --git a/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
index 83e65402c..22248d20a 100644
--- a/src/pkg/encoding/xml/typeinfo.go
+++ b/src/pkg/encoding/xml/typeinfo.go
@@ -75,6 +75,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
if err != nil {
return nil, err
}
+ if tinfo.xmlname == nil {
+ tinfo.xmlname = inner.xmlname
+ }
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
diff --git a/src/pkg/encoding/xml/xml.go b/src/pkg/encoding/xml/xml.go
index 5b9d67002..b473cb845 100644
--- a/src/pkg/encoding/xml/xml.go
+++ b/src/pkg/encoding/xml/xml.go
@@ -200,6 +200,8 @@ type Decoder struct {
}
// NewDecoder creates a new XML parser reading from r.
+// If r does not implement io.ByteReader, NewDecoder will
+// do its own buffering.
func NewDecoder(r io.Reader) *Decoder {
d := &Decoder{
ns: make(map[string]string),
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index b06599505..9b6dab487 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -29,6 +29,7 @@ import (
"net/http"
"os"
"runtime"
+ "sort"
"strconv"
"sync"
)
@@ -40,8 +41,8 @@ type Var interface {
// Int is a 64-bit integer variable that satisfies the Var interface.
type Int struct {
- i int64
mu sync.RWMutex
+ i int64
}
func (v *Int) String() string {
@@ -64,8 +65,8 @@ func (v *Int) Set(value int64) {
// Float is a 64-bit float variable that satisfies the Var interface.
type Float struct {
- f float64
mu sync.RWMutex
+ f float64
}
func (v *Float) String() string {
@@ -90,8 +91,9 @@ func (v *Float) Set(value float64) {
// Map is a string-to-Var map variable that satisfies the Var interface.
type Map struct {
- m map[string]Var
- mu sync.RWMutex
+ mu sync.RWMutex
+ m map[string]Var
+ keys []string // sorted
}
// KeyValue represents a single entry in a Map.
@@ -106,13 +108,13 @@ func (v *Map) String() string {
var b bytes.Buffer
fmt.Fprintf(&b, "{")
first := true
- for key, val := range v.m {
+ v.doLocked(func(kv KeyValue) {
if !first {
fmt.Fprintf(&b, ", ")
}
- fmt.Fprintf(&b, "\"%s\": %v", key, val)
+ fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
first = false
- }
+ })
fmt.Fprintf(&b, "}")
return b.String()
}
@@ -122,6 +124,20 @@ func (v *Map) Init() *Map {
return v
}
+// updateKeys updates the sorted list of keys in v.keys.
+// must be called with v.mu held.
+func (v *Map) updateKeys() {
+ if len(v.m) == len(v.keys) {
+ // No new key.
+ return
+ }
+ v.keys = v.keys[:0]
+ for k := range v.m {
+ v.keys = append(v.keys, k)
+ }
+ sort.Strings(v.keys)
+}
+
func (v *Map) Get(key string) Var {
v.mu.RLock()
defer v.mu.RUnlock()
@@ -132,6 +148,7 @@ func (v *Map) Set(key string, av Var) {
v.mu.Lock()
defer v.mu.Unlock()
v.m[key] = av
+ v.updateKeys()
}
func (v *Map) Add(key string, delta int64) {
@@ -141,9 +158,11 @@ func (v *Map) Add(key string, delta int64) {
if !ok {
// check again under the write lock
v.mu.Lock()
- if _, ok = v.m[key]; !ok {
+ av, ok = v.m[key]
+ if !ok {
av = new(Int)
v.m[key] = av
+ v.updateKeys()
}
v.mu.Unlock()
}
@@ -162,9 +181,11 @@ func (v *Map) AddFloat(key string, delta float64) {
if !ok {
// check again under the write lock
v.mu.Lock()
- if _, ok = v.m[key]; !ok {
+ av, ok = v.m[key]
+ if !ok {
av = new(Float)
v.m[key] = av
+ v.updateKeys()
}
v.mu.Unlock()
}
@@ -181,15 +202,21 @@ func (v *Map) AddFloat(key string, delta float64) {
func (v *Map) Do(f func(KeyValue)) {
v.mu.RLock()
defer v.mu.RUnlock()
- for k, v := range v.m {
- f(KeyValue{k, v})
+ v.doLocked(f)
+}
+
+// doLocked calls f for each entry in the map.
+// v.mu must be held for reads.
+func (v *Map) doLocked(f func(KeyValue)) {
+ for _, k := range v.keys {
+ f(KeyValue{k, v.m[k]})
}
}
// String is a string variable, and satisfies the Var interface.
type String struct {
- s string
mu sync.RWMutex
+ s string
}
func (v *String) String() string {
@@ -215,8 +242,9 @@ func (f Func) String() string {
// All published variables.
var (
- mutex sync.RWMutex
- vars map[string]Var = make(map[string]Var)
+ mutex sync.RWMutex
+ vars = make(map[string]Var)
+ varKeys []string // sorted
)
// Publish declares a named exported variable. This should be called from a
@@ -229,6 +257,8 @@ func Publish(name string, v Var) {
log.Panicln("Reuse of exported var name:", name)
}
vars[name] = v
+ varKeys = append(varKeys, name)
+ sort.Strings(varKeys)
}
// Get retrieves a named exported variable.
@@ -270,8 +300,8 @@ func NewString(name string) *String {
func Do(f func(KeyValue)) {
mutex.RLock()
defer mutex.RUnlock()
- for k, v := range vars {
- f(KeyValue{k, v})
+ for _, k := range varKeys {
+ f(KeyValue{k, vars[k]})
}
}
diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
index 572c62bee..765e3b757 100644
--- a/src/pkg/expvar/expvar_test.go
+++ b/src/pkg/expvar/expvar_test.go
@@ -5,7 +5,10 @@
package expvar
import (
+ "bytes"
"encoding/json"
+ "net/http/httptest"
+ "strconv"
"testing"
)
@@ -15,6 +18,7 @@ func RemoveAll() {
mutex.Lock()
defer mutex.Unlock()
vars = make(map[string]Var)
+ varKeys = nil
}
func TestInt(t *testing.T) {
@@ -93,15 +97,15 @@ func TestMapCounter(t *testing.T) {
colors.Add("red", 1)
colors.Add("red", 2)
colors.Add("blue", 4)
- colors.AddFloat("green", 4.125)
+ colors.AddFloat(`green "midori"`, 4.125)
if x := colors.m["red"].(*Int).i; x != 3 {
t.Errorf("colors.m[\"red\"] = %v, want 3", x)
}
if x := colors.m["blue"].(*Int).i; x != 4 {
t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
}
- if x := colors.m["green"].(*Float).f; x != 4.125 {
- t.Errorf("colors.m[\"green\"] = %v, want 3.14", x)
+ if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
+ t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
}
// colors.String() should be '{"red":3, "blue":4}',
@@ -139,3 +143,25 @@ func TestFunc(t *testing.T) {
t.Errorf(`f.String() = %q, want %q`, s, exp)
}
}
+
+func TestHandler(t *testing.T) {
+ RemoveAll()
+ m := NewMap("map1")
+ m.Add("a", 1)
+ m.Add("z", 2)
+ m2 := NewMap("map2")
+ for i := 0; i < 9; i++ {
+ m2.Add(strconv.Itoa(i), int64(i))
+ }
+ rr := httptest.NewRecorder()
+ rr.Body = new(bytes.Buffer)
+ expvarHandler(rr, nil)
+ want := `{
+"map1": {"a": 1, "z": 2},
+"map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
+}
+`
+ if got := rr.Body.String(); got != want {
+ t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
+ }
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index e7c863ee9..cd2a165be 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -50,7 +50,8 @@
("-" is a non-flag argument) or after the terminator "--".
Integer flags accept 1234, 0664, 0x1234 and may be negative.
- Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+ Boolean flags may be:
+ 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
Duration flags accept any input valid for time.ParseDuration.
The default set of command-line flags is controlled by
@@ -269,7 +270,6 @@ type FlagSet struct {
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
- exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor
}
@@ -755,7 +755,7 @@ func (f *FlagSet) parseOne() (bool, error) {
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
if has_value {
if err := fv.Set(value); err != nil {
- return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
+ return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
}
} else {
fv.Set("true")
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 095fd03b2..02642d6ae 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -37,6 +37,7 @@
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
+ %F synonym for %f
%g whichever of %e or %f produces more compact output
%G whichever of %E or %f produces more compact output
String and slice of bytes:
@@ -50,23 +51,39 @@
There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
Similarly, there is no need to specify the size of the operand (int8, int64).
- The width and precision control formatting and are in units of Unicode
- code points. (This differs from C's printf where the units are numbers
+ Width is specified by an optional decimal number immediately following the verb.
+ If absent, the width is whatever is necessary to represent the value.
+ Precision is specified after the (optional) width by a period followed by a
+ decimal number. If no period is present, a default precision is used.
+ A period with no following number specifies a precision of zero.
+ Examples:
+ %f: default width, default precision
+ %9f width 9, default precision
+ %.2f default width, precision 2
+ %9.2f width 9, precision 2
+ %9.f width 9, precision 0
+
+ Width and precision are measured in units of Unicode code points.
+ (This differs from C's printf where the units are numbers
of bytes.) Either or both of the flags may be replaced with the
character '*', causing their values to be obtained from the next
operand, which must be of type int.
- For numeric values, width sets the minimum width of the field and
+ For most values, width is the minimum number of characters to output,
+ padding the formatted form with spaces if necessary.
+ For strings, precision is the maximum number of characters to output,
+ truncating if necessary.
+
+ For floating-point values, width sets the minimum width of the field and
precision sets the number of places after the decimal, if appropriate,
except that for %g/%G it sets the total number of digits. For example,
given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
The default precision for %e and %f is 6; for %g it is the smallest
number of digits necessary to identify the value uniquely.
- For most values, width is the minimum number of characters to output,
- padding the formatted form with spaces if necessary.
- For strings, precision is the maximum number of characters to output,
- truncating if necessary.
+ For complex numbers, the width and precision apply to the two
+ components independently and the result is parenthesized, so %f applied
+ to 1.2+3.4i produces (1.200000+3.400000i).
Other flags:
+ always print a sign for numeric values;
@@ -98,20 +115,33 @@
fmt.Printf("%v\n", i)
will print 23.
- If an operand implements interface Formatter, that interface
- can be used for fine control of formatting.
+ Except when printed using the verbs %T and %p, special
+ formatting considerations apply for operands that implement
+ certain interfaces. In order of application:
+
+ 1. If an operand implements the Formatter interface, it will
+ be invoked. Formatter provides fine control of formatting.
+
+ 2. If the %v verb is used with the # flag (%#v) and the operand
+ implements the GoStringer interface, that will be invoked.
If the format (which is implicitly %v for Println etc.) is valid
- for a string (%s %q %v %x %X), the following two rules also apply:
+ for a string (%s %q %v %x %X), the following two rules apply:
- 1. If an operand implements the error interface, the Error method
- will be used to convert the object to a string, which will then
+ 3. If an operand implements the error interface, the Error method
+ will be invoked to convert the object to a string, which will then
be formatted as required by the verb (if any).
- 2. If an operand implements method String() string, that method
- will be used to convert the object to a string, which will then
+ 4. If an operand implements method String() string, that method
+ will be invoked to convert the object to a string, which will then
be formatted as required by the verb (if any).
+ For compound operands such as slices and structs, the format
+ applies to the elements of each operand, recursively, not to the
+ operand as a whole. Thus %q will quote each element of a slice
+ of strings, and %6.2f will control formatting for each element
+ of a floating-point array.
+
To avoid recursion in cases such as
type X string
func (x X) String() string { return Sprintf("<%s>", x) }
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index bf50675f5..7e3d06b9f 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -220,6 +220,12 @@ var fmtTests = []struct {
{"%+.3e", 0.0, "+0.000e+00"},
{"%+.3e", 1.0, "+1.000e+00"},
{"%+.3f", -1.0, "-1.000"},
+ {"%+.3F", -1.0, "-1.000"},
+ {"%+.3F", float32(-1.0), "-1.000"},
+ {"%+07.2f", 1.0, "+001.00"},
+ {"%+07.2f", -1.0, "-001.00"},
+ {"%+10.2f", +1.0, " +1.00"},
+ {"%+10.2f", -1.0, " -1.00"},
{"% .3E", -1.0, "-1.000E+00"},
{"% .3e", 1.0, " 1.000e+00"},
{"%+.3g", 0.0, "+0"},
@@ -239,6 +245,8 @@ var fmtTests = []struct {
{"%+.3g", 1 + 2i, "(+1+2i)"},
{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
{"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3F", 0i, "(0.000+0.000i)"},
+ {"%.3F", complex64(0i), "(0.000+0.000i)"},
{"%.3g", 0i, "(0+0i)"},
{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
{"%.3f", 1 + 2i, "(1.000+2.000i)"},
@@ -397,6 +405,8 @@ var fmtTests = []struct {
{"%#v", "foo", `"foo"`},
{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
+ {"%#v", []byte(nil), "[]byte(nil)"},
+ {"%#v", []int32(nil), "[]int32(nil)"},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -495,18 +505,85 @@ var fmtTests = []struct {
{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
// Used to crash because nByte didn't allow for a sign.
- {"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
+ {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
// Used to panic.
- {"%0100d", 1, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
- {"%0100d", -1, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
- {"%0.100f", 1.0, "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
- {"%0.100f", -1.0, "-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
+ {"%0100d", 1, zeroFill("", 100, "1")},
+ {"%0100d", -1, zeroFill("-", 99, "1")},
+ {"%0.100f", 1.0, zeroFill("1.", 100, "")},
+ {"%0.100f", -1.0, zeroFill("-1.", 100, "")},
+
+ // Comparison of padding rules with C printf.
+ /*
+ C program:
+ #include <stdio.h>
+
+ char *format[] = {
+ "[%.2f]",
+ "[% .2f]",
+ "[%+.2f]",
+ "[%7.2f]",
+ "[% 7.2f]",
+ "[%+7.2f]",
+ "[%07.2f]",
+ "[% 07.2f]",
+ "[%+07.2f]",
+ };
+
+ int main(void) {
+ int i;
+ for(i = 0; i < 9; i++) {
+ printf("%s: ", format[i]);
+ printf(format[i], 1.0);
+ printf(" ");
+ printf(format[i], -1.0);
+ printf("\n");
+ }
+ }
- // Zero padding floats used to put the minus sign in the middle.
- {"%020f", -1.0, "-000000000001.000000"},
+ Output:
+ [%.2f]: [1.00] [-1.00]
+ [% .2f]: [ 1.00] [-1.00]
+ [%+.2f]: [+1.00] [-1.00]
+ [%7.2f]: [ 1.00] [ -1.00]
+ [% 7.2f]: [ 1.00] [ -1.00]
+ [%+7.2f]: [ +1.00] [ -1.00]
+ [%07.2f]: [0001.00] [-001.00]
+ [% 07.2f]: [ 001.00] [-001.00]
+ [%+07.2f]: [+001.00] [-001.00]
+ */
+ {"%.2f", 1.0, "1.00"},
+ {"%.2f", -1.0, "-1.00"},
+ {"% .2f", 1.0, " 1.00"},
+ {"% .2f", -1.0, "-1.00"},
+ {"%+.2f", 1.0, "+1.00"},
+ {"%+.2f", -1.0, "-1.00"},
+ {"%7.2f", 1.0, " 1.00"},
+ {"%7.2f", -1.0, " -1.00"},
+ {"% 7.2f", 1.0, " 1.00"},
+ {"% 7.2f", -1.0, " -1.00"},
+ {"%+7.2f", 1.0, " +1.00"},
+ {"%+7.2f", -1.0, " -1.00"},
+ {"%07.2f", 1.0, "0001.00"},
+ {"%07.2f", -1.0, "-001.00"},
+ {"% 07.2f", 1.0, " 001.00"},
+ {"% 07.2f", -1.0, "-001.00"},
+ {"%+07.2f", 1.0, "+001.00"},
+ {"%+07.2f", -1.0, "-001.00"},
+
+ // Complex numbers: exhaustively tested in TestComplexFormatting.
+ {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
+ {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
+ // Zero padding does not apply to infinities.
+ {"%020f", math.Inf(-1), " -Inf"},
+ {"%020f", math.Inf(+1), " +Inf"},
+ {"% 020f", math.Inf(-1), " -Inf"},
+ {"% 020f", math.Inf(+1), " Inf"},
+ {"%+020f", math.Inf(-1), " -Inf"},
+ {"%+020f", math.Inf(+1), " +Inf"},
{"%20f", -1.0, " -1.000000"},
- {"%0100f", -1.0, "-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"},
+ // Make sure we can handle very large widths.
+ {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
// Complex fmt used to leave the plus flag set for future entries in the array
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -515,6 +592,43 @@ var fmtTests = []struct {
// Incomplete format specification caused crash.
{"%.", 3, "%!.(int=3)"},
+
+ // Used to panic with out-of-bounds for very large numeric representations.
+ // nByte is set to handle one bit per uint64 in %b format, with a negative number.
+ // See issue 6777.
+ {"%#064x", 1, zeroFill("0x", 64, "1")},
+ {"%#064x", -1, zeroFill("-0x", 63, "1")},
+ {"%#064b", 1, zeroFill("", 64, "1")},
+ {"%#064b", -1, zeroFill("-", 63, "1")},
+ {"%#064o", 1, zeroFill("", 64, "1")},
+ {"%#064o", -1, zeroFill("-", 63, "1")},
+ {"%#064d", 1, zeroFill("", 64, "1")},
+ {"%#064d", -1, zeroFill("-", 63, "1")},
+ // Test that we handle the crossover above the size of uint64
+ {"%#072x", 1, zeroFill("0x", 72, "1")},
+ {"%#072x", -1, zeroFill("-0x", 71, "1")},
+ {"%#072b", 1, zeroFill("", 72, "1")},
+ {"%#072b", -1, zeroFill("-", 71, "1")},
+ {"%#072o", 1, zeroFill("", 72, "1")},
+ {"%#072o", -1, zeroFill("-", 71, "1")},
+ {"%#072d", 1, zeroFill("", 72, "1")},
+ {"%#072d", -1, zeroFill("-", 71, "1")},
+
+ // Padding for complex numbers. Has been bad, then fixed, then bad again.
+ {"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
+ {"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
+ {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"},
+ {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"},
+ {"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"},
+ {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
+ {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
+ {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
+}
+
+// zeroFill generates zero-filled strings of the specified width. The length
+// of the suffix (but not the prefix) is compensated for in the width calculation.
+func zeroFill(prefix string, width int, suffix string) string {
+ return prefix + strings.Repeat("0", width-len(suffix)) + suffix
}
func TestSprintf(t *testing.T) {
@@ -554,6 +668,50 @@ func TestSprintf(t *testing.T) {
}
}
+// TestComplexFormatting checks that a complex always formats to the same
+// thing as if done by hand with two singleton prints.
+func TestComplexFormatting(t *testing.T) {
+ var yesNo = []bool{true, false}
+ var signs = []float64{1, 0, -1}
+ for _, plus := range yesNo {
+ for _, zero := range yesNo {
+ for _, space := range yesNo {
+ for _, char := range "fFeEgG" {
+ realFmt := "%"
+ if zero {
+ realFmt += "0"
+ }
+ if space {
+ realFmt += " "
+ }
+ if plus {
+ realFmt += "+"
+ }
+ realFmt += "10.2"
+ realFmt += string(char)
+ // Imaginary part always has a sign, so force + and ignore space.
+ imagFmt := "%"
+ if zero {
+ imagFmt += "0"
+ }
+ imagFmt += "+"
+ imagFmt += "10.2"
+ imagFmt += string(char)
+ for _, realSign := range signs {
+ for _, imagSign := range signs {
+ one := Sprintf(realFmt, complex(realSign, imagSign))
+ two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign)
+ if one != two {
+ t.Error(f, one, two)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
type SE []interface{} // slice of empty; notational compactness.
var reorderTests = []struct {
@@ -604,47 +762,61 @@ func TestReorder(t *testing.T) {
}
func BenchmarkSprintfEmpty(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("")
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("")
+ }
+ })
}
func BenchmarkSprintfString(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%s", "hello")
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%s", "hello")
+ }
+ })
}
func BenchmarkSprintfInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%d", 5)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%d", 5)
+ }
+ })
}
func BenchmarkSprintfIntInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%d %d", 5, 6)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%d %d", 5, 6)
+ }
+ })
}
func BenchmarkSprintfPrefixedInt(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+ }
+ })
}
func BenchmarkSprintfFloat(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Sprintf("%g", 5.23184)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ Sprintf("%g", 5.23184)
+ }
+ })
}
func BenchmarkManyArgs(b *testing.B) {
- var buf bytes.Buffer
- for i := 0; i < b.N; i++ {
- buf.Reset()
- Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var buf bytes.Buffer
+ for pb.Next() {
+ buf.Reset()
+ Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+ }
+ })
}
var mallocBuf bytes.Buffer
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 2e2b0716e..a89c542cf 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -5,12 +5,15 @@
package fmt
import (
+ "math"
"strconv"
"unicode/utf8"
)
const (
- nByte = 65 // %b of an int64, plus a sign.
+ // %b of an int64, plus a sign.
+ // Hex can add 0x and we handle it specially.
+ nByte = 65
ldigits = "0123456789abcdef"
udigits = "0123456789ABCDEF"
@@ -160,9 +163,16 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
}
var buf []byte = f.intbuf[0:]
- if f.widPresent && f.wid > nByte {
- // We're going to need a bigger boat.
- buf = make([]byte, f.wid)
+ if f.widPresent {
+ width := f.wid
+ if base == 16 && f.sharp {
+ // Also adds "0x".
+ width += 2
+ }
+ if width > nByte {
+ // We're going to need a bigger boat.
+ buf = make([]byte, width)
+ }
}
negative := signedness == signed && a < 0
@@ -351,35 +361,48 @@ func doPrec(f *fmt, def int) int {
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
- // We leave one byte at the beginning of f.intbuf for a sign if needed,
- // and make it a space, which we might be able to use.
- f.intbuf[0] = ' '
- slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
- // Add a plus sign or space to the floating-point string representation if missing and required.
- // The formatted number starts at slice[1].
- switch slice[1] {
- case '-', '+':
- // If we're zero padding, want the sign before the leading zeros.
- // Achieve this by writing the sign out and padding the postive number.
- if f.zero && f.widPresent && f.wid > len(slice) {
- f.buf.WriteByte(slice[1])
- f.wid--
- f.pad(slice[2:])
- return
+ // Format number, reserving space for leading + sign if needed.
+ num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ if num[1] == '-' || num[1] == '+' {
+ num = num[1:]
+ } else {
+ num[0] = '+'
+ }
+ // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
+ if math.IsInf(v, 0) {
+ if f.zero {
+ defer func() { f.zero = true }()
+ f.zero = false
}
- // We're set; drop the leading space.
- slice = slice[1:]
- default:
- // There's no sign, but we might need one.
- if f.plus {
- slice[0] = '+'
- } else if f.space {
- // space is already there
- } else {
- slice = slice[1:]
+ }
+ // num is now a signed version of the number.
+ // If we're zero padding, want the sign before the leading zeros.
+ // Achieve this by writing the sign out and then padding the unsigned number.
+ if f.zero && f.widPresent && f.wid > len(num) {
+ if f.space && v >= 0 {
+ f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
+ f.wid--
+ } else if f.plus || v < 0 {
+ f.buf.WriteByte(num[0])
+ f.wid--
}
+ f.pad(num[1:])
+ return
+ }
+ // f.space says to replace a leading + with a space.
+ if f.space && num[0] == '+' {
+ num[0] = ' '
+ f.pad(num)
+ return
}
- f.pad(slice)
+ // Now we know the sign is attached directly to the number, if present at all.
+ // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
+ if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+ f.pad(num)
+ return
+ }
+ // No sign to show and the number is positive; just print the unsigned number.
+ f.pad(num[1:])
}
// fmt_e64 formats a float64 in the form -1.23e+12.
@@ -424,60 +447,46 @@ func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
func (f *fmt) fmt_c64(v complex64, verb rune) {
- f.buf.WriteByte('(')
- r := real(v)
- oldPlus := f.plus
- for i := 0; ; i++ {
- switch verb {
- case 'b':
- f.fmt_fb32(r)
- case 'e':
- f.fmt_e32(r)
- case 'E':
- f.fmt_E32(r)
- case 'f':
- f.fmt_f32(r)
- case 'g':
- f.fmt_g32(r)
- case 'G':
- f.fmt_G32(r)
- }
- if i != 0 {
- break
- }
- f.plus = true
- r = imag(v)
- }
- f.plus = oldPlus
- f.buf.Write(irparenBytes)
+ f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
}
// fmt_c128 formats a complex128 according to the verb.
func (f *fmt) fmt_c128(v complex128, verb rune) {
+ f.fmt_complex(real(v), imag(v), 64, verb)
+}
+
+// fmt_complex formats a complex number as (r+ji).
+func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
f.buf.WriteByte('(')
- r := real(v)
oldPlus := f.plus
+ oldSpace := f.space
+ oldWid := f.wid
for i := 0; ; i++ {
switch verb {
case 'b':
- f.fmt_fb64(r)
+ f.formatFloat(r, 'b', 0, size)
case 'e':
- f.fmt_e64(r)
+ f.formatFloat(r, 'e', doPrec(f, 6), size)
case 'E':
- f.fmt_E64(r)
- case 'f':
- f.fmt_f64(r)
+ f.formatFloat(r, 'E', doPrec(f, 6), size)
+ case 'f', 'F':
+ f.formatFloat(r, 'f', doPrec(f, 6), size)
case 'g':
- f.fmt_g64(r)
+ f.formatFloat(r, 'g', doPrec(f, -1), size)
case 'G':
- f.fmt_G64(r)
+ f.formatFloat(r, 'G', doPrec(f, -1), size)
}
if i != 0 {
break
}
+ // Imaginary part always has a sign.
f.plus = true
- r = imag(v)
+ f.space = false
+ f.wid = oldWid
+ r = j
}
+ f.space = oldSpace
f.plus = oldPlus
+ f.wid = oldWid
f.buf.Write(irparenBytes)
}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 1ea816d6d..302661f4c 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -124,45 +124,13 @@ type pp struct {
fmt fmt
}
-// A cache holds a set of reusable objects.
-// The slice is a stack (LIFO).
-// If more are needed, the cache creates them by calling new.
-type cache struct {
- mu sync.Mutex
- saved []interface{}
- new func() interface{}
+var ppFree = sync.Pool{
+ New: func() interface{} { return new(pp) },
}
-func (c *cache) put(x interface{}) {
- c.mu.Lock()
- if len(c.saved) < cap(c.saved) {
- c.saved = append(c.saved, x)
- }
- c.mu.Unlock()
-}
-
-func (c *cache) get() interface{} {
- c.mu.Lock()
- n := len(c.saved)
- if n == 0 {
- c.mu.Unlock()
- return c.new()
- }
- x := c.saved[n-1]
- c.saved = c.saved[0 : n-1]
- c.mu.Unlock()
- return x
-}
-
-func newCache(f func() interface{}) *cache {
- return &cache{saved: make([]interface{}, 0, 100), new: f}
-}
-
-var ppFree = newCache(func() interface{} { return new(pp) })
-
// newPrinter allocates a new pp struct or grab a cached one.
func newPrinter() *pp {
- p := ppFree.get().(*pp)
+ p := ppFree.Get().(*pp)
p.panicking = false
p.erroring = false
p.fmt.init(&p.buf)
@@ -178,7 +146,7 @@ func (p *pp) free() {
p.buf = p.buf[:0]
p.arg = nil
p.value = reflect.Value{}
- ppFree.put(p)
+ ppFree.Put(p)
}
func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
@@ -479,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) {
p.fmt.fmt_e32(v)
case 'E':
p.fmt.fmt_E32(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f32(v)
case 'g', 'v':
p.fmt.fmt_g32(v)
@@ -498,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) {
p.fmt.fmt_e64(v)
case 'E':
p.fmt.fmt_E64(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f64(v)
case 'g', 'v':
p.fmt.fmt_g64(v)
@@ -555,6 +523,15 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) {
if verb == 'v' || verb == 'd' {
if goSyntax {
+ if v == nil {
+ if typ == nil {
+ p.buf.WriteString("[]byte(nil)")
+ } else {
+ p.buf.WriteString(typ.String())
+ p.buf.Write(nilParenBytes)
+ }
+ return
+ }
if typ == nil {
p.buf.Write(bytesBytes)
} else {
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 5b1be5891..8a337e479 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -11,6 +11,7 @@ import (
"os"
"reflect"
"strconv"
+ "sync"
"unicode/utf8"
)
@@ -283,7 +284,6 @@ var space = [][2]uint16{
{0x0085, 0x0085},
{0x00a0, 0x00a0},
{0x1680, 0x1680},
- {0x180e, 0x180e},
{0x2000, 0x200a},
{0x2028, 0x2029},
{0x202f, 0x202f},
@@ -380,7 +380,9 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
return
}
-var ssFree = newCache(func() interface{} { return new(ss) })
+var ssFree = sync.Pool{
+ New: func() interface{} { return new(ss) },
+}
// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
@@ -395,7 +397,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
return
}
- s = ssFree.get().(*ss)
+ s = ssFree.Get().(*ss)
if rr, ok := r.(io.RuneReader); ok {
s.rr = rr
} else {
@@ -427,7 +429,7 @@ func (s *ss) free(old ssave) {
}
s.buf = s.buf[:0]
s.rr = nil
- ssFree.put(s)
+ ssFree.Put(s)
}
// skipSpace skips spaces and maybe newlines.
diff --git a/src/pkg/go/ast/commentmap.go b/src/pkg/go/ast/commentmap.go
index 1fb4867dd..ac999d627 100644
--- a/src/pkg/go/ast/commentmap.go
+++ b/src/pkg/go/ast/commentmap.go
@@ -149,7 +149,7 @@ func NewCommentMap(fset *token.FileSet, node Node, comments []*CommentGroup) Com
// set up comment reader r
tmp := make([]*CommentGroup, len(comments))
- copy(tmp, comments) // don't change incomming comments
+ copy(tmp, comments) // don't change incoming comments
sortComments(tmp)
r := commentListReader{fset: fset, list: tmp} // !r.eol() because len(comments) > 0
r.next()
diff --git a/src/pkg/go/ast/example_test.go b/src/pkg/go/ast/example_test.go
index 632bfcfd0..d2e734f2c 100644
--- a/src/pkg/go/ast/example_test.go
+++ b/src/pkg/go/ast/example_test.go
@@ -5,8 +5,10 @@
package ast_test
import (
+ "bytes"
"fmt"
"go/ast"
+ "go/format"
"go/parser"
"go/token"
)
@@ -134,3 +136,75 @@ func main() {
// 57 . }
// 58 }
}
+
+// This example illustrates how to remove a variable declaration
+// in a Go program while maintaining correct comment association
+// using an ast.CommentMap.
+func ExampleCommentMap() {
+ // src is the input for which we create the AST that we
+ // are going to manipulate.
+ src := `
+// This is the package comment.
+package main
+
+// This comment is associated with the hello constant.
+const hello = "Hello, World!" // line comment 1
+
+// This comment is associated with the foo variable.
+var foo = hello // line comment 2
+
+// This comment is associated with the main function.
+func main() {
+ fmt.Println(hello) // line comment 3
+}
+`
+
+ // Create the AST by parsing src.
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments)
+ if err != nil {
+ panic(err)
+ }
+
+ // Create an ast.CommentMap from the ast.File's comments.
+ // This helps keeping the association between comments
+ // and AST nodes.
+ cmap := ast.NewCommentMap(fset, f, f.Comments)
+
+ // Remove the first variable declaration from the list of declarations.
+ f.Decls = removeFirstVarDecl(f.Decls)
+
+ // Use the comment map to filter comments that don't belong anymore
+ // (the comments associated with the variable declaration), and create
+ // the new comments list.
+ f.Comments = cmap.Filter(f).Comments()
+
+ // Print the modified AST.
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, f); err != nil {
+ panic(err)
+ }
+ fmt.Printf("%s", buf.Bytes())
+
+ // output:
+ // // This is the package comment.
+ // package main
+ //
+ // // This comment is associated with the hello constant.
+ // const hello = "Hello, World!" // line comment 1
+ //
+ // // This comment is associated with the main function.
+ // func main() {
+ // fmt.Println(hello) // line comment 3
+ // }
+}
+
+func removeFirstVarDecl(list []ast.Decl) []ast.Decl {
+ for i, decl := range list {
+ if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR {
+ copy(list[i:], list[i+1:])
+ return list[:len(list)-1]
+ }
+ }
+ panic("variable declaration not found")
+}
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 50d2fb4ae..412abea3a 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -292,10 +292,10 @@ func defaultContext() Context {
// say "+build go1.x", and code that should only be built before Go 1.x
// (perhaps it is the stub to use in that case) should say "+build !go1.x".
//
- // When we reach Go 1.3 the line will read
- // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
+ // When we reach Go 1.4 the line will read
+ // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
// and so on.
- c.ReleaseTags = []string{"go1.1", "go1.2"}
+ c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
switch os.Getenv("CGO_ENABLED") {
case "1":
@@ -303,8 +303,7 @@ func defaultContext() Context {
case "0":
c.CgoEnabled = false
default:
- // golang.org/issue/5141
- // cgo should be disabled for cross compilation builds
+ // cgo must be explicitly enabled for cross compilation builds
if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
break
@@ -358,6 +357,7 @@ type Package struct {
IgnoredGoFiles []string // .go source files ignored for this build
CFiles []string // .c source files
CXXFiles []string // .cc, .cpp and .cxx source files
+ MFiles []string // .m (Objective-C) source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -622,6 +622,9 @@ Found:
case ".cc", ".cpp", ".cxx":
p.CXXFiles = append(p.CXXFiles, name)
continue
+ case ".m":
+ p.MFiles = append(p.MFiles, name)
+ continue
case ".h", ".hh", ".hpp", ".hxx":
p.HFiles = append(p.HFiles, name)
continue
@@ -789,7 +792,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
}
switch ext {
- case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+ case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
case ".syso":
// binary, no reading
@@ -1207,7 +1210,7 @@ func ArchChar(goarch string) (string, error) {
switch goarch {
case "386":
return "8", nil
- case "amd64":
+ case "amd64", "amd64p32":
return "6", nil
case "arm":
return "5", nil
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index dd162c7db..7421e144f 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -8,6 +8,7 @@
package build
import (
+ "runtime"
"sort"
"testing"
)
@@ -29,7 +30,7 @@ var pkgDeps = map[string][]string{
"errors": {},
"io": {"errors", "sync"},
"runtime": {"unsafe"},
- "sync": {"sync/atomic", "unsafe"},
+ "sync": {"runtime", "sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"},
"unsafe": {},
@@ -125,7 +126,7 @@ var pkgDeps = map[string][]string{
"os": {"L1", "os", "syscall", "time"},
"path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
- "os/exec": {"L2", "os", "syscall"},
+ "os/exec": {"L2", "os", "path/filepath", "syscall"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,
@@ -301,7 +302,7 @@ var pkgDeps = map[string][]string{
// SSL/TLS.
"crypto/tls": {
"L4", "CRYPTO-MATH", "CGO", "OS",
- "crypto/x509", "encoding/pem", "net", "syscall",
+ "container/list", "crypto/x509", "encoding/pem", "net", "syscall",
},
"crypto/x509": {
"L4", "CRYPTO-MATH", "OS", "CGO",
@@ -359,7 +360,7 @@ func allowed(pkg string) map[string]bool {
}
var bools = []bool{false, true}
-var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}
+var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
var goarches = []string{"386", "amd64", "arm"}
type osPkg struct {
@@ -374,6 +375,11 @@ var allowedErrors = map[osPkg]bool{
}
func TestDependencies(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ // NaCl tests run in a limited file system and we do not
+ // provide access to every source file.
+ t.Skip("skipping on NaCl")
+ }
var all []string
for k := range pkgDeps {
@@ -387,6 +393,9 @@ func TestDependencies(t *testing.T) {
if isMacro(pkg) {
continue
}
+ if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+ continue
+ }
p, err := ctxt.Import(pkg, "", 0)
if err != nil {
if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
diff --git a/src/pkg/go/build/doc.go b/src/pkg/go/build/doc.go
index b2f04ea45..f17f76ccc 100644
--- a/src/pkg/go/build/doc.go
+++ b/src/pkg/go/build/doc.go
@@ -57,11 +57,15 @@
//
// Build Constraints
//
-// A build constraint is a line comment beginning with the directive +build
+// A build constraint, also known as a build tag, is a line comment that begins
+//
+// // +build
+//
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
-// only by blank lines and other line comments.
+// only by blank lines and other line comments. These rules mean that in Go
+// files a build constraint must appear before the package clause.
//
// To distinguish build constraints from package documentation, a series of
// build constraints must be followed by a blank line.
@@ -95,6 +99,7 @@
// - "cgo", if ctxt.CgoEnabled is true
// - "go1.1", from Go version 1.1 onward
// - "go1.2", from Go version 1.2 onward
+// - "go1.3", from Go version 1.3 onward
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
index e1fbf6330..5c42b946b 100644
--- a/src/pkg/go/build/syslist.go
+++ b/src/pkg/go/build/syslist.go
@@ -4,5 +4,5 @@
package build
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 windows "
-const goarchList = "386 amd64 arm "
+const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index 5c8c43e0c..f414ca409 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -45,13 +45,13 @@ func commentEscape(w io.Writer, text string, nice bool) {
const (
// Regexp for Go identifiers
- identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+ identRx = `[\pL_][\pL_0-9]*`
// Regexp for URLs
- protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+ protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero`
hostPart = `[a-zA-Z0-9_@\-]+`
- filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
- urlRx = protocol + `//` + // http://
+ filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
+ urlRx = `(` + protocol + `)://` + // http://
hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
filePart + `([:.,]` + filePart + `)*`
)
@@ -73,6 +73,29 @@ var (
html_endh = []byte("</h3>\n")
)
+// pairedParensPrefixLen returns the length of the longest prefix of s containing paired parentheses.
+func pairedParensPrefixLen(s string) int {
+ parens := 0
+ l := len(s)
+ for i, ch := range s {
+ switch ch {
+ case '(':
+ if parens == 0 {
+ l = i
+ }
+ parens++
+ case ')':
+ parens--
+ if parens == 0 {
+ l = len(s)
+ } else if parens < 0 {
+ return i
+ }
+ }
+ }
+ return l
+}
+
// Emphasize and escape a line of text for HTML. URLs are converted into links;
// if the URL also appears in the words map, the link is taken from the map (if
// the corresponding map value is the empty string, the URL is not converted
@@ -92,18 +115,26 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
// write text before match
commentEscape(w, line[0:m[0]], nice)
- // analyze match
+ // adjust match if necessary
match := line[m[0]:m[1]]
+ if n := pairedParensPrefixLen(match); n < len(match) {
+ // match contains unpaired parentheses (rare);
+ // redo matching with shortened line for correct indices
+ m = matchRx.FindStringSubmatchIndex(line[:m[0]+n])
+ match = match[:n]
+ }
+
+ // analyze match
url := ""
italics := false
if words != nil {
- url, italics = words[string(match)]
+ url, italics = words[match]
}
if m[2] >= 0 {
// match against first parenthesized sub-regexp; must be match against urlRx
if !italics {
// no alternative URL in words list, use match instead
- url = string(match)
+ url = match
}
italics = false // don't italicize URLs
}
@@ -392,7 +423,9 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
case opPre:
w.Write(nl)
for _, line := range b.lines {
- if !isBlank(line) {
+ if isBlank(line) {
+ w.Write([]byte("\n"))
+ } else {
w.Write([]byte(preIndent))
w.Write([]byte(line))
}
diff --git a/src/pkg/go/doc/comment_test.go b/src/pkg/go/doc/comment_test.go
index aa21b8d1b..ad65c2a27 100644
--- a/src/pkg/go/doc/comment_test.go
+++ b/src/pkg/go/doc/comment_test.go
@@ -42,8 +42,9 @@ func TestIsHeading(t *testing.T) {
}
var blocksTests = []struct {
- in string
- out []block
+ in string
+ out []block
+ text string
}{
{
in: `Para 1.
@@ -59,6 +60,22 @@ Para 3.
pre1
Para 4.
+
+ pre
+ pre1
+
+ pre2
+
+Para 5.
+
+
+ pre
+
+
+ pre1
+ pre2
+
+Para 6.
pre
pre2
`,
@@ -69,8 +86,44 @@ Para 4.
{opPara, []string{"Para 3.\n"}},
{opPre, []string{"pre\n", "pre1\n"}},
{opPara, []string{"Para 4.\n"}},
+ {opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}},
+ {opPara, []string{"Para 5.\n"}},
+ {opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}},
+ {opPara, []string{"Para 6.\n"}},
{opPre, []string{"pre\n", "pre2\n"}},
},
+ text: `. Para 1. Para 1 line 2.
+
+. Para 2.
+
+
+. Section
+
+. Para 3.
+
+$ pre
+$ pre1
+
+. Para 4.
+
+$ pre
+$ pre1
+
+$ pre2
+
+. Para 5.
+
+$ pre
+
+
+$ pre1
+$ pre2
+
+. Para 6.
+
+$ pre
+$ pre2
+`,
},
}
@@ -83,14 +136,28 @@ func TestBlocks(t *testing.T) {
}
}
+func TestToText(t *testing.T) {
+ var buf bytes.Buffer
+ for i, tt := range blocksTests {
+ ToText(&buf, tt.in, ". ", "$\t", 40)
+ if have := buf.String(); have != tt.text {
+ t.Errorf("#%d: mismatch\nhave: %s\nwant: %s\nhave vs want:\n%q\n%q", i, have, tt.text, have, tt.text)
+ }
+ buf.Reset()
+ }
+}
+
var emphasizeTests = []struct {
- in string
- out string
+ in, out string
}{
{"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
{"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
{"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
+ {"http://en.wikipedia.org/wiki/Camellia_(cipher)", `<a href="http://en.wikipedia.org/wiki/Camellia_(cipher)">http://en.wikipedia.org/wiki/Camellia_(cipher)</a>`},
{"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`},
+ {"http://gmail.com)", `<a href="http://gmail.com">http://gmail.com</a>)`},
+ {"((http://gmail.com))", `((<a href="http://gmail.com">http://gmail.com</a>))`},
+ {"http://gmail.com ((http://gmail.com)) ()", `<a href="http://gmail.com">http://gmail.com</a> ((<a href="http://gmail.com">http://gmail.com</a>)) ()`},
{"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`},
{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
@@ -107,3 +174,34 @@ func TestEmphasize(t *testing.T) {
}
}
}
+
+var pairedParensPrefixLenTests = []struct {
+ in, out string
+}{
+ {"", ""},
+ {"foo", "foo"},
+ {"()", "()"},
+ {"foo()", "foo()"},
+ {"foo()()()", "foo()()()"},
+ {"foo()((()()))", "foo()((()()))"},
+ {"foo()((()()))bar", "foo()((()()))bar"},
+ {"foo)", "foo"},
+ {"foo))", "foo"},
+ {"foo)))))", "foo"},
+ {"(foo", ""},
+ {"((foo", ""},
+ {"(((((foo", ""},
+ {"(foo)", "(foo)"},
+ {"((((foo))))", "((((foo))))"},
+ {"foo()())", "foo()()"},
+ {"foo((()())", "foo"},
+ {"foo((()())) (() foo ", "foo((()())) "},
+}
+
+func TestPairedParensPrefixLen(t *testing.T) {
+ for i, tt := range pairedParensPrefixLenTests {
+ if out := tt.in[:pairedParensPrefixLen(tt.in)]; out != tt.out {
+ t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go
index 2358ed389..c414e548c 100644
--- a/src/pkg/go/doc/example.go
+++ b/src/pkg/go/doc/example.go
@@ -32,6 +32,17 @@ type Example struct {
// Examples returns the examples found in the files, sorted by Name field.
// The Order fields record the order in which the examples were encountered.
+//
+// Playable Examples must be in a package whose name ends in "_test".
+// An Example is "playable" (the Play field is non-nil) in either of these
+// circumstances:
+// - The example function is self-contained: the function references only
+// identifiers from other packages (or predeclared identifiers, such as
+// "int") and the test file does not include a dot import.
+// - The entire test file is the example: the file contains exactly one
+// example function, zero test or benchmark functions, and at least one
+// top-level function, type, variable, or constant declaration other
+// than the example function.
func Examples(files ...*ast.File) []*Example {
var list []*Example
for _, file := range files {
@@ -244,7 +255,7 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
}
}
- // Strip "Output:" commment and adjust body end position.
+ // Strip "Output:" comment and adjust body end position.
body, comments = stripOutputComment(body, comments)
// Synthesize import declaration.
@@ -307,7 +318,7 @@ func playExampleFile(file *ast.File) *ast.File {
return &f
}
-// stripOutputComment finds and removes an "Output:" commment from body
+// stripOutputComment finds and removes an "Output:" comment from body
// and comments, and adjusts the body block's end position.
func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) {
// Do nothing if no "Output:" comment found.
diff --git a/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
index d4d4f909d..8506077ce 100644
--- a/src/pkg/go/parser/error_test.go
+++ b/src/pkg/go/parser/error_test.go
@@ -59,8 +59,11 @@ func getPos(filename string, offset int) token.Pos {
// ERROR comments must be of the form /* ERROR "rx" */ and rx is
// a regular expression that matches the expected error message.
+// The special form /* ERROR HERE "rx" */ must be used for error
+// messages that appear immediately after a token, rather than at
+// a token's position.
//
-var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
// expectedErrors collects the regular expressions of ERROR comments found
// in files and returns them as a map of error positions to error messages.
@@ -74,6 +77,7 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
// not match the position information collected by the parser
s.Init(getFile(filename), src, nil, scanner.ScanComments)
var prev token.Pos // position of last non-comment, non-semicolon token
+ var here token.Pos // position immediately after the token at position prev
for {
pos, tok, lit := s.Scan()
@@ -82,11 +86,22 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
return errors
case token.COMMENT:
s := errRx.FindStringSubmatch(lit)
- if len(s) == 2 {
- errors[prev] = string(s[1])
+ if len(s) == 3 {
+ pos := prev
+ if s[1] == "HERE" {
+ pos = here
+ }
+ errors[pos] = string(s[2])
}
default:
prev = pos
+ var l int // token length
+ if tok.IsLiteral() {
+ l = len(lit)
+ } else {
+ l = len(tok.String())
+ }
+ here = prev + token.Pos(l)
}
}
}
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 0f83ca931..57da4ddcd 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -182,6 +182,13 @@ func ParseExpr(x string) (ast.Expr, error) {
p.closeScope()
assert(p.topScope == nil, "unbalanced scopes")
+ // If a semicolon was inserted, consume it;
+ // report an error if there's more tokens.
+ if p.tok == token.SEMICOLON {
+ p.next()
+ }
+ p.expect(token.EOF)
+
if p.errors.Len() > 0 {
p.errors.Sort()
return nil, p.errors.Err()
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index c4523318f..00dd532b2 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -492,6 +492,26 @@ func syncDecl(p *parser) {
}
}
+// safePos returns a valid file position for a given position: If pos
+// is valid to begin with, safePos returns pos. If pos is out-of-range,
+// safePos returns the EOF position.
+//
+// This is hack to work around "artificial" end positions in the AST which
+// are computed by adding 1 to (presumably valid) token positions. If the
+// token positions are invalid due to parse errors, the resulting end position
+// may be past the file's EOF position, which would lead to panics if used
+// later on.
+//
+func (p *parser) safePos(pos token.Pos) (res token.Pos) {
+ defer func() {
+ if recover() != nil {
+ res = token.Pos(p.file.Base() + p.file.Size()) // EOF position
+ }
+ }()
+ _ = p.file.Offset(pos) // trigger a panic if position is out-of-range
+ return pos
+}
+
// ----------------------------------------------------------------------------
// Identifiers
@@ -679,7 +699,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if n := len(list); n > 1 || !isTypeName(deref(typ)) {
pos := typ.Pos()
p.errorExpected(pos, "anonymous field")
- typ = &ast.BadExpr{From: pos, To: list[n-1].End()}
+ typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())}
}
}
@@ -1168,16 +1188,19 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
defer un(trace(p, "IndexOrSlice"))
}
+ const N = 3 // change the 3 to 2 to disable 3-index slices
lbrack := p.expect(token.LBRACK)
p.exprLev++
- var index [3]ast.Expr // change the 3 to 2 to disable slice expressions w/ cap
+ var index [N]ast.Expr
+ var colons [N - 1]token.Pos
if p.tok != token.COLON {
index[0] = p.parseRhs()
}
ncolons := 0
- for p.tok == token.COLON && ncolons < len(index)-1 {
- p.next()
+ for p.tok == token.COLON && ncolons < len(colons) {
+ colons[ncolons] = p.pos
ncolons++
+ p.next()
if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
index[ncolons] = p.parseRhs()
}
@@ -1187,7 +1210,21 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if ncolons > 0 {
// slice expression
- return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: ncolons == 2, Rbrack: rbrack}
+ slice3 := false
+ if ncolons == 2 {
+ slice3 = true
+ // Check presence of 2nd and 3rd index here rather than during type-checking
+ // to prevent erroneous programs from passing through gofmt (was issue 7305).
+ if index[1] == nil {
+ p.error(colons[0], "2nd index required in 3-index slice")
+ index[1] = &ast.BadExpr{From: colons[0] + 1, To: colons[1]}
+ }
+ if index[2] == nil {
+ p.error(colons[1], "3rd index required in 3-index slice")
+ index[2] = &ast.BadExpr{From: colons[1] + 1, To: rbrack}
+ }
+ }
+ return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: slice3, Rbrack: rbrack}
}
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
@@ -1320,7 +1357,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
}
return x
}
@@ -1383,7 +1420,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
p.error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
}
}
@@ -1669,14 +1706,14 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
return &ast.ExprStmt{X: x[0]}, false
}
-func (p *parser) parseCallExpr() *ast.CallExpr {
+func (p *parser) parseCallExpr(callType string) *ast.CallExpr {
x := p.parseRhsOrType() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
if _, isBad := x.(*ast.BadExpr); !isBad {
// only report error if it's a new one
- p.errorExpected(x.Pos(), "function/method call")
+ p.error(p.safePos(x.End()), fmt.Sprintf("function must be invoked in %s statement", callType))
}
return nil
}
@@ -1687,7 +1724,7 @@ func (p *parser) parseGoStmt() ast.Stmt {
}
pos := p.expect(token.GO)
- call := p.parseCallExpr()
+ call := p.parseCallExpr("go")
p.expectSemi()
if call == nil {
return &ast.BadStmt{From: pos, To: pos + 2} // len("go")
@@ -1702,7 +1739,7 @@ func (p *parser) parseDeferStmt() ast.Stmt {
}
pos := p.expect(token.DEFER)
- call := p.parseCallExpr()
+ call := p.parseCallExpr("defer")
p.expectSemi()
if call == nil {
return &ast.BadStmt{From: pos, To: pos + 5} // len("defer")
@@ -1745,15 +1782,15 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
}
-func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+func (p *parser) makeExpr(s ast.Stmt, kind string) ast.Expr {
if s == nil {
return nil
}
if es, isExpr := s.(*ast.ExprStmt); isExpr {
return p.checkExpr(es.X)
}
- p.error(s.Pos(), "expected condition, found simple statement")
- return &ast.BadExpr{From: s.Pos(), To: s.End()}
+ p.error(s.Pos(), fmt.Sprintf("expected %s, found simple statement (missing parentheses around composite literal?)", kind))
+ return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())}
}
func (p *parser) parseIfStmt() *ast.IfStmt {
@@ -1779,7 +1816,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.next()
x = p.parseRhs()
} else {
- x = p.makeExpr(s)
+ x = p.makeExpr(s, "boolean expression")
s = nil
}
}
@@ -1910,7 +1947,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{Switch: pos, Init: s1, Assign: s2, Body: body}
}
- return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2), Body: body}
+ return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2, "switch expression"), Body: body}
}
func (p *parser) parseCommClause() *ast.CommClause {
@@ -2035,7 +2072,7 @@ func (p *parser) parseForStmt() ast.Stmt {
key = as.Lhs[0]
default:
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
- return &ast.BadStmt{From: pos, To: body.End()}
+ return &ast.BadStmt{From: pos, To: p.safePos(body.End())}
}
// parseSimpleStmt returned a right-hand side that
// is a single unary expression of the form "range x"
@@ -2055,7 +2092,7 @@ func (p *parser) parseForStmt() ast.Stmt {
return &ast.ForStmt{
For: pos,
Init: s1,
- Cond: p.makeExpr(s2),
+ Cond: p.makeExpr(s2, "boolean or range expression"),
Post: s3,
Body: body,
}
@@ -2282,7 +2319,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
p.errorExpected(base.Pos(), "(unqualified) identifier")
}
par.List = []*ast.Field{
- {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
+ {Type: &ast.BadExpr{From: recv.Pos(), To: p.safePos(recv.End())}},
}
}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 0a34b7e50..2797ea518 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -78,7 +78,7 @@ func TestParseExpr(t *testing.T) {
}
// sanity check
if _, ok := x.(*ast.BinaryExpr); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+ t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x)
}
// a valid type expression
@@ -89,17 +89,24 @@ func TestParseExpr(t *testing.T) {
}
// sanity check
if _, ok := x.(*ast.StructType); !ok {
- t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+ t.Errorf("ParseExpr(%s): got %T, want *ast.StructType", src, x)
}
// an invalid expression
src = "a + *"
_, err = ParseExpr(src)
if err == nil {
- t.Fatalf("ParseExpr(%s): %v", src, err)
+ t.Fatalf("ParseExpr(%s): got no error", src)
+ }
+
+ // a valid expression followed by extra tokens is invalid
+ src = "a[i] := x"
+ _, err = ParseExpr(src)
+ if err == nil {
+ t.Fatalf("ParseExpr(%s): got no error", src)
}
- // it must not crash
+ // ParseExpr must not crash
for _, src := range valids {
ParseExpr(src)
}
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
index 0ef0c560c..b79406099 100644
--- a/src/pkg/go/parser/short_test.go
+++ b/src/pkg/go/parser/short_test.go
@@ -48,14 +48,14 @@ var invalids = []string{
`package p; func f() { if { /* ERROR "expected operand" */ } };`,
`package p; func f() { if ; { /* ERROR "expected operand" */ } };`,
`package p; func f() { if f(); { /* ERROR "expected operand" */ } };`,
- `package p; func f() { if _ /* ERROR "expected condition" */ = range x; true {} };`,
- `package p; func f() { switch _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { if _ /* ERROR "expected boolean expression" */ = range x; true {} };`,
+ `package p; func f() { switch _ /* ERROR "expected switch expression" */ = range x; true {} };`,
`package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
`package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
- `package p; func f() { for ; _ /* ERROR "expected condition" */ = range x ; {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type) {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ , t = t.(type) {} };`,
- `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type), t {} };`,
+ `package p; func f() { for ; _ /* ERROR "expected boolean or range expression" */ = range x ; {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ , t = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type), t {} };`,
`package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
`package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
`package p; var a = struct /* ERROR "expected expression" */ {}`,
@@ -76,8 +76,19 @@ var invalids = []string{
`package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
`package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
`package p; func f() { var s []int; _ = s[] /* ERROR "expected operand" */ };`,
- `package p; func f() { var s []int; _ = s[::: /* ERROR "expected ']'" */ ] };`,
+ `package p; func f() { var s []int; _ = s[i:j: /* ERROR "3rd index required" */ ] };`,
+ `package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :k] };`,
+ `package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :] };`,
+ `package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ :] };`,
+ `package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ ::] };`,
`package p; func f() { var s []int; _ = s[i:j:k: /* ERROR "expected ']'" */ l] };`,
+ `package p; func f() { for x /* ERROR "boolean or range expression" */ = []string {} }`,
+ `package p; func f() { for x /* ERROR "boolean or range expression" */ := []string {} }`,
+ `package p; func f() { for i /* ERROR "boolean or range expression" */ , x = []string {} }`,
+ `package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`,
+ `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
+ `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
+ `package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
}
func TestInvalid(t *testing.T) {
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 583c6c370..04b5f1a76 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -378,10 +378,6 @@ func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
}
-func (p *printer) isMultiLine(n ast.Node) bool {
- return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
-}
-
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
@@ -428,13 +424,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) == 1 {
sep = blank
}
- newSection := false
+ var line int
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
extraTabs := 0
p.setComment(f.Doc)
+ p.recordLine(&line)
if len(f.Names) > 0 {
// named fields
p.identList(f.Names, false)
@@ -460,7 +457,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
}
p.setComment(f.Comment)
}
- newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -472,12 +468,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
} else { // interface
- newSection := false
+ var line int
for i, f := range list {
if i > 0 {
- p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
p.setComment(f.Doc)
+ p.recordLine(&line)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method
p.expr(f.Names[0])
@@ -487,7 +484,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
p.expr(f.Type)
}
p.setComment(f.Comment)
- newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
@@ -826,10 +822,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
}
p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
- // do not insert extra line breaks because of comments before
- // the closing '}' as it might break the code if there is no
- // trailing ','
- p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
+ // do not insert extra line break following a /*-style comment
+ // before the closing '}' as it might break the code if there
+ // is no trailing ','
+ mode := noExtraLinebreak
+ // do not insert extra blank following a /*-style comment
+ // before the closing '}' unless the literal is empty
+ if len(x.Elts) > 0 {
+ mode |= noExtraBlank
+ }
+ p.print(mode, x.Rbrace, token.RBRACE, mode)
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
@@ -901,20 +903,31 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
if nindent > 0 {
p.print(indent)
}
- multiLine := false
+ var line int
i := 0
for _, s := range list {
// ignore empty statements (was issue 3466)
if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
- // _indent == 0 only for lists of switch/select case clauses;
+ // nindent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
if len(p.output) > 0 {
// only print line break if we are not at the beginning of the output
// (i.e., we are not printing only a partial program)
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.stmt(s, nextIsRBrace && i == len(list)-1)
- multiLine = p.isMultiLine(s)
+ // labeled statements put labels on a separate line, but here
+ // we only care about the start line of the actual statement
+ // without label - correct line for each label
+ for t := s; ; {
+ lt, _ := t.(*ast.LabeledStmt)
+ if lt == nil {
+ break
+ }
+ line++
+ t = lt.Stmt
+ }
i++
}
}
@@ -1375,22 +1388,22 @@ func (p *printer) genDecl(d *ast.GenDecl) {
// two or more grouped const/var declarations:
// determine if the type column must be kept
keepType := keepTypeColumn(d.Specs)
- newSection := false
+ var line int
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.valueSpec(s.(*ast.ValueSpec), keepType[i])
- newSection = p.isMultiLine(s)
}
} else {
- newSection := false
+ var line int
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
}
+ p.recordLine(&line)
p.spec(s, n, false)
- newSection = p.isMultiLine(s)
}
}
p.print(unindent, formfeed)
@@ -1448,13 +1461,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
// opening and closing brace are on different lines - don't make it a one-liner
return maxSize + 1
}
- if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
- // too many statements or there is a comment inside - don't make it a one-liner
+ if len(b.List) > 5 {
+ // too many statements - don't make it a one-liner
return maxSize + 1
}
// otherwise, estimate body size
- bodySize := 0
+ bodySize := p.commentSizeBefore(p.posFor(pos2))
for i, s := range b.List {
+ if bodySize > maxSize {
+ break // no need to continue
+ }
if i > 0 {
bodySize += 2 // space for a semicolon and blank
}
@@ -1488,7 +1504,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
}
p.print(blank)
}
- p.print(b.Rbrace, token.RBRACE)
+ p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
return
}
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index e06d2edfb..280c697a0 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -39,9 +39,17 @@ const (
type pmode int
const (
- noExtraLinebreak pmode = 1 << iota
+ noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment
+ noExtraLinebreak // disables extra line break after /*-style comment
)
+type commentInfo struct {
+ cindex int // current comment index
+ comment *ast.CommentGroup // = printer.comments[cindex]; or nil
+ commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
+ commentNewline bool // true if the comment group contains newlines
+}
+
type printer struct {
// Configuration (does not change after initialization)
Config
@@ -52,7 +60,8 @@ type printer struct {
indent int // current indentation
mode pmode // current printer mode
impliedSemi bool // if set, a linebreak implies a semicolon
- lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+ lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
+ prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
wsbuf []whiteSpace // delayed white space
// Positions
@@ -61,19 +70,17 @@ type printer struct {
// white space). If there's a difference and SourcePos is set in
// ConfigMode, //line comments are used in the output to restore
// original source positions for a reader.
- pos token.Position // current position in AST (source) space
- out token.Position // current position in output space
- last token.Position // value of pos after calling writeString
+ pos token.Position // current position in AST (source) space
+ out token.Position // current position in output space
+ last token.Position // value of pos after calling writeString
+ linePtr *int // if set, record out.Line for the next token in *linePtr
// The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil
- cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes
// Information about p.comments[p.cindex]; set up by nextComment.
- comment *ast.CommentGroup // = p.comments[p.cindex]; or nil
- commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
- commentNewline bool // true if the comment group contains newlines
+ commentInfo
// Cache of already computed node sizes.
nodeSizes map[ast.Node]int
@@ -93,6 +100,14 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]
p.cachedPos = -1
}
+func (p *printer) internalError(msg ...interface{}) {
+ if debug {
+ fmt.Print(p.pos.String() + ": ")
+ fmt.Println(msg...)
+ panic("go/printer")
+ }
+}
+
// commentsHaveNewline reports whether a list of comments belonging to
// an *ast.CommentGroup contains newlines. Because the position information
// may only be partially correct, we also have to read the comment text.
@@ -129,12 +144,49 @@ func (p *printer) nextComment() {
p.commentOffset = infinity
}
-func (p *printer) internalError(msg ...interface{}) {
- if debug {
- fmt.Print(p.pos.String() + ": ")
- fmt.Println(msg...)
- panic("go/printer")
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+ return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
+}
+
+// commentSizeBefore returns the estimated size of the
+// comments on the same line before the next position.
+//
+func (p *printer) commentSizeBefore(next token.Position) int {
+ // save/restore current p.commentInfo (p.nextComment() modifies it)
+ defer func(info commentInfo) {
+ p.commentInfo = info
+ }(p.commentInfo)
+
+ size := 0
+ for p.commentBefore(next) {
+ for _, c := range p.comment.List {
+ size += len(c.Text)
+ }
+ p.nextComment()
}
+ return size
+}
+
+// recordLine records the output line number for the next non-whitespace
+// token in *linePtr. It is used to compute an accurate line number for a
+// formatted construct, independent of pending (not yet emitted) whitespace
+// or comments.
+//
+func (p *printer) recordLine(linePtr *int) {
+ p.linePtr = linePtr
+}
+
+// linesFrom returns the number of output lines between the current
+// output line and the line argument, ignoring any pending (not yet
+// emitted) whitespace or comments. It is used to compute an accurate
+// size (in number of lines) for a formatted construct.
+//
+func (p *printer) linesFrom(line int) int {
+ return p.out.Line - line
}
func (p *printer) posFor(pos token.Pos) token.Position {
@@ -675,10 +727,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
if last != nil {
// if the last comment is a /*-style comment and the next item
- // follows on the same line but is not a comma or a "closing"
- // token, add an extra blank for separation
- if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
- tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
+ // follows on the same line but is not a comma, and not a "closing"
+ // token immediately following its corresponding "opening" token,
+ // add an extra blank for separation unless explicitly disabled
+ if p.mode&noExtraBlank == 0 &&
+ last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
+ tok != token.COMMA &&
+ (tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
+ (tok != token.RBRACK || p.prevOpen == token.LBRACK) {
p.writeByte(' ', 1)
}
// ensure that there is a line break after a //-style comment,
@@ -735,12 +791,8 @@ func (p *printer) writeWhitespace(n int) {
}
// shift remaining entries down
- i := 0
- for ; n < len(p.wsbuf); n++ {
- p.wsbuf[i] = p.wsbuf[n]
- i++
- }
- p.wsbuf = p.wsbuf[0:i]
+ l := copy(p.wsbuf, p.wsbuf[n:])
+ p.wsbuf = p.wsbuf[:l]
}
// ----------------------------------------------------------------------------
@@ -790,6 +842,17 @@ func (p *printer) print(args ...interface{}) {
var isLit bool
var impliedSemi bool // value for p.impliedSemi after this arg
+ // record previous opening token, if any
+ switch p.lastTok {
+ case token.ILLEGAL:
+ // ignore (white space)
+ case token.LPAREN, token.LBRACK:
+ p.prevOpen = p.lastTok
+ default:
+ // other tokens followed any opening token
+ p.prevOpen = token.ILLEGAL
+ }
+
switch x := arg.(type) {
case pmode:
// toggle printer mode
@@ -899,19 +962,17 @@ func (p *printer) print(args ...interface{}) {
}
}
+ // the next token starts now - record its line number if requested
+ if p.linePtr != nil {
+ *p.linePtr = p.out.Line
+ p.linePtr = nil
+ }
+
p.writeString(next, data, isLit)
p.impliedSemi = impliedSemi
}
}
-// commentBefore returns true iff the current comment group occurs
-// before the next position in the source code and printing it does
-// not introduce implicit semicolons.
-//
-func (p *printer) commentBefore(next token.Position) (result bool) {
- return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
-}
-
// flush prints any pending comments and whitespace occurring textually
// before the position of the next token tok. The flush result indicates
// if a newline was written or if a formfeed was dropped from the whitespace
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index 8454ac12b..306928a69 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -63,7 +63,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
return nil, fmt.Errorf("print: %s", err)
}
- // make sure formated output is syntactically correct
+ // make sure formatted output is syntactically correct
res := buf.Bytes()
if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
@@ -179,7 +179,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
// test running past time out
t.Errorf("%s: running too slowly", source)
case <-cc:
- // test finished within alloted time margin
+ // test finished within allotted time margin
}
}
@@ -212,7 +212,7 @@ func TestFiles(t *testing.T) {
}
}
-// TestLineComments, using a simple test case, checks that consequtive line
+// TestLineComments, using a simple test case, checks that consecutive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
//
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index 610a42a68..b1af7958a 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -494,16 +494,21 @@ func _() {
func _( /* this */ x /* is */ /* an */ int) {
}
-func _( /* no params */) {}
+func _( /* no params - extra blank before and after comment */ ) {}
+func _(a, b int /* params - no extra blank after comment */) {}
+
+func _() { f( /* no args - extra blank before and after comment */ ) }
+func _() { f(a, b /* args - no extra blank after comment */) }
func _() {
- f( /* no args */)
+ f( /* no args - extra blank before and after comment */ )
+ f(a, b /* args - no extra blank after comment */)
}
func ( /* comment1 */ T /* comment2 */) _() {}
-func _() { /* one-line functions with comments are formatted as multi-line functions */
-}
+func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _() { x := 0; /* comment */ y = x /* comment */ }
func _() {
_ = 0
diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
index d121dd4be..983e2b2c9 100644
--- a/src/pkg/go/printer/testdata/comments.input
+++ b/src/pkg/go/printer/testdata/comments.input
@@ -500,15 +500,21 @@ func _() {
func _(/* this */x/* is *//* an */ int) {
}
-func _(/* no params */) {}
+func _(/* no params - extra blank before and after comment */) {}
+func _(a, b int /* params - no extra blank after comment */) {}
+
+func _() { f(/* no args - extra blank before and after comment */) }
+func _() { f(a, b /* args - no extra blank after comment */) }
func _() {
- f(/* no args */)
+ f(/* no args - extra blank before and after comment */)
+ f(a, b /* args - no extra blank after comment */)
}
func (/* comment1 */ T /* comment2 */) _() {}
-func _() { /* one-line functions with comments are formatted as multi-line functions */ }
+func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _() { x := 0; /* comment */ y = x /* comment */ }
func _() {
_ = 0
diff --git a/src/pkg/go/printer/testdata/comments2.golden b/src/pkg/go/printer/testdata/comments2.golden
index d3b50bf3e..7676a26c1 100644
--- a/src/pkg/go/printer/testdata/comments2.golden
+++ b/src/pkg/go/printer/testdata/comments2.golden
@@ -77,3 +77,29 @@ func main() {
println("test")
}
}
+
+func issue5623() {
+L:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LLLLLLL:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LL:
+LLLLL:
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+
+ // test case from issue
+label:
+ mask := uint64(1)<<c - 1 // Allocation mask
+ used := atomic.LoadUint64(&h.used) // Current allocations
+}
diff --git a/src/pkg/go/printer/testdata/comments2.input b/src/pkg/go/printer/testdata/comments2.input
index 6f8c85c94..4a055c827 100644
--- a/src/pkg/go/printer/testdata/comments2.input
+++ b/src/pkg/go/printer/testdata/comments2.input
@@ -76,4 +76,30 @@ prints test 5 times
for i := 0; i < 5; i++ {
println("test")
}
-} \ No newline at end of file
+}
+
+func issue5623() {
+L:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LLLLLLL:
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LL:
+LLLLL:
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+ _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+
+ _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+ _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+
+// test case from issue
+label:
+ mask := uint64(1)<<c - 1 // Allocation mask
+ used := atomic.LoadUint64(&h.used) // Current allocations
+}
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 0331615e5..a27f21fc8 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -397,6 +397,21 @@ func _() {
}
}
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+ short = 2 * (1 + 2)
+ aMuchLongerName = 3
+)
+
+var (
+ short = X{}
+ aMuchLongerName = X{}
+
+ x1 = X{} // foo
+ x2 = X{} // foo
+)
+
func _() {
type (
xxxxxx int
@@ -723,7 +738,8 @@ func _() int {
}
// making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */
+func _() { /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */
}
func _() {
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index dbdbdfe74..d9951d386 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -409,6 +409,24 @@ func _() {
}
}
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+ short = 2 * (
+ 1 + 2)
+ aMuchLongerName = 3
+)
+
+var (
+ short = X{
+ }
+ aMuchLongerName = X{}
+
+ x1 = X{} // foo
+ x2 = X{
+ } // foo
+)
+
func _() {
type (
xxxxxx int
@@ -737,7 +755,8 @@ func _() int {
// making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */ }
+func _() { /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ }
func _() {
/* multi-line func because block is on multiple lines */ }
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 1e259d5ed..cec82ea10 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -148,11 +148,14 @@ func (s *Scanner) interpretLineComment(text []byte) {
// get filename and line number, if any
if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
- // valid //line filename:line comment;
- filename := filepath.Clean(string(text[len(prefix):i]))
- if !filepath.IsAbs(filename) {
- // make filename relative to current directory
- filename = filepath.Join(s.dir, filename)
+ // valid //line filename:line comment
+ filename := string(bytes.TrimSpace(text[len(prefix):i]))
+ if filename != "" {
+ filename = filepath.Clean(filename)
+ if !filepath.IsAbs(filename) {
+ // make filename relative to current directory
+ filename = filepath.Join(s.dir, filename)
+ }
}
// update scanner position
s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
@@ -358,73 +361,94 @@ exit:
return tok, string(s.src[offs:s.offset])
}
-func (s *Scanner) scanEscape(quote rune) {
+// scanEscape parses an escape sequence where rune is the accepted
+// escaped quote. In case of a syntax error, it stops at the offending
+// character (without consuming it) and returns false. Otherwise
+// it returns true.
+func (s *Scanner) scanEscape(quote rune) bool {
offs := s.offset
- var i, base, max uint32
+ var n int
+ var base, max uint32
switch s.ch {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
s.next()
- return
+ return true
case '0', '1', '2', '3', '4', '5', '6', '7':
- i, base, max = 3, 8, 255
+ n, base, max = 3, 8, 255
case 'x':
s.next()
- i, base, max = 2, 16, 255
+ n, base, max = 2, 16, 255
case 'u':
s.next()
- i, base, max = 4, 16, unicode.MaxRune
+ n, base, max = 4, 16, unicode.MaxRune
case 'U':
s.next()
- i, base, max = 8, 16, unicode.MaxRune
+ n, base, max = 8, 16, unicode.MaxRune
default:
- s.next() // always make progress
- s.error(offs, "unknown escape sequence")
- return
+ msg := "unknown escape sequence"
+ if s.ch < 0 {
+ msg = "escape sequence not terminated"
+ }
+ s.error(offs, msg)
+ return false
}
var x uint32
- for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+ for n > 0 {
d := uint32(digitVal(s.ch))
if d >= base {
- s.error(s.offset, "illegal character in escape sequence")
- break
+ msg := fmt.Sprintf("illegal character %#U in escape sequence", s.ch)
+ if s.ch < 0 {
+ msg = "escape sequence not terminated"
+ }
+ s.error(s.offset, msg)
+ return false
}
x = x*base + d
s.next()
+ n--
}
- // in case of an error, consume remaining chars
- for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
- s.next()
- }
+
if x > max || 0xD800 <= x && x < 0xE000 {
s.error(offs, "escape sequence is invalid Unicode code point")
+ return false
}
+
+ return true
}
-func (s *Scanner) scanChar() string {
+func (s *Scanner) scanRune() string {
// '\'' opening already consumed
offs := s.offset - 1
+ valid := true
n := 0
- for s.ch != '\'' {
+ for {
ch := s.ch
- n++
- s.next()
if ch == '\n' || ch < 0 {
- s.error(offs, "character literal not terminated")
- n = 1
+ // only report error if we don't have one already
+ if valid {
+ s.error(offs, "rune literal not terminated")
+ valid = false
+ }
break
}
+ s.next()
+ if ch == '\'' {
+ break
+ }
+ n++
if ch == '\\' {
- s.scanEscape('\'')
+ if !s.scanEscape('\'') {
+ valid = false
+ }
+ // continue to read to closing quote
}
}
- s.next()
-
- if n != 1 {
- s.error(offs, "illegal character literal")
+ if valid && n != 1 {
+ s.error(offs, "illegal rune literal")
}
return string(s.src[offs:s.offset])
@@ -434,11 +458,14 @@ func (s *Scanner) scanString() string {
// '"' opening already consumed
offs := s.offset - 1
- for s.ch != '"' {
+ for {
ch := s.ch
- s.next()
if ch == '\n' || ch < 0 {
- s.error(offs, "string not terminated")
+ s.error(offs, "string literal not terminated")
+ break
+ }
+ s.next()
+ if ch == '"' {
break
}
if ch == '\\' {
@@ -446,8 +473,6 @@ func (s *Scanner) scanString() string {
}
}
- s.next()
-
return string(s.src[offs:s.offset])
}
@@ -468,20 +493,21 @@ func (s *Scanner) scanRawString() string {
offs := s.offset - 1
hasCR := false
- for s.ch != '`' {
+ for {
ch := s.ch
+ if ch < 0 {
+ s.error(offs, "raw string literal not terminated")
+ break
+ }
s.next()
+ if ch == '`' {
+ break
+ }
if ch == '\r' {
hasCR = true
}
- if ch < 0 {
- s.error(offs, "string not terminated")
- break
- }
}
- s.next()
-
lit := s.src[offs:s.offset]
if hasCR {
lit = stripCR(lit)
@@ -617,7 +643,7 @@ scanAgain:
case '\'':
insertSemi = true
tok = token.CHAR
- lit = s.scanChar()
+ lit = s.scanRune()
case '`':
insertSemi = true
tok = token.STRING
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 8c64c2b95..fc450d8a6 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -493,9 +493,9 @@ var segments = []segment{
{"\nline3 //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
{"\nline4", filepath.Join("dir", "TestLineComments"), 4},
{"\n//line File1.go:100\n line100", filepath.Join("dir", "File1.go"), 100},
+ {"\n//line \t :42\n line1", "", 42},
{"\n//line File2.go:200\n line200", filepath.Join("dir", "File2.go"), 200},
- {"\n//line :1\n line1", "dir", 1},
- {"\n//line foo:42\n line42", filepath.Join("dir", "foo"), 42},
+ {"\n//line foo\t:42\n line42", filepath.Join("dir", "foo"), 42},
{"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored
{"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored
{"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
@@ -631,7 +631,7 @@ type errorCollector struct {
pos token.Position // last error position encountered
}
-func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+func checkError(t *testing.T, src string, tok token.Token, pos int, lit, err string) {
var s Scanner
var h errorCollector
eh := func(pos token.Position, msg string) {
@@ -640,13 +640,12 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
h.pos = pos
}
s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), eh, ScanComments|dontInsertSemis)
- _, tok0, _ := s.Scan()
- _, tok1, _ := s.Scan()
+ _, tok0, lit0 := s.Scan()
if tok0 != tok {
t.Errorf("%q: got %s, expected %s", src, tok0, tok)
}
- if tok1 != token.EOF {
- t.Errorf("%q: got %s, expected EOF", src, tok1)
+ if tok0 != token.ILLEGAL && lit0 != lit {
+ t.Errorf("%q: got literal %q, expected %q", src, lit0, lit)
}
cnt := 0
if err != "" {
@@ -667,43 +666,71 @@ var errors = []struct {
src string
tok token.Token
pos int
+ lit string
err string
}{
- {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
- {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
- {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
- {`' '`, token.CHAR, 0, ""},
- {`''`, token.CHAR, 0, "illegal character literal"},
- {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
- {`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
- {`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
- {`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
- {`'`, token.CHAR, 0, "character literal not terminated"},
- {`""`, token.STRING, 0, ""},
- {`"`, token.STRING, 0, "string not terminated"},
- {"``", token.STRING, 0, ""},
- {"`", token.STRING, 0, "string not terminated"},
- {"/**/", token.COMMENT, 0, ""},
- {"/*", token.COMMENT, 0, "comment not terminated"},
- {"077", token.INT, 0, ""},
- {"078.", token.FLOAT, 0, ""},
- {"07801234567.", token.FLOAT, 0, ""},
- {"078e0", token.FLOAT, 0, ""},
- {"078", token.INT, 0, "illegal octal number"},
- {"07800000009", token.INT, 0, "illegal octal number"},
- {"0x", token.INT, 0, "illegal hexadecimal number"},
- {"0X", token.INT, 0, "illegal hexadecimal number"},
- {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
- {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
- {"\ufeff\ufeff", token.ILLEGAL, 3, "illegal byte order mark"}, // only first BOM is ignored
- {"//\ufeff", token.COMMENT, 2, "illegal byte order mark"}, // only first BOM is ignored
- {"'\ufeff" + `'`, token.CHAR, 1, "illegal byte order mark"}, // only first BOM is ignored
- {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, "illegal byte order mark"}, // only first BOM is ignored
+ {"\a", token.ILLEGAL, 0, "", "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "", "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "", "illegal character U+2026 '…'"},
+ {`' '`, token.CHAR, 0, `' '`, ""},
+ {`''`, token.CHAR, 0, `''`, "illegal rune literal"},
+ {`'12'`, token.CHAR, 0, `'12'`, "illegal rune literal"},
+ {`'123'`, token.CHAR, 0, `'123'`, "illegal rune literal"},
+ {`'\0'`, token.CHAR, 3, `'\0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\07'`, token.CHAR, 4, `'\07'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\8'`, token.CHAR, 2, `'\8'`, "unknown escape sequence"},
+ {`'\08'`, token.CHAR, 3, `'\08'`, "illegal character U+0038 '8' in escape sequence"},
+ {`'\x'`, token.CHAR, 3, `'\x'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\x0'`, token.CHAR, 4, `'\x0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\x0g'`, token.CHAR, 4, `'\x0g'`, "illegal character U+0067 'g' in escape sequence"},
+ {`'\u'`, token.CHAR, 3, `'\u'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u0'`, token.CHAR, 4, `'\u0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u00'`, token.CHAR, 5, `'\u00'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u000'`, token.CHAR, 6, `'\u000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\u000`, token.CHAR, 6, `'\u000`, "escape sequence not terminated"},
+ {`'\u0000'`, token.CHAR, 0, `'\u0000'`, ""},
+ {`'\U'`, token.CHAR, 3, `'\U'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0'`, token.CHAR, 4, `'\U0'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U00'`, token.CHAR, 5, `'\U00'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U000'`, token.CHAR, 6, `'\U000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000'`, token.CHAR, 7, `'\U0000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U00000'`, token.CHAR, 8, `'\U00000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U000000'`, token.CHAR, 9, `'\U000000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000000'`, token.CHAR, 10, `'\U0000000'`, "illegal character U+0027 ''' in escape sequence"},
+ {`'\U0000000`, token.CHAR, 10, `'\U0000000`, "escape sequence not terminated"},
+ {`'\U00000000'`, token.CHAR, 0, `'\U00000000'`, ""},
+ {`'\Uffffffff'`, token.CHAR, 2, `'\Uffffffff'`, "escape sequence is invalid Unicode code point"},
+ {`'`, token.CHAR, 0, `'`, "rune literal not terminated"},
+ {`'\`, token.CHAR, 2, `'\`, "escape sequence not terminated"},
+ {"'\n", token.CHAR, 0, "'", "rune literal not terminated"},
+ {"'\n ", token.CHAR, 0, "'", "rune literal not terminated"},
+ {`""`, token.STRING, 0, `""`, ""},
+ {`"abc`, token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"\"abc\n", token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"\"abc\n ", token.STRING, 0, `"abc`, "string literal not terminated"},
+ {"``", token.STRING, 0, "``", ""},
+ {"`", token.STRING, 0, "`", "raw string literal not terminated"},
+ {"/**/", token.COMMENT, 0, "/**/", ""},
+ {"/*", token.COMMENT, 0, "/*", "comment not terminated"},
+ {"077", token.INT, 0, "077", ""},
+ {"078.", token.FLOAT, 0, "078.", ""},
+ {"07801234567.", token.FLOAT, 0, "07801234567.", ""},
+ {"078e0", token.FLOAT, 0, "078e0", ""},
+ {"078", token.INT, 0, "078", "illegal octal number"},
+ {"07800000009", token.INT, 0, "07800000009", "illegal octal number"},
+ {"0x", token.INT, 0, "0x", "illegal hexadecimal number"},
+ {"0X", token.INT, 0, "0X", "illegal hexadecimal number"},
+ {"\"abc\x00def\"", token.STRING, 4, "\"abc\x00def\"", "illegal character NUL"},
+ {"\"abc\x80def\"", token.STRING, 4, "\"abc\x80def\"", "illegal UTF-8 encoding"},
+ {"\ufeff\ufeff", token.ILLEGAL, 3, "\ufeff\ufeff", "illegal byte order mark"}, // only first BOM is ignored
+ {"//\ufeff", token.COMMENT, 2, "//\ufeff", "illegal byte order mark"}, // only first BOM is ignored
+ {"'\ufeff" + `'`, token.CHAR, 1, "'\ufeff" + `'`, "illegal byte order mark"}, // only first BOM is ignored
+ {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, `"` + "abc\ufeffdef" + `"`, "illegal byte order mark"}, // only first BOM is ignored
}
func TestScanErrors(t *testing.T) {
for _, e := range errors {
- checkError(t, e.src, e.tok, e.pos, e.err)
+ checkError(t, e.src, e.tok, e.pos, e.lit, e.err)
}
}
diff --git a/src/pkg/hash/crc32/crc32_amd64p32.s b/src/pkg/hash/crc32/crc32_amd64p32.s
new file mode 100644
index 000000000..e34f20867
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64p32.s
@@ -0,0 +1,64 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),NOSPLIT,$0
+ MOVL crc+0(FP), AX // CRC value
+ MOVL p+4(FP), SI // data pointer
+ MOVL p_len+8(FP), CX // len(p)
+
+ NOTL AX
+
+ /* If there's less than 8 bytes to process, we do it byte-by-byte. */
+ CMPQ CX, $8
+ JL cleanup
+
+ /* Process individual bytes until the input is 8-byte aligned. */
+startup:
+ MOVQ SI, BX
+ ANDQ $7, BX
+ JZ aligned
+
+ CRC32B (SI), AX
+ DECQ CX
+ INCQ SI
+ JMP startup
+
+aligned:
+ /* The input is now 8-byte aligned and we can process 8-byte chunks. */
+ CMPQ CX, $8
+ JL cleanup
+
+ CRC32Q (SI), AX
+ ADDQ $8, SI
+ SUBQ $8, CX
+ JMP aligned
+
+cleanup:
+ /* We may have some bytes left over that we process one at a time. */
+ CMPQ CX, $0
+ JE done
+
+ CRC32B (SI), AX
+ INCQ SI
+ DECQ CX
+ JMP cleanup
+
+done:
+ NOTL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),NOSPLIT,$0
+ XORQ AX, AX
+ INCL AX
+ CPUID
+ SHRQ $20, CX
+ ANDQ $1, CX
+ MOVB CX, ret+0(FP)
+ RET
+
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64x.go
index b5bc6d3cf..b7e359930 100644
--- a/src/pkg/hash/crc32/crc32_amd64.go
+++ b/src/pkg/hash/crc32/crc32_amd64x.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build amd64 amd64p32
+
package crc32
// This file contains the code to call the SSE 4.2 version of the Castagnoli
diff --git a/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
index b5ecd4a7c..c0206613a 100644
--- a/src/pkg/hash/fnv/fnv.go
+++ b/src/pkg/hash/fnv/fnv.go
@@ -4,7 +4,8 @@
// Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash functions
// created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
-// See http://isthe.com/chongo/tech/comp/fnv/.
+// See
+// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
package fnv
import (
diff --git a/src/pkg/html/escape_test.go b/src/pkg/html/escape_test.go
index b405d4b4a..2d7ad8ac2 100644
--- a/src/pkg/html/escape_test.go
+++ b/src/pkg/html/escape_test.go
@@ -64,6 +64,24 @@ var unescapeTests = []unescapeTest{
"Footnote&#x87;",
"Footnote‡",
},
+ // Handle single ampersand.
+ {
+ "copySingleAmpersand",
+ "&",
+ "&",
+ },
+ // Handle ampersand followed by non-entity.
+ {
+ "copyAmpersandNonEntity",
+ "text &test",
+ "text &test",
+ },
+ // Handle "&#".
+ {
+ "copyAmpersandHash",
+ "text &#",
+ "text &#",
+ },
}
func TestUnescape(t *testing.T) {
diff --git a/src/pkg/html/template/attr.go b/src/pkg/html/template/attr.go
index 3ea02880d..d65d34007 100644
--- a/src/pkg/html/template/attr.go
+++ b/src/pkg/html/template/attr.go
@@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{
"name": contentTypePlain,
"novalidate": contentTypeUnsafe,
// Skip handler names from
- // http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects
+ // http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
// since we have special handling in attrType.
"open": contentTypePlain,
"optimum": contentTypePlain,
@@ -160,7 +160,7 @@ func attrType(name string) contentType {
// Heuristics to prevent "javascript:..." injection in custom
// data attributes and custom attributes like g:tweetUrl.
- // http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes:
+ // http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
// "Custom data attributes are intended to store custom data
// private to the page or application, for which there are no
// more appropriate attributes or elements."
diff --git a/src/pkg/html/template/content.go b/src/pkg/html/template/content.go
index 41b1116a6..3715ed5c9 100644
--- a/src/pkg/html/template/content.go
+++ b/src/pkg/html/template/content.go
@@ -16,7 +16,8 @@ type (
// 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
// 3. CSS3 declaration productions, such as `color: red; margin: 2px`.
// 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
- // See http://www.w3.org/TR/css3-syntax/#style
+ // See http://www.w3.org/TR/css3-syntax/#parsing and
+ // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
CSS string
// HTML encapsulates a known safe HTML document fragment.
diff --git a/src/pkg/html/template/context.go b/src/pkg/html/template/context.go
index eb47e2be3..59e794d68 100644
--- a/src/pkg/html/template/context.go
+++ b/src/pkg/html/template/context.go
@@ -13,7 +13,7 @@ import (
//
// The zero value of type context is the start context for a template that
// produces an HTML fragment as defined at
-// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
+// http://www.w3.org/TR/html5/syntax.html#the-end
// where the context element is null.
type context struct {
state state
@@ -96,7 +96,7 @@ const (
// stateHTMLCmt occurs inside an <!-- HTML comment -->.
stateHTMLCmt
// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
- // as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
+ // as described at http://www.w3.org/TR/html5/syntax.html#elements-0
stateRCDATA
// stateAttr occurs inside an HTML attribute whose content is text.
stateAttr
diff --git a/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go
index 9ae9749db..4e379828d 100644
--- a/src/pkg/html/template/escape.go
+++ b/src/pkg/html/template/escape.go
@@ -40,10 +40,14 @@ func escapeTemplates(tmpl *Template, names ...string) error {
}
return err
}
- tmpl.escaped = true
- tmpl.Tree = tmpl.text.Tree
}
e.commit()
+ for _, name := range names {
+ if t := tmpl.set[name]; t != nil {
+ t.escaped = true
+ t.Tree = t.text.Tree
+ }
+ }
return nil
}
@@ -207,6 +211,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
return c
}
+// allIdents returns the names of the identifiers under the Ident field of the node,
+// which might be a singleton (Identifier) or a slice (Field).
+func allIdents(node parse.Node) []string {
+ switch node := node.(type) {
+ case *parse.IdentifierNode:
+ return []string{node.Ident}
+ case *parse.FieldNode:
+ return node.Ident
+ }
+ panic("unidentified node type in allIdents")
+}
+
// ensurePipelineContains ensures that the pipeline has commands with
// the identifiers in s in order.
// If the pipeline already has some of the sanitizers, do not interfere.
@@ -229,27 +245,31 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
idents = p.Cmds[i+1:]
}
dups := 0
- for _, id := range idents {
- if escFnsEq(s[dups], (id.Args[0].(*parse.IdentifierNode)).Ident) {
- dups++
- if dups == len(s) {
- return
+ for _, idNode := range idents {
+ for _, ident := range allIdents(idNode.Args[0]) {
+ if escFnsEq(s[dups], ident) {
+ dups++
+ if dups == len(s) {
+ return
+ }
}
}
}
newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)
copy(newCmds, p.Cmds)
// Merge existing identifier commands with the sanitizers needed.
- for _, id := range idents {
- pos := id.Args[0].Position()
- i := indexOfStr((id.Args[0].(*parse.IdentifierNode)).Ident, s, escFnsEq)
- if i != -1 {
- for _, name := range s[:i] {
- newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+ for _, idNode := range idents {
+ pos := idNode.Args[0].Position()
+ for _, ident := range allIdents(idNode.Args[0]) {
+ i := indexOfStr(ident, s, escFnsEq)
+ if i != -1 {
+ for _, name := range s[:i] {
+ newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+ }
+ s = s[i+1:]
}
- s = s[i+1:]
}
- newCmds = appendCmd(newCmds, id)
+ newCmds = appendCmd(newCmds, idNode)
}
// Create any remaining sanitizers.
for _, name := range s {
@@ -664,7 +684,7 @@ func contextAfterText(c context, s []byte) (context, int) {
i = len(s)
}
if c.delim == delimSpaceOrTagEnd {
- // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
+ // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
// lists the runes below as error characters.
// Error out because HTML parsers may differ on whether
// "<a id= onclick=f(" ends inside id's or onclick's value,
diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go
index 58383a6cd..3ccf93ece 100644
--- a/src/pkg/html/template/escape_test.go
+++ b/src/pkg/html/template/escape_test.go
@@ -1649,6 +1649,38 @@ func TestEmptyTemplate(t *testing.T) {
}
}
+type Issue7379 int
+
+func (Issue7379) SomeMethod(x int) string {
+ return fmt.Sprintf("<%d>", x)
+}
+
+// This is a test for issue 7379: type assertion error caused panic, and then
+// the code to handle the panic breaks escaping. It's hard to see the second
+// problem once the first is fixed, but its fix is trivial so we let that go. See
+// the discussion for issue 7379.
+func TestPipeToMethodIsEscaped(t *testing.T) {
+ tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n"))
+ tryExec := func() string {
+ defer func() {
+ panicValue := recover()
+ if panicValue != nil {
+ t.Errorf("panicked: %v\n", panicValue)
+ }
+ }()
+ var b bytes.Buffer
+ tmpl.Execute(&b, Issue7379(0))
+ return b.String()
+ }
+ for i := 0; i < 3; i++ {
+ str := tryExec()
+ const expect = "<html>&lt;0&gt;</html>\n"
+ if str != expect {
+ t.Errorf("expected %q got %q", expect, str)
+ }
+ }
+}
+
func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer
diff --git a/src/pkg/html/template/html.go b/src/pkg/html/template/html.go
index f25f1074c..9c069efd1 100644
--- a/src/pkg/html/template/html.go
+++ b/src/pkg/html/template/html.go
@@ -50,12 +50,12 @@ func htmlEscaper(args ...interface{}) string {
// htmlReplacementTable contains the runes that need to be escaped
// inside a quoted attribute value or in a text node.
var htmlReplacementTable = []string{
- // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state: "
+ // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
// U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT
// CHARACTER character to the current attribute's value.
// "
// and similarly
- // http://www.w3.org/TR/html5/tokenization.html#before-attribute-value-state
+ // http://www.w3.org/TR/html5/syntax.html#before-attribute-value-state
0: "\uFFFD",
'"': "&#34;",
'&': "&amp;",
diff --git a/src/pkg/html/template/js.go b/src/pkg/html/template/js.go
index d594e0ad7..999a61ed0 100644
--- a/src/pkg/html/template/js.go
+++ b/src/pkg/html/template/js.go
@@ -99,7 +99,7 @@ func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
return jsCtxDivOp
}
-// regexPrecederKeywords is a set of reserved JS keywords that can precede a
+// regexpPrecederKeywords is a set of reserved JS keywords that can precede a
// regular expression in JS source.
var regexpPrecederKeywords = map[string]bool{
"break": true,
diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
index 11cc34a50..d38965897 100644
--- a/src/pkg/html/template/template.go
+++ b/src/pkg/html/template/template.go
@@ -62,6 +62,10 @@ func (t *Template) escape() error {
// Execute applies a parsed template to the specified data object,
// writing the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
if err := t.escape(); err != nil {
return err
@@ -71,6 +75,10 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
// ExecuteTemplate applies the template associated with t that has the given
// name to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
tmpl, err := t.lookupAndEscapeTemplate(name)
if err != nil {
diff --git a/src/pkg/image/color/palette/gen.go b/src/pkg/image/color/palette/gen.go
index f20c021de..4f4d88345 100644
--- a/src/pkg/image/color/palette/gen.go
+++ b/src/pkg/image/color/palette/gen.go
@@ -14,6 +14,10 @@ import (
)
func main() {
+ fmt.Println(`// 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.`)
+ fmt.Println()
fmt.Println("// generated by go run gen.go; DO NOT EDIT")
fmt.Println()
fmt.Println("// Package palette provides standard color palettes.")
diff --git a/src/pkg/image/color/palette/palette.go b/src/pkg/image/color/palette/palette.go
index 3aba7401d..f761e5368 100644
--- a/src/pkg/image/color/palette/palette.go
+++ b/src/pkg/image/color/palette/palette.go
@@ -1,3 +1,7 @@
+// 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.
+
// generated by go run gen.go; DO NOT EDIT
// Package palette provides standard color palettes.
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 8b0298a29..926710a45 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -79,7 +79,8 @@ type decoder struct {
imageFields byte
// From graphics control.
- transparentIndex byte
+ transparentIndex byte
+ hasTransparentIndex bool
// Computed.
pixelSize uint
@@ -175,11 +176,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
if err != nil {
return err
}
- // TODO: do we set transparency in this map too? That would be
- // d.setTransparency(m.Palette)
} else {
m.Palette = d.globalColorMap
}
+ if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+ m.Palette[d.transparentIndex] = color.RGBA{}
+ }
litWidth, err := d.r.ReadByte()
if err != nil {
return err
@@ -228,7 +230,11 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
d.image = append(d.image, m)
d.delay = append(d.delay, d.delayTime)
- d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
+ // The GIF89a spec, Section 23 (Graphic Control Extension) says:
+ // "The scope of this extension is the first graphic rendering block
+ // to follow." We therefore reset the GCE fields to zero.
+ d.delayTime = 0
+ d.hasTransparentIndex = false
case sTrailer:
if len(d.image) == 0 {
@@ -339,17 +345,11 @@ func (d *decoder) readGraphicControl() error {
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
if d.flags&gcTransparentColorSet != 0 {
d.transparentIndex = d.tmp[4]
- d.setTransparency(d.globalColorMap)
+ d.hasTransparentIndex = true
}
return nil
}
-func (d *decoder) setTransparency(colorMap color.Palette) {
- if int(d.transparentIndex) < len(colorMap) {
- colorMap[d.transparentIndex] = color.RGBA{}
- }
-}
-
func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
diff --git a/src/pkg/image/gif/reader_test.go b/src/pkg/image/gif/reader_test.go
index 09867132d..fc2041e99 100644
--- a/src/pkg/image/gif/reader_test.go
+++ b/src/pkg/image/gif/reader_test.go
@@ -1,3 +1,7 @@
+// 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 gif
import (
diff --git a/src/pkg/image/jpeg/huffman.go b/src/pkg/image/jpeg/huffman.go
index 9b731fdc4..f53d873a5 100644
--- a/src/pkg/image/jpeg/huffman.go
+++ b/src/pkg/image/jpeg/huffman.go
@@ -37,6 +37,9 @@ func (d *decoder) ensureNBits(n int) error {
for d.b.n < n {
c, err := d.r.ReadByte()
if err != nil {
+ if err == io.EOF {
+ return FormatError("short Huffman data")
+ }
return err
}
d.b.a = d.b.a<<8 | uint32(c)
@@ -50,6 +53,9 @@ func (d *decoder) ensureNBits(n int) error {
if c == 0xff {
c, err = d.r.ReadByte()
if err != nil {
+ if err == io.EOF {
+ return FormatError("short Huffman data")
+ }
return err
}
if c != 0x00 {
diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go
index e951e038c..926bb0434 100644
--- a/src/pkg/image/jpeg/reader_test.go
+++ b/src/pkg/image/jpeg/reader_test.go
@@ -28,6 +28,7 @@ func TestDecodeProgressive(t *testing.T) {
"../testdata/video-001.q50.444",
"../testdata/video-005.gray.q50",
"../testdata/video-005.gray.q50.2x2",
+ "../testdata/video-001.separate.dc.progression",
}
for _, tc := range testCases {
m0, err := decodeFile(tc + ".jpeg")
@@ -44,6 +45,12 @@ func TestDecodeProgressive(t *testing.T) {
t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
continue
}
+ // All of the video-*.jpeg files are 150x103.
+ if m0.Bounds() != image.Rect(0, 0, 150, 103) {
+ t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
+ continue
+ }
+
switch m0 := m0.(type) {
case *image.YCbCr:
m1 := m1.(*image.YCbCr)
@@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) {
// check checks that the two pix data are equal, within the given bounds.
func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error {
- if len(pix0) != len(pix1) {
- return fmt.Errorf("len(pix) %d and %d differ", len(pix0), len(pix1))
- }
- if stride0 != stride1 {
- return fmt.Errorf("strides %d and %d differ", stride0, stride1)
+ if stride0 <= 0 || stride0%8 != 0 {
+ return fmt.Errorf("bad stride %d", stride0)
}
- if stride0%8 != 0 {
- return fmt.Errorf("stride %d is not a multiple of 8", stride0)
+ if stride1 <= 0 || stride1%8 != 0 {
+ return fmt.Errorf("bad stride %d", stride1)
}
// Compare the two pix data, one 8x8 block at a time.
- for y := 0; y < len(pix0)/stride0; y += 8 {
- for x := 0; x < stride0; x += 8 {
+ for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
+ for x := 0; x < stride0 && x < stride1; x += 8 {
if x >= bounds.Max.X || y >= bounds.Max.Y {
// We don't care if the two pix data differ if the 8x8 block is
// entirely outside of the image's bounds. For example, this can
@@ -108,8 +112,9 @@ func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) erro
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
- index := (y+j)*stride0 + (x + i)
- if pix0[index] != pix1[index] {
+ index0 := (y+j)*stride0 + (x + i)
+ index1 := (y+j)*stride1 + (x + i)
+ if pix0[index0] != pix1[index1] {
return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
pixString(pix0, stride0, x, y),
pixString(pix1, stride1, x, y),
diff --git a/src/pkg/image/jpeg/scan.go b/src/pkg/image/jpeg/scan.go
index a69ed1748..559235d51 100644
--- a/src/pkg/image/jpeg/scan.go
+++ b/src/pkg/image/jpeg/scan.go
@@ -141,25 +141,30 @@ func (d *decoder) processSOS(n int) error {
for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ {
// The blocks are traversed one MCU at a time. For 4:2:0 chroma
// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
+ //
// For a baseline 32x16 pixel image, the Y blocks visiting order is:
// 0 1 4 5
// 2 3 6 7
//
- // For progressive images, the DC data blocks (zigStart == 0) are traversed
- // as above, but AC data blocks are traversed left to right, top to bottom:
+ // For progressive images, the interleaved scans (those with nComp > 1)
+ // are traversed as above, but non-interleaved scans are traversed left
+ // to right, top to bottom:
// 0 1 2 3
// 4 5 6 7
+ // Only DC scans (zigStart == 0) can be interleaved. AC scans must have
+ // only one component.
//
- // To further complicate matters, there is no AC data for any blocks that
- // are inside the image at the MCU level but outside the image at the pixel
- // level. For example, a 24x16 pixel 4:2:0 progressive image consists of
- // two 16x16 MCUs. The earlier scans will process 8 Y blocks:
+ // To further complicate matters, for non-interleaved scans, there is no
+ // data for any blocks that are inside the image at the MCU level but
+ // outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
+ // progressive image consists of two 16x16 MCUs. The interleaved scans
+ // will process 8 Y blocks:
// 0 1 4 5
// 2 3 6 7
- // The later scans will process only 6 Y blocks:
+ // The non-interleaved scans will process only 6 Y blocks:
// 0 1 2
// 3 4 5
- if zigStart == 0 {
+ if nComp != 1 {
mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
if h0 == 1 {
my0 += j
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index a6bf86ede..dfe299102 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -505,8 +505,14 @@ func (d *decoder) decode() (image.Image, error) {
}
// Check for EOF, to verify the zlib checksum.
- n, err := r.Read(pr[:1])
- if err != io.EOF {
+ n := 0
+ for i := 0; n == 0 && err == nil; i++ {
+ if i == 100 {
+ return nil, io.ErrNoProgress
+ }
+ n, err = r.Read(pr[:1])
+ }
+ if err != nil && err != io.EOF {
return nil, FormatError(err.Error())
}
if n != 0 || d.idatLength != 0 {
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg
new file mode 100644
index 000000000..107f0fa0c
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg
new file mode 100644
index 000000000..a1d493ef8
--- /dev/null
+++ b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg
Binary files differ
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index f7073ffc0..022fdb676 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -74,6 +74,7 @@ type Reader interface {
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
+// Write must not modify the slice data, even temporarily.
type Writer interface {
Write(p []byte) (n int, err error)
}
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
index bd7a82f17..57db1fbf0 100644
--- a/src/pkg/io/io_test.go
+++ b/src/pkg/io/io_test.go
@@ -281,6 +281,8 @@ func TestSectionReader_ReadAt(t *testing.T) {
{data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil},
{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil},
{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: EOF},
+ {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF},
+ {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF},
}
for i, tt := range tests {
r := strings.NewReader(tt.data)
@@ -319,3 +321,21 @@ func TestSectionReader_Seek(t *testing.T) {
t.Errorf("Read = %v, %v; want 0, EOF", n, err)
}
}
+
+func TestSectionReader_Size(t *testing.T) {
+ tests := []struct {
+ data string
+ want int64
+ }{
+ {"a long sample data, 1234567890", 30},
+ {"", 0},
+ }
+
+ for _, tt := range tests {
+ r := strings.NewReader(tt.data)
+ sr := NewSectionReader(r, 0, int64(len(tt.data)))
+ if got := sr.Size(); got != tt.want {
+ t.Errorf("Size = %v; want %v", got, tt.want)
+ }
+ }
+}
diff --git a/src/pkg/io/ioutil/blackhole.go b/src/pkg/io/ioutil/blackhole.go
deleted file mode 100644
index 101d2c121..000000000
--- a/src/pkg/io/ioutil/blackhole.go
+++ /dev/null
@@ -1,23 +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.
-
-package ioutil
-
-var blackHoleBuf = make(chan []byte, 1)
-
-func blackHole() []byte {
- select {
- case b := <-blackHoleBuf:
- return b
- default:
- }
- return make([]byte, 8192)
-}
-
-func blackHolePut(p []byte) {
- select {
- case blackHoleBuf <- p:
- default:
- }
-}
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index b2508b789..909a81563 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -10,6 +10,7 @@ import (
"io"
"os"
"sort"
+ "sync"
)
// readAll reads from r until an error or EOF and returns the data it read
@@ -136,14 +137,21 @@ func (devNull) WriteString(s string) (int, error) {
return len(s), nil
}
+var blackHolePool = sync.Pool{
+ New: func() interface{} {
+ b := make([]byte, 8192)
+ return &b
+ },
+}
+
func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
- buf := blackHole()
- defer blackHolePut(buf)
+ bufp := blackHolePool.Get().(*[]byte)
readSize := 0
for {
- readSize, err = r.Read(buf)
+ readSize, err = r.Read(*bufp)
n += int64(readSize)
if err != nil {
+ blackHolePool.Put(bufp)
if err == io.EOF {
return n, nil
}
diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go
index 2c7e816cf..e26cc53e9 100644
--- a/src/pkg/io/multi.go
+++ b/src/pkg/io/multi.go
@@ -26,9 +26,12 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
// MultiReader returns a Reader that's the logical concatenation of
// the provided input readers. They're read sequentially. Once all
-// inputs are drained, Read will return EOF.
+// inputs have returned EOF, Read will return EOF. If any of the readers
+// return a non-nil, non-EOF error, Read will return that error.
func MultiReader(readers ...Reader) Reader {
- return &multiReader{readers}
+ r := make([]Reader, len(readers))
+ copy(r, readers)
+ return &multiReader{r}
}
type multiWriter struct {
@@ -52,5 +55,7 @@ func (t *multiWriter) Write(p []byte) (n int, err error) {
// MultiWriter creates a writer that duplicates its writes to all the
// provided writers, similar to the Unix tee(1) command.
func MultiWriter(writers ...Writer) Writer {
- return &multiWriter{writers}
+ w := make([]Writer, len(writers))
+ copy(w, writers)
+ return &multiWriter{w}
}
diff --git a/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go
index eb717f7bc..56c6769a9 100644
--- a/src/pkg/io/multi_test.go
+++ b/src/pkg/io/multi_test.go
@@ -9,6 +9,7 @@ import (
"crypto/sha1"
"fmt"
. "io"
+ "io/ioutil"
"strings"
"testing"
)
@@ -86,3 +87,29 @@ func TestMultiWriter(t *testing.T) {
t.Errorf("expected %q; got %q", sourceString, sink.String())
}
}
+
+// Test that MultiReader copies the input slice and is insulated from future modification.
+func TestMultiReaderCopy(t *testing.T) {
+ slice := []Reader{strings.NewReader("hello world")}
+ r := MultiReader(slice...)
+ slice[0] = nil
+ data, err := ioutil.ReadAll(r)
+ if err != nil || string(data) != "hello world" {
+ t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world")
+ }
+}
+
+// Test that MultiWriter copies the input slice and is insulated from future modification.
+func TestMultiWriterCopy(t *testing.T) {
+ var buf bytes.Buffer
+ slice := []Writer{&buf}
+ w := MultiWriter(slice...)
+ slice[0] = nil
+ n, err := w.Write([]byte("hello world"))
+ if err != nil || n != 11 {
+ t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err)
+ }
+ if buf.String() != "hello world" {
+ t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world")
+ }
+}
diff --git a/src/pkg/log/example_test.go b/src/pkg/log/example_test.go
new file mode 100644
index 000000000..74385a3a0
--- /dev/null
+++ b/src/pkg/log/example_test.go
@@ -0,0 +1,21 @@
+// 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 log_test
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+)
+
+func ExampleLogger() {
+ var buf bytes.Buffer
+ logger := log.New(&buf, "logger: ", log.Lshortfile)
+ logger.Print("Hello, log file!")
+
+ fmt.Print(&buf)
+ // Output:
+ // logger: example_test.go:16: Hello, log file!
+}
diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index 0cbfa9011..5e0959916 100644
--- a/src/pkg/log/syslog/syslog.go
+++ b/src/pkg/log/syslog/syslog.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
// Package syslog provides a simple interface to the system log
// service. It can send messages to the syslog daemon using UNIX
@@ -115,9 +115,10 @@ func New(priority Priority, tag string) (w *Writer, err error) {
}
// Dial establishes a connection to a log daemon by connecting to
-// address raddr on the network net. Each write to the returned
+// address raddr on the specified network. Each write to the returned
// writer sends a log message with the given facility, severity and
// tag.
+// If network is empty, Dial will connect to the local syslog server.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
return nil, errors.New("log/syslog: invalid priority")
diff --git a/src/pkg/log/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 760a5c7d1..24a460f6d 100644
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
package syslog
diff --git a/src/pkg/log/syslog/syslog_unix.go b/src/pkg/log/syslog/syslog_unix.go
index 28a294af9..f6d2f1b7a 100644
--- a/src/pkg/log/syslog/syslog_unix.go
+++ b/src/pkg/log/syslog/syslog_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
package syslog
diff --git a/include/plan9/ureg_arm.h b/src/pkg/math/abs_amd64p32.s
index f83c19a2f..08c8c6b33 100644
--- a/include/plan9/ureg_arm.h
+++ b/src/pkg/math/abs_amd64p32.s
@@ -1,5 +1,5 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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 "/arm/include/ureg.h"
+#include "abs_amd64.s"
diff --git a/src/pkg/math/asin_amd64p32.s b/src/pkg/math/asin_amd64p32.s
new file mode 100644
index 000000000..2751c475f
--- /dev/null
+++ b/src/pkg/math/asin_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "asin_amd64.s"
diff --git a/src/pkg/math/atan2_amd64p32.s b/src/pkg/math/atan2_amd64p32.s
new file mode 100644
index 000000000..3fdc03ca8
--- /dev/null
+++ b/src/pkg/math/atan2_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "atan2_amd64.s"
diff --git a/src/pkg/math/atan_amd64p32.s b/src/pkg/math/atan_amd64p32.s
new file mode 100644
index 000000000..1c1f6ceda
--- /dev/null
+++ b/src/pkg/math/atan_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "atan_amd64.s"
diff --git a/src/pkg/math/big/arith.go b/src/pkg/math/big/arith.go
index f316806d7..3d5a8682d 100644
--- a/src/pkg/math/big/arith.go
+++ b/src/pkg/math/big/arith.go
@@ -131,12 +131,11 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
q1 := un32 / vn1
rhat := un32 - q1*vn1
-again1:
- if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+ for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
q1--
rhat += vn1
- if rhat < _B2 {
- goto again1
+ if rhat >= _B2 {
+ break
}
}
@@ -144,12 +143,11 @@ again1:
q0 := un21 / vn1
rhat = un21 - q0*vn1
-again2:
- if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+ for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
q0--
rhat += vn1
- if rhat < _B2 {
- goto again2
+ if rhat >= _B2 {
+ break
}
}
diff --git a/src/pkg/math/big/arith_amd64p32.s b/src/pkg/math/big/arith_amd64p32.s
new file mode 100644
index 000000000..227870a00
--- /dev/null
+++ b/src/pkg/math/big/arith_amd64p32.s
@@ -0,0 +1,41 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+ JMP ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+ JMP ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+ JMP ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+ JMP ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+ JMP ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+ JMP ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+ JMP ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+ JMP ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+ JMP ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+ JMP ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+ JMP ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+ JMP ·bitLen_g(SB)
diff --git a/src/pkg/math/big/arith_arm.s b/src/pkg/math/big/arith_arm.s
index ecf55b344..8d36761c4 100644
--- a/src/pkg/math/big/arith_arm.s
+++ b/src/pkg/math/big/arith_arm.s
@@ -7,31 +7,26 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
-#define CFLAG 29 // bit position of carry flag
-
// func addVV(z, x, y []Word) (c Word)
TEXT ·addVV(SB),NOSPLIT,$0
- MOVW $0, R0
+ ADD.S $0, R0 // clear carry flag
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
+ ADD R4<<2, R1, R4
B E1
L1:
MOVW.P 4(R2), R5
MOVW.P 4(R3), R6
- MOVW R0, CPSR
ADC.S R6, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E1:
- CMP R1, R4
+ TEQ R1, R4
BNE L1
- MOVW R0>>CFLAG, R0
- AND $1, R0
+ MOVW $0, R0
+ MOVW.CS $1, R0
MOVW R0, c+36(FP)
RET
@@ -39,28 +34,24 @@ E1:
// func subVV(z, x, y []Word) (c Word)
// (same as addVV except for SBC instead of ADC and label names)
TEXT ·subVV(SB),NOSPLIT,$0
- MOVW $(1<<CFLAG), R0
+ SUB.S $0, R0 // clear borrow flag
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
+ ADD R4<<2, R1, R4
B E2
L2:
MOVW.P 4(R2), R5
MOVW.P 4(R3), R6
- MOVW R0, CPSR
SBC.S R6, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E2:
- CMP R1, R4
+ TEQ R1, R4
BNE L2
- MOVW R0>>CFLAG, R0
- AND $1, R0
- EOR $1, R0
+ MOVW $0, R0
+ MOVW.CC $1, R0
MOVW R0, c+36(FP)
RET
@@ -68,12 +59,11 @@ E2:
// func addVW(z, x []Word, y Word) (c Word)
TEXT ·addVW(SB),NOSPLIT,$0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
- CMP R1, R4
+ ADD R4<<2, R1, R4
+ TEQ R1, R4
BNE L3a
MOVW R3, c+28(FP)
RET
@@ -81,20 +71,17 @@ L3a:
MOVW.P 4(R2), R5
ADD.S R3, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
B E3
L3:
MOVW.P 4(R2), R5
- MOVW R0, CPSR
ADC.S $0, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E3:
- CMP R1, R4
+ TEQ R1, R4
BNE L3
- MOVW R0>>CFLAG, R0
- AND $1, R0
+ MOVW $0, R0
+ MOVW.CS $1, R0
MOVW R0, c+28(FP)
RET
@@ -102,12 +89,11 @@ E3:
// func subVW(z, x []Word, y Word) (c Word)
TEXT ·subVW(SB),NOSPLIT,$0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R4
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R4
- MOVW R4<<2, R4
- ADD R1, R4
- CMP R1, R4
+ ADD R4<<2, R1, R4
+ TEQ R1, R4
BNE L4a
MOVW R3, c+28(FP)
RET
@@ -115,21 +101,17 @@ L4a:
MOVW.P 4(R2), R5
SUB.S R3, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
B E4
L4:
MOVW.P 4(R2), R5
- MOVW R0, CPSR
SBC.S $0, R5
MOVW.P R5, 4(R1)
- MOVW CPSR, R0
E4:
- CMP R1, R4
+ TEQ R1, R4
BNE L4
- MOVW R0>>CFLAG, R0
- AND $1, R0
- EOR $1, R0
+ MOVW $0, R0
+ MOVW.CC $1, R0
MOVW R0, c+28(FP)
RET
@@ -137,16 +119,15 @@ E4:
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),NOSPLIT,$0
MOVW z_len+4(FP), R5
- CMP $0, R5
+ TEQ $0, R5
BEQ X7
MOVW z+0(FP), R1
MOVW x+12(FP), R2
- MOVW R5<<2, R5
- ADD R5, R2
- ADD R1, R5
+ ADD R5<<2, R2, R2
+ ADD R5<<2, R1, R5
MOVW s+24(FP), R3
- CMP $0, R3 // shift 0 is special
+ TEQ $0, R3 // shift 0 is special
BEQ Y7
ADD $4, R1 // stop one word early
MOVW $32, R4
@@ -165,7 +146,7 @@ L7:
MOVW.W R7, -4(R5)
MOVW R6<<R3, R7
E7:
- CMP R1, R5
+ TEQ R1, R5
BNE L7
MOVW R7, -4(R5)
@@ -174,7 +155,7 @@ E7:
Y7: // copy loop, because shift 0 == shift 32
MOVW.W -4(R2), R6
MOVW.W R6, -4(R5)
- CMP R1, R5
+ TEQ R1, R5
BNE Y7
X7:
@@ -186,15 +167,14 @@ X7:
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),NOSPLIT,$0
MOVW z_len+4(FP), R5
- CMP $0, R5
+ TEQ $0, R5
BEQ X6
MOVW z+0(FP), R1
MOVW x+12(FP), R2
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
MOVW s+24(FP), R3
- CMP $0, R3 // shift 0 is special
+ TEQ $0, R3 // shift 0 is special
BEQ Y6
SUB $4, R5 // stop one word early
MOVW $32, R4
@@ -215,7 +195,7 @@ L6:
MOVW.P R7, 4(R1)
MOVW R6>>R3, R7
E6:
- CMP R1, R5
+ TEQ R1, R5
BNE L6
MOVW R7, 0(R1)
@@ -224,7 +204,7 @@ E6:
Y6: // copy loop, because shift 0 == shift 32
MOVW.P 4(R2), R6
MOVW.P R6, 4(R1)
- CMP R1, R5
+ TEQ R1, R5
BNE Y6
X6:
@@ -237,12 +217,11 @@ X6:
TEXT ·mulAddVWW(SB),NOSPLIT,$0
MOVW $0, R0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R5
MOVW x+12(FP), R2
MOVW y+24(FP), R3
MOVW r+28(FP), R4
- MOVW z_len+4(FP), R5
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
B E8
// word loop
@@ -254,7 +233,7 @@ L8:
MOVW.P R6, 4(R1)
MOVW R7, R4
E8:
- CMP R1, R5
+ TEQ R1, R5
BNE L8
MOVW R4, c+32(FP)
@@ -265,11 +244,10 @@ E8:
TEXT ·addMulVVW(SB),NOSPLIT,$0
MOVW $0, R0
MOVW z+0(FP), R1
+ MOVW z_len+4(FP), R5
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z_len+4(FP), R5
- MOVW R5<<2, R5
- ADD R1, R5
+ ADD R5<<2, R1, R5
MOVW $0, R4
B E9
@@ -285,7 +263,7 @@ L9:
MOVW.P R6, 4(R1)
MOVW R7, R4
E9:
- CMP R1, R5
+ TEQ R1, R5
BNE L9
MOVW R4, c+28(FP)
@@ -317,7 +295,6 @@ TEXT ·mulWW(SB),NOSPLIT,$0
TEXT ·bitLen(SB),NOSPLIT,$0
MOVW x+0(FP), R0
CLZ R0, R0
- MOVW $32, R1
- SUB.S R0, R1
- MOVW R1, n+4(FP)
+ RSB $32, R0
+ MOVW R0, n+4(FP)
RET
diff --git a/src/pkg/math/big/int.go b/src/pkg/math/big/int.go
index 7bbb152d7..269949d61 100644
--- a/src/pkg/math/big/int.go
+++ b/src/pkg/math/big/int.go
@@ -576,21 +576,22 @@ func (x *Int) BitLen() int {
}
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
-// If y <= 0, the result is 1; if m == nil or m == 0, z = x**y.
+// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
// See Knuth, volume 2, section 4.6.3.
func (z *Int) Exp(x, y, m *Int) *Int {
- if y.neg || len(y.abs) == 0 {
- return z.SetInt64(1)
+ var yWords nat
+ if !y.neg {
+ yWords = y.abs
}
- // y > 0
+ // y >= 0
var mWords nat
if m != nil {
mWords = m.abs // m.abs may be nil for m == 0
}
- z.abs = z.abs.expNN(x.abs, y.abs, mWords)
- z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+ z.abs = z.abs.expNN(x.abs, yWords, mWords)
+ z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
return z
}
@@ -982,17 +983,29 @@ func (z *Int) GobDecode(buf []byte) error {
}
// MarshalJSON implements the json.Marshaler interface.
-func (x *Int) MarshalJSON() ([]byte, error) {
+func (z *Int) MarshalJSON() ([]byte, error) {
// TODO(gri): get rid of the []byte/string conversions
- return []byte(x.String()), nil
+ return []byte(z.String()), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
-func (z *Int) UnmarshalJSON(x []byte) error {
+func (z *Int) UnmarshalJSON(text []byte) error {
// TODO(gri): get rid of the []byte/string conversions
- _, ok := z.SetString(string(x), 0)
- if !ok {
- return fmt.Errorf("math/big: cannot unmarshal %s into a *big.Int", x)
+ if _, ok := z.SetString(string(text), 0); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+ }
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface
+func (z *Int) MarshalText() (text []byte, err error) {
+ return []byte(z.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface
+func (z *Int) UnmarshalText(text []byte) error {
+ if _, ok := z.SetString(string(text), 0); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
}
return nil
}
diff --git a/src/pkg/math/big/int_test.go b/src/pkg/math/big/int_test.go
index 87b975d5c..299dc72fb 100644
--- a/src/pkg/math/big/int_test.go
+++ b/src/pkg/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/gob"
"encoding/hex"
"encoding/json"
+ "encoding/xml"
"fmt"
"math/rand"
"testing"
@@ -767,6 +768,19 @@ var expTests = []struct {
x, y, m string
out string
}{
+ // y <= 0
+ {"0", "0", "", "1"},
+ {"1", "0", "", "1"},
+ {"-10", "0", "", "1"},
+ {"1234", "-1", "", "1"},
+
+ // m == 1
+ {"0", "0", "1", "0"},
+ {"1", "0", "1", "0"},
+ {"-10", "0", "1", "0"},
+ {"1234", "-1", "1", "0"},
+
+ // misc
{"5", "-7", "", "1"},
{"-5", "-7", "", "1"},
{"5", "0", "", "1"},
@@ -1528,6 +1542,58 @@ func TestIntJSONEncoding(t *testing.T) {
}
}
+var intVals = []string{
+ "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+ "-1415926535897932384626433832795028841971",
+ "-141592653589793",
+ "-1",
+ "0",
+ "1",
+ "141592653589793",
+ "1415926535897932384626433832795028841971",
+ "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+func TestIntJSONEncodingTextMarshaller(t *testing.T) {
+ for _, num := range intVals {
+ var tx Int
+ tx.SetString(num, 0)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+}
+
+func TestIntXMLEncodingTextMarshaller(t *testing.T) {
+ for _, num := range intVals {
+ var tx Int
+ tx.SetString(num, 0)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Int
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+}
+
func TestIssue2607(t *testing.T) {
// This code sequence used to hang.
n := NewInt(10)
diff --git a/src/pkg/math/big/nat.go b/src/pkg/math/big/nat.go
index 6874900d0..16a87f5c5 100644
--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -1233,10 +1233,15 @@ func (z nat) expNN(x, y, m nat) nat {
z = nil
}
+ // x**y mod 1 == 0
+ if len(m) == 1 && m[0] == 1 {
+ return z.setWord(0)
+ }
+ // m == 0 || m > 1
+
+ // x**0 == 1
if len(y) == 0 {
- z = z.make(1)
- z[0] = 1
- return z
+ return z.setWord(1)
}
// y > 0
diff --git a/src/pkg/math/big/nat_test.go b/src/pkg/math/big/nat_test.go
index 1d4dfe80d..a2ae53385 100644
--- a/src/pkg/math/big/nat_test.go
+++ b/src/pkg/math/big/nat_test.go
@@ -437,20 +437,11 @@ func BenchmarkStringPiParallel(b *testing.B) {
if x.decimalString() != pi {
panic("benchmark incorrect: conversion failed")
}
- n := runtime.GOMAXPROCS(0)
- m := b.N / n // n*m <= b.N due to flooring, but the error is neglibible (n is not very large)
- c := make(chan int, n)
- for i := 0; i < n; i++ {
- go func() {
- for j := 0; j < m; j++ {
- x.decimalString()
- }
- c <- 0
- }()
- }
- for i := 0; i < n; i++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ x.decimalString()
+ }
+ })
}
func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
@@ -723,6 +714,12 @@ var expNNTests = []struct {
x, y, m string
out string
}{
+ {"0", "0", "0", "1"},
+ {"0", "0", "1", "0"},
+ {"1", "1", "1", "0"},
+ {"2", "1", "1", "0"},
+ {"2", "2", "1", "0"},
+ {"10", "100000000000", "1", "0"},
{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
{"0x8000000000000000", "2", "6719", "4944"},
{"0x8000000000000000", "3", "6719", "5447"},
@@ -750,7 +747,7 @@ func TestExpNN(t *testing.T) {
z := nat(nil).expNN(x, y, m)
if z.cmp(out) != 0 {
- t.Errorf("#%d got %v want %v", i, z, out)
+ t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
}
}
}
diff --git a/src/pkg/math/big/rat.go b/src/pkg/math/big/rat.go
index 7faee61a4..f0973b390 100644
--- a/src/pkg/math/big/rat.go
+++ b/src/pkg/math/big/rat.go
@@ -47,7 +47,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
shift := 52 - exp
- // Optimisation (?): partially pre-normalise.
+ // Optimization (?): partially pre-normalise.
for mantissa&1 == 0 && shift > 0 {
mantissa >>= 1
shift--
@@ -477,7 +477,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
return z, true
}
-// String returns a string representation of z in the form "a/b" (even if b == 1).
+// String returns a string representation of x in the form "a/b" (even if b == 1).
func (x *Rat) String() string {
s := "/1"
if len(x.b.abs) != 0 {
@@ -486,7 +486,7 @@ func (x *Rat) String() string {
return x.a.String() + s
}
-// RatString returns a string representation of z in the form "a/b" if b != 1,
+// RatString returns a string representation of x in the form "a/b" if b != 1,
// and in the form "a" if b == 1.
func (x *Rat) RatString() string {
if x.IsInt() {
@@ -495,7 +495,7 @@ func (x *Rat) RatString() string {
return x.String()
}
-// FloatString returns a string representation of z in decimal form with prec
+// FloatString returns a string representation of x in decimal form with prec
// digits of precision after the decimal point and the last digit rounded.
func (x *Rat) FloatString(prec int) string {
if x.IsInt() {
@@ -585,3 +585,16 @@ func (z *Rat) GobDecode(buf []byte) error {
z.b.abs = z.b.abs.setBytes(buf[i:])
return nil
}
+
+// MarshalText implements the encoding.TextMarshaler interface
+func (r *Rat) MarshalText() (text []byte, err error) {
+ return []byte(r.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface
+func (r *Rat) UnmarshalText(text []byte) error {
+ if _, ok := r.SetString(string(text)); !ok {
+ return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+ }
+ return nil
+}
diff --git a/src/pkg/math/big/rat_test.go b/src/pkg/math/big/rat_test.go
index 0d432637b..414a67d41 100644
--- a/src/pkg/math/big/rat_test.go
+++ b/src/pkg/math/big/rat_test.go
@@ -7,6 +7,8 @@ package big
import (
"bytes"
"encoding/gob"
+ "encoding/json"
+ "encoding/xml"
"fmt"
"math"
"strconv"
@@ -433,6 +435,69 @@ func TestGobEncodingNilRatInSlice(t *testing.T) {
}
}
+var ratNums = []string{
+ "-141592653589793238462643383279502884197169399375105820974944592307816406286",
+ "-1415926535897932384626433832795028841971",
+ "-141592653589793",
+ "-1",
+ "0",
+ "1",
+ "141592653589793",
+ "1415926535897932384626433832795028841971",
+ "141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+ "1",
+ "718281828459045",
+ "7182818284590452353602874713526624977572",
+ "718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := json.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := json.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+ for _, num := range ratNums {
+ for _, denom := range ratDenoms {
+ var tx Rat
+ tx.SetString(num + "/" + denom)
+ b, err := xml.Marshal(&tx)
+ if err != nil {
+ t.Errorf("marshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ var rx Rat
+ if err := xml.Unmarshal(b, &rx); err != nil {
+ t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+ continue
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+ }
+ }
+ }
+}
+
func TestIssue2379(t *testing.T) {
// 1) no aliasing
q := NewRat(3, 2)
diff --git a/src/pkg/math/cmplx/cmath_test.go b/src/pkg/math/cmplx/cmath_test.go
index 610ca8ceb..f285646af 100644
--- a/src/pkg/math/cmplx/cmath_test.go
+++ b/src/pkg/math/cmplx/cmath_test.go
@@ -656,6 +656,19 @@ func TestPolar(t *testing.T) {
}
}
func TestPow(t *testing.T) {
+ // Special cases for Pow(0, c).
+ var zero = complex(0, 0)
+ zeroPowers := [][2]complex128{
+ {0, 1 + 0i},
+ {1.5, 0 + 0i},
+ {-1.5, complex(math.Inf(0), 0)},
+ {-1.5 + 1.5i, Inf()},
+ }
+ for _, zp := range zeroPowers {
+ if f := Pow(zero, zp[0]); f != zp[1] {
+ t.Errorf("Pow(%g, %g) = %g, want %g", zero, zp[0], f, zp[1])
+ }
+ }
var a = complex(3.0, 3.0)
for i := 0; i < len(vc); i++ {
if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
diff --git a/src/pkg/math/cmplx/pow.go b/src/pkg/math/cmplx/pow.go
index 4dbc58398..1630b879b 100644
--- a/src/pkg/math/cmplx/pow.go
+++ b/src/pkg/math/cmplx/pow.go
@@ -43,7 +43,25 @@ import "math"
// IEEE -10,+10 30000 9.4e-15 1.5e-15
// Pow returns x**y, the base-x exponential of y.
+// For generalized compatibility with math.Pow:
+// Pow(0, ±0) returns 1+0i
+// Pow(0, c) for real(c)<0 returns Inf+0i if imag(c) is zero, otherwise Inf+Inf i.
func Pow(x, y complex128) complex128 {
+ if x == 0 { // Guaranteed also true for x == -0.
+ r, i := real(y), imag(y)
+ switch {
+ case r == 0:
+ return 1
+ case r < 0:
+ if i == 0 {
+ return complex(math.Inf(1), 0)
+ }
+ return Inf()
+ case r > 0:
+ return 0
+ }
+ panic("not reached")
+ }
modulus := Abs(x)
if modulus == 0 {
return complex(0, 0)
diff --git a/src/pkg/math/cmplx/sqrt.go b/src/pkg/math/cmplx/sqrt.go
index 179b5396a..4ef6807ad 100644
--- a/src/pkg/math/cmplx/sqrt.go
+++ b/src/pkg/math/cmplx/sqrt.go
@@ -54,6 +54,7 @@ import "math"
// IEEE -10,+10 1,000,000 2.9e-16 6.1e-17
// Sqrt returns the square root of x.
+// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
func Sqrt(x complex128) complex128 {
if imag(x) == 0 {
if real(x) == 0 {
diff --git a/src/pkg/math/dim_amd64p32.s b/src/pkg/math/dim_amd64p32.s
new file mode 100644
index 000000000..e5e34479d
--- /dev/null
+++ b/src/pkg/math/dim_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "dim_amd64.s"
diff --git a/src/pkg/math/exp2_amd64p32.s b/src/pkg/math/exp2_amd64p32.s
new file mode 100644
index 000000000..4d3830914
--- /dev/null
+++ b/src/pkg/math/exp2_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "exp2_amd64.s"
diff --git a/src/pkg/math/exp_amd64p32.s b/src/pkg/math/exp_amd64p32.s
new file mode 100644
index 000000000..98ac2e91e
--- /dev/null
+++ b/src/pkg/math/exp_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "exp_amd64.s"
diff --git a/src/pkg/math/expm1_amd64p32.s b/src/pkg/math/expm1_amd64p32.s
new file mode 100644
index 000000000..709ebefcb
--- /dev/null
+++ b/src/pkg/math/expm1_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "expm1_amd64.s"
diff --git a/src/pkg/math/floor_amd64p32.s b/src/pkg/math/floor_amd64p32.s
new file mode 100644
index 000000000..5b87d7a40
--- /dev/null
+++ b/src/pkg/math/floor_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "floor_amd64.s"
diff --git a/src/pkg/math/frexp_amd64p32.s b/src/pkg/math/frexp_amd64p32.s
new file mode 100644
index 000000000..fbb564539
--- /dev/null
+++ b/src/pkg/math/frexp_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "frexp_amd64.s"
diff --git a/src/pkg/math/hypot_amd64p32.s b/src/pkg/math/hypot_amd64p32.s
new file mode 100644
index 000000000..b84542ae3
--- /dev/null
+++ b/src/pkg/math/hypot_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "hypot_amd64.s"
diff --git a/src/pkg/math/ldexp_amd64p32.s b/src/pkg/math/ldexp_amd64p32.s
new file mode 100644
index 000000000..9aa9d9da3
--- /dev/null
+++ b/src/pkg/math/ldexp_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "ldexp_amd64.s"
diff --git a/src/pkg/math/log10_amd64p32.s b/src/pkg/math/log10_amd64p32.s
new file mode 100644
index 000000000..bf43841e2
--- /dev/null
+++ b/src/pkg/math/log10_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "log10_amd64.s"
diff --git a/src/pkg/math/log1p_amd64p32.s b/src/pkg/math/log1p_amd64p32.s
new file mode 100644
index 000000000..a14b5e38a
--- /dev/null
+++ b/src/pkg/math/log1p_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "log1p_amd64.s"
diff --git a/src/pkg/math/log_amd64p32.s b/src/pkg/math/log_amd64p32.s
new file mode 100644
index 000000000..5058d607e
--- /dev/null
+++ b/src/pkg/math/log_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "log_amd64.s"
diff --git a/src/pkg/math/mod_amd64p32.s b/src/pkg/math/mod_amd64p32.s
new file mode 100644
index 000000000..c1b231124
--- /dev/null
+++ b/src/pkg/math/mod_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "mod_amd64.s"
diff --git a/src/pkg/math/modf_amd64p32.s b/src/pkg/math/modf_amd64p32.s
new file mode 100644
index 000000000..5508c2547
--- /dev/null
+++ b/src/pkg/math/modf_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "modf_amd64.s"
diff --git a/src/pkg/math/rand/rand.go b/src/pkg/math/rand/rand.go
index 2157cdb46..3ffb5c4e5 100644
--- a/src/pkg/math/rand/rand.go
+++ b/src/pkg/math/rand/rand.go
@@ -60,6 +60,9 @@ func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
panic("invalid argument to Int63n")
}
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return r.Int63() & (n - 1)
+ }
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := r.Int63()
for v > max {
@@ -74,6 +77,9 @@ func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
panic("invalid argument to Int31n")
}
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return r.Int31() & (n - 1)
+ }
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := r.Int31()
for v > max {
@@ -95,20 +101,54 @@ func (r *Rand) Intn(n int) int {
}
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+func (r *Rand) Float64() float64 {
+ // A clearer, simpler implementation would be:
+ // return float64(r.Int63n(1<<53)) / (1<<53)
+ // However, Go 1 shipped with
+ // return float64(r.Int63()) / (1 << 63)
+ // and we want to preserve that value stream.
+ //
+ // There is one bug in the value stream: r.Int63() may be so close
+ // to 1<<63 that the division rounds up to 1.0, and we've guaranteed
+ // that the result is always less than 1.0. To fix that, we treat the
+ // range as cyclic and map 1 back to 0. This is justified by observing
+ // that while some of the values rounded down to 0, nothing was
+ // rounding up to 0, so 0 was underrepresented in the results.
+ // Mapping 1 back to zero restores some balance.
+ // (The balance is not perfect because the implementation
+ // returns denormalized numbers for very small r.Int63(),
+ // and those steal from what would normally be 0 results.)
+ // The remapping only happens 1/2⁵³ of the time, so most clients
+ // will not observe it anyway.
+ f := float64(r.Int63()) / (1 << 63)
+ if f == 1 {
+ f = 0
+ }
+ return f
+}
// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+func (r *Rand) Float32() float32 {
+ // Same rationale as in Float64: we want to preserve the Go 1 value
+ // stream except we want to fix it not to return 1.0
+ // There is a double rounding going on here, but the argument for
+ // mapping 1 to 0 still applies: 0 was underrepresented before,
+ // so mapping 1 to 0 doesn't cause too many 0s.
+ // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
+ f := float32(r.Float64())
+ if f == 1 {
+ f = 0
+ }
+ return f
+}
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
func (r *Rand) Perm(n int) []int {
m := make([]int, n)
for i := 0; i < n; i++ {
- m[i] = i
- }
- for i := 0; i < n; i++ {
j := r.Intn(i + 1)
- m[i], m[j] = m[j], m[i]
+ m[i] = m[j]
+ m[j] = i
}
return m
}
diff --git a/src/pkg/math/rand/rand_test.go b/src/pkg/math/rand/rand_test.go
index 4d3abdb60..ab0dc49b4 100644
--- a/src/pkg/math/rand/rand_test.go
+++ b/src/pkg/math/rand/rand_test.go
@@ -322,6 +322,17 @@ func TestExpTables(t *testing.T) {
}
}
+// For issue 6721, the problem came after 7533753 calls, so check 10e6.
+func TestFloat32(t *testing.T) {
+ r := New(NewSource(1))
+ for ct := 0; ct < 10e6; ct++ {
+ f := r.Float32()
+ if f >= 1 {
+ t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
+ }
+ }
+}
+
// Benchmarks
func BenchmarkInt63Threadsafe(b *testing.B) {
@@ -357,3 +368,31 @@ func BenchmarkInt31n1000(b *testing.B) {
r.Int31n(1000)
}
}
+
+func BenchmarkFloat32(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Float32()
+ }
+}
+
+func BenchmarkFloat64(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Float64()
+ }
+}
+
+func BenchmarkPerm3(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Perm(3)
+ }
+}
+
+func BenchmarkPerm30(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Perm(30)
+ }
+}
diff --git a/src/pkg/math/rand/regress_test.go b/src/pkg/math/rand/regress_test.go
new file mode 100644
index 000000000..2b012af89
--- /dev/null
+++ b/src/pkg/math/rand/regress_test.go
@@ -0,0 +1,355 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that random number sequences generated by a specific seed
+// do not change from version to version.
+//
+// Do NOT make changes to the golden outputs. If bugs need to be fixed
+// in the underlying code, find ways to fix them that do not affect the
+// outputs.
+
+package rand_test
+
+import (
+ "flag"
+ "fmt"
+ . "math/rand"
+ "reflect"
+ "testing"
+)
+
+var printgolden = flag.Bool("printgolden", false, "print golden results for regression test")
+
+func TestRegress(t *testing.T) {
+ var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1}
+ var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1}
+ var permSizes = []int{0, 1, 5, 8, 9, 10, 16}
+ r := New(NewSource(0))
+
+ rv := reflect.ValueOf(r)
+ n := rv.NumMethod()
+ p := 0
+ if *printgolden {
+ fmt.Printf("var regressGolden = []interface{}{\n")
+ }
+ for i := 0; i < n; i++ {
+ m := rv.Type().Method(i)
+ mv := rv.Method(i)
+ mt := mv.Type()
+ if mt.NumOut() == 0 {
+ continue
+ }
+ if mt.NumOut() != 1 {
+ t.Fatalf("unexpected result count for r.%s", m.Name)
+ }
+ r.Seed(0)
+ for repeat := 0; repeat < 20; repeat++ {
+ var args []reflect.Value
+ var argstr string
+ if mt.NumIn() == 1 {
+ var x interface{}
+ switch mt.In(0).Kind() {
+ default:
+ t.Fatalf("unexpected argument type for r.%s", m.Name)
+
+ case reflect.Int:
+ if m.Name == "Perm" {
+ x = permSizes[repeat%len(permSizes)]
+ break
+ }
+ big := int64s[repeat%len(int64s)]
+ if int64(int(big)) != big {
+ r.Int63n(big) // what would happen on 64-bit machine, to keep stream in sync
+ if *printgolden {
+ fmt.Printf("\tskipped, // must run printgolden on 64-bit machine\n")
+ }
+ p++
+ continue
+ }
+ x = int(big)
+
+ case reflect.Int32:
+ x = int32s[repeat%len(int32s)]
+
+ case reflect.Int64:
+ x = int64s[repeat%len(int64s)]
+ }
+ argstr = fmt.Sprint(x)
+ args = append(args, reflect.ValueOf(x))
+ }
+ out := mv.Call(args)[0].Interface()
+ if m.Name == "Int" || m.Name == "Intn" {
+ out = int64(out.(int))
+ }
+ if *printgolden {
+ var val string
+ big := int64(1 << 60)
+ if int64(int(big)) != big && (m.Name == "Int" || m.Name == "Intn") {
+ // 32-bit machine cannot print 64-bit results
+ val = "truncated"
+ } else if reflect.TypeOf(out).Kind() == reflect.Slice {
+ val = fmt.Sprintf("%#v", out)
+ } else {
+ val = fmt.Sprintf("%T(%v)", out, out)
+ }
+ fmt.Printf("\t%s, // %s(%s)\n", val, m.Name, argstr)
+ } else {
+ want := regressGolden[p]
+ if m.Name == "Int" {
+ want = int64(int(uint(want.(int64)) << 1 >> 1))
+ }
+ if !reflect.DeepEqual(out, want) {
+ t.Errorf("r.%s(%s) = %v, want %v", m.Name, argstr, out, want)
+ }
+ }
+ p++
+ }
+ }
+ if *printgolden {
+ fmt.Printf("}\n")
+ }
+}
+
+var regressGolden = []interface{}{
+ float64(4.668112973579268), // ExpFloat64()
+ float64(0.1601593871172866), // ExpFloat64()
+ float64(3.0465834105636), // ExpFloat64()
+ float64(0.06385839451671879), // ExpFloat64()
+ float64(1.8578917487258961), // ExpFloat64()
+ float64(0.784676123472182), // ExpFloat64()
+ float64(0.11225477361256932), // ExpFloat64()
+ float64(0.20173283329802255), // ExpFloat64()
+ float64(0.3468619496201105), // ExpFloat64()
+ float64(0.35601103454384536), // ExpFloat64()
+ float64(0.888376329507869), // ExpFloat64()
+ float64(1.4081362450365698), // ExpFloat64()
+ float64(1.0077753823151994), // ExpFloat64()
+ float64(0.23594100766227588), // ExpFloat64()
+ float64(2.777245612300007), // ExpFloat64()
+ float64(0.5202997830662377), // ExpFloat64()
+ float64(1.2842705247770294), // ExpFloat64()
+ float64(0.030307408362776206), // ExpFloat64()
+ float64(2.204156824853721), // ExpFloat64()
+ float64(2.09891923895058), // ExpFloat64()
+ float32(0.94519615), // Float32()
+ float32(0.24496509), // Float32()
+ float32(0.65595627), // Float32()
+ float32(0.05434384), // Float32()
+ float32(0.3675872), // Float32()
+ float32(0.28948045), // Float32()
+ float32(0.1924386), // Float32()
+ float32(0.65533215), // Float32()
+ float32(0.8971697), // Float32()
+ float32(0.16735445), // Float32()
+ float32(0.28858566), // Float32()
+ float32(0.9026048), // Float32()
+ float32(0.84978026), // Float32()
+ float32(0.2730468), // Float32()
+ float32(0.6090802), // Float32()
+ float32(0.253656), // Float32()
+ float32(0.7746542), // Float32()
+ float32(0.017480763), // Float32()
+ float32(0.78707397), // Float32()
+ float32(0.7993937), // Float32()
+ float64(0.9451961492941164), // Float64()
+ float64(0.24496508529377975), // Float64()
+ float64(0.6559562651954052), // Float64()
+ float64(0.05434383959970039), // Float64()
+ float64(0.36758720663245853), // Float64()
+ float64(0.2894804331565928), // Float64()
+ float64(0.19243860967493215), // Float64()
+ float64(0.6553321508148324), // Float64()
+ float64(0.897169713149801), // Float64()
+ float64(0.16735444255905835), // Float64()
+ float64(0.2885856518054551), // Float64()
+ float64(0.9026048462705047), // Float64()
+ float64(0.8497802817628735), // Float64()
+ float64(0.2730468047134829), // Float64()
+ float64(0.6090801919903561), // Float64()
+ float64(0.25365600644283687), // Float64()
+ float64(0.7746542391859803), // Float64()
+ float64(0.017480762156647272), // Float64()
+ float64(0.7870739563039942), // Float64()
+ float64(0.7993936979594545), // Float64()
+ int64(8717895732742165505), // Int()
+ int64(2259404117704393152), // Int()
+ int64(6050128673802995827), // Int()
+ int64(501233450539197794), // Int()
+ int64(3390393562759376202), // Int()
+ int64(2669985732393126063), // Int()
+ int64(1774932891286980153), // Int()
+ int64(6044372234677422456), // Int()
+ int64(8274930044578894929), // Int()
+ int64(1543572285742637646), // Int()
+ int64(2661732831099943416), // Int()
+ int64(8325060299420976708), // Int()
+ int64(7837839688282259259), // Int()
+ int64(2518412263346885298), // Int()
+ int64(5617773211005988520), // Int()
+ int64(2339563716805116249), // Int()
+ int64(7144924247938981575), // Int()
+ int64(161231572858529631), // Int()
+ int64(7259475919510918339), // Int()
+ int64(7373105480197164748), // Int()
+ int32(2029793274), // Int31()
+ int32(526058514), // Int31()
+ int32(1408655353), // Int31()
+ int32(116702506), // Int31()
+ int32(789387515), // Int31()
+ int32(621654496), // Int31()
+ int32(413258767), // Int31()
+ int32(1407315077), // Int31()
+ int32(1926657288), // Int31()
+ int32(359390928), // Int31()
+ int32(619732968), // Int31()
+ int32(1938329147), // Int31()
+ int32(1824889259), // Int31()
+ int32(586363548), // Int31()
+ int32(1307989752), // Int31()
+ int32(544722126), // Int31()
+ int32(1663557311), // Int31()
+ int32(37539650), // Int31()
+ int32(1690228450), // Int31()
+ int32(1716684894), // Int31()
+ int32(0), // Int31n(1)
+ int32(4), // Int31n(10)
+ int32(25), // Int31n(32)
+ int32(310570), // Int31n(1048576)
+ int32(857611), // Int31n(1048577)
+ int32(621654496), // Int31n(1000000000)
+ int32(413258767), // Int31n(1073741824)
+ int32(1407315077), // Int31n(2147483646)
+ int32(1926657288), // Int31n(2147483647)
+ int32(0), // Int31n(1)
+ int32(8), // Int31n(10)
+ int32(27), // Int31n(32)
+ int32(367019), // Int31n(1048576)
+ int32(209005), // Int31n(1048577)
+ int32(307989752), // Int31n(1000000000)
+ int32(544722126), // Int31n(1073741824)
+ int32(1663557311), // Int31n(2147483646)
+ int32(37539650), // Int31n(2147483647)
+ int32(0), // Int31n(1)
+ int32(4), // Int31n(10)
+ int64(8717895732742165505), // Int63()
+ int64(2259404117704393152), // Int63()
+ int64(6050128673802995827), // Int63()
+ int64(501233450539197794), // Int63()
+ int64(3390393562759376202), // Int63()
+ int64(2669985732393126063), // Int63()
+ int64(1774932891286980153), // Int63()
+ int64(6044372234677422456), // Int63()
+ int64(8274930044578894929), // Int63()
+ int64(1543572285742637646), // Int63()
+ int64(2661732831099943416), // Int63()
+ int64(8325060299420976708), // Int63()
+ int64(7837839688282259259), // Int63()
+ int64(2518412263346885298), // Int63()
+ int64(5617773211005988520), // Int63()
+ int64(2339563716805116249), // Int63()
+ int64(7144924247938981575), // Int63()
+ int64(161231572858529631), // Int63()
+ int64(7259475919510918339), // Int63()
+ int64(7373105480197164748), // Int63()
+ int64(0), // Int63n(1)
+ int64(2), // Int63n(10)
+ int64(19), // Int63n(32)
+ int64(959842), // Int63n(1048576)
+ int64(688912), // Int63n(1048577)
+ int64(393126063), // Int63n(1000000000)
+ int64(89212473), // Int63n(1073741824)
+ int64(834026388), // Int63n(2147483646)
+ int64(1577188963), // Int63n(2147483647)
+ int64(543572285742637646), // Int63n(1000000000000000000)
+ int64(355889821886249464), // Int63n(1152921504606846976)
+ int64(8325060299420976708), // Int63n(9223372036854775806)
+ int64(7837839688282259259), // Int63n(9223372036854775807)
+ int64(0), // Int63n(1)
+ int64(0), // Int63n(10)
+ int64(25), // Int63n(32)
+ int64(679623), // Int63n(1048576)
+ int64(882178), // Int63n(1048577)
+ int64(510918339), // Int63n(1000000000)
+ int64(782454476), // Int63n(1073741824)
+ int64(0), // Intn(1)
+ int64(4), // Intn(10)
+ int64(25), // Intn(32)
+ int64(310570), // Intn(1048576)
+ int64(857611), // Intn(1048577)
+ int64(621654496), // Intn(1000000000)
+ int64(413258767), // Intn(1073741824)
+ int64(1407315077), // Intn(2147483646)
+ int64(1926657288), // Intn(2147483647)
+ int64(543572285742637646), // Intn(1000000000000000000)
+ int64(355889821886249464), // Intn(1152921504606846976)
+ int64(8325060299420976708), // Intn(9223372036854775806)
+ int64(7837839688282259259), // Intn(9223372036854775807)
+ int64(0), // Intn(1)
+ int64(2), // Intn(10)
+ int64(14), // Intn(32)
+ int64(515775), // Intn(1048576)
+ int64(839455), // Intn(1048577)
+ int64(690228450), // Intn(1000000000)
+ int64(642943070), // Intn(1073741824)
+ float64(-0.28158587086436215), // NormFloat64()
+ float64(0.570933095808067), // NormFloat64()
+ float64(-1.6920196326157044), // NormFloat64()
+ float64(0.1996229111693099), // NormFloat64()
+ float64(1.9195199291234621), // NormFloat64()
+ float64(0.8954838794918353), // NormFloat64()
+ float64(0.41457072128813166), // NormFloat64()
+ float64(-0.48700161491544713), // NormFloat64()
+ float64(-0.1684059662402393), // NormFloat64()
+ float64(0.37056410998929545), // NormFloat64()
+ float64(1.0156889027029008), // NormFloat64()
+ float64(-0.5174422210625114), // NormFloat64()
+ float64(-0.5565834214413804), // NormFloat64()
+ float64(0.778320596648391), // NormFloat64()
+ float64(-1.8970718197702225), // NormFloat64()
+ float64(0.5229525761688676), // NormFloat64()
+ float64(-1.5515595563231523), // NormFloat64()
+ float64(0.0182029289376123), // NormFloat64()
+ float64(-0.6820951356608795), // NormFloat64()
+ float64(-0.5987943422687668), // NormFloat64()
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{0, 4, 1, 3, 2}, // Perm(5)
+ []int{3, 1, 0, 4, 7, 5, 2, 6}, // Perm(8)
+ []int{5, 0, 3, 6, 7, 4, 2, 1, 8}, // Perm(9)
+ []int{4, 5, 0, 2, 6, 9, 3, 1, 8, 7}, // Perm(10)
+ []int{14, 2, 0, 8, 3, 5, 13, 12, 1, 4, 6, 7, 11, 9, 15, 10}, // Perm(16)
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{3, 0, 1, 2, 4}, // Perm(5)
+ []int{5, 1, 2, 0, 4, 7, 3, 6}, // Perm(8)
+ []int{4, 0, 6, 8, 1, 5, 2, 7, 3}, // Perm(9)
+ []int{8, 6, 1, 7, 5, 4, 3, 2, 9, 0}, // Perm(10)
+ []int{0, 3, 13, 2, 15, 4, 10, 1, 8, 14, 7, 6, 12, 9, 5, 11}, // Perm(16)
+ []int{}, // Perm(0)
+ []int{0}, // Perm(1)
+ []int{0, 4, 2, 1, 3}, // Perm(5)
+ []int{2, 1, 7, 0, 6, 3, 4, 5}, // Perm(8)
+ []int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9)
+ []int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
+ uint32(4059586549), // Uint32()
+ uint32(1052117029), // Uint32()
+ uint32(2817310706), // Uint32()
+ uint32(233405013), // Uint32()
+ uint32(1578775030), // Uint32()
+ uint32(1243308993), // Uint32()
+ uint32(826517535), // Uint32()
+ uint32(2814630155), // Uint32()
+ uint32(3853314576), // Uint32()
+ uint32(718781857), // Uint32()
+ uint32(1239465936), // Uint32()
+ uint32(3876658295), // Uint32()
+ uint32(3649778518), // Uint32()
+ uint32(1172727096), // Uint32()
+ uint32(2615979505), // Uint32()
+ uint32(1089444252), // Uint32()
+ uint32(3327114623), // Uint32()
+ uint32(75079301), // Uint32()
+ uint32(3380456901), // Uint32()
+ uint32(3433369789), // Uint32()
+}
diff --git a/src/pkg/math/remainder_amd64p32.s b/src/pkg/math/remainder_amd64p32.s
new file mode 100644
index 000000000..cd5cf55ff
--- /dev/null
+++ b/src/pkg/math/remainder_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "remainder_amd64.s"
diff --git a/src/pkg/math/sin_amd64p32.s b/src/pkg/math/sin_amd64p32.s
new file mode 100644
index 000000000..9f93eba20
--- /dev/null
+++ b/src/pkg/math/sin_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "sin_amd64.s"
diff --git a/src/pkg/math/sincos_amd64p32.s b/src/pkg/math/sincos_amd64p32.s
new file mode 100644
index 000000000..360e94d09
--- /dev/null
+++ b/src/pkg/math/sincos_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "sincos_amd64.s"
diff --git a/src/pkg/math/sqrt_amd64p32.s b/src/pkg/math/sqrt_amd64p32.s
new file mode 100644
index 000000000..d83a286c2
--- /dev/null
+++ b/src/pkg/math/sqrt_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "sqrt_amd64.s"
diff --git a/src/pkg/math/tan_amd64p32.s b/src/pkg/math/tan_amd64p32.s
new file mode 100644
index 000000000..9b3f70de7
--- /dev/null
+++ b/src/pkg/math/tan_amd64p32.s
@@ -0,0 +1,5 @@
+// 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 "tan_amd64.s"
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index 608f759da..ad63f9bb9 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -8,6 +8,7 @@ import (
"bytes"
"errors"
"fmt"
+ "sort"
"strings"
"unicode"
)
@@ -31,7 +32,14 @@ func FormatMediaType(t string, param map[string]string) string {
b.WriteByte('/')
b.WriteString(strings.ToLower(sub))
- for attribute, value := range param {
+ attrs := make([]string, 0, len(param))
+ for a := range param {
+ attrs = append(attrs, a)
+ }
+ sort.Strings(attrs)
+
+ for _, attribute := range attrs {
+ value := param[attribute]
b.WriteByte(';')
b.WriteByte(' ')
if !isToken(attribute) {
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
index 29511445b..026bfa4d7 100644
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/mime/mediatype_test.go
@@ -293,6 +293,7 @@ var formatTests = []formatTest{
{"foo/BAR", map[string]string{"": "empty attribute"}, ""},
{"foo/BAR", map[string]string{"bad attribute": "baz"}, ""},
{"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""},
+ {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"},
}
func TestFormatMediaType(t *testing.T) {
diff --git a/src/pkg/mime/multipart/example_test.go b/src/pkg/mime/multipart/example_test.go
new file mode 100644
index 000000000..26135b785
--- /dev/null
+++ b/src/pkg/mime/multipart/example_test.go
@@ -0,0 +1,53 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart_test
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "mime"
+ "mime/multipart"
+ "net/mail"
+ "strings"
+)
+
+func ExampleNewReader() {
+ msg := &mail.Message{
+ Header: map[string][]string{
+ "Content-Type": []string{"multipart/mixed; boundary=foo"},
+ },
+ Body: strings.NewReader(
+ "--foo\r\nFoo: one\r\n\r\nA section\r\n" +
+ "--foo\r\nFoo: two\r\n\r\nAnd another\r\n" +
+ "--foo--\r\n"),
+ }
+ mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if strings.HasPrefix(mediaType, "multipart/") {
+ mr := multipart.NewReader(msg.Body, params["boundary"])
+ for {
+ p, err := mr.NextPart()
+ if err == io.EOF {
+ return
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ slurp, err := ioutil.ReadAll(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("Part %q: %q\n", p.Header.Get("Foo"), slurp)
+ }
+ }
+
+ // Output:
+ // Part "one": "A section"
+ // Part "two": "And another"
+}
diff --git a/src/pkg/mime/multipart/formdata_test.go b/src/pkg/mime/multipart/formdata_test.go
index 4bc464931..6e2388baf 100644
--- a/src/pkg/mime/multipart/formdata_test.go
+++ b/src/pkg/mime/multipart/formdata_test.go
@@ -9,12 +9,13 @@ import (
"io"
"os"
"regexp"
+ "strings"
"testing"
)
func TestReadForm(t *testing.T) {
testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
- b := bytes.NewBufferString(testBody)
+ b := strings.NewReader(testBody)
r := NewReader(b, boundary)
f, err := r.ReadForm(25)
if err != nil {
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 2b4f5b433..7382efab9 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -81,12 +81,16 @@ func (p *Part) parseContentDisposition() {
}
}
-// NewReader creates a new multipart Reader reading from reader using the
+// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
-func NewReader(reader io.Reader, boundary string) *Reader {
+//
+// The boundary is usually obtained from the "boundary" parameter of
+// the message's "Content-Type" header. Use mime.ParseMediaType to
+// parse such headers.
+func NewReader(r io.Reader, boundary string) *Reader {
b := []byte("\r\n--" + boundary + "--")
return &Reader{
- bufReader: bufio.NewReader(reader),
+ bufReader: bufio.NewReader(r),
nl: b[:2],
nlDashBoundary: b[:len(b)-2],
diff --git a/src/pkg/mime/multipart/quotedprintable_test.go b/src/pkg/mime/multipart/quotedprintable_test.go
index 8a95f7f03..c4de3eb75 100644
--- a/src/pkg/mime/multipart/quotedprintable_test.go
+++ b/src/pkg/mime/multipart/quotedprintable_test.go
@@ -131,7 +131,7 @@ func TestQPExhaustive(t *testing.T) {
return
}
if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
- // bunch of cases; since whitespace at the end of of a line before \n is removed.
+ // bunch of cases; since whitespace at the end of a line before \n is removed.
return
}
}
diff --git a/src/pkg/mime/type_unix.go b/src/pkg/mime/type_unix.go
index 713e301cd..1d394315a 100644
--- a/src/pkg/mime/type_unix.go
+++ b/src/pkg/mime/type_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package mime
diff --git a/src/pkg/net/cgo_bsd.go b/src/pkg/net/cgo_bsd.go
index 388eab4fe..3090d3019 100644
--- a/src/pkg/net/cgo_bsd.go
+++ b/src/pkg/net/cgo_bsd.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build !netgo
-// +build darwin dragonfly freebsd
+// +build darwin dragonfly freebsd solaris
package net
diff --git a/src/pkg/net/cgo_unix_test.go b/src/pkg/net/cgo_unix_test.go
new file mode 100644
index 000000000..33566ce9c
--- /dev/null
+++ b/src/pkg/net/cgo_unix_test.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import "testing"
+
+func TestCgoLookupIP(t *testing.T) {
+ host := "localhost"
+ _, err, ok := cgoLookupIP(host)
+ if !ok {
+ t.Errorf("cgoLookupIP must not be a placeholder")
+ }
+ if err != nil {
+ t.Errorf("cgoLookupIP failed: %v", err)
+ }
+ if _, err := goLookupIP(host); err != nil {
+ t.Errorf("goLookupIP failed: %v", err)
+ }
+}
diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
index 98bd69549..37bb4e2c0 100644
--- a/src/pkg/net/conn_test.go
+++ b/src/pkg/net/conn_test.go
@@ -16,11 +16,11 @@ import (
var connTests = []struct {
net string
- addr func() string
+ addr string
}{
- {"tcp", func() string { return "127.0.0.1:0" }},
- {"unix", testUnixAddr},
- {"unixpacket", testUnixAddr},
+ {"tcp", "127.0.0.1:0"},
+ {"unix", testUnixAddr()},
+ {"unixpacket", testUnixAddr()},
}
// someTimeout is used just to test that net.Conn implementations
@@ -31,18 +31,21 @@ const someTimeout = 10 * time.Second
func TestConnAndListener(t *testing.T) {
for _, tt := range connTests {
switch tt.net {
- case "unix", "unixpacket":
+ case "unix":
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
continue
}
- if tt.net == "unixpacket" && runtime.GOOS != "linux" {
+ case "unixpacket":
+ switch runtime.GOOS {
+ case "darwin", "nacl", "openbsd", "plan9", "windows":
+ continue
+ case "freebsd": // FreeBSD 8 doesn't support unixpacket
continue
}
}
- addr := tt.addr()
- ln, err := Listen(tt.net, addr)
+ ln, err := Listen(tt.net, tt.addr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
@@ -52,8 +55,10 @@ func TestConnAndListener(t *testing.T) {
case "unix", "unixpacket":
os.Remove(addr)
}
- }(ln, tt.net, addr)
- ln.Addr()
+ }(ln, tt.net, tt.addr)
+ if ln.Addr().Network() != tt.net {
+ t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
+ }
done := make(chan int)
go transponder(t, ln, done)
@@ -63,8 +68,9 @@ func TestConnAndListener(t *testing.T) {
t.Fatalf("Dial failed: %v", err)
}
defer c.Close()
- c.LocalAddr()
- c.RemoteAddr()
+ if c.LocalAddr().Network() != tt.net || c.LocalAddr().Network() != tt.net {
+ t.Fatalf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), tt.net, tt.net)
+ }
c.SetDeadline(time.Now().Add(someTimeout))
c.SetReadDeadline(time.Now().Add(someTimeout))
c.SetWriteDeadline(time.Now().Add(someTimeout))
@@ -96,8 +102,11 @@ func transponder(t *testing.T, ln Listener, done chan<- int) {
return
}
defer c.Close()
- c.LocalAddr()
- c.RemoteAddr()
+ network := ln.Addr().Network()
+ if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+ t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
+ return
+ }
c.SetDeadline(time.Now().Add(someTimeout))
c.SetReadDeadline(time.Now().Add(someTimeout))
c.SetWriteDeadline(time.Now().Add(someTimeout))
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 6304818bf..93569c253 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -44,6 +44,12 @@ type Dialer struct {
// destination is a host name that has multiple address family
// DNS records.
DualStack bool
+
+ // KeepAlive specifies the keep-alive period for an active
+ // network connection.
+ // If zero, keep-alives are not enabled. Network protocols
+ // that do not support keep-alives ignore this field.
+ KeepAlive time.Duration
}
// Return either now+Timeout or Deadline, whichever comes first.
@@ -162,9 +168,19 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
return dialMulti(network, address, d.LocalAddr, ras, deadline)
}
}
- return dial(network, ra.toAddr(), dialer, d.deadline())
+ c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+ if d.KeepAlive > 0 && err == nil {
+ if tc, ok := c.(*TCPConn); ok {
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(d.KeepAlive)
+ testHookSetKeepAlive()
+ }
+ }
+ return c, err
}
+var testHookSetKeepAlive = func() {} // changed by dial_test.go
+
// dialMulti attempts to establish connections to each destination of
// the list of addresses. It will return the first established
// connection and close the other connections. Otherwise it returns
@@ -172,7 +188,6 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
type racer struct {
Conn
- Addr
error
}
// Sig controls the flow of dial results on lane. It passes a
@@ -184,7 +199,7 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
go func(ra Addr) {
c, err := dialSingle(net, addr, la, ra, deadline)
if _, ok := <-sig; ok {
- lane <- racer{c, ra, err}
+ lane <- racer{c, err}
} else if err == nil {
// We have to return the resources
// that belong to the other
@@ -195,7 +210,6 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
}(ra.toAddr())
}
defer close(sig)
- var failAddr Addr
lastErr := errTimeout
nracers := len(ras)
for nracers > 0 {
@@ -205,12 +219,11 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
if racer.error == nil {
return racer.Conn, nil
}
- failAddr = racer.Addr
lastErr = racer.error
nracers--
}
}
- return nil, &OpError{Op: "dial", Net: net, Addr: failAddr, Err: lastErr}
+ return nil, lastErr
}
// dialSingle attempts to establish and returns a single connection to
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index f1d813f41..f9260fd28 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -58,7 +58,7 @@ func TestDialTimeout(t *testing.T) {
errc <- err
}()
}
- case "darwin", "windows":
+ case "darwin", "plan9", "windows":
// At least OS X 10.7 seems to accept any number of
// connections, ignoring listen's backlog, so resort
// to connecting to a hopefully-dead 127/8 address.
@@ -141,13 +141,13 @@ func TestSelfConnect(t *testing.T) {
n = 1000
}
switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "windows":
+ case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
// Non-Linux systems take a long time to figure
// out that there is nothing listening on localhost.
n = 100
}
for i := 0; i < n; i++ {
- c, err := Dial("tcp", addr)
+ c, err := DialTimeout("tcp", addr, time.Millisecond)
if err == nil {
c.Close()
t.Errorf("#%d: Dial %q succeeded", i, addr)
@@ -425,60 +425,6 @@ func numFD() int {
panic("numFDs not implemented on " + runtime.GOOS)
}
-// Assert that a failed Dial attempt does not leak
-// runtime.PollDesc structures
-func TestDialFailPDLeak(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode")
- }
- if runtime.GOOS == "windows" && runtime.GOARCH == "386" {
- // Just skip the test because it takes too long.
- t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
- }
-
- maxprocs := runtime.GOMAXPROCS(0)
- loops := 10 + maxprocs
- // 500 is enough to turn over the chunk of pollcache.
- // See allocPollDesc in runtime/netpoll.goc.
- const count = 500
- var old runtime.MemStats // used by sysdelta
- runtime.ReadMemStats(&old)
- sysdelta := func() uint64 {
- var new runtime.MemStats
- runtime.ReadMemStats(&new)
- delta := old.Sys - new.Sys
- old = new
- return delta
- }
- d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking
- failcount := 0
- for i := 0; i < loops; i++ {
- var wg sync.WaitGroup
- for i := 0; i < count; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- if c, err := d.Dial("tcp", "127.0.0.1:1"); err == nil {
- t.Error("dial should not succeed")
- c.Close()
- }
- }()
- }
- wg.Wait()
- if t.Failed() {
- t.FailNow()
- }
- if delta := sysdelta(); delta > 0 {
- failcount++
- }
- // there are always some allocations on the first loop
- if failcount > maxprocs+2 {
- t.Error("detected possible memory leak in runtime")
- t.FailNow()
- }
- }
-}
-
func TestDialer(t *testing.T) {
ln, err := Listen("tcp4", "127.0.0.1:0")
if err != nil {
@@ -555,3 +501,36 @@ func TestDialDualStackLocalhost(t *testing.T) {
}
}
}
+
+func TestDialerKeepAlive(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+ defer func() {
+ testHookSetKeepAlive = func() {}
+ }()
+ go func() {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ c.Close()
+ }
+ }()
+ for _, keepAlive := range []bool{false, true} {
+ got := false
+ testHookSetKeepAlive = func() { got = true }
+ var d Dialer
+ if keepAlive {
+ d.KeepAlive = 30 * time.Second
+ }
+ c, err := d.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ if got != keepAlive {
+ t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
+ }
+ }
+}
diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
index b4ebad0e0..df5895afa 100644
--- a/src/pkg/net/dialgoogle_test.go
+++ b/src/pkg/net/dialgoogle_test.go
@@ -104,31 +104,7 @@ var googleaddrsipv4 = []string{
"[::ffff:%02x%02x:%02x%02x]:80",
"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
- "[0:0:0:0:0:ffff::%d.%d.%d.%d]:80",
-}
-
-func TestDNSThreadLimit(t *testing.T) {
- if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
- }
-
- const N = 10000
- c := make(chan int, N)
- for i := 0; i < N; i++ {
- go func(i int) {
- LookupIP(fmt.Sprintf("%d.net-test.golang.org", i))
- c <- 1
- }(i)
- }
- // Don't bother waiting for the stragglers; stop at 0.9 N.
- for i := 0; i < N*9/10; i++ {
- if i%100 == 0 {
- //println("TestDNSThreadLimit:", i)
- }
- <-c
- }
-
- // If we're still here, it worked.
+ "[0:0:0:0::ffff:%d.%d.%d.%d]:80",
}
func TestDialGoogleIPv4(t *testing.T) {
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index 01db43729..9bffa11f9 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -191,10 +191,10 @@ func (addrs byPriorityWeight) shuffleByWeight() {
}
for sum > 0 && len(addrs) > 1 {
s := 0
- n := rand.Intn(sum + 1)
+ n := rand.Intn(sum)
for i := range addrs {
s += int(addrs[i].Weight)
- if s >= n {
+ if s > n {
if i > 0 {
t := addrs[i]
copy(addrs[1:i+1], addrs[0:i])
diff --git a/src/pkg/net/dnsclient_test.go b/src/pkg/net/dnsclient_test.go
new file mode 100644
index 000000000..435eb3550
--- /dev/null
+++ b/src/pkg/net/dnsclient_test.go
@@ -0,0 +1,69 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "math/rand"
+ "testing"
+)
+
+func checkDistribution(t *testing.T, data []*SRV, margin float64) {
+ sum := 0
+ for _, srv := range data {
+ sum += int(srv.Weight)
+ }
+
+ results := make(map[string]int)
+
+ count := 1000
+ for j := 0; j < count; j++ {
+ d := make([]*SRV, len(data))
+ copy(d, data)
+ byPriorityWeight(d).shuffleByWeight()
+ key := d[0].Target
+ results[key] = results[key] + 1
+ }
+
+ actual := results[data[0].Target]
+ expected := float64(count) * float64(data[0].Weight) / float64(sum)
+ diff := float64(actual) - expected
+ t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin)
+ if diff < 0 {
+ diff = -diff
+ }
+ if diff > (expected * margin) {
+ t.Errorf("missed target weight: expected %v, %v", expected, actual)
+ }
+}
+
+func testUniformity(t *testing.T, size int, margin float64) {
+ rand.Seed(1)
+ data := make([]*SRV, size)
+ for i := 0; i < size; i++ {
+ data[i] = &SRV{Target: string('a' + i), Weight: 1}
+ }
+ checkDistribution(t, data, margin)
+}
+
+func TestUniformity(t *testing.T) {
+ testUniformity(t, 2, 0.05)
+ testUniformity(t, 3, 0.10)
+ testUniformity(t, 10, 0.20)
+ testWeighting(t, 0.05)
+}
+
+func testWeighting(t *testing.T, margin float64) {
+ rand.Seed(1)
+ data := []*SRV{
+ {Target: "a", Weight: 60},
+ {Target: "b", Weight: 30},
+ {Target: "c", Weight: 10},
+ }
+ checkDistribution(t, data, margin)
+}
+
+func TestWeighting(t *testing.T) {
+ testWeighting(t, 0.05)
+}
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 16cf420dc..3713efd0e 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
// TODO(rsc):
-// Check periodically whether /etc/resolv.conf has changed.
// Could potentially handle many outstanding lookups faster.
// Could have a small cache.
// Random UDP source port (net.Dial should do that for us).
@@ -19,6 +18,7 @@ package net
import (
"io"
"math/rand"
+ "os"
"sync"
"time"
)
@@ -156,32 +156,90 @@ func convertRR_AAAA(records []dnsRR) []IP {
return addrs
}
-var cfg *dnsConfig
-var dnserr error
+var cfg struct {
+ ch chan struct{}
+ mu sync.RWMutex // protects dnsConfig and dnserr
+ dnsConfig *dnsConfig
+ dnserr error
+}
+var onceLoadConfig sync.Once
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
+// Assume dns config file is /etc/resolv.conf here
+func loadDefaultConfig() {
+ loadConfig("/etc/resolv.conf", 5*time.Second, nil)
+}
-var onceLoadConfig sync.Once
+func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
+ var mtime time.Time
+ cfg.ch = make(chan struct{}, 1)
+ if fi, err := os.Stat(resolvConfPath); err != nil {
+ cfg.dnserr = err
+ } else {
+ mtime = fi.ModTime()
+ cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
+ }
+ go func() {
+ for {
+ time.Sleep(reloadTime)
+ select {
+ case qresp := <-quit:
+ qresp <- struct{}{}
+ return
+ case <-cfg.ch:
+ }
+
+ // In case of error, we keep the previous config
+ fi, err := os.Stat(resolvConfPath)
+ if err != nil {
+ continue
+ }
+ // If the resolv.conf mtime didn't change, do not reload
+ m := fi.ModTime()
+ if m.Equal(mtime) {
+ continue
+ }
+ mtime = m
+ // In case of error, we keep the previous config
+ ncfg, err := dnsReadConfig(resolvConfPath)
+ if err != nil || len(ncfg.servers) == 0 {
+ continue
+ }
+ cfg.mu.Lock()
+ cfg.dnsConfig = ncfg
+ cfg.dnserr = nil
+ cfg.mu.Unlock()
+ }
+ }()
+}
func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
if !isDomainName(name) {
return name, nil, &DNSError{Err: "invalid domain name", Name: name}
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
+ onceLoadConfig.Do(loadDefaultConfig)
+
+ select {
+ case cfg.ch <- struct{}{}:
+ default:
+ }
+
+ cfg.mu.RLock()
+ defer cfg.mu.RUnlock()
+
+ if cfg.dnserr != nil || cfg.dnsConfig == nil {
+ err = cfg.dnserr
return
}
// If name is rooted (trailing dot) or has enough dots,
// try it by itself first.
rooted := len(name) > 0 && name[len(name)-1] == '.'
- if rooted || count(name, '.') >= cfg.ndots {
+ if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
rname := name
if !rooted {
rname += "."
}
// Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
@@ -191,12 +249,12 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
}
// Otherwise, try suffixes.
- for i := 0; i < len(cfg.search); i++ {
- rname := name + "." + cfg.search[i]
+ for i := 0; i < len(cfg.dnsConfig.search); i++ {
+ rname := name + "." + cfg.dnsConfig.search[i]
if rname[len(rname)-1] != '.' {
rname += "."
}
- cname, addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
@@ -207,7 +265,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
if !rooted {
rname += "."
}
- cname, addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
if err == nil {
return
}
@@ -232,11 +290,6 @@ func goLookupHost(name string) (addrs []string, err error) {
if len(addrs) > 0 {
return
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
ips, err := goLookupIP(name)
if err != nil {
return
@@ -267,11 +320,6 @@ func goLookupIP(name string) (addrs []IP, err error) {
return
}
}
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
var records []dnsRR
var cname string
var err4, err6 error
@@ -307,11 +355,6 @@ func goLookupIP(name string) (addrs []IP, err error) {
// depending on our lookup code, so that Go and C get the same
// answers.
func goLookupCNAME(name string) (cname string, err error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
_, rr, err := lookup(name, dnsTypeCNAME)
if err != nil {
return
diff --git a/src/pkg/net/dnsclient_unix_test.go b/src/pkg/net/dnsclient_unix_test.go
index 47dcb563b..2350142d6 100644
--- a/src/pkg/net/dnsclient_unix_test.go
+++ b/src/pkg/net/dnsclient_unix_test.go
@@ -2,12 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
import (
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "reflect"
"testing"
+ "time"
)
func TestTCPLookup(t *testing.T) {
@@ -25,3 +31,129 @@ func TestTCPLookup(t *testing.T) {
t.Fatalf("exchange failed: %v", err)
}
}
+
+type resolvConfTest struct {
+ *testing.T
+ dir string
+ path string
+ started bool
+ quitc chan chan struct{}
+}
+
+func newResolvConfTest(t *testing.T) *resolvConfTest {
+ dir, err := ioutil.TempDir("", "resolvConfTest")
+ if err != nil {
+ t.Fatalf("could not create temp dir: %v", err)
+ }
+
+ // Disable the default loadConfig
+ onceLoadConfig.Do(func() {})
+
+ r := &resolvConfTest{
+ T: t,
+ dir: dir,
+ path: path.Join(dir, "resolv.conf"),
+ quitc: make(chan chan struct{}),
+ }
+
+ return r
+}
+
+func (r *resolvConfTest) Start() {
+ loadConfig(r.path, 100*time.Millisecond, r.quitc)
+ r.started = true
+}
+
+func (r *resolvConfTest) SetConf(s string) {
+ // Make sure the file mtime will be different once we're done here,
+ // even on systems with coarse (1s) mtime resolution.
+ time.Sleep(time.Second)
+
+ f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
+ if err != nil {
+ r.Fatalf("failed to create temp file %s: %v", r.path, err)
+ }
+ if _, err := io.WriteString(f, s); err != nil {
+ f.Close()
+ r.Fatalf("failed to write temp file: %v", err)
+ }
+ f.Close()
+
+ if r.started {
+ cfg.ch <- struct{}{} // fill buffer
+ cfg.ch <- struct{}{} // wait for reload to begin
+ cfg.ch <- struct{}{} // wait for reload to complete
+ }
+}
+
+func (r *resolvConfTest) WantServers(want []string) {
+ cfg.mu.RLock()
+ defer cfg.mu.RUnlock()
+ if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) {
+ r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want)
+ }
+}
+
+func (r *resolvConfTest) Close() {
+ resp := make(chan struct{})
+ r.quitc <- resp
+ <-resp
+ if err := os.RemoveAll(r.dir); err != nil {
+ r.Logf("failed to remove temp dir %s: %v", r.dir, err)
+ }
+}
+
+func TestReloadResolvConfFail(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+
+ r := newResolvConfTest(t)
+ defer r.Close()
+
+ // resolv.conf.tmp does not exist yet
+ r.Start()
+ if _, err := goLookupIP("golang.org"); err == nil {
+ t.Fatal("goLookupIP(missing) succeeded")
+ }
+
+ r.SetConf("nameserver 8.8.8.8")
+ if _, err := goLookupIP("golang.org"); err != nil {
+ t.Fatalf("goLookupIP(missing; good) failed: %v", err)
+ }
+
+ // Using a bad resolv.conf while we had a good
+ // one before should not update the config
+ r.SetConf("")
+ if _, err := goLookupIP("golang.org"); err != nil {
+ t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err)
+ }
+}
+
+func TestReloadResolvConfChange(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+
+ r := newResolvConfTest(t)
+ defer r.Close()
+
+ r.SetConf("nameserver 8.8.8.8")
+ r.Start()
+
+ if _, err := goLookupIP("golang.org"); err != nil {
+ t.Fatalf("goLookupIP(good) failed: %v", err)
+ }
+ r.WantServers([]string{"[8.8.8.8]"})
+
+ // Using a bad resolv.conf when we had a good one
+ // before should not update the config
+ r.SetConf("")
+ if _, err := goLookupIP("golang.org"); err != nil {
+ t.Fatalf("goLookupIP(good; bad) failed: %v", err)
+ }
+
+ // A new good config should get picked up
+ r.SetConf("nameserver 8.8.4.4")
+ r.WantServers([]string{"[8.8.4.4]"})
+}
diff --git a/src/pkg/net/dnsconfig_unix.go b/src/pkg/net/dnsconfig_unix.go
index 2f0f6c031..af288253e 100644
--- a/src/pkg/net/dnsconfig_unix.go
+++ b/src/pkg/net/dnsconfig_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Read system DNS config from /etc/resolv.conf
@@ -20,14 +20,13 @@ type dnsConfig struct {
// See resolv.conf(5) on a Linux machine.
// TODO(rsc): Supposed to call uname() and chop the beginning
// of the host name to get the default search domain.
-// We assume it's in resolv.conf anyway.
-func dnsReadConfig() (*dnsConfig, error) {
- file, err := open("/etc/resolv.conf")
+func dnsReadConfig(filename string) (*dnsConfig, error) {
+ file, err := open(filename)
if err != nil {
return nil, &DNSConfigError{err}
}
conf := new(dnsConfig)
- conf.servers = make([]string, 3)[0:0] // small, but the standard limit
+ conf.servers = make([]string, 0, 3) // small, but the standard limit
conf.search = make([]string, 0)
conf.ndots = 1
conf.timeout = 5
diff --git a/src/pkg/net/dnsconfig_unix_test.go b/src/pkg/net/dnsconfig_unix_test.go
new file mode 100644
index 000000000..37ed4931d
--- /dev/null
+++ b/src/pkg/net/dnsconfig_unix_test.go
@@ -0,0 +1,46 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import "testing"
+
+func TestDNSReadConfig(t *testing.T) {
+ dnsConfig, err := dnsReadConfig("testdata/resolv.conf")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(dnsConfig.servers) != 1 {
+ t.Errorf("len(dnsConfig.servers) = %d; want %d", len(dnsConfig.servers), 1)
+ }
+ if dnsConfig.servers[0] != "[192.168.1.1]" {
+ t.Errorf("dnsConfig.servers[0] = %s; want %s", dnsConfig.servers[0], "[192.168.1.1]")
+ }
+
+ if len(dnsConfig.search) != 1 {
+ t.Errorf("len(dnsConfig.search) = %d; want %d", len(dnsConfig.search), 1)
+ }
+ if dnsConfig.search[0] != "Home" {
+ t.Errorf("dnsConfig.search[0] = %s; want %s", dnsConfig.search[0], "Home")
+ }
+
+ if dnsConfig.ndots != 5 {
+ t.Errorf("dnsConfig.ndots = %d; want %d", dnsConfig.ndots, 5)
+ }
+
+ if dnsConfig.timeout != 10 {
+ t.Errorf("dnsConfig.timeout = %d; want %d", dnsConfig.timeout, 10)
+ }
+
+ if dnsConfig.attempts != 3 {
+ t.Errorf("dnsConfig.attempts = %d; want %d", dnsConfig.attempts, 3)
+ }
+
+ if dnsConfig.rotate != true {
+ t.Errorf("dnsConfig.rotate = %t; want %t", dnsConfig.rotate, true)
+ }
+}
diff --git a/src/pkg/net/fd_mutex_test.go b/src/pkg/net/fd_mutex_test.go
index 8383084b7..c34ec59b9 100644
--- a/src/pkg/net/fd_mutex_test.go
+++ b/src/pkg/net/fd_mutex_test.go
@@ -63,7 +63,8 @@ func TestMutexCloseUnblock(t *testing.T) {
for i := 0; i < 4; i++ {
go func() {
if mu.RWLock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
c <- true
}()
@@ -138,36 +139,44 @@ func TestMutexStress(t *testing.T) {
switch r.Intn(3) {
case 0:
if !mu.Incref() {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
if mu.Decref() {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
case 1:
if !mu.RWLock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
// Ensure that it provides mutual exclusion for readers.
if readState[0] != readState[1] {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
readState[0]++
readState[1]++
if mu.RWUnlock(true) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
case 2:
if !mu.RWLock(false) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
// Ensure that it provides mutual exclusion for writers.
if writeState[0] != writeState[1] {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
writeState[0]++
writeState[1]++
if mu.RWUnlock(false) {
- t.Fatal("broken")
+ t.Error("broken")
+ return
}
}
}
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
index acc829402..5fe8effc2 100644
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -13,12 +13,23 @@ import (
// Network file descritor.
type netFD struct {
- proto, name, dir string
- ctl, data *os.File
- laddr, raddr Addr
+ // locking/lifetime of sysfd + serialize access to Read and Write methods
+ fdmu fdMutex
+
+ // immutable until Close
+ proto string
+ n string
+ dir string
+ ctl, data *os.File
+ laddr, raddr Addr
}
+var (
+ netdir string // default network
+)
+
func sysInit() {
+ netdir = "/net"
}
func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
@@ -27,16 +38,99 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti
return dialChannel(net, ra, dialer, deadline)
}
-func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) *netFD {
- return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, data, laddr, raddr}
+func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+ return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+}
+
+func (fd *netFD) init() error {
+ // stub for future fd.pd.Init(fd)
+ return nil
+}
+
+func (fd *netFD) name() string {
+ var ls, rs string
+ if fd.laddr != nil {
+ ls = fd.laddr.String()
+ }
+ if fd.raddr != nil {
+ rs = fd.raddr.String()
+ }
+ return fd.proto + ":" + ls + "->" + rs
}
func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
+func (fd *netFD) destroy() {
+ if !fd.ok() {
+ return
+ }
+ err := fd.ctl.Close()
+ if fd.data != nil {
+ if err1 := fd.data.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
+ fd.ctl = nil
+ fd.data = nil
+}
+
+// Add a reference to this fd.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref() error {
+ if !fd.fdmu.Incref() {
+ return errClosing
+ }
+ return nil
+}
+
+// Remove a reference to this FD and close if we've been asked to do so
+// (and there are no references left).
+func (fd *netFD) decref() {
+ if fd.fdmu.Decref() {
+ fd.destroy()
+ }
+}
+
+// Add a reference to this fd and lock for reading.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) readLock() error {
+ if !fd.fdmu.RWLock(true) {
+ return errClosing
+ }
+ return nil
+}
+
+// Unlock for reading and remove a reference to this FD.
+func (fd *netFD) readUnlock() {
+ if fd.fdmu.RWUnlock(true) {
+ fd.destroy()
+ }
+}
+
+// Add a reference to this fd and lock for writing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) writeLock() error {
+ if !fd.fdmu.RWLock(false) {
+ return errClosing
+ }
+ return nil
+}
+
+// Unlock for writing and remove a reference to this FD.
+func (fd *netFD) writeUnlock() {
+ if fd.fdmu.RWUnlock(false) {
+ fd.destroy()
+ }
+}
+
func (fd *netFD) Read(b []byte) (n int, err error) {
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
+ if err := fd.readLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readUnlock()
n, err = fd.data.Read(b)
if fd.proto == "udp" && err == io.EOF {
n = 0
@@ -49,17 +143,21 @@ func (fd *netFD) Write(b []byte) (n int, err error) {
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
return fd.data.Write(b)
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
if !fd.ok() {
return syscall.EINVAL
}
return syscall.EPLAN9
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
if !fd.ok() {
return syscall.EINVAL
}
@@ -67,6 +165,9 @@ func (fd *netFD) CloseWrite() error {
}
func (fd *netFD) Close() error {
+ if !fd.fdmu.IncrefAndClose() {
+ return errClosing
+ }
if !fd.ok() {
return syscall.EINVAL
}
diff --git a/src/pkg/net/fd_poll_nacl.go b/src/pkg/net/fd_poll_nacl.go
new file mode 100644
index 000000000..a3701f876
--- /dev/null
+++ b/src/pkg/net/fd_poll_nacl.go
@@ -0,0 +1,94 @@
+// 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 net
+
+import (
+ "syscall"
+ "time"
+)
+
+type pollDesc struct {
+ fd *netFD
+ closing bool
+}
+
+func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) Close() {}
+
+func (pd *pollDesc) Lock() {}
+
+func (pd *pollDesc) Unlock() {}
+
+func (pd *pollDesc) Wakeup() {}
+
+func (pd *pollDesc) Evict() bool {
+ pd.closing = true
+ if pd.fd != nil {
+ syscall.StopIO(pd.fd.sysfd)
+ }
+ return false
+}
+
+func (pd *pollDesc) Prepare(mode int) error {
+ if pd.closing {
+ return errClosing
+ }
+ return nil
+}
+
+func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+
+func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+
+func (pd *pollDesc) Wait(mode int) error {
+ if pd.closing {
+ return errClosing
+ }
+ return errTimeout
+}
+
+func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+
+func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+
+func (pd *pollDesc) WaitCanceled(mode int) {}
+
+func (pd *pollDesc) WaitCanceledRead() {}
+
+func (pd *pollDesc) WaitCanceledWrite() {}
+
+func (fd *netFD) setDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func (fd *netFD) setReadDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r')
+}
+
+func (fd *netFD) setWriteDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+ d := t.UnixNano()
+ if t.IsZero() {
+ d = 0
+ }
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ switch mode {
+ case 'r':
+ syscall.SetReadDeadline(fd.sysfd, d)
+ case 'w':
+ syscall.SetWriteDeadline(fd.sysfd, d)
+ case 'r' + 'w':
+ syscall.SetReadDeadline(fd.sysfd, d)
+ syscall.SetWriteDeadline(fd.sysfd, d)
+ }
+ fd.decref()
+ return nil
+}
diff --git a/src/pkg/net/fd_poll_runtime.go b/src/pkg/net/fd_poll_runtime.go
index e2b276886..2bddc836c 100644
--- a/src/pkg/net/fd_poll_runtime.go
+++ b/src/pkg/net/fd_poll_runtime.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
package net
@@ -12,6 +12,9 @@ import (
"time"
)
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
func runtime_pollServerInit()
func runtime_pollOpen(fd uintptr) (uintptr, int)
func runtime_pollClose(ctx uintptr)
@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
- d := t.UnixNano()
+ d := runtimeNano() + int64(t.Sub(time.Now()))
if t.IsZero() {
d = 0
}
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 9ed4f7536..b82ecd11c 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package net
@@ -75,19 +75,47 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
if err := fd.pd.PrepareWrite(); err != nil {
return err
}
+ switch err := syscall.Connect(fd.sysfd, ra); err {
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+ case nil, syscall.EISCONN:
+ return nil
+ case syscall.EINVAL:
+ // On Solaris we can see EINVAL if the socket has
+ // already been accepted and closed by the server.
+ // Treat this as a successful connection--writes to
+ // the socket will see EOF. For details and a test
+ // case in C see http://golang.org/issue/6828.
+ if runtime.GOOS == "solaris" {
+ return nil
+ }
+ fallthrough
+ default:
+ return err
+ }
for {
- err := syscall.Connect(fd.sysfd, ra)
- if err == nil || err == syscall.EISCONN {
- break
+ // Performing multiple connect system calls on a
+ // non-blocking socket under Unix variants does not
+ // necessarily result in earlier errors being
+ // returned. Instead, once runtime-integrated network
+ // poller tells us that the socket is ready, get the
+ // SO_ERROR socket option to see if the connection
+ // succeeded or failed. See issue 7474 for further
+ // details.
+ if err := fd.pd.WaitWrite(); err != nil {
+ return err
}
- if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
return err
}
- if err = fd.pd.WaitWrite(); err != nil {
+ switch err := syscall.Errno(nerr); err {
+ case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+ case syscall.Errno(0), syscall.EISCONN:
+ return nil
+ default:
return err
}
}
- return nil
}
func (fd *netFD) destroy() {
@@ -180,11 +208,11 @@ func (fd *netFD) shutdown(how int) error {
return nil
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
return fd.shutdown(syscall.SHUT_RD)
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
@@ -215,7 +243,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
return
}
-func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, nil, err
}
@@ -242,7 +270,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return
}
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, 0, 0, nil, err
}
@@ -313,7 +341,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
return nn, err
}
-func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
+func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
@@ -338,7 +366,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
return
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
if err := fd.writeLock(); err != nil {
return 0, 0, err
}
@@ -347,7 +375,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
}
for {
- err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
if err = fd.pd.WaitWrite(); err == nil {
continue
@@ -356,7 +384,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
break
}
if err == nil {
- n = len(p)
oobn = len(oob)
} else {
err = &OpError{"write", fd.net, fd.raddr, err}
@@ -455,7 +482,6 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
func (fd *netFD) dup() (f *os.File, err error) {
ns, err := dupCloseOnExec(fd.sysfd)
if err != nil {
- syscall.ForkLock.RUnlock()
return nil, &OpError{"dup", fd.net, fd.laddr, err}
}
diff --git a/src/pkg/net/fd_unix_test.go b/src/pkg/net/fd_unix_test.go
index 65d3e69a7..fe8e8ff6a 100644
--- a/src/pkg/net/fd_unix_test.go
+++ b/src/pkg/net/fd_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 630fc5e6f..a1f6bc5f8 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -119,7 +119,7 @@ func (o *operation) InitBuf(buf []byte) {
o.buf.Len = uint32(len(buf))
o.buf.Buf = nil
if len(buf) != 0 {
- o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
+ o.buf.Buf = &buf[0]
}
}
@@ -431,11 +431,11 @@ func (fd *netFD) shutdown(how int) error {
return nil
}
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
return fd.shutdown(syscall.SHUT_RD)
}
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
@@ -458,7 +458,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
return n, err
}
-func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
if len(buf) == 0 {
return 0, nil, nil
}
@@ -497,7 +497,7 @@ func (fd *netFD) Write(buf []byte) (int, error) {
})
}
-func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 {
return 0, nil
}
@@ -628,10 +628,10 @@ func (fd *netFD) dup() (*os.File, error) {
var errNoSupport = errors.New("address family not supported")
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
return 0, 0, 0, nil, errNoSupport
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
return 0, 0, errNoSupport
}
diff --git a/src/pkg/net/file_plan9.go b/src/pkg/net/file_plan9.go
index f6ee1c29e..068f0881d 100644
--- a/src/pkg/net/file_plan9.go
+++ b/src/pkg/net/file_plan9.go
@@ -43,7 +43,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
}
comp := splitAtBytes(path, "/")
n := len(comp)
- if n < 3 || comp[0] != "net" {
+ if n < 3 || comp[0][0:3] != "net" {
return nil, syscall.EPLAN9
}
@@ -58,7 +58,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
}
defer close(fd)
- dir := "/net/" + comp[n-2]
+ dir := netdir + "/" + comp[n-2]
ctl = os.NewFile(uintptr(fd), dir+"/"+file)
ctl.Seek(0, 0)
var buf [16]byte
@@ -71,19 +71,19 @@ func newFileFD(f *os.File) (net *netFD, err error) {
if len(comp) < 4 {
return nil, errors.New("could not find control file for connection")
}
- dir := "/net/" + comp[1] + "/" + name
+ dir := netdir + "/" + comp[1] + "/" + name
ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0)
if err != nil {
return nil, err
}
defer close(int(ctl.Fd()))
}
- dir := "/net/" + comp[1] + "/" + name
+ dir := netdir + "/" + comp[1] + "/" + name
laddr, err := readPlan9Addr(comp[1], dir+"/local")
if err != nil {
return nil, err
}
- return newFD(comp[1], name, ctl, nil, laddr, nil), nil
+ return newFD(comp[1], name, ctl, nil, laddr, nil)
}
func newFileConn(f *os.File) (c Conn, err error) {
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index acaf18851..d81bca782 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -174,12 +174,14 @@ var filePacketConnTests = []struct {
{net: "udp6", addr: "[::1]", ipv6: true},
+ {net: "ip4:icmp", addr: "127.0.0.1"},
+
{net: "unixgram", addr: "@gotest3/net", linux: true},
}
func TestFilePacketConn(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -187,6 +189,10 @@ func TestFilePacketConn(t *testing.T) {
if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
continue
}
+ if os.Getuid() != 0 && tt.net == "ip4:icmp" {
+ t.Log("skipping test; must be root")
+ continue
+ }
testFilePacketConnListen(t, tt.net, tt.addr)
switch tt.addr {
case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
diff --git a/src/pkg/net/file_unix.go b/src/pkg/net/file_unix.go
index 8fe1b0eb0..07b3ecf62 100644
--- a/src/pkg/net/file_unix.go
+++ b/src/pkg/net/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package net
@@ -129,6 +129,8 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
switch fd.laddr.(type) {
case *UDPAddr:
return newUDPConn(fd), nil
+ case *IPAddr:
+ return newIPConn(fd), nil
case *UnixAddr:
return newUnixConn(fd), nil
}
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index b07ed0baa..2fe358e07 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -41,7 +41,7 @@ func TestLookupStaticHost(t *testing.T) {
if len(ips) != len(tt.ips) {
t.Errorf("# of hosts = %v; want %v",
len(ips), len(tt.ips))
- return
+ continue
}
for k, v := range ips {
if tt.ips[k].String() != v {
diff --git a/src/pkg/net/http/cgi/host.go b/src/pkg/net/http/cgi/host.go
index d27cc4dc9..ec95a972c 100644
--- a/src/pkg/net/http/cgi/host.go
+++ b/src/pkg/net/http/cgi/host.go
@@ -214,12 +214,17 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
internalError(err)
return
}
+ if hook := testHookStartProcess; hook != nil {
+ hook(cmd.Process)
+ }
defer cmd.Wait()
defer stdoutRead.Close()
linebody := bufio.NewReaderSize(stdoutRead, 1024)
headers := make(http.Header)
statusCode := 0
+ headerLines := 0
+ sawBlankLine := false
for {
line, isPrefix, err := linebody.ReadLine()
if isPrefix {
@@ -236,8 +241,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
if len(line) == 0 {
+ sawBlankLine = true
break
}
+ headerLines++
parts := strings.SplitN(string(line), ":", 2)
if len(parts) < 2 {
h.printf("cgi: bogus header line: %s", string(line))
@@ -263,6 +270,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
headers.Add(header, val)
}
}
+ if headerLines == 0 || !sawBlankLine {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: no headers")
+ return
+ }
if loc := headers.Get("Location"); loc != "" {
if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
@@ -274,6 +286,12 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
+ if statusCode == 0 && headers.Get("Content-Type") == "" {
+ rw.WriteHeader(http.StatusInternalServerError)
+ h.printf("cgi: missing required Content-Type in headers")
+ return
+ }
+
if statusCode == 0 {
statusCode = http.StatusOK
}
@@ -292,6 +310,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
_, err = io.Copy(rw, linebody)
if err != nil {
h.printf("cgi: copy error: %v", err)
+ // And kill the child CGI process so we don't hang on
+ // the deferred cmd.Wait above if the error was just
+ // the client (rw) going away. If it was a read error
+ // (because the child died itself), then the extra
+ // kill of an already-dead process is harmless (the PID
+ // won't be reused until the Wait above).
+ cmd.Process.Kill()
}
}
@@ -348,3 +373,5 @@ func upperCaseAndUnderscore(r rune) rune {
// TODO: other transformations in spec or practice?
return r
}
+
+var testHookStartProcess func(*os.Process) // nil except for some tests
diff --git a/src/pkg/net/http/cgi/matryoshka_test.go b/src/pkg/net/http/cgi/matryoshka_test.go
index e1a78c8f6..18c4803e7 100644
--- a/src/pkg/net/http/cgi/matryoshka_test.go
+++ b/src/pkg/net/http/cgi/matryoshka_test.go
@@ -9,15 +9,25 @@
package cgi
import (
+ "bytes"
+ "errors"
"fmt"
+ "io"
"net/http"
+ "net/http/httptest"
"os"
+ "runtime"
"testing"
+ "time"
)
// This test is a CGI host (testing host.go) that runs its own binary
// as a child process testing the other half of CGI (child.go).
func TestHostingOurselves(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
h := &Handler{
Path: os.Args[0],
Root: "/test.go",
@@ -51,8 +61,88 @@ func TestHostingOurselves(t *testing.T) {
}
}
-// Test that a child handler only writing headers works.
+type customWriterRecorder struct {
+ w io.Writer
+ *httptest.ResponseRecorder
+}
+
+func (r *customWriterRecorder) Write(p []byte) (n int, err error) {
+ return r.w.Write(p)
+}
+
+type limitWriter struct {
+ w io.Writer
+ n int
+}
+
+func (w *limitWriter) Write(p []byte) (n int, err error) {
+ if len(p) > w.n {
+ p = p[:w.n]
+ }
+ if len(p) > 0 {
+ n, err = w.w.Write(p)
+ w.n -= n
+ }
+ if w.n == 0 {
+ err = errors.New("past write limit")
+ }
+ return
+}
+
+// If there's an error copying the child's output to the parent, test
+// that we kill the child.
+func TestKillChildAfterCopyError(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
+ defer func() { testHookStartProcess = nil }()
+ proc := make(chan *os.Process, 1)
+ testHookStartProcess = func(p *os.Process) {
+ proc <- p
+ }
+
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil)
+ rec := httptest.NewRecorder()
+ var out bytes.Buffer
+ const writeLen = 50 << 10
+ rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec}
+
+ donec := make(chan bool, 1)
+ go func() {
+ h.ServeHTTP(rw, req)
+ donec <- true
+ }()
+
+ select {
+ case <-donec:
+ if out.Len() != writeLen || out.Bytes()[0] != 'a' {
+ t.Errorf("unexpected output: %q", out.Bytes())
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?")
+ select {
+ case p := <-proc:
+ p.Kill()
+ t.Logf("killed process")
+ default:
+ t.Logf("didn't kill process")
+ }
+ }
+}
+
+// Test that a child handler writing only headers works.
+// golang.org/issue/7196
func TestChildOnlyHeaders(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
h := &Handler{
Path: os.Args[0],
Root: "/test.go",
@@ -67,18 +157,63 @@ func TestChildOnlyHeaders(t *testing.T) {
}
}
+// golang.org/issue/7198
+func Test500WithNoHeaders(t *testing.T) { want500Test(t, "/immediate-disconnect") }
+func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
+func Test500WithEmptyHeaders(t *testing.T) { want500Test(t, "/empty-headers") }
+
+func want500Test(t *testing.T, path string) {
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ expectedMap := map[string]string{
+ "_body": "",
+ }
+ replay := runCgiTest(t, h, "GET "+path+" HTTP/1.0\nHost: example.com\n\n", expectedMap)
+ if replay.Code != 500 {
+ t.Errorf("Got code %d; want 500", replay.Code)
+ }
+}
+
+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
+}
+
// Note: not actually a test.
func TestBeChildCGIProcess(t *testing.T) {
if os.Getenv("REQUEST_METHOD") == "" {
// Not in a CGI environment; skipping test.
return
}
+ switch os.Getenv("REQUEST_URI") {
+ case "/immediate-disconnect":
+ os.Exit(0)
+ case "/no-content-type":
+ fmt.Printf("Content-Length: 6\n\nHello\n")
+ os.Exit(0)
+ case "/empty-headers":
+ fmt.Printf("\nHello")
+ os.Exit(0)
+ }
Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-Test-Header", "X-Test-Value")
req.ParseForm()
if req.FormValue("no-body") == "1" {
return
}
+ if req.FormValue("write-forever") == "1" {
+ io.Copy(rw, neverEnding('a'))
+ for {
+ time.Sleep(5 * time.Second) // hang forever, until killed
+ }
+ }
fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
for k, vv := range req.Form {
for _, v := range vv {
diff --git a/src/pkg/net/http/chunked.go b/src/pkg/net/http/chunked.go
index 91db01724..749f29d32 100644
--- a/src/pkg/net/http/chunked.go
+++ b/src/pkg/net/http/chunked.go
@@ -4,13 +4,14 @@
// The wire protocol for HTTP's "chunked" Transfer-Encoding.
-// This code is duplicated in httputil/chunked.go.
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package http
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -57,26 +58,45 @@ func (cr *chunkedReader) beginChunk() {
}
}
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
- if cr.err != nil {
- return 0, cr.err
+func (cr *chunkedReader) chunkHeaderAvailable() bool {
+ n := cr.r.Buffered()
+ if n > 0 {
+ peek, _ := cr.r.Peek(n)
+ return bytes.IndexByte(peek, '\n') >= 0
}
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
+ return false
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ for cr.err == nil {
+ if cr.n == 0 {
+ if n > 0 && !cr.chunkHeaderAvailable() {
+ // We've read enough. Don't potentially block
+ // reading a new chunk header.
+ break
+ }
+ cr.beginChunk()
+ continue
}
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
+ if len(b) == 0 {
+ break
+ }
+ rbuf := b
+ if uint64(len(rbuf)) > cr.n {
+ rbuf = rbuf[:cr.n]
+ }
+ var n0 int
+ n0, cr.err = cr.r.Read(rbuf)
+ n += n0
+ b = b[n0:]
+ cr.n -= uint64(n0)
+ // If we're at the end of a chunk, read the next two
+ // bytes to verify they are "\r\n".
+ if cr.n == 0 && cr.err == nil {
+ if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+ if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
}
}
}
diff --git a/src/pkg/net/http/chunked_test.go b/src/pkg/net/http/chunked_test.go
index 0b18c7b55..34544790a 100644
--- a/src/pkg/net/http/chunked_test.go
+++ b/src/pkg/net/http/chunked_test.go
@@ -2,17 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This code is duplicated in httputil/chunked_test.go.
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package http
import (
+ "bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
- "runtime"
+ "strings"
"testing"
)
@@ -41,9 +42,77 @@ func TestChunk(t *testing.T) {
}
}
+func TestChunkReadMultiple(t *testing.T) {
+ // Bunch of small chunks, all read together.
+ {
+ var b bytes.Buffer
+ w := newChunkedWriter(&b)
+ w.Write([]byte("foo"))
+ w.Write([]byte("bar"))
+ w.Close()
+
+ r := newChunkedReader(&b)
+ buf := make([]byte, 10)
+ n, err := r.Read(buf)
+ if n != 6 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 6, EOF", n, err)
+ }
+ buf = buf[:n]
+ if string(buf) != "foobar" {
+ t.Errorf("Read = %q; want %q", buf, "foobar")
+ }
+ }
+
+ // One big chunk followed by a little chunk, but the small bufio.Reader size
+ // should prevent the second chunk header from being read.
+ {
+ var b bytes.Buffer
+ w := newChunkedWriter(&b)
+ // fillBufChunk is 11 bytes + 3 bytes header + 2 bytes footer = 16 bytes,
+ // the same as the bufio ReaderSize below (the minimum), so even
+ // though we're going to try to Read with a buffer larger enough to also
+ // receive "foo", the second chunk header won't be read yet.
+ const fillBufChunk = "0123456789a"
+ const shortChunk = "foo"
+ w.Write([]byte(fillBufChunk))
+ w.Write([]byte(shortChunk))
+ w.Close()
+
+ r := newChunkedReader(bufio.NewReaderSize(&b, 16))
+ buf := make([]byte, len(fillBufChunk)+len(shortChunk))
+ n, err := r.Read(buf)
+ if n != len(fillBufChunk) || err != nil {
+ t.Errorf("Read = %d, %v; want %d, nil", n, err, len(fillBufChunk))
+ }
+ buf = buf[:n]
+ if string(buf) != fillBufChunk {
+ t.Errorf("Read = %q; want %q", buf, fillBufChunk)
+ }
+
+ n, err = r.Read(buf)
+ if n != len(shortChunk) || err != io.EOF {
+ t.Errorf("Read = %d, %v; want %d, EOF", n, err, len(shortChunk))
+ }
+ }
+
+ // And test that we see an EOF chunk, even though our buffer is already full:
+ {
+ r := newChunkedReader(bufio.NewReader(strings.NewReader("3\r\nfoo\r\n0\r\n")))
+ buf := make([]byte, 3)
+ n, err := r.Read(buf)
+ if n != 3 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 3, EOF", n, err)
+ }
+ if string(buf) != "foo" {
+ t.Errorf("buf = %q; want foo", buf)
+ }
+ }
+}
+
func TestChunkReaderAllocs(t *testing.T) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
var buf bytes.Buffer
w := newChunkedWriter(&buf)
a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
@@ -52,26 +121,23 @@ func TestChunkReaderAllocs(t *testing.T) {
w.Write(c)
w.Close()
- r := newChunkedReader(&buf)
readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
- var ms runtime.MemStats
- runtime.ReadMemStats(&ms)
- m0 := ms.Mallocs
-
- n, err := io.ReadFull(r, readBuf)
-
- runtime.ReadMemStats(&ms)
- mallocs := ms.Mallocs - m0
- if mallocs > 1 {
- t.Errorf("%d mallocs; want <= 1", mallocs)
- }
-
- if n != len(readBuf)-1 {
- t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
- }
- if err != io.ErrUnexpectedEOF {
- t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
+ byter := bytes.NewReader(buf.Bytes())
+ bufr := bufio.NewReader(byter)
+ mallocs := testing.AllocsPerRun(100, func() {
+ byter.Seek(0, 0)
+ bufr.Reset(byter)
+ r := newChunkedReader(bufr)
+ n, err := io.ReadFull(r, readBuf)
+ if n != len(readBuf)-1 {
+ t.Fatalf("read %d bytes; want %d", n, len(readBuf)-1)
+ }
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("read error = %v; want ErrUnexpectedEOF", err)
+ }
+ })
+ if mallocs > 1.5 {
+ t.Errorf("mallocs = %v; want 1", mallocs)
}
}
diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go
index 22f2e865c..a5a3abe61 100644
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -14,9 +14,12 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
"log"
"net/url"
"strings"
+ "sync"
+ "time"
)
// A Client is an HTTP client. Its zero value (DefaultClient) is a
@@ -52,6 +55,20 @@ type Client struct {
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar CookieJar
+
+ // Timeout specifies a time limit for requests made by this
+ // Client. The timeout includes connection time, any
+ // redirects, and reading the response body. The timer remains
+ // running after Get, Head, Post, or Do return and will
+ // interrupt reading of the Response.Body.
+ //
+ // A Timeout of zero means no timeout.
+ //
+ // The Client's Transport must support the CancelRequest
+ // method or Client will return errors when attempting to make
+ // a request with Get, Head, Post, or Do. Client's default
+ // Transport (DefaultTransport) supports CancelRequest.
+ Timeout time.Duration
}
// DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -74,8 +91,9 @@ type RoundTripper interface {
// authentication, or cookies.
//
// RoundTrip should not modify the request, except for
- // consuming and closing the Body. The request's URL and
- // Header fields are guaranteed to be initialized.
+ // consuming and closing the Body, including on errors. The
+ // request's URL and Header fields are guaranteed to be
+ // initialized.
RoundTrip(*Request) (*Response, error)
}
@@ -97,7 +115,7 @@ func (c *Client) send(req *Request) (*Response, error) {
req.AddCookie(cookie)
}
}
- resp, err := send(req, c.Transport)
+ resp, err := send(req, c.transport())
if err != nil {
return nil, err
}
@@ -123,6 +141,9 @@ func (c *Client) send(req *Request) (*Response, error) {
// (typically Transport) may not be able to re-use a persistent TCP
// connection to the server for a subsequent "keep-alive" request.
//
+// The request Body, if non-nil, will be closed by the underlying
+// Transport, even on errors.
+//
// Generally Get, Post, or PostForm will be used instead of Do.
func (c *Client) Do(req *Request) (resp *Response, err error) {
if req.Method == "GET" || req.Method == "HEAD" {
@@ -134,22 +155,28 @@ func (c *Client) Do(req *Request) (resp *Response, err error) {
return c.send(req)
}
+func (c *Client) transport() RoundTripper {
+ if c.Transport != nil {
+ return c.Transport
+ }
+ return DefaultTransport
+}
+
// send issues an HTTP request.
// Caller should close resp.Body when done reading from it.
func send(req *Request, t RoundTripper) (resp *Response, err error) {
if t == nil {
- t = DefaultTransport
- if t == nil {
- err = errors.New("http: no Client.Transport or DefaultTransport")
- return
- }
+ req.closeBody()
+ return nil, errors.New("http: no Client.Transport or DefaultTransport")
}
if req.URL == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
if req.RequestURI != "" {
+ req.closeBody()
return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
}
@@ -257,21 +284,40 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
var via []*Request
if ireq.URL == nil {
+ ireq.closeBody()
return nil, errors.New("http: nil Request.URL")
}
+ var reqmu sync.Mutex // guards req
req := ireq
+
+ var timer *time.Timer
+ if c.Timeout > 0 {
+ type canceler interface {
+ CancelRequest(*Request)
+ }
+ tr, ok := c.transport().(canceler)
+ if !ok {
+ return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport())
+ }
+ timer = time.AfterFunc(c.Timeout, func() {
+ reqmu.Lock()
+ defer reqmu.Unlock()
+ tr.CancelRequest(req)
+ })
+ }
+
urlStr := "" // next relative or absolute URL to fetch (after first request)
redirectFailed := false
for redirect := 0; ; redirect++ {
if redirect != 0 {
- req = new(Request)
- req.Method = ireq.Method
+ nreq := new(Request)
+ nreq.Method = ireq.Method
if ireq.Method == "POST" || ireq.Method == "PUT" {
- req.Method = "GET"
+ nreq.Method = "GET"
}
- req.Header = make(Header)
- req.URL, err = base.Parse(urlStr)
+ nreq.Header = make(Header)
+ nreq.URL, err = base.Parse(urlStr)
if err != nil {
break
}
@@ -279,15 +325,18 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
// Add the Referer header.
lastReq := via[len(via)-1]
if lastReq.URL.Scheme != "https" {
- req.Header.Set("Referer", lastReq.URL.String())
+ nreq.Header.Set("Referer", lastReq.URL.String())
}
- err = redirectChecker(req, via)
+ err = redirectChecker(nreq, via)
if err != nil {
redirectFailed = true
break
}
}
+ reqmu.Lock()
+ req = nreq
+ reqmu.Unlock()
}
urlStr = req.URL.String()
@@ -296,6 +345,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
}
if shouldRedirect(resp.StatusCode) {
+ // Read the body if small so underlying TCP connection will be re-used.
+ // No need to check for errors: if it fails, Transport won't reuse it anyway.
+ const maxBodySlurpSize = 2 << 10
+ if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
+ io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
+ }
resp.Body.Close()
if urlStr = resp.Header.Get("Location"); urlStr == "" {
err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
@@ -305,7 +360,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
via = append(via, req)
continue
}
- return
+ if timer != nil {
+ resp.Body = &cancelTimerBody{timer, resp.Body}
+ }
+ return resp, nil
}
method := ireq.Method
@@ -349,7 +407,7 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
// Caller should close resp.Body when done reading from it.
//
// If the provided body is also an io.Closer, it is closed after the
-// body is successfully written to the server.
+// request.
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
@@ -408,3 +466,22 @@ func (c *Client) Head(url string) (resp *Response, err error) {
}
return c.doFollowingRedirects(req, shouldRedirectGet)
}
+
+type cancelTimerBody struct {
+ t *time.Timer
+ rc io.ReadCloser
+}
+
+func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
+ n, err = b.rc.Read(p)
+ if err == io.EOF {
+ b.t.Stop()
+ }
+ return
+}
+
+func (b *cancelTimerBody) Close() error {
+ err := b.rc.Close()
+ b.t.Stop()
+ return err
+}
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index 997d04151..6392c1baf 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -15,14 +15,18 @@ import (
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
. "net/http"
"net/http/httptest"
"net/url"
+ "reflect"
+ "sort"
"strconv"
"strings"
"sync"
"testing"
+ "time"
)
var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -54,6 +58,13 @@ func pedanticReadAll(r io.Reader) (b []byte, err error) {
}
}
+type chanWriter chan string
+
+func (w chanWriter) Write(p []byte) (n int, err error) {
+ w <- string(p)
+ return len(p), nil
+}
+
func TestClient(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
@@ -373,24 +384,6 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
return j.perURL[u.Host]
}
-func TestRedirectCookiesOnRequest(t *testing.T) {
- defer afterTest(t)
- var ts *httptest.Server
- ts = httptest.NewServer(echoCookiesRedirectHandler)
- defer ts.Close()
- c := &Client{}
- req, _ := NewRequest("GET", ts.URL, nil)
- req.AddCookie(expectedCookies[0])
- // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands.
- _ = c
- // resp, _ := c.Do(req)
- // matchReturnedCookies(t, expectedCookies, resp.Cookies())
-
- req, _ = NewRequest("GET", ts.URL, nil)
- // resp, _ = c.Do(req)
- // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies())
-}
-
func TestRedirectCookiesJar(t *testing.T) {
defer afterTest(t)
var ts *httptest.Server
@@ -410,8 +403,8 @@ func TestRedirectCookiesJar(t *testing.T) {
}
func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
- t.Logf("Received cookies: %v", given)
if len(given) != len(expected) {
+ t.Logf("Received cookies: %v", given)
t.Errorf("Expected %d cookies, got %d", len(expected), len(given))
}
for _, ec := range expected {
@@ -582,6 +575,8 @@ func TestClientInsecureTransport(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
+ errc := make(chanWriter, 10) // but only expecting 1
+ ts.Config.ErrorLog = log.New(errc, "", 0)
defer ts.Close()
// TODO(bradfitz): add tests for skipping hostname checks too?
@@ -603,6 +598,16 @@ func TestClientInsecureTransport(t *testing.T) {
res.Body.Close()
}
}
+
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "TLS handshake error") {
+ t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
+
}
func TestClientErrorWithRequestURI(t *testing.T) {
@@ -653,6 +658,8 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
+ errc := make(chanWriter, 10) // but only expecting 1
+ ts.Config.ErrorLog = log.New(errc, "", 0)
trans := newTLSTransport(t, ts)
trans.TLSClientConfig.ServerName = "badserver"
@@ -664,6 +671,14 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") {
t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err)
}
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "TLS handshake error") {
+ t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
}
// Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName
@@ -696,6 +711,33 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) {
res.Body.Close()
}
+func TestResponseSetsTLSConnectionState(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Write([]byte("Hello"))
+ }))
+ defer ts.Close()
+
+ tr := newTLSTransport(t, ts)
+ tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
+ tr.Dial = func(netw, addr string) (net.Conn, error) {
+ return net.Dial(netw, ts.Listener.Addr().String())
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get("https://example.com/")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.TLS == nil {
+ t.Fatal("Response didn't set TLS Connection State.")
+ }
+ if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want {
+ t.Errorf("TLS Cipher Suite = %d; want %d", got, want)
+ }
+}
+
// Verify Response.ContentLength is populated. http://golang.org/issue/4126
func TestClientHeadContentLength(t *testing.T) {
defer afterTest(t)
@@ -799,3 +841,198 @@ func TestBasicAuth(t *testing.T) {
t.Errorf("Invalid auth %q", auth)
}
}
+
+func TestClientTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ defer afterTest(t)
+ sawRoot := make(chan bool, 1)
+ sawSlow := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/" {
+ sawRoot <- true
+ Redirect(w, r, "/slow", StatusFound)
+ return
+ }
+ if r.URL.Path == "/slow" {
+ w.Write([]byte("Hello"))
+ w.(Flusher).Flush()
+ sawSlow <- true
+ time.Sleep(2 * time.Second)
+ return
+ }
+ }))
+ defer ts.Close()
+ const timeout = 500 * time.Millisecond
+ c := &Client{
+ Timeout: timeout,
+ }
+
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ select {
+ case <-sawRoot:
+ // good.
+ default:
+ t.Fatal("handler never got / request")
+ }
+
+ select {
+ case <-sawSlow:
+ // good.
+ default:
+ t.Fatal("handler never got /slow request")
+ }
+
+ errc := make(chan error, 1)
+ go func() {
+ _, err := ioutil.ReadAll(res.Body)
+ errc <- err
+ res.Body.Close()
+ }()
+
+ const failTime = timeout * 2
+ select {
+ case err := <-errc:
+ if err == nil {
+ t.Error("expected error from ReadAll")
+ }
+ // Expected error.
+ case <-time.After(failTime):
+ t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
+ }
+}
+
+func TestClientRedirectEatsBody(t *testing.T) {
+ defer afterTest(t)
+ saw := make(chan string, 2)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ saw <- r.RemoteAddr
+ if r.URL.Path == "/" {
+ Redirect(w, r, "/foo", StatusFound) // which includes a body
+ }
+ }))
+ defer ts.Close()
+
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+
+ var first string
+ select {
+ case first = <-saw:
+ default:
+ t.Fatal("server didn't see a request")
+ }
+
+ var second string
+ select {
+ case second = <-saw:
+ default:
+ t.Fatal("server didn't see a second request")
+ }
+
+ if first != second {
+ t.Fatal("server saw different client ports before & after the redirect")
+ }
+}
+
+// eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF.
+type eofReaderFunc func()
+
+func (f eofReaderFunc) Read(p []byte) (n int, err error) {
+ f()
+ return 0, io.EOF
+}
+
+func TestClientTrailers(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
+ w.Header().Add("Trailer", "Server-Trailer-C")
+
+ var decl []string
+ for k := range r.Trailer {
+ decl = append(decl, k)
+ }
+ sort.Strings(decl)
+
+ slurp, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Errorf("Server reading request body: %v", err)
+ }
+ if string(slurp) != "foo" {
+ t.Errorf("Server read request body %q; want foo", slurp)
+ }
+ if r.Trailer == nil {
+ io.WriteString(w, "nil Trailer")
+ } else {
+ fmt.Fprintf(w, "decl: %v, vals: %s, %s",
+ decl,
+ r.Trailer.Get("Client-Trailer-A"),
+ r.Trailer.Get("Client-Trailer-B"))
+ }
+
+ // TODO: golang.org/issue/7759: there's no way yet for
+ // the server to set trailers without hijacking, so do
+ // that for now, just to test the client. Later, in
+ // Go 1.4, it should be implicit that any mutations
+ // to w.Header() after the initial write are the
+ // trailers to be sent, if and only if they were
+ // previously declared with w.Header().Set("Trailer",
+ // ..keys..)
+ w.(Flusher).Flush()
+ conn, buf, _ := w.(Hijacker).Hijack()
+ t := Header{}
+ t.Set("Server-Trailer-A", "valuea")
+ t.Set("Server-Trailer-C", "valuec") // skipping B
+ buf.WriteString("0\r\n") // eof
+ t.Write(buf)
+ buf.WriteString("\r\n") // end of trailers
+ buf.Flush()
+ conn.Close()
+ }))
+ defer ts.Close()
+
+ var req *Request
+ req, _ = NewRequest("POST", ts.URL, io.MultiReader(
+ eofReaderFunc(func() {
+ req.Trailer["Client-Trailer-A"] = []string{"valuea"}
+ }),
+ strings.NewReader("foo"),
+ eofReaderFunc(func() {
+ req.Trailer["Client-Trailer-B"] = []string{"valueb"}
+ }),
+ ))
+ req.Trailer = Header{
+ "Client-Trailer-A": nil, // to be set later
+ "Client-Trailer-B": nil, // to be set later
+ }
+ req.ContentLength = -1
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil {
+ t.Error(err)
+ }
+ want := Header{
+ "Server-Trailer-A": []string{"valuea"},
+ "Server-Trailer-B": nil,
+ "Server-Trailer-C": []string{"valuec"},
+ }
+ if !reflect.DeepEqual(res.Trailer, want) {
+ t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want)
+ }
+}
diff --git a/src/pkg/net/http/cookie.go b/src/pkg/net/http/cookie.go
index 8b01c508e..dc60ba87f 100644
--- a/src/pkg/net/http/cookie.go
+++ b/src/pkg/net/http/cookie.go
@@ -76,11 +76,7 @@ func readSetCookies(h Header) []*Cookie {
attr, val = attr[:j], attr[j+1:]
}
lowerAttr := strings.ToLower(attr)
- parseCookieValueFn := parseCookieValue
- if lowerAttr == "expires" {
- parseCookieValueFn = parseCookieExpiresValue
- }
- val, success = parseCookieValueFn(val)
+ val, success = parseCookieValue(val)
if !success {
c.Unparsed = append(c.Unparsed, parts[i])
continue
@@ -94,7 +90,6 @@ func readSetCookies(h Header) []*Cookie {
continue
case "domain":
c.Domain = val
- // TODO: Add domain parsing
continue
case "max-age":
secs, err := strconv.Atoi(val)
@@ -121,7 +116,6 @@ func readSetCookies(h Header) []*Cookie {
continue
case "path":
c.Path = val
- // TODO: Add path parsing
continue
}
c.Unparsed = append(c.Unparsed, parts[i])
@@ -300,12 +294,23 @@ func sanitizeCookieName(n string) string {
// ; US-ASCII characters excluding CTLs,
// ; whitespace DQUOTE, comma, semicolon,
// ; and backslash
+// We loosen this as spaces and commas are common in cookie values
+// but we produce a quoted cookie-value in when value starts or ends
+// with a comma or space.
+// See http://golang.org/issue/7243 for the discussion.
func sanitizeCookieValue(v string) string {
- return sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+ v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+ if len(v) == 0 {
+ return v
+ }
+ if v[0] == ' ' || v[0] == ',' || v[len(v)-1] == ' ' || v[len(v)-1] == ',' {
+ return `"` + v + `"`
+ }
+ return v
}
func validCookieValueByte(b byte) bool {
- return 0x20 < b && b < 0x7f && b != '"' && b != ',' && b != ';' && b != '\\'
+ return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\'
}
// path-av = "Path=" path-value
@@ -340,38 +345,13 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string {
return string(buf)
}
-func unquoteCookieValue(v string) string {
- if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' {
- return v[1 : len(v)-1]
- }
- return v
-}
-
-func isCookieByte(c byte) bool {
- switch {
- case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
- 0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
- return true
- }
- return false
-}
-
-func isCookieExpiresByte(c byte) (ok bool) {
- return isCookieByte(c) || c == ',' || c == ' '
-}
-
func parseCookieValue(raw string) (string, bool) {
- return parseCookieValueUsing(raw, isCookieByte)
-}
-
-func parseCookieExpiresValue(raw string) (string, bool) {
- return parseCookieValueUsing(raw, isCookieExpiresByte)
-}
-
-func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
- raw = unquoteCookieValue(raw)
+ // Strip the quotes, if present.
+ if len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
+ raw = raw[1 : len(raw)-1]
+ }
for i := 0; i < len(raw); i++ {
- if !validByte(raw[i]) {
+ if !validCookieValueByte(raw[i]) {
return "", false
}
}
diff --git a/src/pkg/net/http/cookie_test.go b/src/pkg/net/http/cookie_test.go
index 11b01cc57..f78f37299 100644
--- a/src/pkg/net/http/cookie_test.go
+++ b/src/pkg/net/http/cookie_test.go
@@ -5,9 +5,13 @@
package http
import (
+ "bytes"
"encoding/json"
"fmt"
+ "log"
+ "os"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -48,15 +52,61 @@ var writeSetCookiesTests = []struct {
&Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"},
"cookie-8=eight",
},
+ // The "special" cookies have values containing commas or spaces which
+ // are disallowed by RFC 6265 but are common in the wild.
+ {
+ &Cookie{Name: "special-1", Value: "a z"},
+ `special-1=a z`,
+ },
+ {
+ &Cookie{Name: "special-2", Value: " z"},
+ `special-2=" z"`,
+ },
+ {
+ &Cookie{Name: "special-3", Value: "a "},
+ `special-3="a "`,
+ },
+ {
+ &Cookie{Name: "special-4", Value: " "},
+ `special-4=" "`,
+ },
+ {
+ &Cookie{Name: "special-5", Value: "a,z"},
+ `special-5=a,z`,
+ },
+ {
+ &Cookie{Name: "special-6", Value: ",z"},
+ `special-6=",z"`,
+ },
+ {
+ &Cookie{Name: "special-7", Value: "a,"},
+ `special-7="a,"`,
+ },
+ {
+ &Cookie{Name: "special-8", Value: ","},
+ `special-8=","`,
+ },
+ {
+ &Cookie{Name: "empty-value", Value: ""},
+ `empty-value=`,
+ },
}
func TestWriteSetCookies(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
for i, tt := range writeSetCookiesTests {
if g, e := tt.Cookie.String(), tt.Raw; g != e {
t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
continue
}
}
+
+ if got, sub := logbuf.String(), "dropping domain attribute"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
type headerOnlyResponseWriter Header
@@ -166,6 +216,40 @@ var readSetCookiesTests = []struct {
Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly",
}},
},
+ // Make sure we can properly read back the Set-Cookie headers we create
+ // for values containing spaces or commas:
+ {
+ Header{"Set-Cookie": {`special-1=a z`}},
+ []*Cookie{{Name: "special-1", Value: "a z", Raw: `special-1=a z`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-2=" z"`}},
+ []*Cookie{{Name: "special-2", Value: " z", Raw: `special-2=" z"`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-3="a "`}},
+ []*Cookie{{Name: "special-3", Value: "a ", Raw: `special-3="a "`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-4=" "`}},
+ []*Cookie{{Name: "special-4", Value: " ", Raw: `special-4=" "`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-5=a,z`}},
+ []*Cookie{{Name: "special-5", Value: "a,z", Raw: `special-5=a,z`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-6=",z"`}},
+ []*Cookie{{Name: "special-6", Value: ",z", Raw: `special-6=",z"`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-7=a,`}},
+ []*Cookie{{Name: "special-7", Value: "a,", Raw: `special-7=a,`}},
+ },
+ {
+ Header{"Set-Cookie": {`special-8=","`}},
+ []*Cookie{{Name: "special-8", Value: ",", Raw: `special-8=","`}},
+ },
// TODO(bradfitz): users have reported seeing this in the
// wild, but do browsers handle it? RFC 6265 just says "don't
@@ -244,22 +328,39 @@ func TestReadCookies(t *testing.T) {
}
func TestCookieSanitizeValue(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
tests := []struct {
in, want string
}{
{"foo", "foo"},
- {"foo bar", "foobar"},
+ {"foo;bar", "foobar"},
+ {"foo\\bar", "foobar"},
+ {"foo\"bar", "foobar"},
{"\x00\x7e\x7f\x80", "\x7e"},
{`"withquotes"`, "withquotes"},
+ {"a z", "a z"},
+ {" z", `" z"`},
+ {"a ", `"a "`},
}
for _, tt := range tests {
if got := sanitizeCookieValue(tt.in); got != tt.want {
t.Errorf("sanitizeCookieValue(%q) = %q; want %q", tt.in, got, tt.want)
}
}
+
+ if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
func TestCookieSanitizePath(t *testing.T) {
+ defer log.SetOutput(os.Stderr)
+ var logbuf bytes.Buffer
+ log.SetOutput(&logbuf)
+
tests := []struct {
in, want string
}{
@@ -272,4 +373,8 @@ func TestCookieSanitizePath(t *testing.T) {
t.Errorf("sanitizeCookiePath(%q) = %q; want %q", tt.in, got, tt.want)
}
}
+
+ if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+ t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+ }
}
diff --git a/src/pkg/net/http/export_test.go b/src/pkg/net/http/export_test.go
index 22b7f2796..960563b24 100644
--- a/src/pkg/net/http/export_test.go
+++ b/src/pkg/net/http/export_test.go
@@ -21,7 +21,7 @@ var ExportAppendTime = appendTime
func (t *Transport) NumPendingRequestsForTesting() int {
t.reqMu.Lock()
defer t.reqMu.Unlock()
- return len(t.reqConn)
+ return len(t.reqCanceler)
}
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
@@ -32,7 +32,7 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
return
}
for key := range t.idleConn {
- keys = append(keys, key)
+ keys = append(keys, key.String())
}
return
}
@@ -43,11 +43,12 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
if t.idleConn == nil {
return 0
}
- conns, ok := t.idleConn[cacheKey]
- if !ok {
- return 0
+ for k, conns := range t.idleConn {
+ if k.String() == cacheKey {
+ return len(conns)
+ }
}
- return len(conns)
+ return 0
}
func (t *Transport) IdleConnChMapSizeForTesting() int {
@@ -63,4 +64,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
return &timeoutHandler{handler, f, ""}
}
+func ResetCachedEnvironment() {
+ httpProxyEnv.reset()
+ noProxyEnv.reset()
+}
+
var DefaultUserAgent = defaultUserAgent
diff --git a/src/pkg/net/http/fcgi/child.go b/src/pkg/net/http/fcgi/child.go
index 60b794e07..a3beaa33a 100644
--- a/src/pkg/net/http/fcgi/child.go
+++ b/src/pkg/net/http/fcgi/child.go
@@ -16,6 +16,7 @@ import (
"net/http/cgi"
"os"
"strings"
+ "sync"
"time"
)
@@ -126,8 +127,10 @@ func (r *response) Close() error {
}
type child struct {
- conn *conn
- handler http.Handler
+ conn *conn
+ handler http.Handler
+
+ mu sync.Mutex // protects requests:
requests map[uint16]*request // keyed by request ID
}
@@ -157,7 +160,9 @@ var errCloseConn = errors.New("fcgi: connection should be closed")
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
func (c *child) handleRecord(rec *record) error {
+ c.mu.Lock()
req, ok := c.requests[rec.h.Id]
+ c.mu.Unlock()
if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
// The spec says to ignore unknown request IDs.
return nil
@@ -179,7 +184,10 @@ func (c *child) handleRecord(rec *record) error {
c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
return nil
}
- c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ req = newRequest(rec.h.Id, br.flags)
+ c.mu.Lock()
+ c.requests[rec.h.Id] = req
+ c.mu.Unlock()
return nil
case typeParams:
// NOTE(eds): Technically a key-value pair can straddle the boundary
@@ -220,7 +228,9 @@ func (c *child) handleRecord(rec *record) error {
return nil
case typeAbortRequest:
println("abort")
+ c.mu.Lock()
delete(c.requests, rec.h.Id)
+ c.mu.Unlock()
c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
if !req.keepConn {
// connection will close upon return
@@ -247,6 +257,9 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
c.handler.ServeHTTP(r, httpReq)
}
r.Close()
+ c.mu.Lock()
+ delete(c.requests, req.reqId)
+ c.mu.Unlock()
c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
// Consume the entire body, so the host isn't still writing to
diff --git a/src/pkg/net/http/fs.go b/src/pkg/net/http/fs.go
index 8b32ca1d0..8576cf844 100644
--- a/src/pkg/net/http/fs.go
+++ b/src/pkg/net/http/fs.go
@@ -13,6 +13,7 @@ import (
"mime"
"mime/multipart"
"net/textproto"
+ "net/url"
"os"
"path"
"path/filepath"
@@ -52,12 +53,14 @@ type FileSystem interface {
// A File is returned by a FileSystem's Open method and can be
// served by the FileServer implementation.
+//
+// The methods should behave the same as those on an *os.File.
type File interface {
- Close() error
- Stat() (os.FileInfo, error)
+ io.Closer
+ io.Reader
Readdir(count int) ([]os.FileInfo, error)
- Read([]byte) (int, error)
Seek(offset int64, whence int) (int64, error)
+ Stat() (os.FileInfo, error)
}
func dirList(w ResponseWriter, f File) {
@@ -73,8 +76,11 @@ func dirList(w ResponseWriter, f File) {
if d.IsDir() {
name += "/"
}
- // TODO htmlescape
- fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+ // name may contain '?' or '#', which must be escaped to remain
+ // part of the URL path, and not indicate the start of a query
+ // string or fragment.
+ url := url.URL{Path: name}
+ fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
}
}
fmt.Fprintf(w, "</pre>\n")
@@ -521,7 +527,7 @@ func (w *countingWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
-// rangesMIMESize returns the nunber of bytes it takes to encode the
+// rangesMIMESize returns the number of bytes it takes to encode the
// provided ranges as a multipart response.
func rangesMIMESize(ranges []httpRange, contentType string, contentSize int64) (encSize int64) {
var w countingWriter
diff --git a/src/pkg/net/http/fs_test.go b/src/pkg/net/http/fs_test.go
index ae54edf0c..f968565f9 100644
--- a/src/pkg/net/http/fs_test.go
+++ b/src/pkg/net/http/fs_test.go
@@ -227,6 +227,54 @@ func TestFileServerCleans(t *testing.T) {
}
}
+func TestFileServerEscapesNames(t *testing.T) {
+ defer afterTest(t)
+ const dirListPrefix = "<pre>\n"
+ const dirListSuffix = "\n</pre>\n"
+ tests := []struct {
+ name, escaped string
+ }{
+ {`simple_name`, `<a href="simple_name">simple_name</a>`},
+ {`"'<>&`, `<a href="%22%27%3C%3E&">&#34;&#39;&lt;&gt;&amp;</a>`},
+ {`?foo=bar#baz`, `<a href="%3Ffoo=bar%23baz">?foo=bar#baz</a>`},
+ {`<combo>?foo`, `<a href="%3Ccombo%3E%3Ffoo">&lt;combo&gt;?foo</a>`},
+ }
+
+ // We put each test file in its own directory in the fakeFS so we can look at it in isolation.
+ fs := make(fakeFS)
+ for i, test := range tests {
+ testFile := &fakeFileInfo{basename: test.name}
+ fs[fmt.Sprintf("/%d", i)] = &fakeFileInfo{
+ dir: true,
+ modtime: time.Unix(1000000000, 0).UTC(),
+ ents: []*fakeFileInfo{testFile},
+ }
+ fs[fmt.Sprintf("/%d/%s", i, test.name)] = testFile
+ }
+
+ ts := httptest.NewServer(FileServer(&fs))
+ defer ts.Close()
+ for i, test := range tests {
+ url := fmt.Sprintf("%s/%d", ts.URL, i)
+ res, err := Get(url)
+ if err != nil {
+ t.Fatalf("test %q: Get: %v", test.name, err)
+ }
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("test %q: read Body: %v", test.name, err)
+ }
+ s := string(b)
+ if !strings.HasPrefix(s, dirListPrefix) || !strings.HasSuffix(s, dirListSuffix) {
+ t.Errorf("test %q: listing dir, full output is %q, want prefix %q and suffix %q", test.name, s, dirListPrefix, dirListSuffix)
+ }
+ if trimmed := strings.TrimSuffix(strings.TrimPrefix(s, dirListPrefix), dirListSuffix); trimmed != test.escaped {
+ t.Errorf("test %q: listing dir, filename escaped to %q, want %q", test.name, trimmed, test.escaped)
+ }
+ res.Body.Close()
+ }
+}
+
func mustRemoveAll(dir string) {
err := os.RemoveAll(dir)
if err != nil {
@@ -457,8 +505,9 @@ func (f *fakeFileInfo) Mode() os.FileMode {
type fakeFile struct {
io.ReadSeeker
- fi *fakeFileInfo
- path string // as opened
+ fi *fakeFileInfo
+ path string // as opened
+ entpos int
}
func (f *fakeFile) Close() error { return nil }
@@ -468,10 +517,20 @@ func (f *fakeFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, os.ErrInvalid
}
var fis []os.FileInfo
- for _, fi := range f.fi.ents {
- fis = append(fis, fi)
+
+ limit := f.entpos + count
+ if count <= 0 || limit > len(f.fi.ents) {
+ limit = len(f.fi.ents)
+ }
+ for ; f.entpos < limit; f.entpos++ {
+ fis = append(fis, f.fi.ents[f.entpos])
+ }
+
+ if len(fis) == 0 && count > 0 {
+ return fis, io.EOF
+ } else {
+ return fis, nil
}
- return fis, nil
}
type fakeFS map[string]*fakeFileInfo
@@ -480,7 +539,6 @@ func (fs fakeFS) Open(name string) (File, error) {
name = path.Clean(name)
f, ok := fs[name]
if !ok {
- println("fake filesystem didn't find file", name)
return nil, os.ErrNotExist
}
return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
diff --git a/src/pkg/net/http/header.go b/src/pkg/net/http/header.go
index ca1ae07c2..153b94370 100644
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -9,9 +9,12 @@ import (
"net/textproto"
"sort"
"strings"
+ "sync"
"time"
)
+var raceEnabled = false // set by race.go
+
// A Header represents the key-value pairs in an HTTP header.
type Header map[string][]string
@@ -114,18 +117,15 @@ func (s *headerSorter) Len() int { return len(s.kvs) }
func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
-// TODO: convert this to a sync.Cache (issue 4720)
-var headerSorterCache = make(chan *headerSorter, 8)
+var headerSorterPool = sync.Pool{
+ New: func() interface{} { return new(headerSorter) },
+}
// sortedKeyValues returns h's keys sorted in the returned kvs
// slice. The headerSorter used to sort is also returned, for possible
// return to headerSorterCache.
func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
- select {
- case hs = <-headerSorterCache:
- default:
- hs = new(headerSorter)
- }
+ hs = headerSorterPool.Get().(*headerSorter)
if cap(hs.kvs) < len(h) {
hs.kvs = make([]keyValues, 0, len(h))
}
@@ -159,10 +159,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
}
}
}
- select {
- case headerSorterCache <- sorter:
- default:
- }
+ headerSorterPool.Put(sorter)
return nil
}
diff --git a/src/pkg/net/http/header_test.go b/src/pkg/net/http/header_test.go
index 9fd9837a5..9dcd591fa 100644
--- a/src/pkg/net/http/header_test.go
+++ b/src/pkg/net/http/header_test.go
@@ -192,9 +192,12 @@ func BenchmarkHeaderWriteSubset(b *testing.B) {
}
}
-func TestHeaderWriteSubsetMallocs(t *testing.T) {
+func TestHeaderWriteSubsetAllocs(t *testing.T) {
if testing.Short() {
- t.Skip("skipping malloc count in short mode")
+ t.Skip("skipping alloc test in short mode")
+ }
+ if raceEnabled {
+ t.Skip("skipping test under race detector")
}
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
@@ -204,6 +207,6 @@ func TestHeaderWriteSubsetMallocs(t *testing.T) {
testHeader.WriteSubset(&buf, nil)
})
if n > 0 {
- t.Errorf("mallocs = %g; want 0", n)
+ t.Errorf("allocs = %g; want 0", n)
}
}
diff --git a/src/pkg/net/http/httptest/server_test.go b/src/pkg/net/http/httptest/server_test.go
index 500a9f0b8..501cc8a99 100644
--- a/src/pkg/net/http/httptest/server_test.go
+++ b/src/pkg/net/http/httptest/server_test.go
@@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/http"
"testing"
+ "time"
)
func TestServer(t *testing.T) {
@@ -27,3 +28,25 @@ func TestServer(t *testing.T) {
t.Errorf("got %q, want hello", string(got))
}
}
+
+func TestIssue7264(t *testing.T) {
+ for i := 0; i < 1000; i++ {
+ func() {
+ inHandler := make(chan bool, 1)
+ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ inHandler <- true
+ }))
+ defer ts.Close()
+ tr := &http.Transport{
+ ResponseHeaderTimeout: time.Nanosecond,
+ }
+ defer tr.CloseIdleConnections()
+ c := &http.Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ <-inHandler
+ if err == nil {
+ res.Body.Close()
+ }
+ }()
+ }
+}
diff --git a/src/pkg/net/http/httputil/chunked.go b/src/pkg/net/http/httputil/chunked.go
index b66d40951..9632bfd19 100644
--- a/src/pkg/net/http/httputil/chunked.go
+++ b/src/pkg/net/http/httputil/chunked.go
@@ -4,15 +4,14 @@
// The wire protocol for HTTP's "chunked" Transfer-Encoding.
-// This code is a duplicate of ../chunked.go with these edits:
-// s/newChunked/NewChunked/g
-// s/package http/package httputil/
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package httputil
import (
"bufio"
+ "bytes"
"errors"
"fmt"
"io"
@@ -22,13 +21,13 @@ const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
var ErrLineTooLong = errors.New("header line too long")
-// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// newChunkedReader returns a new chunkedReader that translates the data read from r
// out of HTTP "chunked" format before returning it.
// The chunkedReader returns io.EOF when the final 0-length chunk is read.
//
-// NewChunkedReader is not needed by normal applications. The http package
+// newChunkedReader is not needed by normal applications. The http package
// automatically decodes chunking when reading response bodies.
-func NewChunkedReader(r io.Reader) io.Reader {
+func newChunkedReader(r io.Reader) io.Reader {
br, ok := r.(*bufio.Reader)
if !ok {
br = bufio.NewReader(r)
@@ -59,26 +58,45 @@ func (cr *chunkedReader) beginChunk() {
}
}
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
- if cr.err != nil {
- return 0, cr.err
+func (cr *chunkedReader) chunkHeaderAvailable() bool {
+ n := cr.r.Buffered()
+ if n > 0 {
+ peek, _ := cr.r.Peek(n)
+ return bytes.IndexByte(peek, '\n') >= 0
}
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
+ return false
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ for cr.err == nil {
+ if cr.n == 0 {
+ if n > 0 && !cr.chunkHeaderAvailable() {
+ // We've read enough. Don't potentially block
+ // reading a new chunk header.
+ break
+ }
+ cr.beginChunk()
+ continue
}
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
+ if len(b) == 0 {
+ break
+ }
+ rbuf := b
+ if uint64(len(rbuf)) > cr.n {
+ rbuf = rbuf[:cr.n]
+ }
+ var n0 int
+ n0, cr.err = cr.r.Read(rbuf)
+ n += n0
+ b = b[n0:]
+ cr.n -= uint64(n0)
+ // If we're at the end of a chunk, read the next two
+ // bytes to verify they are "\r\n".
+ if cr.n == 0 && cr.err == nil {
+ if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+ if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
}
}
}
@@ -117,16 +135,16 @@ func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
-// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
// "chunked" format before writing them to w. Closing the returned chunkedWriter
// sends the final 0-length chunk that marks the end of the stream.
//
-// NewChunkedWriter is not needed by normal applications. The http
+// newChunkedWriter is not needed by normal applications. The http
// package adds chunking automatically if handlers don't set a
-// Content-Length header. Using NewChunkedWriter inside a handler
+// Content-Length header. Using newChunkedWriter inside a handler
// would result in double chunking or chunking with a Content-Length
// length, both of which are wrong.
-func NewChunkedWriter(w io.Writer) io.WriteCloser {
+func newChunkedWriter(w io.Writer) io.WriteCloser {
return &chunkedWriter{w}
}
diff --git a/src/pkg/net/http/httputil/chunked_test.go b/src/pkg/net/http/httputil/chunked_test.go
index a06bffad5..a7a577468 100644
--- a/src/pkg/net/http/httputil/chunked_test.go
+++ b/src/pkg/net/http/httputil/chunked_test.go
@@ -2,26 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This code is a duplicate of ../chunked_test.go with these edits:
-// s/newChunked/NewChunked/g
-// s/package http/package httputil/
+// This code is duplicated in net/http and net/http/httputil.
// Please make any changes in both files.
package httputil
import (
+ "bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
- "runtime"
+ "strings"
"testing"
)
func TestChunk(t *testing.T) {
var b bytes.Buffer
- w := NewChunkedWriter(&b)
+ w := newChunkedWriter(&b)
const chunk1 = "hello, "
const chunk2 = "world! 0123456789abcdef"
w.Write([]byte(chunk1))
@@ -32,7 +31,7 @@ func TestChunk(t *testing.T) {
t.Fatalf("chunk writer wrote %q; want %q", g, e)
}
- r := NewChunkedReader(&b)
+ r := newChunkedReader(&b)
data, err := ioutil.ReadAll(r)
if err != nil {
t.Logf(`data: "%s"`, data)
@@ -43,37 +42,102 @@ func TestChunk(t *testing.T) {
}
}
+func TestChunkReadMultiple(t *testing.T) {
+ // Bunch of small chunks, all read together.
+ {
+ var b bytes.Buffer
+ w := newChunkedWriter(&b)
+ w.Write([]byte("foo"))
+ w.Write([]byte("bar"))
+ w.Close()
+
+ r := newChunkedReader(&b)
+ buf := make([]byte, 10)
+ n, err := r.Read(buf)
+ if n != 6 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 6, EOF", n, err)
+ }
+ buf = buf[:n]
+ if string(buf) != "foobar" {
+ t.Errorf("Read = %q; want %q", buf, "foobar")
+ }
+ }
+
+ // One big chunk followed by a little chunk, but the small bufio.Reader size
+ // should prevent the second chunk header from being read.
+ {
+ var b bytes.Buffer
+ w := newChunkedWriter(&b)
+ // fillBufChunk is 11 bytes + 3 bytes header + 2 bytes footer = 16 bytes,
+ // the same as the bufio ReaderSize below (the minimum), so even
+ // though we're going to try to Read with a buffer larger enough to also
+ // receive "foo", the second chunk header won't be read yet.
+ const fillBufChunk = "0123456789a"
+ const shortChunk = "foo"
+ w.Write([]byte(fillBufChunk))
+ w.Write([]byte(shortChunk))
+ w.Close()
+
+ r := newChunkedReader(bufio.NewReaderSize(&b, 16))
+ buf := make([]byte, len(fillBufChunk)+len(shortChunk))
+ n, err := r.Read(buf)
+ if n != len(fillBufChunk) || err != nil {
+ t.Errorf("Read = %d, %v; want %d, nil", n, err, len(fillBufChunk))
+ }
+ buf = buf[:n]
+ if string(buf) != fillBufChunk {
+ t.Errorf("Read = %q; want %q", buf, fillBufChunk)
+ }
+
+ n, err = r.Read(buf)
+ if n != len(shortChunk) || err != io.EOF {
+ t.Errorf("Read = %d, %v; want %d, EOF", n, err, len(shortChunk))
+ }
+ }
+
+ // And test that we see an EOF chunk, even though our buffer is already full:
+ {
+ r := newChunkedReader(bufio.NewReader(strings.NewReader("3\r\nfoo\r\n0\r\n")))
+ buf := make([]byte, 3)
+ n, err := r.Read(buf)
+ if n != 3 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 3, EOF", n, err)
+ }
+ if string(buf) != "foo" {
+ t.Errorf("buf = %q; want foo", buf)
+ }
+ }
+}
+
func TestChunkReaderAllocs(t *testing.T) {
- // temporarily set GOMAXPROCS to 1 as we are testing memory allocations
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
var buf bytes.Buffer
- w := NewChunkedWriter(&buf)
+ w := newChunkedWriter(&buf)
a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
w.Write(a)
w.Write(b)
w.Write(c)
w.Close()
- r := NewChunkedReader(&buf)
readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
- var ms runtime.MemStats
- runtime.ReadMemStats(&ms)
- m0 := ms.Mallocs
-
- n, err := io.ReadFull(r, readBuf)
-
- runtime.ReadMemStats(&ms)
- mallocs := ms.Mallocs - m0
- if mallocs > 1 {
- t.Errorf("%d mallocs; want <= 1", mallocs)
- }
-
- if n != len(readBuf)-1 {
- t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
- }
- if err != io.ErrUnexpectedEOF {
- t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
+ byter := bytes.NewReader(buf.Bytes())
+ bufr := bufio.NewReader(byter)
+ mallocs := testing.AllocsPerRun(100, func() {
+ byter.Seek(0, 0)
+ bufr.Reset(byter)
+ r := newChunkedReader(bufr)
+ n, err := io.ReadFull(r, readBuf)
+ if n != len(readBuf)-1 {
+ t.Fatalf("read %d bytes; want %d", n, len(readBuf)-1)
+ }
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("read error = %v; want ErrUnexpectedEOF", err)
+ }
+ })
+ if mallocs > 1.5 {
+ t.Errorf("mallocs = %v; want 1", mallocs)
}
}
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
index 265499fb0..2a7a413d0 100644
--- a/src/pkg/net/http/httputil/dump.go
+++ b/src/pkg/net/http/httputil/dump.go
@@ -7,6 +7,7 @@ package httputil
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -29,7 +30,7 @@ func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
if err = b.Close(); err != nil {
return nil, nil, err
}
- return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
+ return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
}
// dumpConn is a net.Conn which writes to Writer and reads from Reader
@@ -106,6 +107,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
},
}
+ defer t.CloseIdleConnections()
_, err := t.RoundTrip(reqSend)
@@ -230,14 +232,31 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
return
}
+// errNoBody is a sentinel error value used by failureToReadBody so we can detect
+// that the lack of body was intentional.
+var errNoBody = errors.New("sentinel error value")
+
+// failureToReadBody is a io.ReadCloser that just returns errNoBody on
+// Read. It's swapped in when we don't actually want to consume the
+// body, but need a non-nil one, and want to distinguish the error
+// from reading the dummy body.
+type failureToReadBody struct{}
+
+func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
+func (failureToReadBody) Close() error { return nil }
+
+var emptyBody = ioutil.NopCloser(strings.NewReader(""))
+
// DumpResponse is like DumpRequest but dumps a response.
func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
var b bytes.Buffer
save := resp.Body
savecl := resp.ContentLength
- if !body || resp.Body == nil {
- resp.Body = nil
- resp.ContentLength = 0
+
+ if !body {
+ resp.Body = failureToReadBody{}
+ } else if resp.Body == nil {
+ resp.Body = emptyBody
} else {
save, resp.Body, err = drainBody(resp.Body)
if err != nil {
@@ -245,11 +264,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
}
}
err = resp.Write(&b)
+ if err == errNoBody {
+ err = nil
+ }
resp.Body = save
resp.ContentLength = savecl
if err != nil {
- return
+ return nil, err
}
- dump = b.Bytes()
- return
+ return b.Bytes(), nil
}
diff --git a/src/pkg/net/http/httputil/dump_test.go b/src/pkg/net/http/httputil/dump_test.go
index 987a82048..e1ffb3935 100644
--- a/src/pkg/net/http/httputil/dump_test.go
+++ b/src/pkg/net/http/httputil/dump_test.go
@@ -11,6 +11,8 @@ import (
"io/ioutil"
"net/http"
"net/url"
+ "runtime"
+ "strings"
"testing"
)
@@ -112,6 +114,7 @@ var dumpTests = []dumpTest{
}
func TestDumpRequest(t *testing.T) {
+ numg0 := runtime.NumGoroutine()
for i, tt := range dumpTests {
setBody := func() {
if tt.Body == nil {
@@ -119,7 +122,7 @@ func TestDumpRequest(t *testing.T) {
}
switch b := tt.Body.(type) {
case []byte:
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
case func() io.ReadCloser:
tt.Req.Body = b()
}
@@ -155,6 +158,9 @@ func TestDumpRequest(t *testing.T) {
}
}
}
+ if dg := runtime.NumGoroutine() - numg0; dg > 4 {
+ t.Errorf("Unexpectedly large number of new goroutines: %d new", dg)
+ }
}
func chunk(s string) string {
@@ -176,3 +182,82 @@ func mustNewRequest(method, url string, body io.Reader) *http.Request {
}
return req
}
+
+var dumpResTests = []struct {
+ res *http.Response
+ body bool
+ want string
+}{
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 50,
+ Header: http.Header{
+ "Foo": []string{"Bar"},
+ },
+ Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
+ },
+ body: false, // to verify we see 50, not empty or 3.
+ want: `HTTP/1.1 200 OK
+Content-Length: 50
+Foo: Bar`,
+ },
+
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 3,
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ },
+ body: true,
+ want: `HTTP/1.1 200 OK
+Content-Length: 3
+
+foo`,
+ },
+
+ {
+ res: &http.Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: -1,
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ TransferEncoding: []string{"chunked"},
+ },
+ body: true,
+ want: `HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+3
+foo
+0`,
+ },
+}
+
+func TestDumpResponse(t *testing.T) {
+ for i, tt := range dumpResTests {
+ gotb, err := DumpResponse(tt.res, tt.body)
+ if err != nil {
+ t.Errorf("%d. DumpResponse = %v", i, err)
+ continue
+ }
+ got := string(gotb)
+ got = strings.TrimSpace(got)
+ got = strings.Replace(got, "\r", "", -1)
+
+ if got != tt.want {
+ t.Errorf("%d.\nDumpResponse got:\n%s\n\nWant:\n%s\n", i, got, tt.want)
+ }
+ }
+}
diff --git a/src/pkg/net/http/httputil/httputil.go b/src/pkg/net/http/httputil/httputil.go
new file mode 100644
index 000000000..74fb6c655
--- /dev/null
+++ b/src/pkg/net/http/httputil/httputil.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httputil provides HTTP utility functions, complementing the
+// more common ones in the net/http package.
+package httputil
+
+import "io"
+
+// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r io.Reader) io.Reader {
+ return newChunkedReader(r)
+}
+
+// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// sends the final 0-length chunk that marks the end of the stream.
+//
+// NewChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using NewChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+ return newChunkedWriter(w)
+}
diff --git a/src/pkg/net/http/httputil/persist.go b/src/pkg/net/http/httputil/persist.go
index 507938aca..987bcc96b 100644
--- a/src/pkg/net/http/httputil/persist.go
+++ b/src/pkg/net/http/httputil/persist.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package httputil provides HTTP utility functions, complementing the
-// more common ones in the net/http package.
package httputil
import (
@@ -33,8 +31,8 @@ var errClosed = errors.New("i/o operation on closed connection")
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
//
-// ServerConn is low-level and should not be needed by most applications.
-// See Server.
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
type ServerConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -47,8 +45,11 @@ type ServerConn struct {
pipe textproto.Pipeline
}
-// NewServerConn returns a new ServerConn reading and writing c. If r is not
+// NewServerConn returns a new ServerConn reading and writing c. If r is not
// nil, it is the buffer to use when reading c.
+//
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
if r == nil {
r = bufio.NewReader(c)
@@ -223,8 +224,8 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
// supports hijacking the connection calling Hijack to
// regain control of the underlying net.Conn and deal with it as desired.
//
-// ClientConn is low-level and should not be needed by most applications.
-// See Client.
+// ClientConn is low-level and old. Applications should instead use
+// Client or Transport in the net/http package.
type ClientConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -240,6 +241,9 @@ type ClientConn struct {
// NewClientConn returns a new ClientConn reading and writing c. If r is not
// nil, it is the buffer to use when reading c.
+//
+// ClientConn is low-level and old. Applications should use Client or
+// Transport in the net/http package.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
if r == nil {
r = bufio.NewReader(c)
@@ -254,6 +258,9 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
// NewProxyClientConn works like NewClientConn but writes Requests
// using Request's WriteProxy method.
+//
+// New code should not use NewProxyClientConn. See Client or
+// Transport in the net/http package instead.
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
cc := NewClientConn(c, r)
cc.writeReq = (*http.Request).WriteProxy
diff --git a/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 1990f64db..48ada5f5f 100644
--- a/src/pkg/net/http/httputil/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -144,6 +144,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
defer res.Body.Close()
+ for _, h := range hopHeaders {
+ res.Header.Del(h)
+ }
+
copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
index 1c0444ec4..e9539b44b 100644
--- a/src/pkg/net/http/httputil/reverseproxy_test.go
+++ b/src/pkg/net/http/httputil/reverseproxy_test.go
@@ -16,6 +16,12 @@ import (
"time"
)
+const fakeHopHeader = "X-Fake-Hop-Header-For-Test"
+
+func init() {
+ hopHeaders = append(hopHeaders, fakeHopHeader)
+}
+
func TestReverseProxy(t *testing.T) {
const backendResponse = "I am the backend"
const backendStatus = 404
@@ -36,6 +42,10 @@ func TestReverseProxy(t *testing.T) {
t.Errorf("backend got Host header %q, want %q", g, e)
}
w.Header().Set("X-Foo", "bar")
+ w.Header().Set("Upgrade", "foo")
+ w.Header().Set(fakeHopHeader, "foo")
+ w.Header().Add("X-Multi-Value", "foo")
+ w.Header().Add("X-Multi-Value", "bar")
http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
@@ -64,6 +74,12 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
t.Errorf("got X-Foo %q; expected %q", g, e)
}
+ if c := res.Header.Get(fakeHopHeader); c != "" {
+ t.Errorf("got %s header value %q", fakeHopHeader, c)
+ }
+ if g, e := len(res.Header["X-Multi-Value"]), 2; g != e {
+ t.Errorf("got %d X-Multi-Value header values; expected %d", g, e)
+ }
if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
t.Fatalf("got %d SetCookies, want %d", g, e)
}
diff --git a/src/pkg/net/http/proxy_test.go b/src/pkg/net/http/proxy_test.go
index 449ccaeea..b6aed3792 100644
--- a/src/pkg/net/http/proxy_test.go
+++ b/src/pkg/net/http/proxy_test.go
@@ -35,12 +35,8 @@ var UseProxyTests = []struct {
}
func TestUseProxy(t *testing.T) {
- oldenv := os.Getenv("NO_PROXY")
- defer os.Setenv("NO_PROXY", oldenv)
-
- no_proxy := "foobar.com, .barbaz.net"
- os.Setenv("NO_PROXY", no_proxy)
-
+ ResetProxyEnv()
+ os.Setenv("NO_PROXY", "foobar.com, .barbaz.net")
for _, test := range UseProxyTests {
if useProxy(test.host+":80") != test.match {
t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
@@ -71,8 +67,15 @@ func TestCacheKeys(t *testing.T) {
proxy = u
}
cm := connectMethod{proxy, tt.scheme, tt.addr}
- if cm.String() != tt.key {
- t.Fatalf("{%q, %q, %q} cache key %q; want %q", tt.proxy, tt.scheme, tt.addr, cm.String(), tt.key)
+ if got := cm.key().String(); got != tt.key {
+ t.Fatalf("{%q, %q, %q} cache key = %q; want %q", tt.proxy, tt.scheme, tt.addr, got, tt.key)
}
}
}
+
+func ResetProxyEnv() {
+ for _, v := range []string{"HTTP_PROXY", "http_proxy", "NO_PROXY", "no_proxy"} {
+ os.Setenv(v, "")
+ }
+ ResetCachedEnvironment()
+}
diff --git a/src/pkg/net/http/race.go b/src/pkg/net/http/race.go
new file mode 100644
index 000000000..766503967
--- /dev/null
+++ b/src/pkg/net/http/race.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build race
+
+package http
+
+func init() {
+ raceEnabled = true
+}
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 57b5d0948..a67092066 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -20,6 +20,7 @@ import (
"net/url"
"strconv"
"strings"
+ "sync"
)
const (
@@ -68,18 +69,31 @@ var reqWriteExcludeHeader = map[string]bool{
// A Request represents an HTTP request received by a server
// or to be sent by a client.
+//
+// The field semantics differ slightly between client and server
+// usage. In addition to the notes on the fields below, see the
+// documentation for Request.Write and RoundTripper.
type Request struct {
- Method string // GET, POST, PUT, etc.
+ // Method specifies the HTTP method (GET, POST, PUT, etc.).
+ // For client requests an empty string means GET.
+ Method string
- // URL is created from the URI supplied on the Request-Line
- // as stored in RequestURI.
+ // URL specifies either the URI being requested (for server
+ // requests) or the URL to access (for client requests).
+ //
+ // For server requests the URL is parsed from the URI
+ // supplied on the Request-Line as stored in RequestURI. For
+ // most requests, fields other than Path and RawQuery will be
+ // empty. (See RFC 2616, Section 5.1.2)
//
- // For most requests, fields other than Path and RawQuery
- // will be empty. (See RFC 2616, Section 5.1.2)
+ // For client requests, the URL's Host specifies the server to
+ // connect to, while the Request's Host field optionally
+ // specifies the Host header value to send in the HTTP
+ // request.
URL *url.URL
// The protocol version for incoming requests.
- // Outgoing requests always use HTTP/1.1.
+ // Client requests always use HTTP/1.1.
Proto string // "HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
@@ -103,15 +117,20 @@ type Request struct {
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
+ //
+ // For client requests certain headers are automatically
+ // added and may override values in Header.
+ //
+ // See the documentation for the Request.Write method.
Header Header
// Body is the request's body.
//
- // For client requests, a nil body means the request has no
+ // For client requests a nil body means the request has no
// body, such as a GET request. The HTTP Client's Transport
// is responsible for calling the Close method.
//
- // For server requests, the Request Body is always non-nil
+ // For server requests the Request Body is always non-nil
// but will return EOF immediately when no body is present.
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
@@ -121,7 +140,7 @@ type Request struct {
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
- // For outgoing requests, a value of 0 means unknown if Body is not nil.
+ // For client requests, a value of 0 means unknown if Body is not nil.
ContentLength int64
// TransferEncoding lists the transfer encodings from outermost to
@@ -132,13 +151,18 @@ type Request struct {
TransferEncoding []string
// Close indicates whether to close the connection after
- // replying to this request.
+ // replying to this request (for servers) or after sending
+ // the request (for clients).
Close bool
- // The host on which the URL is sought.
- // Per RFC 2616, this is either the value of the Host: header
- // or the host name given in the URL itself.
+ // For server requests Host specifies the host on which the
+ // URL is sought. Per RFC 2616, this is either the value of
+ // the "Host" header or the host name given in the URL itself.
// It may be of the form "host:port".
+ //
+ // For client requests Host optionally overrides the Host
+ // header to send. If empty, the Request.Write method uses
+ // the value of URL.Host.
Host string
// Form contains the parsed form data, including both the URL
@@ -158,12 +182,24 @@ type Request struct {
// The HTTP client ignores MultipartForm and uses Body instead.
MultipartForm *multipart.Form
- // Trailer maps trailer keys to values. Like for Header, if the
- // response has multiple trailer lines with the same key, they will be
- // concatenated, delimited by commas.
- // For server requests, Trailer is only populated after Body has been
- // closed or fully consumed.
- // Trailer support is only partially complete.
+ // Trailer specifies additional headers that are sent after the request
+ // body.
+ //
+ // For server requests the Trailer map initially contains only the
+ // trailer keys, with nil values. (The client declares which trailers it
+ // will later send.) While the handler is reading from Body, it must
+ // not reference Trailer. After reading from Body returns EOF, Trailer
+ // can be read again and will contain non-nil values, if they were sent
+ // by the client.
+ //
+ // For client requests Trailer must be initialized to a map containing
+ // the trailer keys to later send. The values may be nil or their final
+ // values. The ContentLength must be 0 or -1, to send a chunked request.
+ // After the HTTP request is sent the map values can be updated while
+ // the request body is read. Once the body returns EOF, the caller must
+ // not mutate Trailer.
+ //
+ // Few HTTP clients, servers, or proxies support HTTP trailers.
Trailer Header
// RemoteAddr allows HTTP servers and other software to record
@@ -381,7 +417,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
return err
}
- // TODO: split long values? (If so, should share code with Conn.Write)
err = req.Header.WriteSubset(w, reqWriteExcludeHeader)
if err != nil {
return err
@@ -494,25 +529,20 @@ func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
return line[:s1], line[s1+1 : s2], line[s2+1:], true
}
-// TODO(bradfitz): use a sync.Cache when available
-var textprotoReaderCache = make(chan *textproto.Reader, 4)
+var textprotoReaderPool sync.Pool
func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
- select {
- case r := <-textprotoReaderCache:
- r.R = br
- return r
- default:
- return textproto.NewReader(br)
+ if v := textprotoReaderPool.Get(); v != nil {
+ tr := v.(*textproto.Reader)
+ tr.R = br
+ return tr
}
+ return textproto.NewReader(br)
}
func putTextprotoReader(r *textproto.Reader) {
r.R = nil
- select {
- case textprotoReaderCache <- r:
- default:
- }
+ textprotoReaderPool.Put(r)
}
// ReadRequest reads and parses a request from b.
@@ -588,32 +618,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
fixPragmaCacheControl(req.Header)
- // TODO: Parse specific header values:
- // Accept
- // Accept-Encoding
- // Accept-Language
- // Authorization
- // Cache-Control
- // Connection
- // Date
- // Expect
- // From
- // If-Match
- // If-Modified-Since
- // If-None-Match
- // If-Range
- // If-Unmodified-Since
- // Max-Forwards
- // Proxy-Authorization
- // Referer [sic]
- // TE (transfer-codings)
- // Trailer
- // Transfer-Encoding
- // Upgrade
- // User-Agent
- // Via
- // Warning
-
err = readTransfer(req, b)
if err != nil {
return nil, err
@@ -677,6 +681,11 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
ct := r.Header.Get("Content-Type")
+ // RFC 2616, section 7.2.1 - empty type
+ // SHOULD be treated as application/octet-stream
+ if ct == "" {
+ ct = "application/octet-stream"
+ }
ct, _, err = mime.ParseMediaType(ct)
switch {
case ct == "application/x-www-form-urlencoded":
@@ -707,7 +716,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
// orders to call too many functions here.
// Clean this up and write more tests.
// request_test.go contains the start of this,
- // in TestRequestMultipartCallOrder.
+ // in TestParseMultipartFormOrder and others.
}
return
}
@@ -727,7 +736,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
func (r *Request) ParseForm() error {
var err error
if r.PostForm == nil {
- if r.Method == "POST" || r.Method == "PUT" {
+ if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
r.PostForm, err = parsePostForm(r)
}
if r.PostForm == nil {
@@ -780,9 +789,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
}
mr, err := r.multipartReader()
- if err == ErrNotMultipart {
- return nil
- } else if err != nil {
+ if err != nil {
return err
}
@@ -860,3 +867,9 @@ func (r *Request) wantsHttp10KeepAlive() bool {
func (r *Request) wantsClose() bool {
return hasToken(r.Header.get("Connection"), "close")
}
+
+func (r *Request) closeBody() {
+ if r.Body != nil {
+ r.Body.Close()
+ }
+}
diff --git a/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 89303c336..b9fa3c2bf 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -60,6 +60,37 @@ func TestPostQuery(t *testing.T) {
}
}
+func TestPatchQuery(t *testing.T) {
+ req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&empty="))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+ if z := req.FormValue("z"); z != "post" {
+ t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+ }
+ if bq, found := req.PostForm["q"]; found {
+ t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
+ }
+ if bz := req.PostFormValue("z"); bz != "post" {
+ t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
+ }
+ if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
+ t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
+ }
+ if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
+ t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
+ }
+ if prio := req.FormValue("prio"); prio != "2" {
+ t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
+ }
+ if empty := req.FormValue("empty"); empty != "" {
+ t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
+ }
+}
+
type stringMap map[string][]string
type parseContentTypeTest struct {
shouldError bool
@@ -68,8 +99,9 @@ type parseContentTypeTest struct {
var parseContentTypeTests = []parseContentTypeTest{
{false, stringMap{"Content-Type": {"text/plain"}}},
- // Non-existent keys are not placed. The value nil is illegal.
- {true, stringMap{}},
+ // Empty content type is legal - shoult be treated as
+ // application/octet-stream (RFC 2616, section 7.2.1)
+ {false, stringMap{}},
{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
{false, stringMap{"Content-Type": {"application/unknown"}}},
}
@@ -79,7 +111,7 @@ func TestParseFormUnknownContentType(t *testing.T) {
req := &Request{
Method: "POST",
Header: Header(test.contentType),
- Body: ioutil.NopCloser(bytes.NewBufferString("body")),
+ Body: ioutil.NopCloser(strings.NewReader("body")),
}
err := req.ParseForm()
switch {
@@ -122,7 +154,25 @@ func TestMultipartReader(t *testing.T) {
req.Header = Header{"Content-Type": {"text/plain"}}
multipart, err = req.MultipartReader()
if multipart != nil {
- t.Errorf("unexpected multipart for text/plain")
+ t.Error("unexpected multipart for text/plain")
+ }
+}
+
+func TestParseMultipartForm(t *testing.T) {
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
+ Body: ioutil.NopCloser(new(bytes.Buffer)),
+ }
+ err := req.ParseMultipartForm(25)
+ if err == nil {
+ t.Error("expected multipart EOF, got nil")
+ }
+
+ req.Header = Header{"Content-Type": {"text/plain"}}
+ err = req.ParseMultipartForm(25)
+ if err != ErrNotMultipart {
+ t.Error("expected ErrNotMultipart for text/plain")
}
}
@@ -188,25 +238,72 @@ func TestMultipartRequestAuto(t *testing.T) {
validateTestMultipartContents(t, req, true)
}
-func TestEmptyMultipartRequest(t *testing.T) {
- // Test that FormValue and FormFile automatically invoke
- // ParseMultipartForm and return the right values.
- req, err := NewRequest("GET", "/", nil)
- if err != nil {
- t.Errorf("NewRequest err = %q", err)
- }
+func TestMissingFileMultipartRequest(t *testing.T) {
+ // Test that FormFile returns an error if
+ // the named file is missing.
+ req := newTestMultipartRequest(t)
testMissingFile(t, req)
}
-func TestRequestMultipartCallOrder(t *testing.T) {
+// Test that FormValue invokes ParseMultipartForm.
+func TestFormValueCallsParseMultipartForm(t *testing.T) {
+ req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+ if req.Form != nil {
+ t.Fatal("Unexpected request Form, want nil")
+ }
+ req.FormValue("z")
+ if req.Form == nil {
+ t.Fatal("ParseMultipartForm not called by FormValue")
+ }
+}
+
+// Test that FormFile invokes ParseMultipartForm.
+func TestFormFileCallsParseMultipartForm(t *testing.T) {
req := newTestMultipartRequest(t)
- _, err := req.MultipartReader()
- if err != nil {
+ if req.Form != nil {
+ t.Fatal("Unexpected request Form, want nil")
+ }
+ req.FormFile("")
+ if req.Form == nil {
+ t.Fatal("ParseMultipartForm not called by FormFile")
+ }
+}
+
+// Test that ParseMultipartForm errors if called
+// after MultipartReader on the same request.
+func TestParseMultipartFormOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if _, err := req.MultipartReader(); err != nil {
t.Fatalf("MultipartReader: %v", err)
}
- err = req.ParseMultipartForm(1024)
- if err == nil {
- t.Errorf("expected an error from ParseMultipartForm after call to MultipartReader")
+ if err := req.ParseMultipartForm(1024); err == nil {
+ t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
+ }
+}
+
+// Test that MultipartReader errors if called
+// after ParseMultipartForm on the same request.
+func TestMultipartReaderOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if err := req.ParseMultipartForm(25); err != nil {
+ t.Fatalf("ParseMultipartForm: %v", err)
+ }
+ defer req.MultipartForm.RemoveAll()
+ if _, err := req.MultipartReader(); err == nil {
+ t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
+ }
+}
+
+// Test that FormFile errors if called after
+// MultipartReader on the same request.
+func TestFormFileOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ if _, err := req.MultipartReader(); err != nil {
+ t.Fatalf("MultipartReader: %v", err)
+ }
+ if _, _, err := req.FormFile(""); err == nil {
+ t.Fatal("expected an error from FormFile after call to MultipartReader")
}
}
@@ -343,7 +440,7 @@ func testMissingFile(t *testing.T, req *Request) {
}
func newTestMultipartRequest(t *testing.T) *Request {
- b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
+ b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
req, err := NewRequest("POST", "/", b)
if err != nil {
t.Fatal("NewRequest:", err)
diff --git a/src/pkg/net/http/requestwrite_test.go b/src/pkg/net/http/requestwrite_test.go
index b27b1f7ce..dc0e204ca 100644
--- a/src/pkg/net/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -310,6 +310,46 @@ var reqWriteTests = []reqWriteTest{
WantError: errors.New("http: Request.ContentLength=5 with nil Body"),
},
+ // Request with a 0 ContentLength and a body with 1 byte content and an error.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser {
+ err := errors.New("Custom reader error")
+ errReader := &errorReader{err}
+ return ioutil.NopCloser(io.MultiReader(strings.NewReader("x"), errReader))
+ },
+
+ WantError: errors.New("Custom reader error"),
+ },
+
+ // Request with a 0 ContentLength and a body without content and an error.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser {
+ err := errors.New("Custom reader error")
+ errReader := &errorReader{err}
+ return ioutil.NopCloser(errReader)
+ },
+
+ WantError: errors.New("Custom reader error"),
+ },
+
// Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
// and doesn't add a User-Agent.
{
@@ -427,7 +467,7 @@ func TestRequestWrite(t *testing.T) {
}
switch b := tt.Body.(type) {
case []byte:
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
case func() io.ReadCloser:
tt.Req.Body = b()
}
diff --git a/src/pkg/net/http/response.go b/src/pkg/net/http/response.go
index 35d0ba3bb..5d2c39080 100644
--- a/src/pkg/net/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -8,6 +8,8 @@ package http
import (
"bufio"
+ "bytes"
+ "crypto/tls"
"errors"
"io"
"net/textproto"
@@ -45,7 +47,8 @@ type Response struct {
//
// The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
- // a zero-lengthed body.
+ // a zero-length body. It is the caller's responsibility to
+ // close Body.
//
// The Body is automatically dechunked if the server replied
// with a "chunked" Transfer-Encoding.
@@ -74,6 +77,12 @@ type Response struct {
// Request's Body is nil (having already been consumed).
// This is only populated for Client requests.
Request *Request
+
+ // TLS contains information about the TLS connection on which the
+ // response was received. It is nil for unencrypted responses.
+ // The pointer is shared between responses and should not be
+ // modified.
+ TLS *tls.ConnectionState
}
// Cookies parses and returns the cookies set in the Set-Cookie headers.
@@ -141,6 +150,9 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
// Parse the response headers.
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return nil, err
}
resp.Header = Header(mimeHeader)
@@ -187,8 +199,8 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
// ContentLength
// Header, values for non-canonical keys will have unpredictable behavior
//
+// Body is closed after it is sent.
func (r *Response) Write(w io.Writer) error {
-
// Status line
text := r.Status
if text == "" {
@@ -201,10 +213,45 @@ func (r *Response) Write(w io.Writer) error {
protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
statusCode := strconv.Itoa(r.StatusCode) + " "
text = strings.TrimPrefix(text, statusCode)
- io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n")
+ if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil {
+ return err
+ }
+
+ // Clone it, so we can modify r1 as needed.
+ r1 := new(Response)
+ *r1 = *r
+ if r1.ContentLength == 0 && r1.Body != nil {
+ // Is it actually 0 length? Or just unknown?
+ var buf [1]byte
+ n, err := r1.Body.Read(buf[:])
+ if err != nil && err != io.EOF {
+ return err
+ }
+ if n == 0 {
+ // Reset it to a known zero reader, in case underlying one
+ // is unhappy being read repeatedly.
+ r1.Body = eofReader
+ } else {
+ r1.ContentLength = -1
+ r1.Body = struct {
+ io.Reader
+ io.Closer
+ }{
+ io.MultiReader(bytes.NewReader(buf[:1]), r.Body),
+ r.Body,
+ }
+ }
+ }
+ // If we're sending a non-chunked HTTP/1.1 response without a
+ // content-length, the only way to do that is the old HTTP/1.0
+ // way, by noting the EOF with a connection close, so we need
+ // to set Close.
+ if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) {
+ r1.Close = true
+ }
// Process Body,ContentLength,Close,Trailer
- tw, err := newTransferWriter(r)
+ tw, err := newTransferWriter(r1)
if err != nil {
return err
}
@@ -219,8 +266,19 @@ func (r *Response) Write(w io.Writer) error {
return err
}
+ // contentLengthAlreadySent may have been already sent for
+ // POST/PUT requests, even if zero length. See Issue 8180.
+ contentLengthAlreadySent := tw.shouldSendContentLength()
+ if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent {
+ if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil {
+ return err
+ }
+ }
+
// End-of-header
- io.WriteString(w, "\r\n")
+ if _, err := io.WriteString(w, "\r\n"); err != nil {
+ return err
+ }
// Write body and trailer
err = tw.WriteBody(w)
diff --git a/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 5044306a8..4b8946f7a 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -14,6 +14,7 @@ import (
"io/ioutil"
"net/url"
"reflect"
+ "regexp"
"strings"
"testing"
)
@@ -28,6 +29,10 @@ func dummyReq(method string) *Request {
return &Request{Method: method}
}
+func dummyReq11(method string) *Request {
+ return &Request{Method: method, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1}
+}
+
var respTests = []respTest{
// Unchunked response without Content-Length.
{
@@ -406,8 +411,7 @@ func TestWriteResponse(t *testing.T) {
t.Errorf("#%d: %v", i, err)
continue
}
- bout := bytes.NewBuffer(nil)
- err = resp.Write(bout)
+ err = resp.Write(ioutil.Discard)
if err != nil {
t.Errorf("#%d: %v", i, err)
continue
@@ -506,6 +510,9 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
rest, err := ioutil.ReadAll(bufr)
checkErr(err, "ReadAll on remainder")
if e, g := "Next Request Here", string(rest); e != g {
+ g = regexp.MustCompile(`(xx+)`).ReplaceAllStringFunc(g, func(match string) string {
+ return fmt.Sprintf("x(repeated x%d)", len(match))
+ })
fatalf("remainder = %q, expected %q", g, e)
}
}
@@ -615,6 +622,15 @@ func TestResponseContentLengthShortBody(t *testing.T) {
}
}
+func TestReadResponseUnexpectedEOF(t *testing.T) {
+ br := bufio.NewReader(strings.NewReader("HTTP/1.1 301 Moved Permanently\r\n" +
+ "Location: http://example.com"))
+ _, err := ReadResponse(br, nil)
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("ReadResponse = %v; want io.ErrUnexpectedEOF", err)
+ }
+}
+
func TestNeedsSniff(t *testing.T) {
// needsSniff returns true with an empty response.
r := &response{}
diff --git a/src/pkg/net/http/responsewrite_test.go b/src/pkg/net/http/responsewrite_test.go
index 5c10e2161..585b13b85 100644
--- a/src/pkg/net/http/responsewrite_test.go
+++ b/src/pkg/net/http/responsewrite_test.go
@@ -7,6 +7,7 @@ package http
import (
"bytes"
"io/ioutil"
+ "strings"
"testing"
)
@@ -25,7 +26,7 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 0,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: 6,
},
@@ -41,13 +42,113 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 0,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: -1,
},
"HTTP/1.0 200 OK\r\n" +
"\r\n" +
"abcdef",
},
+ // HTTP/1.1 response with unknown length and Connection: close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ Close: true,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1 response with unknown length and not setting connection: close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1 response with unknown length and not setting connection: close, but
+ // setting chunked.
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
+ ContentLength: -1,
+ TransferEncoding: []string{"chunked"},
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and nil body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: nil,
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and non-nil empty body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("")),
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n",
+ },
+ // HTTP/1.1 response 0 content-length, and non-nil non-empty body
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq11("GET"),
+ Header: Header{},
+ Body: ioutil.NopCloser(strings.NewReader("foo")),
+ ContentLength: 0,
+ Close: false,
+ },
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\nfoo",
+ },
// HTTP/1.1, chunked coding; empty trailer; close
{
Response{
@@ -56,7 +157,7 @@ func TestResponseWrite(t *testing.T) {
ProtoMinor: 1,
Request: dummyReq("GET"),
Header: Header{},
- Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+ Body: ioutil.NopCloser(strings.NewReader("abcdef")),
ContentLength: 6,
TransferEncoding: []string{"chunked"},
Close: true,
@@ -90,6 +191,22 @@ func TestResponseWrite(t *testing.T) {
"Foo: Bar Baz\r\n" +
"\r\n",
},
+
+ // Want a single Content-Length header. Fixing issue 8180 where
+ // there were two.
+ {
+ Response{
+ StatusCode: StatusOK,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: &Request{Method: "POST"},
+ Header: Header{},
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Body: nil,
+ },
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ },
}
for i := range respWriteTests {
diff --git a/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go
index 955112bc2..9e4d226bf 100644
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -419,7 +419,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
func TestMuxRedirectLeadingSlashes(t *testing.T) {
paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
for _, path := range paths {
- req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
if err != nil {
t.Errorf("%s", err)
}
@@ -441,6 +441,9 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
}
func TestServerTimeouts(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
reqNum := 0
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
@@ -517,6 +520,9 @@ func TestServerTimeouts(t *testing.T) {
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
@@ -840,9 +846,14 @@ func TestHeadResponses(t *testing.T) {
}
func TestTLSHandshakeTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ errc := make(chanWriter, 10) // but only expecting 1
ts.Config.ReadTimeout = 250 * time.Millisecond
+ ts.Config.ErrorLog = log.New(errc, "", 0)
ts.StartTLS()
defer ts.Close()
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
@@ -857,6 +868,14 @@ func TestTLSHandshakeTimeout(t *testing.T) {
t.Errorf("Read = %d, %v; want an error and no bytes", n, err)
}
})
+ select {
+ case v := <-errc:
+ if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") {
+ t.Errorf("expected a TLS handshake timeout error; got %q", v)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting for logged error")
+ }
}
func TestTLSServer(t *testing.T) {
@@ -869,6 +888,7 @@ func TestTLSServer(t *testing.T) {
}
}
}))
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
defer ts.Close()
// Connect an idle TCP connection to this server before we run
@@ -913,31 +933,50 @@ func TestTLSServer(t *testing.T) {
}
type serverExpectTest struct {
- contentLength int // of request body
+ contentLength int // of request body
+ chunked bool
expectation string // e.g. "100-continue"
readBody bool // whether handler should read the body (if false, sends StatusUnauthorized)
expectedResponse string // expected substring in first line of http response
}
+func expectTest(contentLength int, expectation string, readBody bool, expectedResponse string) serverExpectTest {
+ return serverExpectTest{
+ contentLength: contentLength,
+ expectation: expectation,
+ readBody: readBody,
+ expectedResponse: expectedResponse,
+ }
+}
+
var serverExpectTests = []serverExpectTest{
// Normal 100-continues, case-insensitive.
- {100, "100-continue", true, "100 Continue"},
- {100, "100-cOntInUE", true, "100 Continue"},
+ expectTest(100, "100-continue", true, "100 Continue"),
+ expectTest(100, "100-cOntInUE", true, "100 Continue"),
// No 100-continue.
- {100, "", true, "200 OK"},
+ expectTest(100, "", true, "200 OK"),
// 100-continue but requesting client to deny us,
// so it never reads the body.
- {100, "100-continue", false, "401 Unauthorized"},
+ expectTest(100, "100-continue", false, "401 Unauthorized"),
// Likewise without 100-continue:
- {100, "", false, "401 Unauthorized"},
+ expectTest(100, "", false, "401 Unauthorized"),
// Non-standard expectations are failures
- {0, "a-pony", false, "417 Expectation Failed"},
+ expectTest(0, "a-pony", false, "417 Expectation Failed"),
- // Expect-100 requested but no body
- {0, "100-continue", true, "400 Bad Request"},
+ // Expect-100 requested but no body (is apparently okay: Issue 7625)
+ expectTest(0, "100-continue", true, "200 OK"),
+ // Expect-100 requested but handler doesn't read the body
+ expectTest(0, "100-continue", false, "401 Unauthorized"),
+ // Expect-100 continue with no body, but a chunked body.
+ {
+ expectation: "100-continue",
+ readBody: true,
+ chunked: true,
+ expectedResponse: "100 Continue",
+ },
}
// Tests that the server responds to the "Expect" request header
@@ -966,21 +1005,38 @@ func TestServerExpect(t *testing.T) {
// Only send the body immediately if we're acting like an HTTP client
// that doesn't send 100-continue expectations.
- writeBody := test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue"
+ writeBody := test.contentLength != 0 && strings.ToLower(test.expectation) != "100-continue"
go func() {
+ contentLen := fmt.Sprintf("Content-Length: %d", test.contentLength)
+ if test.chunked {
+ contentLen = "Transfer-Encoding: chunked"
+ }
_, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+
"Connection: close\r\n"+
- "Content-Length: %d\r\n"+
+ "%s\r\n"+
"Expect: %s\r\nHost: foo\r\n\r\n",
- test.readBody, test.contentLength, test.expectation)
+ test.readBody, contentLen, test.expectation)
if err != nil {
t.Errorf("On test %#v, error writing request headers: %v", test, err)
return
}
if writeBody {
+ var targ io.WriteCloser = struct {
+ io.Writer
+ io.Closer
+ }{
+ conn,
+ ioutil.NopCloser(nil),
+ }
+ if test.chunked {
+ targ = httputil.NewChunkedWriter(conn)
+ }
body := strings.Repeat("A", test.contentLength)
- _, err = fmt.Fprint(conn, body)
+ _, err = fmt.Fprint(targ, body)
+ if err == nil {
+ err = targ.Close()
+ }
if err != nil {
if !test.readBody {
// Server likely already hung up on us.
@@ -1414,6 +1470,9 @@ func TestRequestBodyLimit(t *testing.T) {
// TestClientWriteShutdown tests that if the client shuts down the write
// side of their TCP connection, the server doesn't send a 400 Bad Request.
func TestClientWriteShutdown(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
@@ -1934,6 +1993,31 @@ func TestWriteAfterHijack(t *testing.T) {
}
}
+func TestDoubleHijack(t *testing.T) {
+ req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
+ var buf bytes.Buffer
+ conn := &rwTestConn{
+ Reader: bytes.NewReader(req),
+ Writer: &buf,
+ closec: make(chan bool, 1),
+ }
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ conn, _, err := rw.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ _, _, err = rw.(Hijacker).Hijack()
+ if err == nil {
+ t.Errorf("got err = nil; want err != nil")
+ }
+ conn.Close()
+ })
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, handler)
+ <-conn.closec
+}
+
// http://code.google.com/p/go/issues/detail?id=5955
// Note that this does not test the "request too large"
// exit path from the http server. This is intentional;
@@ -2037,31 +2121,160 @@ func TestServerReaderFromOrder(t *testing.T) {
}
}
-// Issue 6157
-func TestNoContentTypeOnNotModified(t *testing.T) {
+// Issue 6157, Issue 6685
+func TestCodesPreventingContentTypeAndBody(t *testing.T) {
+ for _, code := range []int{StatusNotModified, StatusNoContent, StatusContinue} {
+ ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.URL.Path == "/header" {
+ w.Header().Set("Content-Length", "123")
+ }
+ w.WriteHeader(code)
+ if r.URL.Path == "/more" {
+ w.Write([]byte("stuff"))
+ }
+ }))
+ for _, req := range []string{
+ "GET / HTTP/1.0",
+ "GET /header HTTP/1.0",
+ "GET /more HTTP/1.0",
+ "GET / HTTP/1.1",
+ "GET /header HTTP/1.1",
+ "GET /more HTTP/1.1",
+ } {
+ got := ht.rawResponse(req)
+ wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
+ if !strings.Contains(got, wantStatus) {
+ t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
+ } else if strings.Contains(got, "Content-Length") {
+ t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
+ } else if strings.Contains(got, "stuff") {
+ t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got)
+ }
+ }
+ }
+}
+
+func TestContentTypeOkayOn204(t *testing.T) {
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
- if r.URL.Path == "/header" {
- w.Header().Set("Content-Length", "123")
+ w.Header().Set("Content-Length", "123") // suppressed
+ w.Header().Set("Content-Type", "foo/bar")
+ w.WriteHeader(204)
+ }))
+ got := ht.rawResponse("GET / HTTP/1.1")
+ if !strings.Contains(got, "Content-Type: foo/bar") {
+ t.Errorf("Response = %q; want Content-Type: foo/bar", got)
+ }
+ if strings.Contains(got, "Content-Length: 123") {
+ t.Errorf("Response = %q; don't want a Content-Length", got)
+ }
+}
+
+// Issue 6995
+// A server Handler can receive a Request, and then turn around and
+// give a copy of that Request.Body out to the Transport (e.g. any
+// proxy). So then two people own that Request.Body (both the server
+// and the http client), and both think they can close it on failure.
+// Therefore, all incoming server requests Bodies need to be thread-safe.
+func TestTransportAndServerSharedBodyRace(t *testing.T) {
+ defer afterTest(t)
+
+ const bodySize = 1 << 20
+
+ unblockBackend := make(chan bool)
+ backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ io.CopyN(rw, req.Body, bodySize/2)
+ <-unblockBackend
+ }))
+ defer backend.Close()
+
+ backendRespc := make(chan *Response, 1)
+ proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ if req.RequestURI == "/foo" {
+ rw.Write([]byte("bar"))
+ return
}
- w.WriteHeader(StatusNotModified)
- if r.URL.Path == "/more" {
- w.Write([]byte("stuff"))
+ req2, _ := NewRequest("POST", backend.URL, req.Body)
+ req2.ContentLength = bodySize
+
+ bresp, err := DefaultClient.Do(req2)
+ if err != nil {
+ t.Errorf("Proxy outbound request: %v", err)
+ return
+ }
+ _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4)
+ if err != nil {
+ t.Errorf("Proxy copy error: %v", err)
+ return
}
+ backendRespc <- bresp // to close later
+
+ // Try to cause a race: Both the DefaultTransport and the proxy handler's Server
+ // will try to read/close req.Body (aka req2.Body)
+ DefaultTransport.(*Transport).CancelRequest(req2)
+ rw.Write([]byte("OK"))
+ }))
+ defer proxy.Close()
+
+ req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("Original request: %v", err)
+ }
+
+ // Cleanup, so we don't leak goroutines.
+ res.Body.Close()
+ close(unblockBackend)
+ (<-backendRespc).Body.Close()
+}
+
+// Test that a hanging Request.Body.Read from another goroutine can't
+// cause the Handler goroutine's Request.Body.Close to block.
+func TestRequestBodyCloseDoesntBlock(t *testing.T) {
+ t.Skipf("Skipping known issue; see golang.org/issue/7121")
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ defer afterTest(t)
+
+ readErrCh := make(chan error, 1)
+ errCh := make(chan error, 2)
+
+ server := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ go func(body io.Reader) {
+ _, err := body.Read(make([]byte, 100))
+ readErrCh <- err
+ }(req.Body)
+ time.Sleep(500 * time.Millisecond)
}))
- for _, req := range []string{
- "GET / HTTP/1.0",
- "GET /header HTTP/1.0",
- "GET /more HTTP/1.0",
- "GET / HTTP/1.1",
- "GET /header HTTP/1.1",
- "GET /more HTTP/1.1",
- } {
- got := ht.rawResponse(req)
- if !strings.Contains(got, "304 Not Modified") {
- t.Errorf("Non-304 Not Modified for %q: %s", req, got)
- } else if strings.Contains(got, "Content-Length") {
- t.Errorf("Got a Content-Length from %q: %s", req, got)
+ defer server.Close()
+
+ closeConn := make(chan bool)
+ defer close(closeConn)
+ go func() {
+ conn, err := net.Dial("tcp", server.Listener.Addr().String())
+ if err != nil {
+ errCh <- err
+ return
+ }
+ defer conn.Close()
+ _, err = conn.Write([]byte("POST / HTTP/1.1\r\nConnection: close\r\nHost: foo\r\nContent-Length: 100000\r\n\r\n"))
+ if err != nil {
+ errCh <- err
+ return
}
+ // And now just block, making the server block on our
+ // 100000 bytes of body that will never arrive.
+ <-closeConn
+ }()
+ select {
+ case err := <-readErrCh:
+ if err == nil {
+ t.Error("Read was nil. Expected error.")
+ }
+ case err := <-errCh:
+ t.Error(err)
+ case <-time.After(5 * time.Second):
+ t.Error("timeout")
}
}
@@ -2073,8 +2286,8 @@ func TestResponseWriterWriteStringAllocs(t *testing.T) {
w.Write([]byte("Hello world"))
}
}))
- before := testing.AllocsPerRun(25, func() { ht.rawResponse("GET / HTTP/1.0") })
- after := testing.AllocsPerRun(25, func() { ht.rawResponse("GET /s HTTP/1.0") })
+ before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") })
+ after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") })
if int(after) >= int(before) {
t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before)
}
@@ -2093,6 +2306,230 @@ func TestAppendTime(t *testing.T) {
}
}
+func TestServerConnState(t *testing.T) {
+ defer afterTest(t)
+ handler := map[string]func(w ResponseWriter, r *Request){
+ "/": func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "Hello.")
+ },
+ "/close": func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ fmt.Fprintf(w, "Hello.")
+ },
+ "/hijack": func(w ResponseWriter, r *Request) {
+ c, _, _ := w.(Hijacker).Hijack()
+ c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+ c.Close()
+ },
+ "/hijack-panic": func(w ResponseWriter, r *Request) {
+ c, _, _ := w.(Hijacker).Hijack()
+ c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+ c.Close()
+ panic("intentional panic")
+ },
+ }
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ handler[r.URL.Path](w, r)
+ }))
+ defer ts.Close()
+
+ var mu sync.Mutex // guard stateLog and connID
+ var stateLog = map[int][]ConnState{}
+ var connID = map[net.Conn]int{}
+
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+ ts.Config.ConnState = func(c net.Conn, state ConnState) {
+ if c == nil {
+ t.Errorf("nil conn seen in state %s", state)
+ return
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ id, ok := connID[c]
+ if !ok {
+ id = len(connID) + 1
+ connID[c] = id
+ }
+ stateLog[id] = append(stateLog[id], state)
+ }
+ ts.Start()
+
+ mustGet(t, ts.URL+"/")
+ mustGet(t, ts.URL+"/close")
+
+ mustGet(t, ts.URL+"/")
+ mustGet(t, ts.URL+"/", "Connection", "close")
+
+ mustGet(t, ts.URL+"/hijack")
+ mustGet(t, ts.URL+"/hijack-panic")
+
+ // New->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ // New->Active->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ // New->Idle->Closed
+ {
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
+ t.Fatal(err)
+ }
+ res, err := ReadResponse(bufio.NewReader(c), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+ }
+
+ want := map[int][]ConnState{
+ 1: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 2: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+ 3: []ConnState{StateNew, StateActive, StateHijacked},
+ 4: []ConnState{StateNew, StateActive, StateHijacked},
+ 5: []ConnState{StateNew, StateClosed},
+ 6: []ConnState{StateNew, StateActive, StateClosed},
+ 7: []ConnState{StateNew, StateActive, StateIdle, StateClosed},
+ }
+ logString := func(m map[int][]ConnState) string {
+ var b bytes.Buffer
+ for id, l := range m {
+ fmt.Fprintf(&b, "Conn %d: ", id)
+ for _, s := range l {
+ fmt.Fprintf(&b, "%s ", s)
+ }
+ b.WriteString("\n")
+ }
+ return b.String()
+ }
+
+ for i := 0; i < 5; i++ {
+ time.Sleep(time.Duration(i) * 50 * time.Millisecond)
+ mu.Lock()
+ match := reflect.DeepEqual(stateLog, want)
+ mu.Unlock()
+ if match {
+ return
+ }
+ }
+
+ mu.Lock()
+ t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want))
+ mu.Unlock()
+}
+
+func mustGet(t *testing.T, url string, headers ...string) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for len(headers) > 0 {
+ req.Header.Add(headers[0], headers[1])
+ headers = headers[2:]
+ }
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Errorf("Error fetching %s: %v", url, err)
+ return
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ defer res.Body.Close()
+ if err != nil {
+ t.Errorf("Error reading %s: %v", url, err)
+ }
+}
+
+func TestServerKeepAlivesEnabled(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ ts.Config.SetKeepAlivesEnabled(false)
+ ts.Start()
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if !res.Close {
+ t.Errorf("Body.Close == false; want true")
+ }
+}
+
+// golang.org/issue/7856
+func TestServerEmptyBodyRace(t *testing.T) {
+ defer afterTest(t)
+ var n int32
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ atomic.AddInt32(&n, 1)
+ }))
+ defer ts.Close()
+ var wg sync.WaitGroup
+ const reqs = 20
+ for i := 0; i < reqs; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer res.Body.Close()
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ }()
+ }
+ wg.Wait()
+ if got := atomic.LoadInt32(&n); got != reqs {
+ t.Errorf("handler ran %d times; want %d", got, reqs)
+ }
+}
+
+func TestServerConnStateNew(t *testing.T) {
+ sawNew := false // if the test is buggy, we'll race on this variable.
+ srv := &Server{
+ ConnState: func(c net.Conn, state ConnState) {
+ if state == StateNew {
+ sawNew = true // testing that this write isn't racy
+ }
+ },
+ Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant
+ }
+ srv.Serve(&oneConnListener{
+ conn: &rwTestConn{
+ Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"),
+ Writer: ioutil.Discard,
+ },
+ })
+ if !sawNew { // testing that this read isn't racy
+ t.Error("StateNew not seen")
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
@@ -2108,6 +2545,7 @@ func BenchmarkClientServer(b *testing.B) {
b.Fatal("Get:", err)
}
all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
b.Fatal("ReadAll:", err)
}
@@ -2128,41 +2566,33 @@ func BenchmarkClientServerParallel64(b *testing.B) {
benchmarkClientServerParallel(b, 64)
}
-func benchmarkClientServerParallel(b *testing.B, conc int) {
+func benchmarkClientServerParallel(b *testing.B, parallelism int) {
b.ReportAllocs()
- b.StopTimer()
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
fmt.Fprintf(rw, "Hello world.\n")
}))
defer ts.Close()
- b.StartTimer()
-
- numProcs := runtime.GOMAXPROCS(-1) * conc
- var wg sync.WaitGroup
- wg.Add(numProcs)
- n := int32(b.N)
- for p := 0; p < numProcs; p++ {
- go func() {
- for atomic.AddInt32(&n, -1) >= 0 {
- res, err := Get(ts.URL)
- if err != nil {
- b.Logf("Get: %v", err)
- continue
- }
- all, err := ioutil.ReadAll(res.Body)
- if err != nil {
- b.Logf("ReadAll: %v", err)
- continue
- }
- body := string(all)
- if body != "Hello world.\n" {
- panic("Got body: " + body)
- }
+ b.ResetTimer()
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ res, err := Get(ts.URL)
+ if err != nil {
+ b.Logf("Get: %v", err)
+ continue
}
- wg.Done()
- }()
- }
- wg.Wait()
+ all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ b.Logf("ReadAll: %v", err)
+ continue
+ }
+ body := string(all)
+ if body != "Hello world.\n" {
+ panic("Got body: " + body)
+ }
+ }
+ })
}
// A benchmark for profiling the server without the HTTP client code.
@@ -2187,6 +2617,7 @@ func BenchmarkServer(b *testing.B) {
log.Panicf("Get: %v", err)
}
all, err := ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
log.Panicf("ReadAll: %v", err)
}
@@ -2390,3 +2821,28 @@ Host: golang.org
b.Errorf("b.N=%d but handled %d", b.N, handled)
}
}
+
+func BenchmarkServerHijack(b *testing.B) {
+ b.ReportAllocs()
+ req := reqBytes(`GET / HTTP/1.1
+Host: golang.org
+`)
+ h := HandlerFunc(func(w ResponseWriter, r *Request) {
+ conn, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ panic(err)
+ }
+ conn.Close()
+ })
+ conn := &rwTestConn{
+ Writer: ioutil.Discard,
+ closec: make(chan bool, 1),
+ }
+ ln := &oneConnListener{conn: conn}
+ for i := 0; i < b.N; i++ {
+ conn.Reader = bytes.NewReader(req)
+ ln.conn = conn
+ Serve(ln, h)
+ <-conn.closec
+ }
+}
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 0e46863d5..eae097eb8 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
)
@@ -138,6 +139,7 @@ func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
buf = c.buf
c.rwc = nil
c.buf = nil
+ c.setState(rwc, StateHijacked)
return
}
@@ -435,56 +437,52 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
return c, nil
}
-// TODO: use a sync.Cache instead
var (
- bufioReaderCache = make(chan *bufio.Reader, 4)
- bufioWriterCache2k = make(chan *bufio.Writer, 4)
- bufioWriterCache4k = make(chan *bufio.Writer, 4)
+ bufioReaderPool sync.Pool
+ bufioWriter2kPool sync.Pool
+ bufioWriter4kPool sync.Pool
)
-func bufioWriterCache(size int) chan *bufio.Writer {
+func bufioWriterPool(size int) *sync.Pool {
switch size {
case 2 << 10:
- return bufioWriterCache2k
+ return &bufioWriter2kPool
case 4 << 10:
- return bufioWriterCache4k
+ return &bufioWriter4kPool
}
return nil
}
func newBufioReader(r io.Reader) *bufio.Reader {
- select {
- case p := <-bufioReaderCache:
- p.Reset(r)
- return p
- default:
- return bufio.NewReader(r)
+ if v := bufioReaderPool.Get(); v != nil {
+ br := v.(*bufio.Reader)
+ br.Reset(r)
+ return br
}
+ return bufio.NewReader(r)
}
func putBufioReader(br *bufio.Reader) {
br.Reset(nil)
- select {
- case bufioReaderCache <- br:
- default:
- }
+ bufioReaderPool.Put(br)
}
func newBufioWriterSize(w io.Writer, size int) *bufio.Writer {
- select {
- case p := <-bufioWriterCache(size):
- p.Reset(w)
- return p
- default:
- return bufio.NewWriterSize(w, size)
+ pool := bufioWriterPool(size)
+ if pool != nil {
+ if v := pool.Get(); v != nil {
+ bw := v.(*bufio.Writer)
+ bw.Reset(w)
+ return bw
+ }
}
+ return bufio.NewWriterSize(w, size)
}
func putBufioWriter(bw *bufio.Writer) {
bw.Reset(nil)
- select {
- case bufioWriterCache(bw.Available()) <- bw:
- default:
+ if pool := bufioWriterPool(bw.Available()); pool != nil {
+ pool.Put(bw)
}
}
@@ -500,6 +498,10 @@ func (srv *Server) maxHeaderBytes() int {
return DefaultMaxHeaderBytes
}
+func (srv *Server) initialLimitedReaderSize() int64 {
+ return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
+}
+
// wrapper around io.ReaderCloser which on first read, sends an
// HTTP/1.1 100 Continue header
type expectContinueReader struct {
@@ -570,7 +572,7 @@ func (c *conn) readRequest() (w *response, err error) {
}()
}
- c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
+ c.lr.N = c.server.initialLimitedReaderSize()
var req *Request
if req, err = ReadRequest(c.buf.Reader); err != nil {
if c.lr.N == 0 {
@@ -618,11 +620,11 @@ const maxPostHandlerReadBytes = 256 << 10
func (w *response) WriteHeader(code int) {
if w.conn.hijacked() {
- log.Print("http: response.WriteHeader on hijacked connection")
+ w.conn.server.logf("http: response.WriteHeader on hijacked connection")
return
}
if w.wroteHeader {
- log.Print("http: multiple response.WriteHeader calls")
+ w.conn.server.logf("http: multiple response.WriteHeader calls")
return
}
w.wroteHeader = true
@@ -637,7 +639,7 @@ func (w *response) WriteHeader(code int) {
if err == nil && v >= 0 {
w.contentLength = v
} else {
- log.Printf("http: invalid Content-Length of %q", cl)
+ w.conn.server.logf("http: invalid Content-Length of %q", cl)
w.handlerHeader.Del("Content-Length")
}
}
@@ -707,6 +709,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
cw.wroteHeader = true
w := cw.res
+ keepAlivesEnabled := w.conn.server.doKeepAlives()
isHEAD := w.req.Method == "HEAD"
// header is written out to w.conn.buf below. Depending on the
@@ -739,7 +742,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// response header and this is our first (and last) write, set
// it, even to zero. This helps HTTP/1.0 clients keep their
// "keep-alive" connections alive.
- // Exceptions: 304 responses never get Content-Length, and if
+ // Exceptions: 304/204/1xx responses never get Content-Length, and if
// it was a HEAD request, we don't know the difference between
// 0 actual bytes and 0 bytes because the handler noticed it
// was a HEAD request and chose not to write anything. So for
@@ -747,14 +750,14 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// write non-zero bytes. If it's actually 0 bytes and the
// handler never looked at the Request.Method, we just don't
// send a Content-Length header.
- if w.handlerDone && w.status != StatusNotModified && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+ if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
w.contentLength = int64(len(p))
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
}
// If this was an HTTP/1.0 request with keep-alive and we sent a
// Content-Length back, we can make this a keep-alive response ...
- if w.req.wantsHttp10KeepAlive() {
+ if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled {
sentLength := header.get("Content-Length") != ""
if sentLength && header.get("Connection") == "keep-alive" {
w.closeAfterReply = false
@@ -773,7 +776,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
w.closeAfterReply = true
}
- if header.get("Connection") == "close" {
+ if header.get("Connection") == "close" || !keepAlivesEnabled {
w.closeAfterReply = true
}
@@ -796,18 +799,16 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
code := w.status
- if code == StatusNotModified {
- // Must not have body.
- // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
- for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
- delHeader(k)
- }
- } else {
+ if bodyAllowedForStatus(code) {
// If no content type, apply sniffing algorithm to body.
_, haveType := header["Content-Type"]
if !haveType {
setHeader.contentType = DetectContentType(p)
}
+ } else {
+ for _, k := range suppressedHeaders(code) {
+ delHeader(k)
+ }
}
if _, ok := header["Date"]; !ok {
@@ -819,13 +820,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if hasCL && hasTE && te != "identity" {
// TODO: return an error if WriteHeader gets a return parameter
// For now just ignore the Content-Length.
- log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
+ w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
te, w.contentLength)
delHeader("Content-Length")
hasCL = false
}
- if w.req.Method == "HEAD" || code == StatusNotModified {
+ if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) {
// do nothing
} else if code == StatusNoContent {
delHeader("Transfer-Encoding")
@@ -855,7 +856,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
return
}
- if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
+ if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) {
delHeader("Connection")
if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close"
@@ -919,7 +920,7 @@ func (w *response) bodyAllowed() bool {
if !w.wroteHeader {
panic("")
}
- return w.status != StatusNotModified
+ return bodyAllowedForStatus(w.status)
}
// The Life Of A Write is like this:
@@ -965,7 +966,7 @@ func (w *response) WriteString(data string) (n int, err error) {
// either dataB or dataS is non-zero.
func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
if w.conn.hijacked() {
- log.Print("http: response.Write on hijacked connection")
+ w.conn.server.logf("http: response.Write on hijacked connection")
return 0, ErrHijacked
}
if !w.wroteHeader {
@@ -1001,11 +1002,10 @@ func (w *response) finishRequest() {
w.cw.close()
w.conn.buf.Flush()
- // Close the body, unless we're about to close the whole TCP connection
- // anyway.
- if !w.closeAfterReply {
- w.req.Body.Close()
- }
+ // Close the body (regardless of w.closeAfterReply) so we can
+ // re-use its bufio.Reader later safely.
+ w.req.Body.Close()
+
if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll()
}
@@ -1084,17 +1084,25 @@ func validNPN(proto string) bool {
return true
}
+func (c *conn) setState(nc net.Conn, state ConnState) {
+ if hook := c.server.ConnState; hook != nil {
+ hook(nc, state)
+ }
+}
+
// Serve a new connection.
func (c *conn) serve() {
+ origConn := c.rwc // copy it before it's set nil on Close or Hijack
defer func() {
if err := recover(); err != nil {
- const size = 4096
+ const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
- log.Printf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
+ c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
}
if !c.hijacked() {
c.close()
+ c.setState(origConn, StateClosed)
}
}()
@@ -1106,6 +1114,7 @@ func (c *conn) serve() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
if err := tlsConn.Handshake(); err != nil {
+ c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
return
}
c.tlsState = new(tls.ConnectionState)
@@ -1121,6 +1130,10 @@ func (c *conn) serve() {
for {
w, err := c.readRequest()
+ if c.lr.N != c.server.initialLimitedReaderSize() {
+ // If we read any bytes off the wire, we're active.
+ c.setState(c.rwc, StateActive)
+ }
if err != nil {
if err == errTooLarge {
// Their HTTP client may or may not be
@@ -1143,16 +1156,10 @@ func (c *conn) serve() {
// Expect 100 Continue support
req := w.req
if req.expectsContinue() {
- if req.ProtoAtLeast(1, 1) {
+ if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
- if req.ContentLength == 0 {
- w.Header().Set("Connection", "close")
- w.WriteHeader(StatusBadRequest)
- w.finishRequest()
- break
- }
req.Header.Del("Expect")
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
@@ -1175,6 +1182,7 @@ func (c *conn) serve() {
}
break
}
+ c.setState(c.rwc, StateIdle)
}
}
@@ -1202,7 +1210,14 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if w.wroteHeader {
w.cw.flush()
}
- return w.conn.hijack()
+ // Release the bufioWriter that writes to the chunk writer, it is not
+ // used after a connection has been hijacked.
+ rwc, buf, err = w.conn.hijack()
+ if err == nil {
+ putBufioWriter(w.w)
+ w.w = nil
+ }
+ return rwc, buf, err
}
func (w *response) CloseNotify() <-chan bool {
@@ -1562,6 +1577,7 @@ func Serve(l net.Listener, handler Handler) error {
}
// A Server defines parameters for running an HTTP server.
+// The zero value for Server is a valid configuration.
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
@@ -1578,6 +1594,66 @@ type Server struct {
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
+
+ // ConnState specifies an optional callback function that is
+ // called when a client connection changes state. See the
+ // ConnState type and associated constants for details.
+ ConnState func(net.Conn, ConnState)
+
+ // ErrorLog specifies an optional logger for errors accepting
+ // connections and unexpected behavior from handlers.
+ // If nil, logging goes to os.Stderr via the log package's
+ // standard logger.
+ ErrorLog *log.Logger
+
+ disableKeepAlives int32 // accessed atomically.
+}
+
+// A ConnState represents the state of a client connection to a server.
+// It's used by the optional Server.ConnState hook.
+type ConnState int
+
+const (
+ // StateNew represents a new connection that is expected to
+ // send a request immediately. Connections begin at this
+ // state and then transition to either StateActive or
+ // StateClosed.
+ StateNew ConnState = iota
+
+ // StateActive represents a connection that has read 1 or more
+ // bytes of a request. The Server.ConnState hook for
+ // StateActive fires before the request has entered a handler
+ // and doesn't fire again until the request has been
+ // handled. After the request is handled, the state
+ // transitions to StateClosed, StateHijacked, or StateIdle.
+ StateActive
+
+ // StateIdle represents a connection that has finished
+ // handling a request and is in the keep-alive state, waiting
+ // for a new request. Connections transition from StateIdle
+ // to either StateActive or StateClosed.
+ StateIdle
+
+ // StateHijacked represents a hijacked connection.
+ // This is a terminal state. It does not transition to StateClosed.
+ StateHijacked
+
+ // StateClosed represents a closed connection.
+ // This is a terminal state. Hijacked connections do not
+ // transition to StateClosed.
+ StateClosed
+)
+
+var stateName = map[ConnState]string{
+ StateNew: "new",
+ StateActive: "active",
+ StateIdle: "idle",
+ StateHijacked: "hijacked",
+ StateClosed: "closed",
+}
+
+func (c ConnState) String() string {
+ return stateName[c]
}
// serverHandler delegates to either the server's Handler or
@@ -1605,11 +1681,11 @@ func (srv *Server) ListenAndServe() error {
if addr == "" {
addr = ":http"
}
- l, e := net.Listen("tcp", addr)
- if e != nil {
- return e
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
}
- return srv.Serve(l)
+ return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
// Serve accepts incoming connections on the Listener l, creating a
@@ -1630,7 +1706,7 @@ func (srv *Server) Serve(l net.Listener) error {
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
- log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
+ srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
@@ -1641,10 +1717,35 @@ func (srv *Server) Serve(l net.Listener) error {
if err != nil {
continue
}
+ c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
}
}
+func (s *Server) doKeepAlives() bool {
+ return atomic.LoadInt32(&s.disableKeepAlives) == 0
+}
+
+// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
+// By default, keep-alives are always enabled. Only very
+// resource-constrained environments or servers in the process of
+// shutting down should disable them.
+func (s *Server) SetKeepAlivesEnabled(v bool) {
+ if v {
+ atomic.StoreInt32(&s.disableKeepAlives, 0)
+ } else {
+ atomic.StoreInt32(&s.disableKeepAlives, 1)
+ }
+}
+
+func (s *Server) logf(format string, args ...interface{}) {
+ if s.ErrorLog != nil {
+ s.ErrorLog.Printf(format, args...)
+ } else {
+ log.Printf(format, args...)
+ }
+}
+
// ListenAndServe listens on the TCP network address addr
// and then calls Serve with handler to handle requests
// on incoming connections. Handler is typically nil,
@@ -1739,12 +1840,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return err
}
- conn, err := net.Listen("tcp", addr)
+ ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
- tlsListener := tls.NewListener(conn, config)
+ tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
return srv.Serve(tlsListener)
}
@@ -1834,6 +1935,24 @@ func (tw *timeoutWriter) WriteHeader(code int) {
tw.w.WriteHeader(code)
}
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
+ }
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
+}
+
// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}
@@ -1850,17 +1969,24 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
}
}
+type eofReaderWithWriteTo struct{}
+
+func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil }
+func (eofReaderWithWriteTo) Read([]byte) (int, error) { return 0, io.EOF }
+
// eofReader is a non-nil io.ReadCloser that always returns EOF.
-// It embeds a *strings.Reader so it still has a WriteTo method
-// and io.Copy won't need a buffer.
+// It has a WriteTo method so io.Copy won't need a buffer.
var eofReader = &struct {
- *strings.Reader
+ eofReaderWithWriteTo
io.Closer
}{
- strings.NewReader(""),
+ eofReaderWithWriteTo{},
ioutil.NopCloser(nil),
}
+// Verify that an io.Copy from an eofReader won't require a buffer.
+var _ io.WriterTo = eofReader
+
// initNPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
// Requests come from NPN protocol handlers.
diff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go
index bacd83732..7f6368652 100644
--- a/src/pkg/net/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -12,10 +12,20 @@ import (
"io"
"io/ioutil"
"net/textproto"
+ "sort"
"strconv"
"strings"
+ "sync"
)
+type errorReader struct {
+ err error
+}
+
+func (r *errorReader) Read(p []byte) (n int, err error) {
+ return 0, r.err
+}
+
// transferWriter inspects the fields of a user-supplied Request or Response,
// sanitizes them without changing the user object and provides methods for
// writing the respective header, body and trailer in wire format.
@@ -52,14 +62,17 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
if t.ContentLength == 0 {
// Test to see if it's actually zero or just unset.
var buf [1]byte
- n, _ := io.ReadFull(t.Body, buf[:])
- if n == 1 {
+ n, rerr := io.ReadFull(t.Body, buf[:])
+ if rerr != nil && rerr != io.EOF {
+ t.ContentLength = -1
+ t.Body = &errorReader{rerr}
+ } else if n == 1 {
// Oh, guess there is data in this Body Reader after all.
// The ContentLength field just wasn't set.
// Stich the Body back together again, re-attaching our
// consumed byte.
t.ContentLength = -1
- t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+ t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
} else {
// Body is actually empty.
t.Body = nil
@@ -131,11 +144,10 @@ func (t *transferWriter) shouldSendContentLength() bool {
return false
}
-func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
+func (t *transferWriter) WriteHeader(w io.Writer) error {
if t.Close {
- _, err = io.WriteString(w, "Connection: close\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
+ return err
}
}
@@ -143,43 +155,44 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
// function of the sanitized field triple (Body, ContentLength,
// TransferEncoding)
if t.shouldSendContentLength() {
- io.WriteString(w, "Content-Length: ")
- _, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Content-Length: "); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil {
+ return err
}
} else if chunked(t.TransferEncoding) {
- _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
- if err != nil {
- return
+ if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil {
+ return err
}
}
// Write Trailer header
if t.Trailer != nil {
- // TODO: At some point, there should be a generic mechanism for
- // writing long headers, using HTTP line splitting
- io.WriteString(w, "Trailer: ")
- needComma := false
+ keys := make([]string, 0, len(t.Trailer))
for k := range t.Trailer {
k = CanonicalHeaderKey(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return &badStringError{"invalid Trailer key", k}
}
- if needComma {
- io.WriteString(w, ",")
+ keys = append(keys, k)
+ }
+ if len(keys) > 0 {
+ sort.Strings(keys)
+ // TODO: could do better allocation-wise here, but trailers are rare,
+ // so being lazy for now.
+ if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil {
+ return err
}
- io.WriteString(w, k)
- needComma = true
}
- _, err = io.WriteString(w, "\r\n")
}
- return
+ return nil
}
-func (t *transferWriter) WriteBody(w io.Writer) (err error) {
+func (t *transferWriter) WriteBody(w io.Writer) error {
+ var err error
var ncopy int64
// Write body
@@ -216,11 +229,16 @@ func (t *transferWriter) WriteBody(w io.Writer) (err error) {
// TODO(petar): Place trailer writer code here.
if chunked(t.TransferEncoding) {
+ // Write Trailer header
+ if t.Trailer != nil {
+ if err := t.Trailer.Write(w); err != nil {
+ return err
+ }
+ }
// Last chunk, empty trailer
_, err = io.WriteString(w, "\r\n")
}
-
- return
+ return err
}
type transferReader struct {
@@ -252,6 +270,22 @@ func bodyAllowedForStatus(status int) bool {
return true
}
+var (
+ suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"}
+ suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"}
+)
+
+func suppressedHeaders(status int) []string {
+ switch {
+ case status == 304:
+ // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
+ return suppressedHeaders304
+ case !bodyAllowedForStatus(status):
+ return suppressedHeadersNoBody
+ }
+ return nil
+}
+
// msg is *Request or *Response.
func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t := &transferReader{RequestMethod: "GET"}
@@ -331,17 +365,17 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
if noBodyExpected(t.RequestMethod) {
t.Body = eofReader
} else {
- t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+ t.Body = &body{src: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
}
case realLength == 0:
t.Body = eofReader
case realLength > 0:
- t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
+ t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
default:
// realLength < 0, i.e. "Content-Length" not mentioned in header
if t.Close {
// Close semantics (i.e. HTTP/1.0)
- t.Body = &body{Reader: r, closing: t.Close}
+ t.Body = &body{src: r, closing: t.Close}
} else {
// Persistent connection (i.e. HTTP/1.1)
t.Body = eofReader
@@ -498,7 +532,7 @@ func fixTrailer(header Header, te []string) (Header, error) {
case "Transfer-Encoding", "Trailer", "Content-Length":
return nil, &badStringError{"bad trailer key", key}
}
- trailer.Del(key)
+ trailer[key] = nil
}
if len(trailer) == 0 {
return nil, nil
@@ -514,11 +548,13 @@ func fixTrailer(header Header, te []string) (Header, error) {
// Close ensures that the body has been fully read
// and then reads the trailer if necessary.
type body struct {
- io.Reader
+ src io.Reader
hdr interface{} // non-nil (Response or Request) value means read trailer
r *bufio.Reader // underlying wire-format reader for the trailer
closing bool // is the connection to be closed after reading body?
- closed bool
+
+ mu sync.Mutex // guards closed, and calls to Read and Close
+ closed bool
}
// ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -528,10 +564,17 @@ type body struct {
var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
func (b *body) Read(p []byte) (n int, err error) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
if b.closed {
return 0, ErrBodyReadAfterClose
}
- n, err = b.Reader.Read(p)
+ return b.readLocked(p)
+}
+
+// Must hold b.mu.
+func (b *body) readLocked(p []byte) (n int, err error) {
+ n, err = b.src.Read(p)
if err == io.EOF {
// Chunked case. Read the trailer.
@@ -543,12 +586,23 @@ func (b *body) Read(p []byte) (n int, err error) {
} else {
// If the server declared the Content-Length, our body is a LimitedReader
// and we need to check whether this EOF arrived early.
- if lr, ok := b.Reader.(*io.LimitedReader); ok && lr.N > 0 {
+ if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 {
err = io.ErrUnexpectedEOF
}
}
}
+ // If we can return an EOF here along with the read data, do
+ // so. This is optional per the io.Reader contract, but doing
+ // so helps the HTTP transport code recycle its connection
+ // earlier (since it will see this EOF itself), even if the
+ // client doesn't do future reads or Close.
+ if err == nil && n > 0 {
+ if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
+ err = io.EOF
+ }
+ }
+
return n, err
}
@@ -610,14 +664,26 @@ func (b *body) readTrailer() error {
}
switch rr := b.hdr.(type) {
case *Request:
- rr.Trailer = Header(hdr)
+ mergeSetHeader(&rr.Trailer, Header(hdr))
case *Response:
- rr.Trailer = Header(hdr)
+ mergeSetHeader(&rr.Trailer, Header(hdr))
}
return nil
}
+func mergeSetHeader(dst *Header, src Header) {
+ if *dst == nil {
+ *dst = src
+ return
+ }
+ for k, vv := range src {
+ (*dst)[k] = vv
+ }
+}
+
func (b *body) Close() error {
+ b.mu.Lock()
+ defer b.mu.Unlock()
if b.closed {
return nil
}
@@ -629,12 +695,25 @@ func (b *body) Close() error {
default:
// Fully consume the body, which will also lead to us reading
// the trailer headers after the body, if present.
- _, err = io.Copy(ioutil.Discard, b)
+ _, err = io.Copy(ioutil.Discard, bodyLocked{b})
}
b.closed = true
return err
}
+// bodyLocked is a io.Reader reading from a *body when its mutex is
+// already held.
+type bodyLocked struct {
+ b *body
+}
+
+func (bl bodyLocked) Read(p []byte) (n int, err error) {
+ if bl.b.closed {
+ return 0, ErrBodyReadAfterClose
+ }
+ return bl.b.readLocked(p)
+}
+
// parseContentLength trims whitespace from s and returns -1 if no value
// is set, or the value if it's >= 0.
func parseContentLength(cl string) (int64, error) {
diff --git a/src/pkg/net/http/transfer_test.go b/src/pkg/net/http/transfer_test.go
index 8627a374c..48cd540b9 100644
--- a/src/pkg/net/http/transfer_test.go
+++ b/src/pkg/net/http/transfer_test.go
@@ -6,15 +6,16 @@ package http
import (
"bufio"
+ "io"
"strings"
"testing"
)
func TestBodyReadBadTrailer(t *testing.T) {
b := &body{
- Reader: strings.NewReader("foobar"),
- hdr: true, // force reading the trailer
- r: bufio.NewReader(strings.NewReader("")),
+ src: strings.NewReader("foobar"),
+ hdr: true, // force reading the trailer
+ r: bufio.NewReader(strings.NewReader("")),
}
buf := make([]byte, 7)
n, err := b.Read(buf[:3])
@@ -35,3 +36,29 @@ func TestBodyReadBadTrailer(t *testing.T) {
t.Errorf("final Read was successful (%q), expected error from trailer read", got)
}
}
+
+func TestFinalChunkedBodyReadEOF(t *testing.T) {
+ res, err := ReadResponse(bufio.NewReader(strings.NewReader(
+ "HTTP/1.1 200 OK\r\n"+
+ "Transfer-Encoding: chunked\r\n"+
+ "\r\n"+
+ "0a\r\n"+
+ "Body here\n\r\n"+
+ "09\r\n"+
+ "continued\r\n"+
+ "0\r\n"+
+ "\r\n")), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "Body here\ncontinued"
+ buf := make([]byte, len(want))
+ n, err := res.Body.Read(buf)
+ if n != len(want) || err != io.EOF {
+ t.Logf("body = %#v", res.Body)
+ t.Errorf("Read = %v, %v; want %d, EOF", n, err, len(want))
+ }
+ if string(buf) != want {
+ t.Errorf("buf = %q; want %q", buf, want)
+ }
+}
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index f6871afac..b1cc632a7 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -30,7 +30,14 @@ import (
// and caches them for reuse by subsequent calls. It uses HTTP proxies
// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
// $no_proxy) environment variables.
-var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
+var DefaultTransport RoundTripper = &Transport{
+ Proxy: ProxyFromEnvironment,
+ Dial: (&net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ TLSHandshakeTimeout: 10 * time.Second,
+}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
@@ -40,13 +47,13 @@ const DefaultMaxIdleConnsPerHost = 2
// https, and http proxies (for either http or https with CONNECT).
// Transport can also cache connections for future re-use.
type Transport struct {
- idleMu sync.Mutex
- idleConn map[string][]*persistConn
- idleConnCh map[string]chan *persistConn
- reqMu sync.Mutex
- reqConn map[*Request]*persistConn
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+ idleMu sync.Mutex
+ idleConn map[connectMethodKey][]*persistConn
+ idleConnCh map[connectMethodKey]chan *persistConn
+ reqMu sync.Mutex
+ reqCanceler map[*Request]func()
+ altMu sync.RWMutex
+ altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
@@ -63,6 +70,10 @@ type Transport struct {
// tls.Client. If nil, the default configuration is used.
TLSClientConfig *tls.Config
+ // TLSHandshakeTimeout specifies the maximum amount of time waiting to
+ // wait for a TLS handshake. Zero means no timeout.
+ TLSHandshakeTimeout time.Duration
+
// DisableKeepAlives, if true, prevents re-use of TCP connections
// between different HTTP requests.
DisableKeepAlives bool
@@ -98,8 +109,11 @@ type Transport struct {
// An error is returned if the proxy environment is invalid.
// A nil URL and nil error are returned if no proxy is defined in the
// environment, or a proxy should not be used for the given request.
+//
+// As a special case, if req.URL.Host is "localhost" (with or without
+// a port number), then a nil URL and nil error will be returned.
func ProxyFromEnvironment(req *Request) (*url.URL, error) {
- proxy := getenvEitherCase("HTTP_PROXY")
+ proxy := httpProxyEnv.Get()
if proxy == "" {
return nil, nil
}
@@ -149,9 +163,11 @@ func (tr *transportRequest) extraHeaders() Header {
// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
if req.URL == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
if req.Header == nil {
+ req.closeBody()
return nil, errors.New("http: nil Request.Header")
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
@@ -162,16 +178,19 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
}
t.altMu.RUnlock()
if rt == nil {
+ req.closeBody()
return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
}
return rt.RoundTrip(req)
}
if req.URL.Host == "" {
+ req.closeBody()
return nil, errors.New("http: no Host in request URL")
}
treq := &transportRequest{Request: req}
cm, err := t.connectMethodForRequest(treq)
if err != nil {
+ req.closeBody()
return nil, err
}
@@ -179,8 +198,10 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
// host (for http or https), the http proxy, or the http proxy
// pre-CONNECTed to https server. In any case, we'll be ready
// to send it requests.
- pconn, err := t.getConn(cm)
+ pconn, err := t.getConn(req, cm)
if err != nil {
+ t.setReqCanceler(req, nil)
+ req.closeBody()
return nil, err
}
@@ -218,9 +239,6 @@ func (t *Transport) CloseIdleConnections() {
t.idleConn = nil
t.idleConnCh = nil
t.idleMu.Unlock()
- if m == nil {
- return
- }
for _, conns := range m {
for _, pconn := range conns {
pconn.close()
@@ -232,10 +250,10 @@ func (t *Transport) CloseIdleConnections() {
// connection.
func (t *Transport) CancelRequest(req *Request) {
t.reqMu.Lock()
- pc := t.reqConn[req]
+ cancel := t.reqCanceler[req]
t.reqMu.Unlock()
- if pc != nil {
- pc.conn.Close()
+ if cancel != nil {
+ cancel()
}
}
@@ -243,24 +261,49 @@ func (t *Transport) CancelRequest(req *Request) {
// Private implementation past this point.
//
-func getenvEitherCase(k string) string {
- if v := os.Getenv(strings.ToUpper(k)); v != "" {
- return v
+var (
+ httpProxyEnv = &envOnce{
+ names: []string{"HTTP_PROXY", "http_proxy"},
}
- return os.Getenv(strings.ToLower(k))
+ noProxyEnv = &envOnce{
+ names: []string{"NO_PROXY", "no_proxy"},
+ }
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+type envOnce struct {
+ names []string
+ once sync.Once
+ val string
+}
+
+func (e *envOnce) Get() string {
+ e.once.Do(e.init)
+ return e.val
}
-func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
- cm := &connectMethod{
- targetScheme: treq.URL.Scheme,
- targetAddr: canonicalAddr(treq.URL),
+func (e *envOnce) init() {
+ for _, n := range e.names {
+ e.val = os.Getenv(n)
+ if e.val != "" {
+ return
+ }
}
+}
+
+// reset is used by tests
+func (e *envOnce) reset() {
+ e.once = sync.Once{}
+ e.val = ""
+}
+
+func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+ cm.targetScheme = treq.URL.Scheme
+ cm.targetAddr = canonicalAddr(treq.URL)
if t.Proxy != nil {
- var err error
cm.proxyURL, err = t.Proxy(treq.Request)
- if err != nil {
- return nil, err
- }
}
return cm, nil
}
@@ -316,7 +359,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
}
}
if t.idleConn == nil {
- t.idleConn = make(map[string][]*persistConn)
+ t.idleConn = make(map[connectMethodKey][]*persistConn)
}
if len(t.idleConn[key]) >= max {
t.idleMu.Unlock()
@@ -336,7 +379,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
// getIdleConnCh returns a channel to receive and return idle
// persistent connection for the given connectMethod.
// It may return nil, if persistent connections are not being used.
-func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
+func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
if t.DisableKeepAlives {
return nil
}
@@ -344,7 +387,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
t.idleMu.Lock()
defer t.idleMu.Unlock()
if t.idleConnCh == nil {
- t.idleConnCh = make(map[string]chan *persistConn)
+ t.idleConnCh = make(map[connectMethodKey]chan *persistConn)
}
ch, ok := t.idleConnCh[key]
if !ok {
@@ -354,7 +397,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
return ch
}
-func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
+func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
key := cm.key()
t.idleMu.Lock()
defer t.idleMu.Unlock()
@@ -373,7 +416,7 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
// 2 or more cached connections; pop last
// TODO: queue?
pconn = pconns[len(pconns)-1]
- t.idleConn[key] = pconns[0 : len(pconns)-1]
+ t.idleConn[key] = pconns[:len(pconns)-1]
}
if !pconn.isBroken() {
return
@@ -381,16 +424,16 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
}
}
-func (t *Transport) setReqConn(r *Request, pc *persistConn) {
+func (t *Transport) setReqCanceler(r *Request, fn func()) {
t.reqMu.Lock()
defer t.reqMu.Unlock()
- if t.reqConn == nil {
- t.reqConn = make(map[*Request]*persistConn)
+ if t.reqCanceler == nil {
+ t.reqCanceler = make(map[*Request]func())
}
- if pc != nil {
- t.reqConn[r] = pc
+ if fn != nil {
+ t.reqCanceler[r] = fn
} else {
- delete(t.reqConn, r)
+ delete(t.reqCanceler, r)
}
}
@@ -405,7 +448,7 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
// specified in the connectMethod. This includes doing a proxy CONNECT
// and/or setting up TLS. If this doesn't return an error, the persistConn
// is ready to write requests to.
-func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
if pc := t.getIdleConn(cm); pc != nil {
return pc, nil
}
@@ -415,6 +458,16 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
err error
}
dialc := make(chan dialRes)
+
+ handlePendingDial := func() {
+ if v := <-dialc; v.err == nil {
+ t.putIdleConn(v.pc)
+ }
+ }
+
+ cancelc := make(chan struct{})
+ t.setReqCanceler(req, func() { close(cancelc) })
+
go func() {
pc, err := t.dialConn(cm)
dialc <- dialRes{pc, err}
@@ -431,16 +484,15 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
// else's dial that they didn't use.
// But our dial is still going, so give it away
// when it finishes:
- go func() {
- if v := <-dialc; v.err == nil {
- t.putIdleConn(v.pc)
- }
- }()
+ go handlePendingDial()
return pc, nil
+ case <-cancelc:
+ go handlePendingDial()
+ return nil, errors.New("net/http: request canceled while waiting for connection")
}
}
-func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
conn, err := t.dial("tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
@@ -452,12 +504,13 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
pa := cm.proxyAuth()
pconn := &persistConn{
- t: t,
- cacheKey: cm.key(),
- conn: conn,
- reqch: make(chan requestAndChan, 50),
- writech: make(chan writeRequest, 50),
- closech: make(chan struct{}),
+ t: t,
+ cacheKey: cm.key(),
+ conn: conn,
+ reqch: make(chan requestAndChan, 1),
+ writech: make(chan writeRequest, 1),
+ closech: make(chan struct{}),
+ writeErrCh: make(chan error, 1),
}
switch {
@@ -511,19 +564,38 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
cfg = &clone
}
}
- conn = tls.Client(conn, cfg)
- if err = conn.(*tls.Conn).Handshake(); err != nil {
+ plainConn := conn
+ tlsConn := tls.Client(plainConn, cfg)
+ errc := make(chan error, 2)
+ var timer *time.Timer // for canceling TLS handshake
+ if d := t.TLSHandshakeTimeout; d != 0 {
+ timer = time.AfterFunc(d, func() {
+ errc <- tlsHandshakeTimeoutError{}
+ })
+ }
+ go func() {
+ err := tlsConn.Handshake()
+ if timer != nil {
+ timer.Stop()
+ }
+ errc <- err
+ }()
+ if err := <-errc; err != nil {
+ plainConn.Close()
return nil, err
}
if !cfg.InsecureSkipVerify {
- if err = conn.(*tls.Conn).VerifyHostname(cfg.ServerName); err != nil {
+ if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+ plainConn.Close()
return nil, err
}
}
- pconn.conn = conn
+ cs := tlsConn.ConnectionState()
+ pconn.tlsState = &cs
+ pconn.conn = tlsConn
}
- pconn.br = bufio.NewReader(pconn.conn)
+ pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
pconn.bw = bufio.NewWriter(pconn.conn)
go pconn.readLoop()
go pconn.writeLoop()
@@ -550,7 +622,7 @@ func useProxy(addr string) bool {
}
}
- no_proxy := getenvEitherCase("NO_PROXY")
+ no_proxy := noProxyEnv.Get()
if no_proxy == "*" {
return false
}
@@ -590,8 +662,8 @@ func useProxy(addr string) bool {
//
// Cache key form Description
// ----------------- -------------------------
-// ||http|foo.com http directly to server, no proxy
-// ||https|foo.com https directly to server, no proxy
+// |http|foo.com http directly to server, no proxy
+// |https|foo.com https directly to server, no proxy
// http://proxy.com|https|foo.com http to proxy, then CONNECT to foo.com
// http://proxy.com|http http to proxy, http to anywhere after that
//
@@ -603,20 +675,20 @@ type connectMethod struct {
targetAddr string // Not used if proxy + http targetScheme (4th example in table)
}
-func (ck *connectMethod) key() string {
- return ck.String() // TODO: use a struct type instead
-}
-
-func (ck *connectMethod) String() string {
+func (cm *connectMethod) key() connectMethodKey {
proxyStr := ""
- targetAddr := ck.targetAddr
- if ck.proxyURL != nil {
- proxyStr = ck.proxyURL.String()
- if ck.targetScheme == "http" {
+ targetAddr := cm.targetAddr
+ if cm.proxyURL != nil {
+ proxyStr = cm.proxyURL.String()
+ if cm.targetScheme == "http" {
targetAddr = ""
}
}
- return strings.Join([]string{proxyStr, ck.targetScheme, targetAddr}, "|")
+ return connectMethodKey{
+ proxy: proxyStr,
+ scheme: cm.targetScheme,
+ addr: targetAddr,
+ }
}
// addr returns the first hop "host:port" to which we need to TCP connect.
@@ -637,22 +709,41 @@ func (cm *connectMethod) tlsHost() string {
return h
}
+// connectMethodKey is the map key version of connectMethod, with a
+// stringified proxy URL (or the empty string) instead of a pointer to
+// a URL.
+type connectMethodKey struct {
+ proxy, scheme, addr string
+}
+
+func (k connectMethodKey) String() string {
+ // Only used by tests.
+ return fmt.Sprintf("%s|%s|%s", k.proxy, k.scheme, k.addr)
+}
+
// persistConn wraps a connection, usually a persistent one
// (but may be used for non-keep-alive requests as well)
type persistConn struct {
t *Transport
- cacheKey string // its connectMethod.String()
+ cacheKey connectMethodKey
conn net.Conn
- closed bool // whether conn has been closed
+ tlsState *tls.ConnectionState
br *bufio.Reader // from conn
+ sawEOF bool // whether we've seen EOF from conn; owned by readLoop
bw *bufio.Writer // to conn
reqch chan requestAndChan // written by roundTrip; read by readLoop
writech chan writeRequest // written by roundTrip; read by writeLoop
- closech chan struct{} // broadcast close when readLoop (TCP connection) closes
+ closech chan struct{} // closed when conn closed
isProxy bool
+ // writeErrCh passes the request write error (usually nil)
+ // from the writeLoop goroutine to the readLoop which passes
+ // it off to the res.Body reader, which then uses it to decide
+ // whether or not a connection can be reused. Issue 7569.
+ writeErrCh chan error
- lk sync.Mutex // guards following 3 fields
+ lk sync.Mutex // guards following fields
numExpectedResponses int
+ closed bool // whether conn has been closed
broken bool // an error has happened on this connection; marked broken so it's not reused.
// mutateHeaderFunc is an optional func to modify extra
// headers on each outbound request before it's written. (the
@@ -660,6 +751,7 @@ type persistConn struct {
mutateHeaderFunc func(Header)
}
+// isBroken reports whether this connection is in a known broken state.
func (pc *persistConn) isBroken() bool {
pc.lk.Lock()
b := pc.broken
@@ -667,6 +759,10 @@ func (pc *persistConn) isBroken() bool {
return b
}
+func (pc *persistConn) cancelRequest() {
+ pc.conn.Close()
+}
+
var remoteSideClosedFunc func(error) bool // or nil to use default
func remoteSideClosed(err error) bool {
@@ -680,7 +776,6 @@ func remoteSideClosed(err error) bool {
}
func (pc *persistConn) readLoop() {
- defer close(pc.closech)
alive := true
for alive {
@@ -688,12 +783,14 @@ func (pc *persistConn) readLoop() {
pc.lk.Lock()
if pc.numExpectedResponses == 0 {
- pc.closeLocked()
- pc.lk.Unlock()
- if len(pb) > 0 {
- log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
- string(pb), err)
+ if !pc.closed {
+ pc.closeLocked()
+ if len(pb) > 0 {
+ log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
+ string(pb), err)
+ }
}
+ pc.lk.Unlock()
return
}
pc.lk.Unlock()
@@ -712,6 +809,11 @@ func (pc *persistConn) readLoop() {
resp, err = ReadResponse(pc.br, rc.req)
}
}
+
+ if resp != nil {
+ resp.TLS = pc.tlsState
+ }
+
hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
if err != nil {
@@ -721,13 +823,7 @@ func (pc *persistConn) readLoop() {
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
resp.ContentLength = -1
- gzReader, zerr := gzip.NewReader(resp.Body)
- if zerr != nil {
- pc.close()
- err = zerr
- } else {
- resp.Body = &readerAndCloser{gzReader, resp.Body}
- }
+ resp.Body = &gzipReader{body: resp.Body}
}
resp.Body = &bodyEOFSignal{body: resp.Body}
}
@@ -750,24 +846,18 @@ func (pc *persistConn) readLoop() {
return nil
}
resp.Body.(*bodyEOFSignal).fn = func(err error) {
- alive1 := alive
- if err != nil {
- alive1 = false
- }
- if alive1 && !pc.t.putIdleConn(pc) {
- alive1 = false
- }
- if !alive1 || pc.isBroken() {
- pc.close()
- }
- waitForBodyRead <- alive1
+ waitForBodyRead <- alive &&
+ err == nil &&
+ !pc.sawEOF &&
+ pc.wroteRequest() &&
+ pc.t.putIdleConn(pc)
}
}
if alive && !hasBody {
- if !pc.t.putIdleConn(pc) {
- alive = false
- }
+ alive = !pc.sawEOF &&
+ pc.wroteRequest() &&
+ pc.t.putIdleConn(pc)
}
rc.ch <- responseAndError{resp, err}
@@ -775,10 +865,14 @@ func (pc *persistConn) readLoop() {
// Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader.
if waitForBodyRead != nil {
- alive = <-waitForBodyRead
+ select {
+ case alive = <-waitForBodyRead:
+ case <-pc.closech:
+ alive = false
+ }
}
- pc.t.setReqConn(rc.req, nil)
+ pc.t.setReqCanceler(rc.req, nil)
if !alive {
pc.close()
@@ -800,14 +894,44 @@ func (pc *persistConn) writeLoop() {
}
if err != nil {
pc.markBroken()
+ wr.req.Request.closeBody()
}
- wr.ch <- err
+ pc.writeErrCh <- err // to the body reader, which might recycle us
+ wr.ch <- err // to the roundTrip function
case <-pc.closech:
return
}
}
}
+// wroteRequest is a check before recycling a connection that the previous write
+// (from writeLoop above) happened and was successful.
+func (pc *persistConn) wroteRequest() bool {
+ select {
+ case err := <-pc.writeErrCh:
+ // Common case: the write happened well before the response, so
+ // avoid creating a timer.
+ return err == nil
+ default:
+ // Rare case: the request was written in writeLoop above but
+ // before it could send to pc.writeErrCh, the reader read it
+ // all, processed it, and called us here. In this case, give the
+ // write goroutine a bit of time to finish its send.
+ //
+ // Less rare case: We also get here in the legitimate case of
+ // Issue 7569, where the writer is still writing (or stalled),
+ // but the server has already replied. In this case, we don't
+ // want to wait too long, and we want to return false so this
+ // connection isn't re-used.
+ select {
+ case err := <-pc.writeErrCh:
+ return err == nil
+ case <-time.After(50 * time.Millisecond):
+ return false
+ }
+ }
+}
+
type responseAndError struct {
res *Response
err error
@@ -832,8 +956,20 @@ type writeRequest struct {
ch chan<- error
}
+type httpError struct {
+ err string
+ timeout bool
+}
+
+func (e *httpError) Error() string { return e.err }
+func (e *httpError) Timeout() bool { return e.timeout }
+func (e *httpError) Temporary() bool { return true }
+
+var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
+var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+
func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
- pc.t.setReqConn(req.Request, pc)
+ pc.t.setReqCanceler(req.Request, pc.cancelRequest)
pc.lk.Lock()
pc.numExpectedResponses++
headerFn := pc.mutateHeaderFunc
@@ -902,11 +1038,11 @@ WaitResponse:
pconnDeadCh = nil // avoid spinning
failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
case <-failTicker:
- re = responseAndError{err: errors.New("net/http: transport closed before response was received")}
+ re = responseAndError{err: errClosed}
break WaitResponse
case <-respHeaderTimer:
pc.close()
- re = responseAndError{err: errors.New("net/http: timeout awaiting response headers")}
+ re = responseAndError{err: errTimeout}
break WaitResponse
case re = <-resc:
break WaitResponse
@@ -918,7 +1054,7 @@ WaitResponse:
pc.lk.Unlock()
if re.err != nil {
- pc.t.setReqConn(req.Request, nil)
+ pc.t.setReqCanceler(req.Request, nil)
}
return re.res, re.err
}
@@ -943,6 +1079,7 @@ func (pc *persistConn) closeLocked() {
if !pc.closed {
pc.conn.Close()
pc.closed = true
+ close(pc.closech)
}
pc.mutateHeaderFunc = nil
}
@@ -1025,7 +1162,47 @@ func (es *bodyEOFSignal) condfn(err error) {
es.fn = nil
}
+// gzipReader wraps a response body so it can lazily
+// call gzip.NewReader on the first call to Read
+type gzipReader struct {
+ body io.ReadCloser // underlying Response.Body
+ zr io.Reader // lazily-initialized gzip reader
+}
+
+func (gz *gzipReader) Read(p []byte) (n int, err error) {
+ if gz.zr == nil {
+ gz.zr, err = gzip.NewReader(gz.body)
+ if err != nil {
+ return 0, err
+ }
+ }
+ return gz.zr.Read(p)
+}
+
+func (gz *gzipReader) Close() error {
+ return gz.body.Close()
+}
+
type readerAndCloser struct {
io.Reader
io.Closer
}
+
+type tlsHandshakeTimeoutError struct{}
+
+func (tlsHandshakeTimeoutError) Timeout() bool { return true }
+func (tlsHandshakeTimeoutError) Temporary() bool { return true }
+func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
+
+type noteEOFReader struct {
+ r io.Reader
+ sawEOF *bool
+}
+
+func (nr noteEOFReader) Read(p []byte) (n int, err error) {
+ n, err = nr.r.Read(p)
+ if err == io.EOF {
+ *nr.sawEOF = true
+ }
+ return
+}
diff --git a/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index e4df30a98..964ca0fca 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -11,9 +11,12 @@ import (
"bytes"
"compress/gzip"
"crypto/rand"
+ "crypto/tls"
+ "errors"
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
"net/http"
. "net/http"
@@ -54,21 +57,21 @@ func (c *testCloseConn) Close() error {
// been closed.
type testConnSet struct {
t *testing.T
+ mu sync.Mutex // guards closed and list
closed map[net.Conn]bool
list []net.Conn // in order created
- mutex sync.Mutex
}
func (tcs *testConnSet) insert(c net.Conn) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
tcs.closed[c] = false
tcs.list = append(tcs.list, c)
}
func (tcs *testConnSet) remove(c net.Conn) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
tcs.closed[c] = true
}
@@ -91,11 +94,19 @@ func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, e
}
func (tcs *testConnSet) check(t *testing.T) {
- tcs.mutex.Lock()
- defer tcs.mutex.Unlock()
-
- for i, c := range tcs.list {
- if !tcs.closed[c] {
+ tcs.mu.Lock()
+ defer tcs.mu.Unlock()
+ for i := 4; i >= 0; i-- {
+ for i, c := range tcs.list {
+ if tcs.closed[c] {
+ continue
+ }
+ if i != 0 {
+ tcs.mu.Unlock()
+ time.Sleep(50 * time.Millisecond)
+ tcs.mu.Lock()
+ continue
+ }
t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list))
}
}
@@ -271,6 +282,58 @@ func TestTransportIdleCacheKeys(t *testing.T) {
}
}
+// Tests that the HTTP transport re-uses connections when a client
+// reads to the end of a response Body without closing it.
+func TestTransportReadToEndReusesConn(t *testing.T) {
+ defer afterTest(t)
+ const msg = "foobar"
+
+ var addrSeen map[string]int
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ addrSeen[r.RemoteAddr]++
+ if r.URL.Path == "/chunked/" {
+ w.WriteHeader(200)
+ w.(http.Flusher).Flush()
+ } else {
+ w.Header().Set("Content-Type", strconv.Itoa(len(msg)))
+ w.WriteHeader(200)
+ }
+ w.Write([]byte(msg))
+ }))
+ defer ts.Close()
+
+ buf := make([]byte, len(msg))
+
+ for pi, path := range []string{"/content-length/", "/chunked/"} {
+ wantLen := []int{len(msg), -1}[pi]
+ addrSeen = make(map[string]int)
+ for i := 0; i < 3; i++ {
+ res, err := http.Get(ts.URL + path)
+ if err != nil {
+ t.Errorf("Get %s: %v", path, err)
+ continue
+ }
+ // We want to close this body eventually (before the
+ // defer afterTest at top runs), but not before the
+ // len(addrSeen) check at the bottom of this test,
+ // since Closing this early in the loop would risk
+ // making connections be re-used for the wrong reason.
+ defer res.Body.Close()
+
+ if res.ContentLength != int64(wantLen) {
+ t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen)
+ }
+ n, err := res.Body.Read(buf)
+ if n != len(msg) || err != io.EOF {
+ t.Errorf("%s Read = %v, %v; want %d, EOF", path, n, err, len(msg))
+ }
+ }
+ if len(addrSeen) != 1 {
+ t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen))
+ }
+ }
+}
+
func TestTransportMaxPerHostIdleConns(t *testing.T) {
defer afterTest(t)
resch := make(chan string)
@@ -295,10 +358,11 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
resp, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
+ return
}
- _, err = ioutil.ReadAll(resp.Body)
- if err != nil {
- t.Fatalf("ReadAll: %v", err)
+ if _, err := ioutil.ReadAll(resp.Body); err != nil {
+ t.Errorf("ReadAll: %v", err)
+ return
}
donech <- true
}
@@ -739,8 +803,38 @@ func TestTransportGzipRecursive(t *testing.T) {
}
}
+// golang.org/issue/7750: request fails when server replies with
+// a short gzip body
+func TestTransportGzipShort(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Encoding", "gzip")
+ w.Write([]byte{0x1f, 0x8b})
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ _, err = ioutil.ReadAll(res.Body)
+ if err == nil {
+ t.Fatal("Expect an error from reading a body.")
+ }
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err)
+ }
+}
+
// tests that persistent goroutine connections shut down when no longer desired.
func TestTransportPersistConnLeak(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
gotReqCh := make(chan bool)
unblockCh := make(chan bool)
@@ -798,8 +892,8 @@ func TestTransportPersistConnLeak(t *testing.T) {
// We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
// Previously we were leaking one per numReq.
- t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
if int(growth) > 5 {
+ t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
t.Error("too many new goroutines")
}
}
@@ -807,6 +901,9 @@ func TestTransportPersistConnLeak(t *testing.T) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
@@ -1014,6 +1111,9 @@ func TestTransportConcurrency(t *testing.T) {
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1075,6 +1175,9 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7237")
+ }
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1147,9 +1250,13 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
if testing.Short() {
t.Skip("skipping timeout test in -short mode")
}
+ inHandler := make(chan bool, 1)
mux := NewServeMux()
- mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {})
+ mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {
+ inHandler <- true
+ })
mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) {
+ inHandler <- true
time.Sleep(2 * time.Second)
})
ts := httptest.NewServer(mux)
@@ -1172,7 +1279,27 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
}
for i, tt := range tests {
res, err := c.Get(ts.URL + tt.path)
+ select {
+ case <-inHandler:
+ case <-time.After(5 * time.Second):
+ t.Errorf("never entered handler for test index %d, %s", i, tt.path)
+ continue
+ }
if err != nil {
+ uerr, ok := err.(*url.Error)
+ if !ok {
+ t.Errorf("error is not an url.Error; got: %#v", err)
+ continue
+ }
+ nerr, ok := uerr.Err.(net.Error)
+ if !ok {
+ t.Errorf("error does not satisfy net.Error interface; got: %#v", err)
+ continue
+ }
+ if !nerr.Timeout() {
+ t.Errorf("want timeout error; got: %q", nerr)
+ continue
+ }
if strings.Contains(err.Error(), tt.wantErr) {
continue
}
@@ -1243,6 +1370,60 @@ func TestTransportCancelRequest(t *testing.T) {
}
}
+func TestTransportCancelRequestInDial(t *testing.T) {
+ defer afterTest(t)
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+ var logbuf bytes.Buffer
+ eventLog := log.New(&logbuf, "", 0)
+
+ unblockDial := make(chan bool)
+ defer close(unblockDial)
+
+ inDial := make(chan bool)
+ tr := &Transport{
+ Dial: func(network, addr string) (net.Conn, error) {
+ eventLog.Println("dial: blocking")
+ inDial <- true
+ <-unblockDial
+ return nil, errors.New("nope")
+ },
+ }
+ cl := &Client{Transport: tr}
+ gotres := make(chan bool)
+ req, _ := NewRequest("GET", "http://something.no-network.tld/", nil)
+ go func() {
+ _, err := cl.Do(req)
+ eventLog.Printf("Get = %v", err)
+ gotres <- true
+ }()
+
+ select {
+ case <-inDial:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout; never saw blocking dial")
+ }
+
+ eventLog.Printf("canceling")
+ tr.CancelRequest(req)
+
+ select {
+ case <-gotres:
+ case <-time.After(5 * time.Second):
+ panic("hang. events are: " + logbuf.String())
+ }
+
+ got := logbuf.String()
+ want := `dial: blocking
+canceling
+Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection
+`
+ if got != want {
+ t.Errorf("Got events:\n%s\nWant:\n%s", got, want)
+ }
+}
+
// golang.org/issue/3672 -- Client can't close HTTP stream
// Calling Close on a Response.Body used to just read until EOF.
// Now it actually closes the TCP connection.
@@ -1283,7 +1464,7 @@ func TestTransportCloseResponseBody(t *testing.T) {
t.Fatal(err)
}
if !bytes.Equal(buf, want) {
- t.Errorf("read %q; want %q", buf, want)
+ t.Fatalf("read %q; want %q", buf, want)
}
didClose := make(chan error, 1)
go func() {
@@ -1372,8 +1553,10 @@ func TestTransportSocketLateBinding(t *testing.T) {
dialGate := make(chan bool, 1)
tr := &Transport{
Dial: func(n, addr string) (net.Conn, error) {
- <-dialGate
- return net.Dial(n, addr)
+ if <-dialGate {
+ return net.Dial(n, addr)
+ }
+ return nil, errors.New("manually closed")
},
DisableKeepAlives: false,
}
@@ -1408,7 +1591,7 @@ func TestTransportSocketLateBinding(t *testing.T) {
t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
}
barRes.Body.Close()
- dialGate <- true
+ dialGate <- false
}
// Issue 2184
@@ -1559,13 +1742,11 @@ var proxyFromEnvTests = []proxyFromEnvTest{
}
func TestProxyFromEnvironment(t *testing.T) {
- os.Setenv("HTTP_PROXY", "")
- os.Setenv("http_proxy", "")
- os.Setenv("NO_PROXY", "")
- os.Setenv("no_proxy", "")
+ ResetProxyEnv()
for _, tt := range proxyFromEnvTests {
os.Setenv("HTTP_PROXY", tt.env)
os.Setenv("NO_PROXY", tt.noenv)
+ ResetCachedEnvironment()
reqURL := tt.req
if reqURL == "" {
reqURL = "http://example.com"
@@ -1643,6 +1824,308 @@ func TestTransportClosesRequestBody(t *testing.T) {
}
}
+func TestTransportTLSHandshakeTimeout(t *testing.T) {
+ defer afterTest(t)
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ ln := newLocalListener(t)
+ defer ln.Close()
+ testdonec := make(chan struct{})
+ defer close(testdonec)
+
+ go func() {
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ <-testdonec
+ c.Close()
+ }()
+
+ getdonec := make(chan struct{})
+ go func() {
+ defer close(getdonec)
+ tr := &Transport{
+ Dial: func(_, _ string) (net.Conn, error) {
+ return net.Dial("tcp", ln.Addr().String())
+ },
+ TLSHandshakeTimeout: 250 * time.Millisecond,
+ }
+ cl := &Client{Transport: tr}
+ _, err := cl.Get("https://dummy.tld/")
+ if err == nil {
+ t.Error("expected error")
+ return
+ }
+ ue, ok := err.(*url.Error)
+ if !ok {
+ t.Errorf("expected url.Error; got %#v", err)
+ return
+ }
+ ne, ok := ue.Err.(net.Error)
+ if !ok {
+ t.Errorf("expected net.Error; got %#v", err)
+ return
+ }
+ if !ne.Timeout() {
+ t.Errorf("expected timeout error; got %v", err)
+ }
+ if !strings.Contains(err.Error(), "handshake timeout") {
+ t.Errorf("expected 'handshake timeout' in error; got %v", err)
+ }
+ }()
+ select {
+ case <-getdonec:
+ case <-time.After(5 * time.Second):
+ t.Error("test timeout; TLS handshake hung?")
+ }
+}
+
+// Trying to repro golang.org/issue/3514
+func TestTLSServerClosesConnection(t *testing.T) {
+ defer afterTest(t)
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping flaky test on Windows; golang.org/issue/7634")
+ }
+ closedc := make(chan bool, 1)
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if strings.Contains(r.URL.Path, "/keep-alive-then-die") {
+ conn, _, _ := w.(Hijacker).Hijack()
+ conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
+ conn.Close()
+ closedc <- true
+ return
+ }
+ fmt.Fprintf(w, "hello")
+ }))
+ defer ts.Close()
+ tr := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ defer tr.CloseIdleConnections()
+ client := &Client{Transport: tr}
+
+ var nSuccess = 0
+ var errs []error
+ const trials = 20
+ for i := 0; i < trials; i++ {
+ tr.CloseIdleConnections()
+ res, err := client.Get(ts.URL + "/keep-alive-then-die")
+ if err != nil {
+ t.Fatal(err)
+ }
+ <-closedc
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != "foo" {
+ t.Errorf("Got %q, want foo", slurp)
+ }
+
+ // Now try again and see if we successfully
+ // pick a new connection.
+ res, err = client.Get(ts.URL + "/")
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ slurp, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ nSuccess++
+ }
+ if nSuccess > 0 {
+ t.Logf("successes = %d of %d", nSuccess, trials)
+ } else {
+ t.Errorf("All runs failed:")
+ }
+ for _, err := range errs {
+ t.Logf(" err: %v", err)
+ }
+}
+
+// byteFromChanReader is an io.Reader that reads a single byte at a
+// time from the channel. When the channel is closed, the reader
+// returns io.EOF.
+type byteFromChanReader chan byte
+
+func (c byteFromChanReader) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return
+ }
+ b, ok := <-c
+ if !ok {
+ return 0, io.EOF
+ }
+ p[0] = b
+ return 1, nil
+}
+
+// Verifies that the Transport doesn't reuse a connection in the case
+// where the server replies before the request has been fully
+// written. We still honor that reply (see TestIssue3595), but don't
+// send future requests on the connection because it's then in a
+// questionable state.
+// golang.org/issue/7569
+func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
+ defer afterTest(t)
+ var sconn struct {
+ sync.Mutex
+ c net.Conn
+ }
+ var getOkay bool
+ closeConn := func() {
+ sconn.Lock()
+ defer sconn.Unlock()
+ if sconn.c != nil {
+ sconn.c.Close()
+ sconn.c = nil
+ if !getOkay {
+ t.Logf("Closed server connection")
+ }
+ }
+ }
+ defer closeConn()
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method == "GET" {
+ io.WriteString(w, "bar")
+ return
+ }
+ conn, _, _ := w.(Hijacker).Hijack()
+ sconn.Lock()
+ sconn.c = conn
+ sconn.Unlock()
+ conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive
+ go io.Copy(ioutil.Discard, conn)
+ }))
+ defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ client := &Client{Transport: tr}
+
+ const bodySize = 256 << 10
+ finalBit := make(byteFromChanReader, 1)
+ req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit))
+ req.ContentLength = bodySize
+ res, err := client.Do(req)
+ if err := wantBody(res, err, "foo"); err != nil {
+ t.Errorf("POST response: %v", err)
+ }
+ donec := make(chan bool)
+ go func() {
+ defer close(donec)
+ res, err = client.Get(ts.URL)
+ if err := wantBody(res, err, "bar"); err != nil {
+ t.Errorf("GET response: %v", err)
+ return
+ }
+ getOkay = true // suppress test noise
+ }()
+ time.AfterFunc(5*time.Second, closeConn)
+ select {
+ case <-donec:
+ finalBit <- 'x' // unblock the writeloop of the first Post
+ close(finalBit)
+ case <-time.After(7 * time.Second):
+ t.Fatal("timeout waiting for GET request to finish")
+ }
+}
+
+type errorReader struct {
+ err error
+}
+
+func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
+
+type closerFunc func() error
+
+func (f closerFunc) Close() error { return f() }
+
+// Issue 6981
+func TestTransportClosesBodyOnError(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping test; see http://golang.org/issue/7782")
+ }
+ defer afterTest(t)
+ readBody := make(chan error, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ _, err := ioutil.ReadAll(r.Body)
+ readBody <- err
+ }))
+ defer ts.Close()
+ fakeErr := errors.New("fake error")
+ didClose := make(chan bool, 1)
+ req, _ := NewRequest("POST", ts.URL, struct {
+ io.Reader
+ io.Closer
+ }{
+ io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
+ closerFunc(func() error {
+ select {
+ case didClose <- true:
+ default:
+ }
+ return nil
+ }),
+ })
+ res, err := DefaultClient.Do(req)
+ if res != nil {
+ defer res.Body.Close()
+ }
+ if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) {
+ t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
+ }
+ select {
+ case err := <-readBody:
+ if err == nil {
+ t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'")
+ }
+ case <-time.After(5 * time.Second):
+ t.Error("timeout waiting for server handler to complete")
+ }
+ select {
+ case <-didClose:
+ default:
+ t.Errorf("didn't see Body.Close")
+ }
+}
+
+func wantBody(res *http.Response, err error, want string) error {
+ if err != nil {
+ return err
+ }
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return fmt.Errorf("error reading body: %v", err)
+ }
+ if string(slurp) != want {
+ return fmt.Errorf("body = %q; want %q", slurp, want)
+ }
+ if err := res.Body.Close(); err != nil {
+ return fmt.Errorf("body Close = %v", err)
+ }
+ return nil
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
type countCloseReader struct {
n *int
io.Reader
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index 0713e9cd6..2e9f1ebc6 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -7,11 +7,11 @@ package net
import "errors"
var (
- errInvalidInterface = errors.New("net: invalid interface")
- errInvalidInterfaceIndex = errors.New("net: invalid interface index")
- errInvalidInterfaceName = errors.New("net: invalid interface name")
- errNoSuchInterface = errors.New("net: no such interface")
- errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
+ errInvalidInterface = errors.New("invalid network interface")
+ errInvalidInterfaceIndex = errors.New("invalid network interface index")
+ errInvalidInterfaceName = errors.New("invalid network interface name")
+ errNoSuchInterface = errors.New("no such network interface")
+ errNoSuchMulticastInterface = errors.New("no such multicast network interface")
)
// Interface represents a mapping between network interface name
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 1207c0f26..1115d0fc4 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -45,15 +45,41 @@ loop:
return ift, nil
}
+const (
+ // See linux/if_arp.h.
+ // Note that Linux doesn't support IPv4 over IPv6 tunneling.
+ sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling
+ sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling
+ sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling
+ sysARPHardwareGREIPv4 = 778 // any over GRE over IPv4 tunneling
+ sysARPHardwareGREIPv6 = 823 // any over GRE over IPv6 tunneling
+)
+
func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFLA_ADDRESS:
+ // We never return any /32 or /128 IP address
+ // prefix on any IP tunnel interface as the
+ // hardware address.
+ switch len(a.Value) {
+ case IPv4len:
+ switch ifim.Type {
+ case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
+ continue
+ }
+ case IPv6len:
+ switch ifim.Type {
+ case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
+ continue
+ }
+ }
var nonzero bool
for _, b := range a.Value {
if b != 0 {
nonzero = true
+ break
}
}
if nonzero {
@@ -147,19 +173,31 @@ loop:
}
func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
- for _, a := range attrs {
- if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL ||
- ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS {
- switch ifam.Family {
- case syscall.AF_INET:
- return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
- case syscall.AF_INET6:
- ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
- copy(ifa.IP, a.Value[:])
- return ifa
+ var ipPointToPoint bool
+ // Seems like we need to make sure whether the IP interface
+ // stack consists of IP point-to-point numbered or unnumbered
+ // addressing over point-to-point link encapsulation.
+ if ifi.Flags&FlagPointToPoint != 0 {
+ for _, a := range attrs {
+ if a.Attr.Type == syscall.IFA_LOCAL {
+ ipPointToPoint = true
+ break
}
}
}
+ for _, a := range attrs {
+ if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
+ continue
+ }
+ switch ifam.Family {
+ case syscall.AF_INET:
+ return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
+ case syscall.AF_INET6:
+ ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
+ copy(ifa.IP, a.Value[:])
+ return ifa
+ }
+ }
return nil
}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index a4eb731da..c38fb7f76 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9
+// +build nacl plan9 solaris
package net
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
index fd6a7d4ee..0582009b8 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -623,6 +623,9 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
for k := ellipsis + n - 1; k >= ellipsis; k-- {
ip[k] = 0
}
+ } else if ellipsis >= 0 {
+ // Ellipsis must represent at least one 0 group.
+ return nil, zone
}
return ip, zone
}
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index 26b53729b..ffeb9d315 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/net/ip_test.go
@@ -25,6 +25,7 @@ var parseIPTests = []struct {
{"fe80::1%lo0", nil},
{"fe80::1%911", nil},
{"", nil},
+ {"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
}
func TestParseIP(t *testing.T) {
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index ea183f1d3..0632dafc6 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -247,7 +247,7 @@ var ipConnLocalNameTests = []struct {
func TestIPConnLocalName(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
default:
if os.Getuid() != 0 {
@@ -277,7 +277,7 @@ func TestIPConnRemoteName(t *testing.T) {
}
}
- raddr := &IPAddr{IP: IPv4(127, 0, 0, 10).To4()}
+ raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}
c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr)
if err != nil {
t.Fatalf("DialIP failed: %v", err)
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 722853257..bbb3f3ed6 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -19,7 +19,7 @@ import (
// that you do not uses these methods if it is important to receive a
// full packet.
//
-// The Go 1 compatibliity guidelines make it impossible for us to
+// The Go 1 compatibility guidelines make it impossible for us to
// change the behavior of these methods; use Read or ReadMsgIP
// instead.
@@ -79,7 +79,7 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
var addr *IPAddr
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
@@ -112,7 +112,7 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
return 0, 0, 0, nil, syscall.EINVAL
}
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
@@ -133,6 +133,9 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
+ if c.fd.isConnected {
+ return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+ }
if addr == nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -140,7 +143,7 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
if err != nil {
return 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -162,6 +165,9 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
if !c.ok() {
return 0, 0, syscall.EINVAL
}
+ if c.fd.isConnected {
+ return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+ }
if addr == nil {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -169,7 +175,7 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
if err != nil {
return 0, 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
// DialIP connects to the remote address raddr on the network protocol
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 8b586ef7c..dda857803 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -16,7 +16,7 @@ var (
// networking functionality.
supportsIPv4 bool
- // supportsIPv6 reports whether the platfrom supports IPv6
+ // supportsIPv6 reports whether the platform supports IPv6
// networking functionality.
supportsIPv6 bool
@@ -207,7 +207,7 @@ missingBrackets:
}
func splitHostZone(s string) (host, zone string) {
- // The IPv6 scoped addressing zone identifer starts after the
+ // The IPv6 scoped addressing zone identifier starts after the
// last percent sign.
if i := last(s, '%'); i > 0 {
host, zone = s[:i], s[i+1:]
@@ -232,7 +232,7 @@ func JoinHostPort(host, port string) string {
// address or a DNS name and returns an internet protocol family
// address. It returns a list that contains a pair of different
// address family addresses when addr is a DNS name and the name has
-// mutiple address family records. The result contains at least one
+// multiple address family records. The result contains at least one
// address when error is nil.
func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
var (
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index fcec4164f..94ceea31b 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -12,19 +12,45 @@ import (
"syscall"
)
+func probe(filename, query string) bool {
+ var file *file
+ var err error
+ if file, err = open(filename); err != nil {
+ return false
+ }
+
+ r := false
+ for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
+ f := getFields(line)
+ if len(f) < 3 {
+ continue
+ }
+ for i := 0; i < len(f); i++ {
+ if query == f[i] {
+ r = true
+ break
+ }
+ }
+ }
+ file.close()
+ return r
+}
+
func probeIPv4Stack() bool {
- // TODO(mikio): implement this when Plan 9 supports IPv6-only
- // kernel.
- return true
+ return probe(netdir+"/iproute", "4i")
}
// probeIPv6Stack returns two boolean values. If the first boolean
// value is true, kernel supports basic IPv6 functionality. If the
// second boolean value is true, kernel supports IPv6 IPv4-mapping.
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
- // TODO(mikio): implement this once Plan 9 gets an IPv6
- // protocol stack implementation.
- return false, false
+ // Plan 9 uses IPv6 natively, see ip(3).
+ r := probe(netdir+"/iproute", "6i")
+ v := false
+ if r {
+ v = probe(netdir+"/iproute", "4i")
+ }
+ return r, v
}
// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
@@ -34,12 +60,12 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
if i >= 0 {
addr = ParseIP(s[:i])
if addr == nil {
- return nil, 0, errors.New("net: parsing IP failed")
+ return nil, 0, errors.New("parsing IP failed")
}
}
p, _, ok := dtoi(s[i+1:], 0)
if !ok {
- return nil, 0, errors.New("net: parsing port failed")
+ return nil, 0, errors.New("parsing port failed")
}
if p < 0 || p > 0xFFFF {
return nil, 0, &AddrError{"invalid port", string(p)}
@@ -133,18 +159,18 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
f.Close()
return nil, &OpError{"dial", f.Name(), raddr, err}
}
- data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0)
+ data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
f.Close()
return nil, &OpError{"dial", net, raddr, err}
}
- laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
data.Close()
f.Close()
return nil, &OpError{"dial", proto, raddr, err}
}
- return newFD(proto, name, f, data, laddr, raddr), nil
+ return newFD(proto, name, f, data, laddr, raddr)
}
func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
@@ -158,20 +184,24 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
f.Close()
return nil, &OpError{"announce", proto, laddr, err}
}
- laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
if err != nil {
f.Close()
return nil, &OpError{Op: "listen", Net: net, Err: err}
}
- return newFD(proto, name, f, nil, laddr, nil), nil
+ return newFD(proto, name, f, nil, laddr, nil)
}
-func (l *netFD) netFD() *netFD {
- return newFD(l.proto, l.name, l.ctl, l.data, l.laddr, l.raddr)
+func (l *netFD) netFD() (*netFD, error) {
+ return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
}
func (l *netFD) acceptPlan9() (fd *netFD, err error) {
defer func() { netErr(err) }()
+ if err := l.readLock(); err != nil {
+ return nil, err
+ }
+ defer l.readUnlock()
f, err := os.Open(l.dir + "/listen")
if err != nil {
return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
@@ -183,16 +213,16 @@ func (l *netFD) acceptPlan9() (fd *netFD, err error) {
return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
}
name := string(buf[:n])
- data, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
+ data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
f.Close()
return nil, &OpError{"accept", l.proto, l.laddr, err}
}
- raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
+ raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
if err != nil {
data.Close()
f.Close()
return nil, &OpError{"accept", l.proto, l.laddr, err}
}
- return newFD(l.proto, name, f, data, l.laddr, raddr), nil
+ return newFD(l.proto, name, f, data, l.laddr, raddr)
}
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index a83e52561..2ba4c8efd 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/net/ipsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
// Internet protocol family sockets for POSIX
@@ -40,12 +40,13 @@ func probeIPv4Stack() bool {
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
var probes = []struct {
laddr TCPAddr
+ value int
ok bool
}{
// IPv6 communication capability
- {TCPAddr{IP: ParseIP("::1")}, false},
+ {laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
// IPv6 IPv4-mapped address communication capability
- {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+ {laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
}
for i := range probes {
@@ -54,7 +55,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
continue
}
defer closesocket(s)
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
if err != nil {
continue
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index f1204a99f..b80ac10e0 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -16,6 +16,10 @@ func query(filename, query string, bufSize int) (res []string, err error) {
}
defer file.Close()
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ return
+ }
_, err = file.WriteString(query)
if err != nil {
return
@@ -45,7 +49,7 @@ func queryCS(net, host, service string) (res []string, err error) {
if host == "" {
host = "*"
}
- return query("/net/cs", net+"!"+host+"!"+service, 128)
+ return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
}
func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
@@ -59,20 +63,41 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
}
f := getFields(lines[0])
if len(f) < 2 {
- return "", "", errors.New("net: bad response from ndb/cs")
+ return "", "", errors.New("bad response from ndb/cs")
}
clone, dest = f[0], f[1]
return
}
func queryDNS(addr string, typ string) (res []string, err error) {
- return query("/net/dns", addr+" "+typ, 1024)
+ return query(netdir+"/dns", addr+" "+typ, 1024)
+}
+
+// toLower returns a lower-case version of in. Restricting us to
+// ASCII is sufficient to handle the IP protocol names and allow
+// us to not depend on the strings and unicode packages.
+func toLower(in string) string {
+ for _, c := range in {
+ if 'A' <= c && c <= 'Z' {
+ // Has upper case; need to fix.
+ out := []byte(in)
+ for i := 0; i < len(in); i++ {
+ c := in[i]
+ if 'A' <= c && c <= 'Z' {
+ c += 'a' - 'A'
+ }
+ out[i] = c
+ }
+ return string(out)
+ }
+ }
+ return in
}
// lookupProtocol looks up IP protocol name and returns
// the corresponding protocol number.
func lookupProtocol(name string) (proto int, err error) {
- lines, err := query("/net/cs", "!protocol="+name, 128)
+ lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
if err != nil {
return 0, err
}
@@ -92,12 +117,13 @@ func lookupProtocol(name string) (proto int, err error) {
}
func lookupHost(host string) (addrs []string, err error) {
- // Use /net/cs instead of /net/dns because cs knows about
+ // Use netdir/cs instead of netdir/dns because cs knows about
// host names in local network (e.g. from /lib/ndb/local)
- lines, err := queryCS("tcp", host, "1")
+ lines, err := queryCS("net", host, "1")
if err != nil {
return
}
+loop:
for _, line := range lines {
f := getFields(line)
if len(f) < 2 {
@@ -110,6 +136,12 @@ func lookupHost(host string) (addrs []string, err error) {
if ParseIP(addr) == nil {
continue
}
+ // only return unique addresses
+ for _, a := range addrs {
+ if a == addr {
+ continue loop
+ }
+ }
addrs = append(addrs, addr)
}
return
@@ -167,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) {
return f[2] + ".", nil
}
}
- return "", errors.New("net: bad response from ndb/dns")
+ return "", errors.New("bad response from ndb/dns")
}
func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index 59e9f6321..b1d2f8f31 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/net/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package net
diff --git a/src/pkg/net/mail/message.go b/src/pkg/net/mail/message.go
index dc2ab44da..ba0778caa 100644
--- a/src/pkg/net/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -159,7 +159,9 @@ func (a *Address) String() string {
// If every character is printable ASCII, quoting is simple.
allPrintable := true
for i := 0; i < len(a.Name); i++ {
- if !isVchar(a.Name[i]) {
+ // isWSP here should actually be isFWS,
+ // but we don't support folding yet.
+ if !isVchar(a.Name[i]) && !isWSP(a.Name[i]) {
allPrintable = false
break
}
@@ -167,7 +169,7 @@ func (a *Address) String() string {
if allPrintable {
b := bytes.NewBufferString(`"`)
for i := 0; i < len(a.Name); i++ {
- if !isQtext(a.Name[i]) {
+ if !isQtext(a.Name[i]) && !isWSP(a.Name[i]) {
b.WriteByte('\\')
}
b.WriteByte(a.Name[i])
@@ -361,7 +363,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
// Ignore any error if we got at least one word.
if err != nil && len(words) == 0 {
debug.Printf("consumePhrase: hit err: %v", err)
- return "", errors.New("mail: missing word in phrase")
+ return "", fmt.Errorf("mail: missing word in phrase: %v", err)
}
phrase = strings.Join(words, " ")
return phrase, nil
@@ -440,11 +442,11 @@ func (p *addrParser) len() int {
func decodeRFC2047Word(s string) (string, error) {
fields := strings.Split(s, "?")
if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
- return "", errors.New("mail: address not RFC 2047 encoded")
+ return "", errors.New("address not RFC 2047 encoded")
}
charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
if charset != "iso-8859-1" && charset != "utf-8" {
- return "", fmt.Errorf("mail: charset not supported: %q", charset)
+ return "", fmt.Errorf("charset not supported: %q", charset)
}
in := bytes.NewBufferString(fields[3])
@@ -455,7 +457,7 @@ func decodeRFC2047Word(s string) (string, error) {
case "q":
r = qDecoder{r: in}
default:
- return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
}
dec, err := ioutil.ReadAll(r)
@@ -535,3 +537,9 @@ func isVchar(c byte) bool {
// Visible (printing) characters.
return '!' <= c && c <= '~'
}
+
+// isWSP returns true if c is a WSP (white space).
+// WSP is a space or horizontal tab (RFC5234 Appendix B).
+func isWSP(c byte) bool {
+ return c == ' ' || c == '\t'
+}
diff --git a/src/pkg/net/mail/message_test.go b/src/pkg/net/mail/message_test.go
index 3c037f383..eb9c8cbdc 100644
--- a/src/pkg/net/mail/message_test.go
+++ b/src/pkg/net/mail/message_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io/ioutil"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -116,6 +117,14 @@ func TestDateParsing(t *testing.T) {
}
}
+func TestAddressParsingError(t *testing.T) {
+ const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>"
+ _, err := ParseAddress(txt)
+ if err == nil || !strings.Contains(err.Error(), "charset not supported") {
+ t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err)
+ }
+}
+
func TestAddressParsing(t *testing.T) {
tests := []struct {
addrsStr string
@@ -277,6 +286,14 @@ func TestAddressFormatting(t *testing.T) {
&Address{Name: "Böb", Address: "bob@example.com"},
`=?utf-8?q?B=C3=B6b?= <bob@example.com>`,
},
+ {
+ &Address{Name: "Bob Jane", Address: "bob@example.com"},
+ `"Bob Jane" <bob@example.com>`,
+ },
+ {
+ &Address{Name: "Böb Jacöb", Address: "bob@example.com"},
+ `=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= <bob@example.com>`,
+ },
}
for _, test := range tests {
s := test.addr.String()
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 5660fd42f..63dbce88e 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -25,8 +25,10 @@ var ipv4MulticastListenerTests = []struct {
// port.
func TestIPv4MulticastListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ case "nacl", "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
+ case "solaris":
+ t.Skipf("skipping test on solaris, see issue 7399")
}
closer := func(cs []*UDPConn) {
@@ -93,8 +95,10 @@ var ipv6MulticastListenerTests = []struct {
// port.
func TestIPv6MulticastListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "solaris":
+ case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
+ case "solaris":
+ t.Skipf("skipping test on solaris, see issue 7399")
}
if !supportsIPv6 {
t.Skip("ipv6 is not supported")
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 2e6db5551..ca56af54f 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -275,7 +275,16 @@ type Listener interface {
Addr() Addr
}
-var errMissingAddress = errors.New("missing address")
+// Various errors contained in OpError.
+var (
+ // For connection setup and write operations.
+ errMissingAddress = errors.New("missing address")
+
+ // For both read and write operations.
+ errTimeout error = &timeoutError{}
+ errClosing = errors.New("use of closed network connection")
+ ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
+)
// OpError is the error type usually returned by functions in the net
// package. It describes the operation, network type, and address of
@@ -337,10 +346,6 @@ func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
-var errTimeout error = &timeoutError{}
-
-var errClosing = errors.New("use of closed network connection")
-
type AddrError struct {
Err string
Addr string
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 1320096df..bfed4d657 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -28,12 +28,14 @@ func TestShutdown(t *testing.T) {
defer ln.Close()
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
var buf [10]byte
n, err := c.Read(buf[:])
if n != 0 || err != io.EOF {
- t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+ t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+ return
}
c.Write([]byte("response"))
c.Close()
@@ -62,7 +64,7 @@ func TestShutdown(t *testing.T) {
func TestShutdownUnix(t *testing.T) {
switch runtime.GOOS {
- case "windows", "plan9":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
f, err := ioutil.TempFile("", "go_net_unixtest")
@@ -84,12 +86,14 @@ func TestShutdownUnix(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
var buf [10]byte
n, err := c.Read(buf[:])
if n != 0 || err != io.EOF {
- t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+ t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+ return
}
c.Write([]byte("response"))
c.Close()
@@ -196,7 +200,8 @@ func TestTCPClose(t *testing.T) {
go func() {
c, err := Dial("tcp", l.Addr().String())
if err != nil {
- t.Fatal(err)
+ t.Errorf("Dial: %v", err)
+ return
}
go read(c)
@@ -231,12 +236,12 @@ func TestErrorNil(t *testing.T) {
// 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)
+ t.Fatalf("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)
+ t.Fatalf("second Listen %v: %v", l.Addr(), err)
}
if l1 != nil {
t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1)
@@ -245,12 +250,12 @@ func TestErrorNil(t *testing.T) {
// 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)
+ t.Fatalf("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)
+ t.Fatalf("second Listen %v: %v", lp.LocalAddr(), err)
}
if lp1 != nil {
t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1)
diff --git a/src/pkg/net/net_windows_test.go b/src/pkg/net/net_windows_test.go
index 8b1c9cdc5..2f57745e3 100644
--- a/src/pkg/net/net_windows_test.go
+++ b/src/pkg/net/net_windows_test.go
@@ -84,7 +84,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
}
err = cmd.Start()
if err != nil {
- t.Fatalf("cmd.Start failed: %v\n%s\n", err)
+ t.Fatalf("cmd.Start failed: %v\n", err)
}
outReader := bufio.NewReader(stdout)
for {
@@ -107,7 +107,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
result := make(chan error)
go func() {
time.Sleep(alittle)
- err = send(ln.Addr().String(), "abc")
+ err := send(ln.Addr().String(), "abc")
if err != nil {
result <- err
}
diff --git a/src/pkg/net/netgo_unix_test.go b/src/pkg/net/netgo_unix_test.go
new file mode 100644
index 000000000..9fb2a567d
--- /dev/null
+++ b/src/pkg/net/netgo_unix_test.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build !cgo netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import "testing"
+
+func TestGoLookupIP(t *testing.T) {
+ host := "localhost"
+ _, err, ok := cgoLookupIP(host)
+ if ok {
+ t.Errorf("cgoLookupIP must be a placeholder")
+ }
+ if err != nil {
+ t.Errorf("cgoLookupIP failed: %v", err)
+ }
+ if _, err := goLookupIP(host); err != nil {
+ t.Errorf("goLookupIP failed: %v", err)
+ }
+}
diff --git a/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go
index 945003f67..b6e4e76f9 100644
--- a/src/pkg/net/packetconn_test.go
+++ b/src/pkg/net/packetconn_test.go
@@ -15,12 +15,6 @@ import (
"time"
)
-func strfunc(s string) func() string {
- return func() string {
- return s
- }
-}
-
func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
switch net {
case "udp":
@@ -46,7 +40,7 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
return b, nil
case "unixgram":
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
return nil, func() {
t.Logf("skipping %q test on %q", net, runtime.GOOS)
}
@@ -62,12 +56,12 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
var packetConnTests = []struct {
net string
- addr1 func() string
- addr2 func() string
+ addr1 string
+ addr2 string
}{
- {"udp", strfunc("127.0.0.1:0"), strfunc("127.0.0.1:0")},
- {"ip:icmp", strfunc("127.0.0.1"), strfunc("127.0.0.1")},
- {"unixgram", testUnixAddr, testUnixAddr},
+ {"udp", "127.0.0.1:0", "127.0.0.1:0"},
+ {"ip:icmp", "127.0.0.1", "127.0.0.1"},
+ {"unixgram", testUnixAddr(), testUnixAddr()},
}
func TestPacketConn(t *testing.T) {
@@ -88,22 +82,21 @@ func TestPacketConn(t *testing.T) {
continue
}
- addr1, addr2 := tt.addr1(), tt.addr2()
- c1, err := ListenPacket(tt.net, addr1)
+ c1, err := ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], addr1, addr2)
+ defer closer(c1, netstr[0], tt.addr1, tt.addr2)
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
- c2, err := ListenPacket(tt.net, addr2)
+ c2, err := ListenPacket(tt.net, tt.addr2)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c2, netstr[0], addr1, addr2)
+ defer closer(c2, netstr[0], tt.addr1, tt.addr2)
c2.LocalAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
@@ -145,12 +138,11 @@ func TestConnAndPacketConn(t *testing.T) {
continue
}
- addr1, addr2 := tt.addr1(), tt.addr2()
- c1, err := ListenPacket(tt.net, addr1)
+ c1, err := ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], addr1, addr2)
+ defer closer(c1, netstr[0], tt.addr1, tt.addr2)
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go
index 6056de248..ee6e7e995 100644
--- a/src/pkg/net/parse.go
+++ b/src/pkg/net/parse.go
@@ -67,7 +67,7 @@ func open(name string) (*file, error) {
if err != nil {
return nil, err
}
- return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
+ return &file{fd, make([]byte, 0, os.Getpagesize()), false}, nil
}
func byteIndex(s string, c byte) int {
diff --git a/src/pkg/net/port_unix.go b/src/pkg/net/port_unix.go
index 3cd9ca2aa..89558c1f0 100644
--- a/src/pkg/net/port_unix.go
+++ b/src/pkg/net/port_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Read system port mappings from /etc/services
@@ -10,12 +10,16 @@ package net
import "sync"
-var services map[string]map[string]int
+// services contains minimal mappings between services names and port
+// numbers for platforms that don't have a complete list of port numbers
+// (some Solaris distros).
+var services = map[string]map[string]int{
+ "tcp": {"http": 80},
+}
var servicesError error
var onceReadServices sync.Once
func readServices() {
- services = make(map[string]map[string]int)
var file *file
if file, servicesError = open("/etc/services"); servicesError != nil {
return
@@ -29,7 +33,7 @@ func readServices() {
if len(f) < 2 {
continue
}
- portnet := f[1] // "tcp/80"
+ portnet := f[1] // "80/tcp"
port, j, ok := dtoi(portnet, 0)
if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
continue
diff --git a/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go
index 5a8958b08..12856b6c3 100644
--- a/src/pkg/net/protoconn_test.go
+++ b/src/pkg/net/protoconn_test.go
@@ -19,7 +19,7 @@ import (
// also uses /tmp directory in case it is prohibited to create UNIX
// sockets in TMPDIR.
func testUnixAddr() string {
- f, err := ioutil.TempFile("/tmp", "nettest")
+ f, err := ioutil.TempFile("", "nettest")
if err != nil {
panic(err)
}
@@ -236,7 +236,7 @@ func TestIPConnSpecificMethods(t *testing.T) {
func TestUnixListenerSpecificMethods(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -278,7 +278,7 @@ func TestUnixListenerSpecificMethods(t *testing.T) {
func TestUnixConnSpecificMethods(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
t.Skipf("skipping test on %q", runtime.GOOS)
}
diff --git a/src/pkg/net/rpc/client.go b/src/pkg/net/rpc/client.go
index c524d0a0a..21f79b068 100644
--- a/src/pkg/net/rpc/client.go
+++ b/src/pkg/net/rpc/client.go
@@ -39,14 +39,16 @@ type Call struct {
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
- mutex sync.Mutex // protects pending, seq, request
- sending sync.Mutex
+ codec ClientCodec
+
+ sending sync.Mutex
+
+ mutex sync.Mutex // protects following
request Request
seq uint64
- codec ClientCodec
pending map[uint64]*Call
- closing bool
- shutdown bool
+ closing bool // user has called Close
+ shutdown bool // server has told us to stop
}
// A ClientCodec implements writing of RPC requests and
@@ -274,7 +276,7 @@ func Dial(network, address string) (*Client, error) {
func (client *Client) Close() error {
client.mutex.Lock()
- if client.shutdown || client.closing {
+ if client.closing {
client.mutex.Unlock()
return ErrShutdown
}
diff --git a/src/pkg/net/rpc/client_test.go b/src/pkg/net/rpc/client_test.go
new file mode 100644
index 000000000..bbfc1ec3a
--- /dev/null
+++ b/src/pkg/net/rpc/client_test.go
@@ -0,0 +1,36 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+ "errors"
+ "testing"
+)
+
+type shutdownCodec struct {
+ responded chan int
+ closed bool
+}
+
+func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseBody(interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseHeader(*Response) error {
+ c.responded <- 1
+ return errors.New("shutdownCodec ReadResponseHeader")
+}
+func (c *shutdownCodec) Close() error {
+ c.closed = true
+ return nil
+}
+
+func TestCloseCodec(t *testing.T) {
+ codec := &shutdownCodec{responded: make(chan int)}
+ client := NewClientWithCodec(codec)
+ <-codec.responded
+ client.Close()
+ if !codec.closed {
+ t.Error("client.Close did not close codec")
+ }
+}
diff --git a/src/pkg/net/rpc/jsonrpc/all_test.go b/src/pkg/net/rpc/jsonrpc/all_test.go
index 40d4b82d7..a433a365e 100644
--- a/src/pkg/net/rpc/jsonrpc/all_test.go
+++ b/src/pkg/net/rpc/jsonrpc/all_test.go
@@ -5,6 +5,7 @@
package jsonrpc
import (
+ "bytes"
"encoding/json"
"errors"
"fmt"
@@ -12,6 +13,7 @@ import (
"io/ioutil"
"net"
"net/rpc"
+ "strings"
"testing"
)
@@ -202,6 +204,39 @@ func TestMalformedOutput(t *testing.T) {
}
}
+func TestServerErrorHasNullResult(t *testing.T) {
+ var out bytes.Buffer
+ sc := NewServerCodec(struct {
+ io.Reader
+ io.Writer
+ io.Closer
+ }{
+ Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`),
+ Writer: &out,
+ Closer: ioutil.NopCloser(nil),
+ })
+ r := new(rpc.Request)
+ if err := sc.ReadRequestHeader(r); err != nil {
+ t.Fatal(err)
+ }
+ const valueText = "the value we don't want to see"
+ const errorText = "some error"
+ err := sc.WriteResponse(&rpc.Response{
+ ServiceMethod: "Method",
+ Seq: 1,
+ Error: errorText,
+ }, valueText)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(out.String(), errorText) {
+ t.Fatalf("Response didn't contain expected error %q: %s", errorText, &out)
+ }
+ if strings.Contains(out.String(), valueText) {
+ t.Errorf("Response contains both an error and value: %s", &out)
+ }
+}
+
func TestUnexpectedError(t *testing.T) {
cli, srv := myPipe()
go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
diff --git a/src/pkg/net/rpc/jsonrpc/server.go b/src/pkg/net/rpc/jsonrpc/server.go
index 16ec0fe9a..e6d37cfa6 100644
--- a/src/pkg/net/rpc/jsonrpc/server.go
+++ b/src/pkg/net/rpc/jsonrpc/server.go
@@ -100,7 +100,6 @@ func (c *serverCodec) ReadRequestBody(x interface{}) error {
var null = json.RawMessage([]byte("null"))
func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
- var resp serverResponse
c.mutex.Lock()
b, ok := c.pending[r.Seq]
if !ok {
@@ -114,10 +113,9 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
// Invalid request so no id. Use JSON null.
b = &null
}
- resp.Id = b
- resp.Result = x
+ resp := serverResponse{Id: b}
if r.Error == "" {
- resp.Error = nil
+ resp.Result = x
} else {
resp.Error = r.Error
}
diff --git a/src/pkg/net/rpc/server.go b/src/pkg/net/rpc/server.go
index 7eb2dcf5a..6b264b46b 100644
--- a/src/pkg/net/rpc/server.go
+++ b/src/pkg/net/rpc/server.go
@@ -217,10 +217,11 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// Register publishes in the server the set of methods of the
// receiver value that satisfy the following conditions:
// - exported method
-// - two arguments, both pointers to exported structs
+// - two arguments, both of exported type
+// - the second argument is a pointer
// - one return value, of type error
// It returns an error if the receiver is not an exported type or has
-// no methods or unsuitable methods. It also logs the error using package log.
+// no suitable methods. It also logs the error using package log.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver's concrete type.
func (server *Server) Register(rcvr interface{}) error {
diff --git a/src/pkg/net/rpc/server_test.go b/src/pkg/net/rpc/server_test.go
index 3b9a88380..0dc4ddc2d 100644
--- a/src/pkg/net/rpc/server_test.go
+++ b/src/pkg/net/rpc/server_test.go
@@ -594,7 +594,6 @@ func TestErrorAfterClientClose(t *testing.T) {
}
func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
- b.StopTimer()
once.Do(startServer)
client, err := dial()
if err != nil {
@@ -604,33 +603,24 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
// Synchronous calls
args := &Args{7, 8}
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N)
- var wg sync.WaitGroup
- wg.Add(procs)
- b.StartTimer()
-
- for p := 0; p < procs; p++ {
- go func() {
- reply := new(Reply)
- for atomic.AddInt32(&N, -1) >= 0 {
- err := client.Call("Arith.Add", args, reply)
- if err != nil {
- b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
- }
- if reply.C != args.A+args.B {
- b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
- }
+ b.ResetTimer()
+
+ b.RunParallel(func(pb *testing.PB) {
+ reply := new(Reply)
+ for pb.Next() {
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
}
- wg.Done()
- }()
- }
- wg.Wait()
+ if reply.C != args.A+args.B {
+ b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+ }
+ })
}
func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
const MaxConcurrentCalls = 100
- b.StopTimer()
once.Do(startServer)
client, err := dial()
if err != nil {
@@ -647,7 +637,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
wg.Add(procs)
gate := make(chan bool, MaxConcurrentCalls)
res := make(chan *Call, MaxConcurrentCalls)
- b.StartTimer()
+ b.ResetTimer()
for p := 0; p < procs; p++ {
go func() {
diff --git a/src/pkg/net/sendfile_dragonfly.go b/src/pkg/net/sendfile_dragonfly.go
index a2219c163..bc88fd3b9 100644
--- a/src/pkg/net/sendfile_dragonfly.go
+++ b/src/pkg/net/sendfile_dragonfly.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
// if handled == false, sendFile performed no work.
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// DragonFly uses 0 as the "until EOF" value. If you pass in more bytes than the
- // file contains, it will loop back to the beginning ad nauseum until it's sent
+ // file contains, it will loop back to the beginning ad nauseam until it's sent
// exactly the number of bytes told to. As such, we need to know exactly how many
// bytes to send.
var remain int64 = 0
diff --git a/src/pkg/net/sendfile_freebsd.go b/src/pkg/net/sendfile_freebsd.go
index 42fe799ef..ffc147262 100644
--- a/src/pkg/net/sendfile_freebsd.go
+++ b/src/pkg/net/sendfile_freebsd.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
// if handled == false, sendFile performed no work.
func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
// FreeBSD uses 0 as the "until EOF" value. If you pass in more bytes than the
- // file contains, it will loop back to the beginning ad nauseum until it's sent
+ // file contains, it will loop back to the beginning ad nauseam until it's sent
// exactly the number of bytes told to. As such, we need to know exactly how many
// bytes to send.
var remain int64 = 0
diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
index 3660849c1..03426ef0d 100644
--- a/src/pkg/net/sendfile_stub.go
+++ b/src/pkg/net/sendfile_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin netbsd openbsd
+// +build darwin nacl netbsd openbsd solaris
package net
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 9194a8ec2..6a2bb9243 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,21 +9,20 @@ import (
"io"
"os"
"runtime"
- "strconv"
"testing"
"time"
)
-func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool {
switch runtime.GOOS {
case "linux":
- case "plan9", "windows":
+ case "nacl", "plan9", "windows":
// "unix" sockets are not supported on Windows and Plan 9.
if net == unixsotype {
return true
}
default:
- if net == unixsotype && linuxonly {
+ if net == unixsotype && linuxOnly {
return true
}
}
@@ -42,21 +41,15 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
return false
}
-func tempfile(filename string) string {
- // use /tmp in case it is prohibited to create
- // UNIX sockets in TMPDIR
- return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
-}
-
var streamConnServerTests = []struct {
- snet string // server side
- saddr string
- cnet string // client side
- caddr string
- ipv6 bool // test with underlying AF_INET6 socket
- ipv4map bool // test with IPv6 IPv4-mapping functionality
- empty bool // test with empty data
- linux bool // test with abstract unix domain socket, a Linux-ism
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ empty bool // test with empty data
+ linuxOnly bool // test with abstract unix domain socket, a Linux-ism
}{
{snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
@@ -93,13 +86,13 @@ var streamConnServerTests = []struct {
{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
- {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
- {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+ {snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
+ {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
}
func TestStreamConnServer(t *testing.T) {
for _, tt := range streamConnServerTests {
- if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
continue
}
@@ -137,21 +130,28 @@ func TestStreamConnServer(t *testing.T) {
}
var seqpacketConnServerTests = []struct {
- net string
- saddr string // server address
- caddr string // client address
- empty bool // test with empty data
+ net string
+ saddr string // server address
+ caddr string // client address
+ empty bool // test with empty data
+ linuxOnly bool // test with abstract unix domain socket, a Linux-ism
}{
- {net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
- {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+ {net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
+ {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
}
func TestSeqpacketConnServer(t *testing.T) {
- if runtime.GOOS != "linux" {
+ switch runtime.GOOS {
+ case "darwin", "nacl", "openbsd", "plan9", "windows":
+ fallthrough
+ case "freebsd": // FreeBSD 8 doesn't support unixpacket
t.Skipf("skipping test on %q", runtime.GOOS)
}
for _, tt := range seqpacketConnServerTests {
+ if runtime.GOOS != "linux" && tt.linuxOnly {
+ continue
+ }
listening := make(chan string)
done := make(chan int)
switch tt.net {
@@ -248,15 +248,15 @@ func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
var datagramPacketConnServerTests = []struct {
- snet string // server side
- saddr string
- cnet string // client side
- caddr string
- ipv6 bool // test with underlying AF_INET6 socket
- ipv4map bool // test with IPv6 IPv4-mapping functionality
- dial bool // test with Dial or DialUnix
- empty bool // test with empty data
- linux bool // test with abstract unix domain socket, a Linux-ism
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ dial bool // test with Dial or DialUnix
+ empty bool // test with empty data
+ linuxOnly bool // test with abstract unix domain socket, a Linux-ism
}{
{snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
@@ -301,12 +301,12 @@ var datagramPacketConnServerTests = []struct {
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
- {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true},
+ {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()},
+ {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true},
+ {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true},
+ {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true},
- {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
+ {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true},
}
func TestDatagramPacketConnServer(t *testing.T) {
@@ -315,7 +315,7 @@ func TestDatagramPacketConnServer(t *testing.T) {
}
for _, tt := range datagramPacketConnServerTests {
- if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
continue
}
diff --git a/src/pkg/net/smtp/example_test.go b/src/pkg/net/smtp/example_test.go
new file mode 100644
index 000000000..d551e365a
--- /dev/null
+++ b/src/pkg/net/smtp/example_test.go
@@ -0,0 +1,61 @@
+// 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 smtp_test
+
+import (
+ "fmt"
+ "log"
+ "net/smtp"
+)
+
+func Example() {
+ // Connect to the remote SMTP server.
+ c, err := smtp.Dial("mail.example.com:25")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Set the sender and recipient first
+ if err := c.Mail("sender@example.org"); err != nil {
+ log.Fatal(err)
+ }
+ if err := c.Rcpt("recipient@example.net"); err != nil {
+ log.Fatal(err)
+ }
+
+ // Send the email body.
+ wc, err := c.Data()
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, err = fmt.Fprintf(wc, "This is the email body")
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = wc.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Send the QUIT command and close the connection.
+ err = c.Quit()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExamplePlainAuth() {
+ // Set up authentication information.
+ auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
+
+ // Connect to the server, authenticate, set the sender and recipient,
+ // and send the email all in one step.
+ to := []string{"recipient@example.net"}
+ msg := []byte("This is the email body.")
+ err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/pkg/net/smtp/smtp.go b/src/pkg/net/smtp/smtp.go
index a0a478a85..87dea442c 100644
--- a/src/pkg/net/smtp/smtp.go
+++ b/src/pkg/net/smtp/smtp.go
@@ -264,6 +264,8 @@ func (c *Client) Data() (io.WriteCloser, error) {
return &dataCloser{c, c.Text.DotWriter()}, nil
}
+var testHookStartTLS func(*tls.Config) // nil, except for tests
+
// SendMail connects to the server at addr, switches to TLS if
// possible, authenticates with the optional mechanism a if possible,
// and then sends an email from address from, to addresses to, with
@@ -278,7 +280,11 @@ func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
return err
}
if ok, _ := c.Extension("STARTTLS"); ok {
- if err = c.StartTLS(nil); err != nil {
+ config := &tls.Config{ServerName: c.serverName}
+ if testHookStartTLS != nil {
+ testHookStartTLS(config)
+ }
+ if err = c.StartTLS(config); err != nil {
return err
}
}
diff --git a/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index 2133dc7c7..3fba1ea5a 100644
--- a/src/pkg/net/smtp/smtp_test.go
+++ b/src/pkg/net/smtp/smtp_test.go
@@ -7,6 +7,8 @@ package smtp
import (
"bufio"
"bytes"
+ "crypto/tls"
+ "crypto/x509"
"io"
"net"
"net/textproto"
@@ -548,3 +550,145 @@ AUTH PLAIN AHVzZXIAcGFzcw==
*
QUIT
`
+
+func TestTLSClient(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+ errc := make(chan error)
+ go func() {
+ errc <- sendMail(ln.Addr().String())
+ }()
+ conn, err := ln.Accept()
+ if err != nil {
+ t.Fatalf("failed to accept connection: %v", err)
+ }
+ defer conn.Close()
+ if err := serverHandle(conn, t); err != nil {
+ t.Fatalf("failed to handle connection: %v", err)
+ }
+ if err := <-errc; err != nil {
+ t.Fatalf("client error: %v", err)
+ }
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+type smtpSender struct {
+ w io.Writer
+}
+
+func (s smtpSender) send(f string) {
+ s.w.Write([]byte(f + "\r\n"))
+}
+
+// smtp server, finely tailored to deal with our own client only!
+func serverHandle(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ send("220 127.0.0.1 ESMTP service ready")
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250-127.0.0.1 ESMTP offers a warm hug of welcome")
+ send("250-STARTTLS")
+ send("250 Ok")
+ case "STARTTLS":
+ send("220 Go ahead")
+ keypair, err := tls.X509KeyPair(localhostCert, localhostKey)
+ if err != nil {
+ return err
+ }
+ config := &tls.Config{Certificates: []tls.Certificate{keypair}}
+ c = tls.Server(c, config)
+ defer c.Close()
+ return serverHandleTLS(c, t)
+ default:
+ t.Fatalf("unrecognized command: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func serverHandleTLS(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250 Ok")
+ case "MAIL FROM:<joe1@example.com>":
+ send("250 Ok")
+ case "RCPT TO:<joe2@example.com>":
+ send("250 Ok")
+ case "DATA":
+ send("354 send the mail data, end with .")
+ send("250 Ok")
+ case "Subject: test":
+ case "":
+ case "howdy!":
+ case ".":
+ case "QUIT":
+ send("221 127.0.0.1 Service closing transmission channel")
+ return nil
+ default:
+ t.Fatalf("unrecognized command during TLS: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func init() {
+ testRootCAs := x509.NewCertPool()
+ testRootCAs.AppendCertsFromPEM(localhostCert)
+ testHookStartTLS = func(config *tls.Config) {
+ config.RootCAs = testRootCAs
+ }
+}
+
+func sendMail(hostPort string) error {
+ host, _, err := net.SplitHostPort(hostPort)
+ if err != nil {
+ return err
+ }
+ auth := PlainAuth("", "", "", host)
+ from := "joe1@example.com"
+ to := []string{"joe2@example.com"}
+ return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!"))
+}
+
+// (copied from net/http/httptest)
+// localhostCert is a PEM-encoded TLS cert with SAN IPs
+// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
+// of ASN.1 time).
+// generated from src/pkg/crypto/tls:
+// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
+bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
+bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
+IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
+AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
+AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
+Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+-----END CERTIFICATE-----`)
+
+// localhostKey is the private key for localhostCert.
+var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
+0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
+NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
+AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
+MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
+EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
+1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+-----END RSA PRIVATE KEY-----`)
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 6c37109f5..48fb78527 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
package net
diff --git a/src/pkg/net/sock_cloexec.go b/src/pkg/net/sock_cloexec.go
index 3f22cd8f5..dec81855b 100644
--- a/src/pkg/net/sock_cloexec.go
+++ b/src/pkg/net/sock_cloexec.go
@@ -5,7 +5,7 @@
// This file implements sysSocket and accept for platforms that
// provide a fast path for setting SetNonblock and CloseOnExec.
-// +build linux
+// +build freebsd linux
package net
@@ -13,18 +13,20 @@ import "syscall"
// Wrapper around the socket system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
- s, err := syscall.Socket(f, t|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, p)
- // The SOCK_NONBLOCK and SOCK_CLOEXEC flags were introduced in
- // Linux 2.6.27. If we get an EINVAL error, fall back to
- // using socket without them.
- if err == nil || err != syscall.EINVAL {
+func sysSocket(family, sotype, proto int) (int, error) {
+ s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
+ // On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were
+ // introduced in 2.6.27 kernel and on FreeBSD both flags were
+ // introduced in 10 kernel. If we get an EINVAL error on Linux
+ // or EPROTONOSUPPORT error on FreeBSD, fall back to using
+ // socket without them.
+ if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) {
return s, err
}
// See ../syscall/exec_unix.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, err = syscall.Socket(f, t, p)
+ s, err = syscall.Socket(family, sotype, proto)
if err == nil {
syscall.CloseOnExec(s)
}
@@ -41,12 +43,19 @@ func sysSocket(f, t, p int) (int, error) {
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
- nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
- // The accept4 system call was introduced in Linux 2.6.28. If
- // we get an ENOSYS or EINVAL error, fall back to using accept.
- if err == nil || (err != syscall.ENOSYS && err != syscall.EINVAL) {
- return nfd, sa, err
+func accept(s int) (int, syscall.Sockaddr, error) {
+ ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+ // On Linux the accept4 system call was introduced in 2.6.28
+ // kernel and on FreeBSD it was introduced in 10 kernel. If we
+ // get an ENOSYS error on both Linux and FreeBSD, or EINVAL
+ // error on Linux, fall back to using accept.
+ switch err {
+ default: // nil and errors other than the ones listed
+ return ns, sa, err
+ case syscall.ENOSYS: // syscall missing
+ case syscall.EINVAL: // some Linux use this instead of ENOSYS
+ case syscall.EACCES: // some Linux use this instead of ENOSYS
+ case syscall.EFAULT: // some Linux use this instead of ENOSYS
}
// See ../syscall/exec_unix.go for description of ForkLock.
@@ -54,16 +63,16 @@ func accept(fd int) (int, syscall.Sockaddr, error) {
// because we have put fd.sysfd into non-blocking mode.
// However, a call to the File method will put it back into
// blocking mode. We can't take that risk, so no use of ForkLock here.
- nfd, sa, err = syscall.Accept(fd)
+ ns, sa, err = syscall.Accept(s)
if err == nil {
- syscall.CloseOnExec(nfd)
+ syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, err
}
- if err = syscall.SetNonblock(nfd, true); err != nil {
- syscall.Close(nfd)
+ if err = syscall.SetNonblock(ns, true); err != nil {
+ syscall.Close(ns)
return -1, nil, err
}
- return nfd, sa, nil
+ return ns, sa, nil
}
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index c2d343c58..a6ef874c9 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
diff --git a/src/pkg/net/sock_solaris.go b/src/pkg/net/sock_solaris.go
new file mode 100644
index 000000000..90fe9de89
--- /dev/null
+++ b/src/pkg/net/sock_solaris.go
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "syscall"
+
+func maxListenerBacklog() int {
+ // TODO: Implement this
+ // NOTE: Never return a number bigger than 1<<16 - 1. See issue 5030.
+ return syscall.SOMAXCONN
+}
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index ef6eb8505..77d51d737 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -2,16 +2,29 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
package net
import (
"os"
+ "runtime"
"syscall"
)
func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+ if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW {
+ // On DragonFly BSD, we adjust the ephemeral port
+ // range because unlike other BSD systems its default
+ // port range doesn't conform to IANA recommendation
+ // as described in RFC 6355 and is pretty narrow.
+ switch family {
+ case syscall.AF_INET:
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH)
+ case syscall.AF_INET6:
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
+ }
+ }
if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
// Allow both IP versions even if the OS default
// is otherwise. Note that some operating systems
diff --git a/src/pkg/net/sockopt_plan9.go b/src/pkg/net/sockopt_plan9.go
new file mode 100644
index 000000000..8bc689b6c
--- /dev/null
+++ b/src/pkg/net/sockopt_plan9.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+func setKeepAlive(fd *netFD, keepalive bool) error {
+ if keepalive {
+ _, e := fd.ctl.WriteAt([]byte("keepalive"), 0)
+ return e
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockopt_posix.go b/src/pkg/net/sockopt_posix.go
index ff3bc6899..921918c37 100644
--- a/src/pkg/net/sockopt_posix.go
+++ b/src/pkg/net/sockopt_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
diff --git a/src/pkg/net/sockopt_solaris.go b/src/pkg/net/sockopt_solaris.go
new file mode 100644
index 000000000..54c20b140
--- /dev/null
+++ b/src/pkg/net/sockopt_solaris.go
@@ -0,0 +1,32 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+ if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
+ }
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+}
+
+func setDefaultListenerSockopts(s int) error {
+ // Allow reuse of recently-used addresses.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
+}
+
+func setDefaultMulticastSockopts(s int) error {
+ // Allow multicast UDP and raw IP datagram sockets to listen
+ // concurrently across multiple listeners.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
+}
diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
index 2199e480d..87132f0f4 100644
--- a/src/pkg/net/sockoptip_bsd.go
+++ b/src/pkg/net/sockoptip_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
package net
diff --git a/src/pkg/net/sockoptip_posix.go b/src/pkg/net/sockoptip_posix.go
index c2579be91..b5c80e449 100644
--- a/src/pkg/net/sockoptip_posix.go
+++ b/src/pkg/net/sockoptip_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows
package net
diff --git a/src/pkg/net/sockoptip_stub.go b/src/pkg/net/sockoptip_stub.go
new file mode 100644
index 000000000..dcd3a22b5
--- /dev/null
+++ b/src/pkg/net/sockoptip_stub.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package net
+
+import "syscall"
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func setIPv6MulticastLoopback(fd *netFD, v bool) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
+
+func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+ // See golang.org/issue/7399.
+ return syscall.EINVAL
+}
diff --git a/src/pkg/net/sys_cloexec.go b/src/pkg/net/sys_cloexec.go
index bbfcc1a4f..898fb7c0c 100644
--- a/src/pkg/net/sys_cloexec.go
+++ b/src/pkg/net/sys_cloexec.go
@@ -5,7 +5,7 @@
// This file implements sysSocket and accept for platforms that do not
// provide a fast path for setting SetNonblock and CloseOnExec.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly nacl netbsd openbsd solaris
package net
@@ -13,10 +13,10 @@ import "syscall"
// Wrapper around the socket system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
+func sysSocket(family, sotype, proto int) (int, error) {
// See ../syscall/exec_unix.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, err := syscall.Socket(f, t, p)
+ s, err := syscall.Socket(family, sotype, proto)
if err == nil {
syscall.CloseOnExec(s)
}
@@ -33,22 +33,22 @@ func sysSocket(f, t, p int) (int, error) {
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
+func accept(s int) (int, syscall.Sockaddr, error) {
// See ../syscall/exec_unix.go for description of ForkLock.
// It is probably okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
// However, a call to the File method will put it back into
// blocking mode. We can't take that risk, so no use of ForkLock here.
- nfd, sa, err := syscall.Accept(fd)
+ ns, sa, err := syscall.Accept(s)
if err == nil {
- syscall.CloseOnExec(nfd)
+ syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, err
}
- if err = syscall.SetNonblock(nfd, true); err != nil {
- syscall.Close(nfd)
+ if err = syscall.SetNonblock(ns, true); err != nil {
+ syscall.Close(ns)
return -1, nil, err
}
- return nfd, sa, nil
+ return ns, sa, nil
}
diff --git a/src/pkg/net/tcp_test.go b/src/pkg/net/tcp_test.go
index 62fd99f5c..c04198ea0 100644
--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -97,6 +97,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
b.Fatalf("Listen failed: %v", err)
}
defer ln.Close()
+ serverSem := make(chan bool, numConcurrent)
// Acceptor.
go func() {
for {
@@ -104,9 +105,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
if err != nil {
break
}
+ serverSem <- true
// Server connection.
go func(c Conn) {
- defer c.Close()
+ defer func() {
+ c.Close()
+ <-serverSem
+ }()
if timeout {
c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
}
@@ -119,13 +124,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
}(c)
}
}()
- sem := make(chan bool, numConcurrent)
+ clientSem := make(chan bool, numConcurrent)
for i := 0; i < conns; i++ {
- sem <- true
+ clientSem <- true
// Client connection.
go func() {
defer func() {
- <-sem
+ <-clientSem
}()
c, err := Dial("tcp", ln.Addr().String())
if err != nil {
@@ -144,8 +149,9 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
}
}()
}
- for i := 0; i < cap(sem); i++ {
- sem <- true
+ for i := 0; i < numConcurrent; i++ {
+ clientSem <- true
+ serverSem <- true
}
}
@@ -185,7 +191,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for p := 0; p < P; p++ {
s, err := ln.Accept()
if err != nil {
- b.Fatalf("Accept failed: %v", err)
+ b.Errorf("Accept failed: %v", err)
+ return
}
servers[p] = s
}
@@ -217,7 +224,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
buf[0] = v
_, err := c.Write(buf[:])
if err != nil {
- b.Fatalf("Write failed: %v", err)
+ b.Errorf("Write failed: %v", err)
+ return
}
}
}(clients[p])
@@ -232,7 +240,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for i := 0; i < N; i++ {
_, err := s.Read(buf[:])
if err != nil {
- b.Fatalf("Read failed: %v", err)
+ b.Errorf("Read failed: %v", err)
+ return
}
pipe <- buf[0]
}
@@ -250,7 +259,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
buf[0] = v
_, err := s.Write(buf[:])
if err != nil {
- b.Fatalf("Write failed: %v", err)
+ b.Errorf("Write failed: %v", err)
+ return
}
}
s.Close()
@@ -263,7 +273,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
for i := 0; i < N; i++ {
_, err := c.Read(buf[:])
if err != nil {
- b.Fatalf("Read failed: %v", err)
+ b.Errorf("Read failed: %v", err)
+ return
}
}
c.Close()
@@ -388,7 +399,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
}
switch runtime.GOOS {
- case "darwin", "freebsd", "opensbd", "netbsd":
+ case "darwin", "freebsd", "openbsd", "netbsd":
tests = append(tests, []test{
{"tcp", "[localhost%" + ifi.Name + "]:0", true},
{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
@@ -460,15 +471,25 @@ func TestTCPConcurrentAccept(t *testing.T) {
wg.Done()
}()
}
- for i := 0; i < 10*N; i++ {
- c, err := Dial("tcp", ln.Addr().String())
+ attempts := 10 * N
+ fails := 0
+ d := &Dialer{Timeout: 200 * time.Millisecond}
+ for i := 0; i < attempts; i++ {
+ c, err := d.Dial("tcp", ln.Addr().String())
if err != nil {
- t.Fatalf("Dial failed: %v", err)
+ fails++
+ } else {
+ c.Close()
}
- c.Close()
}
ln.Close()
wg.Wait()
+ if fails > attempts/9 { // see issues 7400 and 7541
+ t.Fatalf("too many Dial failed: %v", fails)
+ }
+ if fails > 0 {
+ t.Logf("# of failed Dials: %v", fails)
+ }
}
func TestTCPReadWriteMallocs(t *testing.T) {
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index cf9c0f890..52019d7b4 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -32,7 +32,7 @@ func (c *TCPConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the TCP connection.
@@ -41,20 +41,21 @@ func (c *TCPConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error {
return syscall.EPLAN9
}
@@ -62,12 +63,18 @@ func (c *TCPConn) SetLinger(sec int) error {
// SetKeepAlive sets whether the operating system should send
// keepalive messages on the connection.
func (c *TCPConn) SetKeepAlive(keepalive bool) error {
- return syscall.EPLAN9
+ if !c.ok() {
+ return syscall.EPLAN9
+ }
+ return setKeepAlive(c.fd, keepalive)
}
// SetKeepAlivePeriod sets period between keep alives.
func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
- return syscall.EPLAN9
+ if !c.ok() {
+ return syscall.EPLAN9
+ }
+ return setKeepAlivePeriod(c.fd, d)
}
// SetNoDelay controls whether the operating system should delay
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 00c692e42..b79b115ca 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -78,7 +78,7 @@ func (c *TCPConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the TCP connection.
@@ -87,20 +87,21 @@ func (c *TCPConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
return syscall.EINVAL
diff --git a/src/pkg/net/tcpsockopt_dragonfly.go b/src/pkg/net/tcpsockopt_dragonfly.go
new file mode 100644
index 000000000..d10a77773
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_dragonfly.go
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+
+ // The kernel expects milliseconds so round to next highest millisecond.
+ d += (time.Millisecond - time.Nanosecond)
+ msecs := int(time.Duration(d.Nanoseconds()) / time.Millisecond)
+
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs))
+ if err != nil {
+ return err
+ }
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs))
+}
diff --git a/src/pkg/net/tcpsockopt_plan9.go b/src/pkg/net/tcpsockopt_plan9.go
new file mode 100644
index 000000000..0e7a6647c
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_plan9.go
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP socket options for plan9
+
+package net
+
+import (
+ "time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ cmd := "keepalive " + string(int64(d/time.Millisecond))
+ _, e := fd.ctl.WriteAt([]byte(cmd), 0)
+ return e
+}
diff --git a/src/pkg/net/tcpsockopt_posix.go b/src/pkg/net/tcpsockopt_posix.go
index e03476ac6..6484bad4b 100644
--- a/src/pkg/net/tcpsockopt_posix.go
+++ b/src/pkg/net/tcpsockopt_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
diff --git a/src/pkg/net/tcpsockopt_solaris.go b/src/pkg/net/tcpsockopt_solaris.go
new file mode 100644
index 000000000..eaab6b678
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_solaris.go
@@ -0,0 +1,27 @@
+// 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.
+
+// TCP socket options for solaris
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+
+ // The kernel expects seconds so round to next highest second.
+ d += (time.Second - time.Nanosecond)
+ secs := int(d.Seconds())
+
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs))
+}
diff --git a/src/pkg/net/tcpsockopt_unix.go b/src/pkg/net/tcpsockopt_unix.go
index 89d9143b5..2693a541d 100644
--- a/src/pkg/net/tcpsockopt_unix.go
+++ b/src/pkg/net/tcpsockopt_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly freebsd linux netbsd
+// +build freebsd linux nacl netbsd
package net
diff --git a/src/pkg/net/tcpsockopt_windows.go b/src/pkg/net/tcpsockopt_windows.go
index 0bf4312f2..8ef140797 100644
--- a/src/pkg/net/tcpsockopt_windows.go
+++ b/src/pkg/net/tcpsockopt_windows.go
@@ -7,7 +7,10 @@
package net
import (
+ "os"
+ "syscall"
"time"
+ "unsafe"
)
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
@@ -16,6 +19,16 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
}
defer fd.decref()
- // We can't actually set this per connection. Act as a noop rather than an error.
- return nil
+ // Windows expects milliseconds so round to next highest millisecond.
+ d += (time.Millisecond - time.Nanosecond)
+ millis := uint32(d / time.Millisecond)
+ ka := syscall.TCPKeepalive{
+ OnOff: 1,
+ Time: millis,
+ Interval: millis,
+ }
+ ret := uint32(0)
+ size := uint32(unsafe.Sizeof(ka))
+ err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+ return os.NewSyscallError("WSAIoctl", err)
}
diff --git a/src/pkg/net/testdata/resolv.conf b/src/pkg/net/testdata/resolv.conf
new file mode 100644
index 000000000..b5972e09c
--- /dev/null
+++ b/src/pkg/net/testdata/resolv.conf
@@ -0,0 +1,5 @@
+# /etc/resolv.conf
+
+domain Home
+nameserver 192.168.1.1
+options ndots:5 timeout:10 attempts:3 rotate
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index b0c07413c..eea9207f2 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/net/textproto/reader.go
@@ -562,19 +562,12 @@ const toLower = 'a' - 'A'
// allowed to mutate the provided byte slice before returning the
// string.
func canonicalMIMEHeaderKey(a []byte) string {
- // Look for it in commonHeaders , so that we can avoid an
- // allocation by sharing the strings among all users
- // of textproto. If we don't find it, a has been canonicalized
- // so just return string(a).
upper := true
- lo := 0
- hi := len(commonHeaders)
- for i := 0; i < len(a); i++ {
+ for i, c := range a {
// Canonicalize: first letter upper case
// and upper case after each dash.
// (Host, User-Agent, If-Modified-Since).
// MIME headers are ASCII only, so no Unicode issues.
- c := a[i]
if c == ' ' {
c = '-'
} else if upper && 'a' <= c && c <= 'z' {
@@ -584,60 +577,61 @@ func canonicalMIMEHeaderKey(a []byte) string {
}
a[i] = c
upper = c == '-' // for next time
-
- if lo < hi {
- for lo < hi && (len(commonHeaders[lo]) <= i || commonHeaders[lo][i] < c) {
- lo++
- }
- for hi > lo && commonHeaders[hi-1][i] > c {
- hi--
- }
- }
}
- if lo < hi && len(commonHeaders[lo]) == len(a) {
- return commonHeaders[lo]
+ // The compiler recognizes m[string(byteSlice)] as a special
+ // case, so a copy of a's bytes into a new string does not
+ // happen in this map lookup:
+ if v := commonHeader[string(a)]; v != "" {
+ return v
}
return string(a)
}
-var commonHeaders = []string{
- "Accept",
- "Accept-Charset",
- "Accept-Encoding",
- "Accept-Language",
- "Accept-Ranges",
- "Cache-Control",
- "Cc",
- "Connection",
- "Content-Id",
- "Content-Language",
- "Content-Length",
- "Content-Transfer-Encoding",
- "Content-Type",
- "Cookie",
- "Date",
- "Dkim-Signature",
- "Etag",
- "Expires",
- "From",
- "Host",
- "If-Modified-Since",
- "If-None-Match",
- "In-Reply-To",
- "Last-Modified",
- "Location",
- "Message-Id",
- "Mime-Version",
- "Pragma",
- "Received",
- "Return-Path",
- "Server",
- "Set-Cookie",
- "Subject",
- "To",
- "User-Agent",
- "Via",
- "X-Forwarded-For",
- "X-Imforwards",
- "X-Powered-By",
+// commonHeader interns common header strings.
+var commonHeader = make(map[string]string)
+
+func init() {
+ for _, v := range []string{
+ "Accept",
+ "Accept-Charset",
+ "Accept-Encoding",
+ "Accept-Language",
+ "Accept-Ranges",
+ "Cache-Control",
+ "Cc",
+ "Connection",
+ "Content-Id",
+ "Content-Language",
+ "Content-Length",
+ "Content-Transfer-Encoding",
+ "Content-Type",
+ "Cookie",
+ "Date",
+ "Dkim-Signature",
+ "Etag",
+ "Expires",
+ "From",
+ "Host",
+ "If-Modified-Since",
+ "If-None-Match",
+ "In-Reply-To",
+ "Last-Modified",
+ "Location",
+ "Message-Id",
+ "Mime-Version",
+ "Pragma",
+ "Received",
+ "Return-Path",
+ "Server",
+ "Set-Cookie",
+ "Subject",
+ "To",
+ "User-Agent",
+ "Via",
+ "X-Forwarded-For",
+ "X-Imforwards",
+ "X-Powered-By",
+ } {
+ commonHeader[v] = v
+ }
}
diff --git a/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
index cc12912b6..cbc0ed183 100644
--- a/src/pkg/net/textproto/reader_test.go
+++ b/src/pkg/net/textproto/reader_test.go
@@ -247,24 +247,20 @@ func TestRFC959Lines(t *testing.T) {
}
func TestCommonHeaders(t *testing.T) {
- // need to disable the commonHeaders-based optimization
- // during this check, or we'd not be testing anything
- oldch := commonHeaders
- commonHeaders = []string{}
- defer func() { commonHeaders = oldch }()
-
- last := ""
- for _, h := range oldch {
- if last > h {
- t.Errorf("%v is out of order", h)
- }
- if last == h {
- t.Errorf("%v is duplicated", h)
+ for h := range commonHeader {
+ if h != CanonicalMIMEHeaderKey(h) {
+ t.Errorf("Non-canonical header %q in commonHeader", h)
}
- if canon := CanonicalMIMEHeaderKey(h); h != canon {
- t.Errorf("%v is not canonical", h)
+ }
+ b := []byte("content-Length")
+ want := "Content-Length"
+ n := testing.AllocsPerRun(200, func() {
+ if x := canonicalMIMEHeaderKey(b); x != want {
+ t.Fatalf("canonicalMIMEHeaderKey(%q) = %q; want %q", b, x, want)
}
- last = h
+ })
+ if n > 0 {
+ t.Errorf("canonicalMIMEHeaderKey allocs = %v; want 0", n)
}
}
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 35d427a69..9ef0c4d15 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -120,6 +120,9 @@ func TestReadTimeout(t *testing.T) {
t.Fatalf("Read: expected err %v, got %v", errClosing, err)
}
default:
+ if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
+ break
+ }
if err != errClosing {
t.Fatalf("Read: expected err %v, got %v", errClosing, err)
}
@@ -348,7 +351,8 @@ func TestReadWriteDeadline(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
lnquit <- true
@@ -493,10 +497,7 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
clientc <- copyRes{n, err, d}
}()
- tooLong := 2 * time.Second
- if runtime.GOOS == "windows" {
- tooLong = 5 * time.Second
- }
+ tooLong := 5 * time.Second
select {
case res := <-clientc:
if isTimeout(res.err) {
@@ -536,7 +537,8 @@ func TestReadDeadlineDataAvailable(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
n, err := c.Write([]byte(msg))
@@ -574,7 +576,8 @@ func TestWriteDeadlineBufferAvailable(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("Accept: %v", err)
+ t.Errorf("Accept: %v", err)
+ return
}
defer c.Close()
c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
@@ -610,7 +613,8 @@ func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
go func() {
c, err := Dial("tcp", ln.Addr().String())
if err != nil {
- t.Fatalf("Dial: %v", err)
+ t.Errorf("Dial: %v", err)
+ return
}
defer c.Close()
var buf [1]byte
@@ -669,7 +673,8 @@ func TestProlongTimeout(t *testing.T) {
s, err := ln.Accept()
connected <- true
if err != nil {
- t.Fatalf("ln.Accept: %v", err)
+ t.Errorf("ln.Accept: %v", err)
+ return
}
defer s.Close()
s.SetDeadline(time.Now().Add(time.Hour))
@@ -706,7 +711,7 @@ func TestProlongTimeout(t *testing.T) {
func TestDeadlineRace(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ case "nacl", "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
}
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index 6f4d2152c..e1778779c 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -201,6 +201,10 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
{"udp", "[" + laddr + "%" + ifi.Name + "]:0", false},
{"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
}
+ // The first udp test fails on DragonFly - see issue 7473.
+ if runtime.GOOS == "dragonfly" {
+ tests = tests[1:]
+ }
switch runtime.GOOS {
case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
tests = append(tests, []test{
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 0dd0dbd71..4c99ae4af 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -4,10 +4,6 @@
package net
-import "errors"
-
-var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
-
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index 73621706d..510ac5e4a 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -190,7 +190,8 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
if err != nil {
return nil, err
}
- return newUDPConn(l.netFD()), nil
+ fd, err := l.netFD()
+ return newUDPConn(fd), err
}
// ListenMulticastUDP listens for incoming multicast UDP packets
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 142da8186..5dfba94e9 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -64,7 +64,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -93,7 +93,7 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
return 0, 0, 0, nil, syscall.EINVAL
}
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -124,7 +124,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
if err != nil {
return 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -156,7 +156,7 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
if err != nil {
return 0, 0, &OpError{"write", c.fd.net, addr, err}
}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
// DialUDP connects to the remote address raddr on the network net,
diff --git a/src/pkg/net/unicast_posix_test.go b/src/pkg/net/unicast_posix_test.go
index 5deb8f47c..452ac9254 100644
--- a/src/pkg/net/unicast_posix_test.go
+++ b/src/pkg/net/unicast_posix_test.go
@@ -166,9 +166,12 @@ var dualStackListenerTests = []struct {
}
// TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
// listening address and same port.
func TestDualStackTCPListener(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode, see issue 5001")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
@@ -178,7 +181,7 @@ func TestDualStackTCPListener(t *testing.T) {
}
for _, tt := range dualStackListenerTests {
- if tt.wildcard && (testing.Short() || !*testExternal) {
+ if tt.wildcard && !*testExternal {
continue
}
switch runtime.GOOS {
diff --git a/src/pkg/net/unix_test.go b/src/pkg/net/unix_test.go
index 91df3ff88..05643ddf9 100644
--- a/src/pkg/net/unix_test.go
+++ b/src/pkg/net/unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !plan9,!windows
+// +build !nacl,!plan9,!windows
package net
@@ -151,6 +151,73 @@ func TestUnixAutobindClose(t *testing.T) {
ln.Close()
}
+func TestUnixgramWrite(t *testing.T) {
+ addr := testUnixAddr()
+ laddr, err := ResolveUnixAddr("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ c, err := ListenPacket("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ListenPacket failed: %v", err)
+ }
+ defer os.Remove(addr)
+ defer c.Close()
+
+ testUnixgramWriteConn(t, laddr)
+ testUnixgramWritePacketConn(t, laddr)
+}
+
+func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
+ c, err := Dial("unixgram", raddr.String())
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c.Close()
+
+ if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil {
+ t.Fatal("WriteToUnix should fail")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
+ }
+ if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil {
+ t.Fatal("WriteTo should fail")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+ }
+ if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil {
+ t.Fatal("WriteTo should fail")
+ } else if err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
+ }
+ if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
+ t.Fatalf("Write failed: %v", err)
+ }
+}
+
+func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
+ addr := testUnixAddr()
+ c, err := ListenPacket("unixgram", addr)
+ if err != nil {
+ t.Fatalf("ListenPacket failed: %v", err)
+ }
+ defer os.Remove(addr)
+ defer c.Close()
+
+ if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil {
+ t.Fatalf("WriteToUnix failed: %v", err)
+ }
+ if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
+ t.Fatalf("WriteTo failed: %v", err)
+ }
+ if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil {
+ t.Fatalf("WriteMsgUnix failed: %v", err)
+ }
+ if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
+ t.Fatal("Write should fail")
+ }
+}
+
func TestUnixConnLocalAndRemoteNames(t *testing.T) {
for _, laddr := range []string{"", testUnixAddr()} {
laddr := laddr
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index b82f3cee0..2610779bf 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -124,7 +124,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
- n, sa, err := c.fd.ReadFrom(b)
+ n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
@@ -151,7 +151,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
}
- n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
@@ -171,6 +171,9 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
}
+ if c.fd.isConnected {
+ return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+ }
if addr == nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
@@ -178,7 +181,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
return 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteTo(b, sa)
+ return c.fd.writeTo(b, sa)
}
// WriteTo implements the PacketConn WriteTo method.
@@ -200,14 +203,17 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
if !c.ok() {
return 0, 0, syscall.EINVAL
}
+ if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
+ return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+ }
if addr != nil {
if addr.Net != sotypeToNet(c.fd.sotype) {
return 0, 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteMsg(b, oob, sa)
+ return c.fd.writeMsg(b, oob, sa)
}
- return c.fd.WriteMsg(b, oob, nil)
+ return c.fd.writeMsg(b, oob, nil)
}
// CloseRead shuts down the reading side of the Unix domain connection.
@@ -216,7 +222,7 @@ func (c *UnixConn) CloseRead() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseRead()
+ return c.fd.closeRead()
}
// CloseWrite shuts down the writing side of the Unix domain connection.
@@ -225,7 +231,7 @@ func (c *UnixConn) CloseWrite() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.CloseWrite()
+ return c.fd.closeWrite()
}
// DialUnix connects to the remote address raddr on the network net,
@@ -280,7 +286,11 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
- fd, err := l.fd.accept(sockaddrToUnix)
+ toAddr := sockaddrToUnix
+ if l.fd.sotype == syscall.SOCK_SEQPACKET {
+ toAddr = sockaddrToUnixpacket
+ }
+ fd, err := l.fd.accept(toAddr)
if err != nil {
return nil, err
}
diff --git a/src/pkg/net/url/url.go b/src/pkg/net/url/url.go
index 3b3787202..75f650a27 100644
--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -502,7 +502,7 @@ func (v Values) Set(key, value string) {
v[key] = []string{value}
}
-// Add adds the key to value. It appends to any existing
+// Add adds the value to key. It appends to any existing
// values associated with key.
func (v Values) Add(key, value string) {
v[key] = append(v[key], value)
diff --git a/src/pkg/net/url/url_test.go b/src/pkg/net/url/url_test.go
index 7578eb15b..cad758f23 100644
--- a/src/pkg/net/url/url_test.go
+++ b/src/pkg/net/url/url_test.go
@@ -251,6 +251,17 @@ var urltests = []URLTest{
},
"file:///home/adg/rabbits",
},
+ // "Windows" paths are no exception to the rule.
+ // See golang.org/issue/6027, especially comment #9.
+ {
+ "file:///C:/FooBar/Baz.txt",
+ &URL{
+ Scheme: "file",
+ Host: "",
+ Path: "/C:/FooBar/Baz.txt",
+ },
+ "file:///C:/FooBar/Baz.txt",
+ },
// case-insensitive scheme
{
"MaIlTo:webmaster@golang.org",
diff --git a/src/pkg/net/z_last_test.go b/src/pkg/net/z_last_test.go
new file mode 100644
index 000000000..4f6a54a56
--- /dev/null
+++ b/src/pkg/net/z_last_test.go
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+)
+
+var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
+
+func TestDNSThreadLimit(t *testing.T) {
+ if !*testDNSFlood {
+ t.Skip("test disabled; use -dnsflood to enable")
+ }
+
+ const N = 10000
+ c := make(chan int, N)
+ for i := 0; i < N; i++ {
+ go func(i int) {
+ LookupIP(fmt.Sprintf("%d.net-test.golang.org", i))
+ c <- 1
+ }(i)
+ }
+ // Don't bother waiting for the stragglers; stop at 0.9 N.
+ for i := 0; i < N*9/10; i++ {
+ if i%100 == 0 {
+ //println("TestDNSThreadLimit:", i)
+ }
+ <-c
+ }
+
+ // If we're still here, it worked.
+}
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
index 9fa7ad664..d353e405e 100644
--- a/src/pkg/os/dir_unix.go
+++ b/src/pkg/os/dir_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
diff --git a/src/pkg/os/doc.go b/src/pkg/os/doc.go
index a954e313d..389a8eb14 100644
--- a/src/pkg/os/doc.go
+++ b/src/pkg/os/doc.go
@@ -39,11 +39,14 @@ func (p *Process) Kill() error {
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
// Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
return p.signal(sig)
}
diff --git a/src/pkg/os/env_unix_test.go b/src/pkg/os/env_unix_test.go
index e16d71a64..5ec07ee1b 100644
--- a/src/pkg/os/env_unix_test.go
+++ b/src/pkg/os/env_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
diff --git a/src/pkg/os/error_unix.go b/src/pkg/os/error_unix.go
index 6250349e5..f2aabbb45 100644
--- a/src/pkg/os/error_unix.go
+++ b/src/pkg/os/error_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index 491cc242b..a70ed0d20 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -12,7 +12,10 @@ import (
"errors"
"io"
"os"
+ "path/filepath"
+ "runtime"
"strconv"
+ "strings"
"sync"
"syscall"
)
@@ -33,7 +36,8 @@ type Cmd struct {
// Path is the path of the command to run.
//
// This is the only field that must be set to a non-zero
- // value.
+ // value. If Path is relative, it is evaluated relative
+ // to Dir.
Path string
// Args holds command line arguments, including the command as Args[0].
@@ -84,7 +88,7 @@ type Cmd struct {
// available after a call to Wait or Run.
ProcessState *os.ProcessState
- err error // last error (from LookPath, stdin, stdout, stderr)
+ lookPathErr error // LookPath error, if any.
finished bool // when Wait was called
childFiles []*os.File
closeAfterStart []io.Closer
@@ -96,8 +100,7 @@ type Cmd struct {
// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
-// It sets Path and Args in the returned structure and zeroes the
-// other fields.
+// It sets only the Path and Args in the returned structure.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
@@ -107,19 +110,22 @@ type Cmd struct {
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
- aname, err := LookPath(name)
- if err != nil {
- aname = name
- }
- return &Cmd{
- Path: aname,
+ cmd := &Cmd{
+ Path: name,
Args: append([]string{name}, arg...),
- err: err,
}
+ if filepath.Base(name) == name {
+ if lp, err := LookPath(name); err != nil {
+ cmd.lookPathErr = err
+ } else {
+ cmd.Path = lp
+ }
+ }
+ return cmd
}
// interfaceEqual protects against panics from doing equality tests on
-// two interfaces with non-comparable underlying types
+// two interfaces with non-comparable underlying types.
func interfaceEqual(a, b interface{}) bool {
defer func() {
recover()
@@ -233,12 +239,50 @@ func (c *Cmd) Run() error {
return c.Wait()
}
+// lookExtensions finds windows executable by its dir and path.
+// It uses LookPath to try appropriate extensions.
+// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
+func lookExtensions(path, dir string) (string, error) {
+ if filepath.Base(path) == path {
+ path = filepath.Join(".", path)
+ }
+ if dir == "" {
+ return LookPath(path)
+ }
+ if filepath.VolumeName(path) != "" {
+ return LookPath(path)
+ }
+ if len(path) > 1 && os.IsPathSeparator(path[0]) {
+ return LookPath(path)
+ }
+ dirandpath := filepath.Join(dir, path)
+ // We assume that LookPath will only add file extension.
+ lp, err := LookPath(dirandpath)
+ if err != nil {
+ return "", err
+ }
+ ext := strings.TrimPrefix(lp, dirandpath)
+ return path + ext, nil
+}
+
// Start starts the specified command but does not wait for it to complete.
+//
+// The Wait method will return the exit code and release associated resources
+// once the command exits.
func (c *Cmd) Start() error {
- if c.err != nil {
+ if c.lookPathErr != nil {
c.closeDescriptors(c.closeAfterStart)
c.closeDescriptors(c.closeAfterWait)
- return c.err
+ return c.lookPathErr
+ }
+ if runtime.GOOS == "windows" {
+ lp, err := lookExtensions(c.Path, c.Dir)
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+ c.Path = lp
}
if c.Process != nil {
return errors.New("exec: already started")
@@ -300,6 +344,8 @@ func (e *ExitError) Error() string {
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
+//
+// Wait releases any resources associated with the Cmd.
func (c *Cmd) Wait() error {
if c.Process == nil {
return errors.New("exec: not started")
@@ -383,15 +429,17 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
type closeOnce struct {
*os.File
- close sync.Once
- closeErr error
+ once sync.Once
+ err error
}
func (c *closeOnce) Close() error {
- c.close.Do(func() {
- c.closeErr = c.File.Close()
- })
- return c.closeErr
+ c.once.Do(c.close)
+ return c.err
+}
+
+func (c *closeOnce) close() {
+ c.err = c.File.Close()
}
// StdoutPipe returns a pipe that will be connected to the command's
diff --git a/src/pkg/os/exec/exec_test.go b/src/pkg/os/exec/exec_test.go
index c380d6506..6f77ac38a 100644
--- a/src/pkg/os/exec/exec_test.go
+++ b/src/pkg/os/exec/exec_test.go
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package exec
+// Use an external test to avoid os/exec -> net/http -> crypto/x509 -> os/exec
+// circular dependency on non-cgo darwin.
+
+package exec_test
import (
"bufio"
@@ -10,10 +13,12 @@ import (
"fmt"
"io"
"io/ioutil"
+ "log"
"net"
"net/http"
"net/http/httptest"
"os"
+ "os/exec"
"path/filepath"
"runtime"
"strconv"
@@ -22,16 +27,19 @@ import (
"time"
)
-func helperCommand(s ...string) *Cmd {
+func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
- cmd := Command(os.Args[0], cs...)
+ cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
func TestEcho(t *testing.T) {
- bs, err := helperCommand("echo", "foo bar", "baz").Output()
+ bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
if err != nil {
t.Errorf("echo: %v", err)
}
@@ -40,10 +48,37 @@ func TestEcho(t *testing.T) {
}
}
+func TestCommandRelativeName(t *testing.T) {
+ // Run our own binary as a relative path
+ // (e.g. "_test/exec.test") our parent directory.
+ base := filepath.Base(os.Args[0]) // "exec.test"
+ dir := filepath.Dir(os.Args[0]) // "/tmp/go-buildNNNN/os/exec/_test"
+ if dir == "." {
+ t.Skip("skipping; running test at root somehow")
+ }
+ parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
+ dirBase := filepath.Base(dir) // "_test"
+ if dirBase == "." {
+ t.Skipf("skipping; unexpected shallow dir of %q", dir)
+ }
+
+ cmd := exec.Command(filepath.Join(dirBase, base), "-test.run=TestHelperProcess", "--", "echo", "foo")
+ cmd.Dir = parentDir
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+
+ out, err := cmd.Output()
+ if err != nil {
+ t.Errorf("echo: %v", err)
+ }
+ if g, e := string(out), "foo\n"; g != e {
+ t.Errorf("echo: want %q, got %q", e, g)
+ }
+}
+
func TestCatStdin(t *testing.T) {
// Cat, testing stdin and stdout.
input := "Input string\nLine 2"
- p := helperCommand("cat")
+ p := helperCommand(t, "cat")
p.Stdin = strings.NewReader(input)
bs, err := p.Output()
if err != nil {
@@ -57,9 +92,9 @@ func TestCatStdin(t *testing.T) {
func TestCatGoodAndBadFile(t *testing.T) {
// Testing combined output and error values.
- bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
- if _, ok := err.(*ExitError); !ok {
- t.Errorf("expected *ExitError from cat combined; got %T: %v", err, err)
+ bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
+ if _, ok := err.(*exec.ExitError); !ok {
+ t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err)
}
s := string(bs)
sp := strings.SplitN(s, "\n", 2)
@@ -77,7 +112,7 @@ func TestCatGoodAndBadFile(t *testing.T) {
func TestNoExistBinary(t *testing.T) {
// Can't run a non-existent binary
- err := Command("/no-exist-binary").Run()
+ err := exec.Command("/no-exist-binary").Run()
if err == nil {
t.Error("expected error from /no-exist-binary")
}
@@ -85,19 +120,19 @@ func TestNoExistBinary(t *testing.T) {
func TestExitStatus(t *testing.T) {
// Test that exit values are returned correctly
- cmd := helperCommand("exit", "42")
+ cmd := helperCommand(t, "exit", "42")
err := cmd.Run()
want := "exit status 42"
switch runtime.GOOS {
case "plan9":
want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd.Path), cmd.ProcessState.Pid())
}
- if werr, ok := err.(*ExitError); ok {
+ if werr, ok := err.(*exec.ExitError); ok {
if s := werr.Error(); s != want {
t.Errorf("from exit 42 got exit %q, want %q", s, want)
}
} else {
- t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
+ t.Fatalf("expected *exec.ExitError from exit 42; got %T: %v", err, err)
}
}
@@ -108,7 +143,7 @@ func TestPipes(t *testing.T) {
}
}
// Cat, testing stdin and stdout.
- c := helperCommand("pipetest")
+ c := helperCommand(t, "pipetest")
stdin, err := c.StdinPipe()
check("StdinPipe", err)
stdout, err := c.StdoutPipe()
@@ -161,7 +196,7 @@ func TestStdinClose(t *testing.T) {
t.Fatalf("%s: %v", what, err)
}
}
- cmd := helperCommand("stdinClose")
+ cmd := helperCommand(t, "stdinClose")
stdin, err := cmd.StdinPipe()
check("StdinPipe", err)
// Check that we can access methods of the underlying os.File.`
@@ -182,9 +217,9 @@ func TestStdinClose(t *testing.T) {
// Issue 5071
func TestPipeLookPathLeak(t *testing.T) {
- fd0 := numOpenFDS(t)
+ fd0, lsof0 := numOpenFDS(t)
for i := 0; i < 4; i++ {
- cmd := Command("something-that-does-not-exist-binary")
+ cmd := exec.Command("something-that-does-not-exist-binary")
cmd.StdoutPipe()
cmd.StderrPipe()
cmd.StdinPipe()
@@ -192,19 +227,30 @@ func TestPipeLookPathLeak(t *testing.T) {
t.Fatal("unexpected success")
}
}
- fdGrowth := numOpenFDS(t) - fd0
- if fdGrowth > 2 {
- t.Errorf("leaked %d fds; want ~0", fdGrowth)
+ for triesLeft := 3; triesLeft >= 0; triesLeft-- {
+ open, lsof := numOpenFDS(t)
+ fdGrowth := open - fd0
+ if fdGrowth > 2 {
+ if triesLeft > 0 {
+ // Work around what appears to be a race with Linux's
+ // proc filesystem (as used by lsof). It seems to only
+ // be eventually consistent. Give it awhile to settle.
+ // See golang.org/issue/7808
+ time.Sleep(100 * time.Millisecond)
+ continue
+ }
+ t.Errorf("leaked %d fds; want ~0; have:\n%s\noriginally:\n%s", fdGrowth, lsof, lsof0)
+ }
+ break
}
}
-func numOpenFDS(t *testing.T) int {
- lsof, err := Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+func numOpenFDS(t *testing.T) (n int, lsof []byte) {
+ lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
if err != nil {
t.Skip("skipping test; error finding or running lsof")
- return 0
}
- return bytes.Count(lsof, []byte("\n"))
+ return bytes.Count(lsof, []byte("\n")), lsof
}
var testedAlreadyLeaked = false
@@ -270,7 +316,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
// Moving this test case around within the overall tests may
// affect the FDs obtained and hence the checks to catch these cases.
npipes := 2
- c := helperCommand("extraFilesAndPipes", strconv.Itoa(npipes+1))
+ c := helperCommand(t, "extraFilesAndPipes", strconv.Itoa(npipes+1))
rd, wr, _ := os.Pipe()
defer rd.Close()
if rd.Fd() != 3 {
@@ -370,11 +416,15 @@ func TestExtraFiles(t *testing.T) {
// Force TLS root certs to be loaded (which might involve
// cgo), to make sure none of that potential C code leaks fds.
- ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Hello"))
- }))
+ ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ // quiet expected TLS handshake error "remote error: bad certificate"
+ ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+ ts.StartTLS()
defer ts.Close()
- http.Get(ts.URL) // ignore result; just calling to force root cert loading
+ _, err = http.Get(ts.URL)
+ if err == nil {
+ t.Errorf("success trying to fetch %s; want an error", ts.URL)
+ }
tf, err := ioutil.TempFile("", "")
if err != nil {
@@ -393,7 +443,7 @@ func TestExtraFiles(t *testing.T) {
t.Fatalf("Seek: %v", err)
}
- c := helperCommand("read3")
+ c := helperCommand(t, "read3")
var stdout, stderr bytes.Buffer
c.Stdout = &stdout
c.Stderr = &stderr
@@ -425,7 +475,7 @@ func TestExtraFilesRace(t *testing.T) {
}
return f
}
- runCommand := func(c *Cmd, out chan<- string) {
+ runCommand := func(c *exec.Cmd, out chan<- string) {
bout, err := c.CombinedOutput()
if err != nil {
out <- "ERROR:" + err.Error()
@@ -436,10 +486,10 @@ func TestExtraFilesRace(t *testing.T) {
for i := 0; i < 10; i++ {
la := listen()
- ca := helperCommand("describefiles")
+ ca := helperCommand(t, "describefiles")
ca.ExtraFiles = []*os.File{listenerFile(la)}
lb := listen()
- cb := helperCommand("describefiles")
+ cb := helperCommand(t, "describefiles")
cb.ExtraFiles = []*os.File{listenerFile(lb)}
ares := make(chan string)
bres := make(chan string)
@@ -476,6 +526,8 @@ func TestHelperProcess(*testing.T) {
switch runtime.GOOS {
case "dragonfly", "freebsd", "netbsd", "openbsd":
ofcmd = "fstat"
+ case "plan9":
+ ofcmd = "/bin/cat"
}
args := os.Args
@@ -566,6 +618,14 @@ func TestHelperProcess(*testing.T) {
// the cloned file descriptors that result from opening
// /dev/urandom.
// http://golang.org/issue/3955
+ case "plan9":
+ // TODO(0intro): Determine why Plan 9 is leaking
+ // file descriptors.
+ // http://golang.org/issue/7118
+ case "solaris":
+ // TODO(aram): This fails on Solaris because libc opens
+ // its own files, as it sees fit. Darwin does the same,
+ // see: http://golang.org/issue/2603
default:
// Now verify that there are no other open fds.
var files []*os.File
@@ -577,7 +637,14 @@ func TestHelperProcess(*testing.T) {
}
if got := f.Fd(); got != wantfd {
fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
- out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+ var args []string
+ switch runtime.GOOS {
+ case "plan9":
+ args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())}
+ default:
+ args = []string{"-p", fmt.Sprint(os.Getpid())}
+ }
+ out, _ := exec.Command(ofcmd, args...).CombinedOutput()
fmt.Print(string(out))
os.Exit(1)
}
@@ -634,6 +701,24 @@ func TestHelperProcess(*testing.T) {
}
fmt.Fprintf(os.Stderr, "child: %s", response)
os.Exit(0)
+ case "exec":
+ cmd := exec.Command(args[1])
+ cmd.Dir = args[0]
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output))
+ os.Exit(1)
+ }
+ fmt.Printf("%s", string(output))
+ os.Exit(0)
+ case "lookpath":
+ p, err := exec.LookPath(args[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err)
+ os.Exit(1)
+ }
+ fmt.Print(p)
+ os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
os.Exit(2)
diff --git a/src/pkg/os/exec/lp_unix.go b/src/pkg/os/exec/lp_unix.go
index 7ff2d201b..3f895d5b3 100644
--- a/src/pkg/os/exec/lp_unix.go
+++ b/src/pkg/os/exec/lp_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package exec
diff --git a/src/pkg/os/exec/lp_unix_test.go b/src/pkg/os/exec/lp_unix_test.go
index f1ab6deff..051db664a 100644
--- a/src/pkg/os/exec/lp_unix_test.go
+++ b/src/pkg/os/exec/lp_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package exec
diff --git a/src/pkg/os/exec/lp_windows_test.go b/src/pkg/os/exec/lp_windows_test.go
index 385dd331b..72df03ed2 100644
--- a/src/pkg/os/exec/lp_windows_test.go
+++ b/src/pkg/os/exec/lp_windows_test.go
@@ -13,10 +13,48 @@ import (
"strconv"
"strings"
"testing"
- "text/template"
)
+func installExe(t *testing.T, dest, src string) {
+ fsrc, err := os.Open(src)
+ if err != nil {
+ t.Fatal("os.Open failed: ", err)
+ }
+ defer fsrc.Close()
+ fdest, err := os.Create(dest)
+ if err != nil {
+ t.Fatal("os.Create failed: ", err)
+ }
+ defer fdest.Close()
+ _, err = io.Copy(fdest, fsrc)
+ if err != nil {
+ t.Fatal("io.Copy failed: ", err)
+ }
+}
+
+func installBat(t *testing.T, dest string) {
+ f, err := os.Create(dest)
+ if err != nil {
+ t.Fatalf("failed to create batch file: %v", err)
+ }
+ defer f.Close()
+ fmt.Fprintf(f, "@echo %s\n", dest)
+}
+
+func installProg(t *testing.T, dest, srcExe string) {
+ err := os.MkdirAll(filepath.Dir(dest), 0700)
+ if err != nil {
+ t.Fatal("os.MkdirAll failed: ", err)
+ }
+ if strings.ToLower(filepath.Ext(dest)) == ".bat" {
+ installBat(t, dest)
+ return
+ }
+ installExe(t, dest, srcExe)
+}
+
type lookPathTest struct {
+ rootDir string
PATH string
PATHEXT string
files []string
@@ -24,13 +62,97 @@ type lookPathTest struct {
fails bool // test is expected to fail
}
-// PrefixPATH returns p.PATH with every element prefixed by prefix.
-func (t lookPathTest) PrefixPATH(prefix string) string {
- a := strings.SplitN(t.PATH, ";", -1)
- for i := range a {
- a[i] = filepath.Join(prefix, a[i])
+func (test lookPathTest) runProg(t *testing.T, env []string, args ...string) (string, error) {
+ cmd := Command(args[0], args[1:]...)
+ cmd.Env = env
+ cmd.Dir = test.rootDir
+ args[0] = filepath.Base(args[0])
+ cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
+ out, err := cmd.CombinedOutput()
+ if (err != nil) != test.fails {
+ if test.fails {
+ t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+ }
+ t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
+ }
+ if err != nil {
+ return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
+ }
+ // normalise program output
+ p := string(out)
+ // trim terminating \r and \n that batch file outputs
+ for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
+ p = p[:len(p)-1]
+ }
+ if !filepath.IsAbs(p) {
+ return p, nil
+ }
+ if p[:len(test.rootDir)] != test.rootDir {
+ t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, test.rootDir)
+ }
+ return p[len(test.rootDir)+1:], nil
+}
+
+func updateEnv(env []string, name, value string) []string {
+ for i, e := range env {
+ if strings.HasPrefix(strings.ToUpper(e), name+"=") {
+ env[i] = name + "=" + value
+ return env
+ }
+ }
+ return append(env, name+"="+value)
+}
+
+func createEnv(dir, PATH, PATHEXT string) []string {
+ env := os.Environ()
+ env = updateEnv(env, "PATHEXT", PATHEXT)
+ // Add dir in front of every directory in the PATH.
+ dirs := splitList(PATH)
+ for i := range dirs {
+ dirs[i] = filepath.Join(dir, dirs[i])
+ }
+ path := strings.Join(dirs, ";")
+ env = updateEnv(env, "PATH", path)
+ return env
+}
+
+// createFiles copies srcPath file into multiply files.
+// It uses dir as preifx for all destination files.
+func createFiles(t *testing.T, dir string, files []string, srcPath string) {
+ for _, f := range files {
+ installProg(t, filepath.Join(dir, f), srcPath)
+ }
+}
+
+func (test lookPathTest) run(t *testing.T, tmpdir, printpathExe string) {
+ test.rootDir = tmpdir
+ createFiles(t, test.rootDir, test.files, printpathExe)
+ env := createEnv(test.rootDir, test.PATH, test.PATHEXT)
+ // Run "cmd.exe /c test.searchFor" with new environment and
+ // work directory set. All candidates are copies of printpath.exe.
+ // These will output their program paths when run.
+ should, errCmd := test.runProg(t, env, "cmd", "/c", test.searchFor)
+ // Run the lookpath program with new environment and work directory set.
+ env = append(env, "GO_WANT_HELPER_PROCESS=1")
+ have, errLP := test.runProg(t, env, os.Args[0], "-test.run=TestHelperProcess", "--", "lookpath", test.searchFor)
+ // Compare results.
+ if errCmd == nil && errLP == nil {
+ // both succeeded
+ if should != have {
+ t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
+ }
+ return
+ }
+ if errCmd != nil && errLP != nil {
+ // both failed -> continue
+ return
+ }
+ if errCmd != nil {
+ t.Fatal(errCmd)
+ }
+ if errLP != nil {
+ t.Fatal(errLP)
}
- return strings.Join(a, ";")
}
var lookPathTests = []lookPathTest{
@@ -179,190 +301,250 @@ var lookPathTests = []lookPathTest{
},
}
-func updateEnv(env []string, name, value string) []string {
- for i, e := range env {
- if strings.HasPrefix(strings.ToUpper(e), name+"=") {
- env[i] = name + "=" + value
- return env
- }
- }
- return append(env, name+"="+value)
-}
-
-func installExe(t *testing.T, dest, src string) {
- fsrc, err := os.Open(src)
- if err != nil {
- t.Fatal("os.Open failed: ", err)
- }
- defer fsrc.Close()
- fdest, err := os.Create(dest)
+func TestLookPath(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestLookPath")
if err != nil {
- t.Fatal("os.Create failed: ", err)
+ t.Fatal("TempDir failed: ", err)
}
- defer fdest.Close()
- _, err = io.Copy(fdest, fsrc)
- if err != nil {
- t.Fatal("io.Copy failed: ", err)
+ defer os.RemoveAll(tmp)
+
+ printpathExe := buildPrintPathExe(t, tmp)
+
+ // Run all tests.
+ for i, test := range lookPathTests {
+ dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
+ err := os.Mkdir(dir, 0700)
+ if err != nil {
+ t.Fatal("Mkdir failed: ", err)
+ }
+ test.run(t, dir, printpathExe)
}
}
-func installBat(t *testing.T, dest string) {
- f, err := os.Create(dest)
- if err != nil {
- t.Fatalf("failed to create batch file: %v", err)
- }
- defer f.Close()
- fmt.Fprintf(f, "@echo %s\n", dest)
+type commandTest struct {
+ PATH string
+ files []string
+ dir string
+ arg0 string
+ want string
+ fails bool // test is expected to fail
}
-func installProg(t *testing.T, dest, srcExe string) {
- err := os.MkdirAll(filepath.Dir(dest), 0700)
+func (test commandTest) isSuccess(rootDir, output string, err error) error {
if err != nil {
- t.Fatal("os.MkdirAll failed: ", err)
+ return fmt.Errorf("test=%+v: exec: %v %v", test, err, output)
}
- if strings.ToLower(filepath.Ext(dest)) == ".bat" {
- installBat(t, dest)
- return
+ path := output
+ if path[:len(rootDir)] != rootDir {
+ return fmt.Errorf("test=%+v: %q must have %q prefix", test, path, rootDir)
}
- installExe(t, dest, srcExe)
+ path = path[len(rootDir)+1:]
+ if path != test.want {
+ return fmt.Errorf("test=%+v: want %q, got %q", test, test.want, path)
+ }
+ return nil
}
-func runProg(t *testing.T, test lookPathTest, env []string, dir string, args ...string) (string, error) {
- cmd := Command(args[0], args[1:]...)
+func (test commandTest) runOne(rootDir string, env []string, dir, arg0 string) error {
+ cmd := Command(os.Args[0], "-test.run=TestHelperProcess", "--", "exec", dir, arg0)
+ cmd.Dir = rootDir
cmd.Env = env
- cmd.Dir = dir
- args[0] = filepath.Base(args[0])
- cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
- out, err := cmd.CombinedOutput()
+ output, err := cmd.CombinedOutput()
+ err = test.isSuccess(rootDir, string(output), err)
if (err != nil) != test.fails {
if test.fails {
- t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+ return fmt.Errorf("test=%+v: succeeded, but expected to fail", test)
}
- t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
- }
- if err != nil {
- return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
- }
- // normalise program output
- p := string(out)
- // trim terminating \r and \n that batch file outputs
- for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
- p = p[:len(p)-1]
- }
- if !filepath.IsAbs(p) {
- return p, nil
- }
- if p[:len(dir)] != dir {
- t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, dir)
+ return err
}
- return p[len(dir)+1:], nil
+ return nil
}
-func testLookPath(t *testing.T, test lookPathTest, tmpdir, lookpathExe, printpathExe string) {
- // Create files listed in test.files in tmp directory.
- for i := range test.files {
- installProg(t, filepath.Join(tmpdir, test.files[i]), printpathExe)
- }
- // Create environment with test.PATH and test.PATHEXT set.
- env := os.Environ()
- env = updateEnv(env, "PATH", test.PrefixPATH(tmpdir))
- env = updateEnv(env, "PATHEXT", test.PATHEXT)
- // Run "cmd.exe /c test.searchFor" with new environment and
- // work directory set. All candidates are copies of printpath.exe.
- // These will output their program paths when run.
- should, errCmd := runProg(t, test, env, tmpdir, "cmd", "/c", test.searchFor)
- // Run the lookpath program with new environment and work directory set.
- have, errLP := runProg(t, test, env, tmpdir, lookpathExe, test.searchFor)
- // Compare results.
- if errCmd == nil && errLP == nil {
- // both succeeded
- if should != have {
- // t.Fatalf("test=%+v failed: expected to find %v, but found %v", test, should, have)
- t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
- }
- return
- }
- if errCmd != nil && errLP != nil {
- // both failed -> continue
- return
- }
- if errCmd != nil {
- t.Fatal(errCmd)
- }
- if errLP != nil {
- t.Fatal(errLP)
+func (test commandTest) run(t *testing.T, rootDir, printpathExe string) {
+ createFiles(t, rootDir, test.files, printpathExe)
+ PATHEXT := `.COM;.EXE;.BAT`
+ env := createEnv(rootDir, test.PATH, PATHEXT)
+ env = append(env, "GO_WANT_HELPER_PROCESS=1")
+ err := test.runOne(rootDir, env, test.dir, test.arg0)
+ if err != nil {
+ t.Error(err)
}
}
-func buildExe(t *testing.T, templ, dir, name string) string {
- srcname := name + ".go"
- f, err := os.Create(filepath.Join(dir, srcname))
- if err != nil {
- t.Fatalf("failed to create source: %v", err)
- }
- err = template.Must(template.New("template").Parse(templ)).Execute(f, nil)
- f.Close()
- if err != nil {
- t.Fatalf("failed to execute template: %v", err)
- }
- outname := name + ".exe"
- cmd := Command("go", "build", "-o", outname, srcname)
- cmd.Dir = dir
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf("failed to build executable: %v - %v", err, string(out))
- }
- return filepath.Join(dir, outname)
+var commandTests = []commandTest{
+ // testing commands with no slash, like `a.exe`
+ {
+ // should find a.exe in current directory
+ files: []string{`a.exe`},
+ arg0: `a.exe`,
+ want: `a.exe`,
+ },
+ {
+ // like above, but add PATH in attempt to break the test
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ arg0: `a.exe`,
+ want: `a.exe`,
+ },
+ {
+ // like above, but use "a" instead of "a.exe" for command
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ arg0: `a`,
+ want: `a.exe`,
+ },
+ // testing commands with slash, like `.\a.exe`
+ {
+ // should find p\a.exe
+ files: []string{`p\a.exe`},
+ arg0: `p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but adding `.` in front of executable should still be OK
+ files: []string{`p\a.exe`},
+ arg0: `.\p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but with PATH added in attempt to break it
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ arg0: `p\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but make sure .exe is tried even for commands with slash
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ arg0: `p\a`,
+ want: `p\a.exe`,
+ },
+ // tests commands, like `a.exe`, with c.Dir set
+ {
+ // should not find a.exe in p, becasue LookPath(`a.exe`) will fail
+ files: []string{`p\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ fails: true,
+ },
+ {
+ // LookPath(`a.exe`) will find `.\a.exe`, but prefixing that with
+ // dir `p\a.exe` will refer to not existant file
+ files: []string{`a.exe`, `p\not_important_file`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `a.exe`,
+ fails: true,
+ },
+ {
+ // like above, but making test succeed by installing file
+ // in refered destination (so LookPath(`a.exe`) will still
+ // find `.\a.exe`, but we successfully execute `p\a.exe`)
+ files: []string{`a.exe`, `p\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but add PATH in attempt to break the test
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but use "a" instead of "a.exe" for command
+ PATH: `p2;p`,
+ files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a`,
+ want: `p\a.exe`,
+ },
+ {
+ // finds `a.exe` in the PATH regardless of dir set
+ // because LookPath returns full path in that case
+ PATH: `p2;p`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `a.exe`,
+ want: `p2\a.exe`,
+ },
+ // tests commands, like `.\a.exe`, with c.Dir set
+ {
+ // should use dir when command is path, like ".\a.exe"
+ files: []string{`p\a.exe`},
+ dir: `p`,
+ arg0: `.\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but with PATH added in attempt to break it
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `.\a.exe`,
+ want: `p\a.exe`,
+ },
+ {
+ // like above, but make sure .exe is tried even for commands with slash
+ PATH: `p2`,
+ files: []string{`p\a.exe`, `p2\a.exe`},
+ dir: `p`,
+ arg0: `.\a`,
+ want: `p\a.exe`,
+ },
}
-func TestLookPath(t *testing.T) {
- tmp, err := ioutil.TempDir("", "TestLookPath")
+func TestCommand(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestCommand")
if err != nil {
t.Fatal("TempDir failed: ", err)
}
defer os.RemoveAll(tmp)
- // Create a Go program that uses LookPath to find executable passed as command line parameter.
- lookpathExe := buildExe(t, lookpathSrc, tmp, "lookpath")
-
- // Create a Go program that prints its own path.
- printpathExe := buildExe(t, printpathSrc, tmp, "printpath")
+ printpathExe := buildPrintPathExe(t, tmp)
// Run all tests.
- for i, test := range lookPathTests {
+ for i, test := range commandTests {
dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
err := os.Mkdir(dir, 0700)
if err != nil {
t.Fatal("Mkdir failed: ", err)
}
- testLookPath(t, test, dir, lookpathExe, printpathExe)
+ test.run(t, dir, printpathExe)
}
}
-const lookpathSrc = `
-package main
-
-import (
- "fmt"
- "os"
- "os/exec"
-)
-
-func main() {
- p, err := exec.LookPath(os.Args[1])
+// buildPrintPathExe creates a Go program that prints its own path.
+// dir is a temp directory where executable will be created.
+// The function returns full path to the created program.
+func buildPrintPathExe(t *testing.T, dir string) string {
+ const name = "printpath"
+ srcname := name + ".go"
+ err := ioutil.WriteFile(filepath.Join(dir, srcname), []byte(printpathSrc), 0644)
if err != nil {
- fmt.Printf("LookPath failed: %v\n", err)
- os.Exit(1)
+ t.Fatalf("failed to create source: %v", err)
+ }
+ if err != nil {
+ t.Fatalf("failed to execute template: %v", err)
+ }
+ outname := name + ".exe"
+ cmd := Command("go", "build", "-o", outname, srcname)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build executable: %v - %v", err, string(out))
}
- fmt.Print(p)
+ return filepath.Join(dir, outname)
}
-`
const printpathSrc = `
package main
import (
- "fmt"
"os"
"syscall"
"unicode/utf16"
@@ -383,9 +565,9 @@ func getMyName() (string, error) {
func main() {
path, err := getMyName()
if err != nil {
- fmt.Printf("getMyName failed: %v\n", err)
+ os.Stderr.Write([]byte("getMyName failed: " + err.Error() + "\n"))
os.Exit(1)
}
- fmt.Print(path)
+ os.Stdout.Write([]byte(path))
}
`
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 2bd5b6888..676be36ac 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
- if sig == Kill {
- // Special-case the kill signal since it doesn't use /proc/$pid/note.
- return p.Kill()
- }
if e := p.writeProcFile("note", sig.String()); e != nil {
return NewSyscallError("signal", e)
}
@@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error {
}
func (p *Process) kill() error {
- if e := p.writeProcFile("ctl", "kill"); e != nil {
- return NewSyscallError("kill", e)
- }
- return nil
+ return p.signal(Kill)
}
func (p *Process) wait() (ps *ProcessState, err error) {
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index fb123aefb..fb9d291e6 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package os
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 5572e628e..1b1e3350b 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
@@ -38,6 +38,9 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
+ if p.Pid == -1 {
+ return errors.New("os: process already released")
+ }
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index 2dd1fcf28..b4a745801 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -140,6 +140,9 @@ func (f *File) Write(b []byte) (n int, err error) {
if n < 0 {
n = 0
}
+ if n != len(b) {
+ err = io.ErrShortWrite
+ }
epipecheck(f, e)
@@ -247,3 +250,8 @@ func Create(name string) (file *File, err error) {
// lstat is overridden in tests.
var lstat = Lstat
+
+// Rename renames (moves) a file. OS-specific restrictions might apply.
+func Rename(oldpath, newpath string) error {
+ return rename(oldpath, newpath)
+}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 708163ee1..a804b8197 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -313,8 +313,33 @@ func Remove(name string) error {
return nil
}
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+// HasPrefix from the strings package.
+func hasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// Variant of LastIndex from the strings package.
+func lastIndex(s string, sep byte) int {
+ for i := len(s) - 1; i >= 0; i-- {
+ if s[i] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+func rename(oldname, newname string) error {
+ dirname := oldname[:lastIndex(oldname, '/')+1]
+ if hasPrefix(newname, dirname) {
+ newname = newname[len(dirname):]
+ } else {
+ return &LinkError{"rename", oldname, newname, ErrInvalid}
+ }
+
+ // If newname still contains slashes after removing the oldname
+ // prefix, the rename is cross-directory and must be rejected.
+ // This case is caught by d.Marshal below.
+
var d syscall.Dir
d.Null()
@@ -323,10 +348,10 @@ func Rename(oldname, newname string) error {
buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
n, err := d.Marshal(buf[:])
if err != nil {
- return &PathError{"rename", oldname, err}
+ return &LinkError{"rename", oldname, newname, err}
}
if err = syscall.Wstat(oldname, buf[:n]); err != nil {
- return &PathError{"rename", oldname, err}
+ return &LinkError{"rename", oldname, newname, err}
}
return nil
}
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index a8bef359b..b3466b15c 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package os
@@ -48,8 +48,7 @@ func Readlink(name string) (string, error) {
}
}
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+func rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
if e != nil {
return &LinkError{"rename", oldname, newname, e}
@@ -145,7 +144,7 @@ func (f *File) Truncate(size int64) error {
// of recently written data to disk.
func (f *File) Sync() (err error) {
if f == nil {
- return syscall.EINVAL
+ return ErrInvalid
}
if e := syscall.Fsync(f.fd); e != nil {
return NewSyscallError("fsync", e)
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index ff1a597e7..76168339d 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
@@ -81,12 +81,7 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec_unix.go.
- // On OS X 10.6, the O_CLOEXEC flag is not respected.
- // On OS X 10.7, the O_CLOEXEC flag works.
- // Without a cheap & reliable way to detect 10.6 vs 10.7 at
- // runtime, we just always call syscall.CloseOnExec on Darwin.
- // Once >=10.7 is prevalent, this extra call can removed.
- if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
+ if !supportsCloseOnExec {
syscall.CloseOnExec(r)
}
@@ -160,30 +155,48 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
if dirname == "" {
dirname = "."
}
- dirname += "/"
names, err := f.Readdirnames(n)
- fi = make([]FileInfo, len(names))
- for i, filename := range names {
- fip, lerr := lstat(dirname + filename)
- if lerr != nil {
- fi[i] = &fileStat{name: filename}
+ fi = make([]FileInfo, 0, len(names))
+ for _, filename := range names {
+ fip, lerr := lstat(dirname + "/" + filename)
+ if IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
continue
}
- fi[i] = fip
+ if lerr != nil {
+ return fi, lerr
+ }
+ fi = append(fi, fip)
}
return fi, err
}
+// Darwin and FreeBSD can't read or write 2GB+ at a time,
+// even on 64-bit systems. See golang.org/issue/7812.
+// Use 1GB instead of, say, 2GB-1, to keep subsequent
+// reads aligned.
+const (
+ needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
+ maxRW = 1 << 30
+)
+
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return syscall.Read(f.fd, b)
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
-// EOF is signaled by a zero count with err set to 0.
+// EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return syscall.Pread(f.fd, b, off)
}
@@ -191,13 +204,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
for {
- m, err := syscall.Write(f.fd, b)
+ bcap := b
+ if needsMaxRW && len(bcap) > maxRW {
+ bcap = bcap[:maxRW]
+ }
+ m, err := syscall.Write(f.fd, bcap)
n += m
// If the syscall wrote some data but not all (short write)
// or it returned EINTR, then assume it stopped early for
// reasons that are uninteresting to the caller, and try again.
- if 0 < m && m < len(b) || err == syscall.EINTR {
+ if 0 < m && m < len(bcap) || err == syscall.EINTR {
+ b = b[m:]
+ continue
+ }
+
+ if needsMaxRW && len(bcap) != len(b) && err == nil {
b = b[m:]
continue
}
@@ -209,6 +231,9 @@ func (f *File) write(b []byte) (n int, err error) {
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
+ if needsMaxRW && len(b) > maxRW {
+ b = b[:maxRW]
+ }
return syscall.Pwrite(f.fd, b, off)
}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index fab7de342..efe8bc03f 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -134,20 +134,19 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
if name == "" {
return nil, &PathError{"open", name, syscall.ENOENT}
}
- // TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
- r, e := openDir(name)
- if e == nil {
+ r, errf := openFile(name, flag, perm)
+ if errf == nil {
+ return r, nil
+ }
+ r, errd := openDir(name)
+ if errd == nil {
if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
r.Close()
return nil, &PathError{"open", name, syscall.EISDIR}
}
return r, nil
}
- r, e = openFile(name, flag, perm)
- if e == nil {
- return r, nil
- }
- return nil, &PathError{"open", name, e}
+ return nil, &PathError{"open", name, errf}
}
// Close closes the File, rendering it unusable for I/O.
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
index 8c5ff7fca..a72edeaee 100644
--- a/src/pkg/os/getwd.go
+++ b/src/pkg/os/getwd.go
@@ -22,7 +22,7 @@ var useSyscallwd = func(error) bool { return true }
// current directory. If the current directory can be
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
-func Getwd() (pwd string, err error) {
+func Getwd() (dir string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
@@ -39,22 +39,22 @@ func Getwd() (pwd string, err error) {
// Clumsy but widespread kludge:
// if $PWD is set and matches ".", use it.
- pwd = Getenv("PWD")
- if len(pwd) > 0 && pwd[0] == '/' {
- d, err := Stat(pwd)
+ dir = Getenv("PWD")
+ if len(dir) > 0 && dir[0] == '/' {
+ d, err := Stat(dir)
if err == nil && SameFile(dot, d) {
- return pwd, nil
+ return dir, nil
}
}
// Apply same kludge but to cached dir instead of $PWD.
getwdCache.Lock()
- pwd = getwdCache.dir
+ dir = getwdCache.dir
getwdCache.Unlock()
- if len(pwd) > 0 {
- d, err := Stat(pwd)
+ if len(dir) > 0 {
+ d, err := Stat(dir)
if err == nil && SameFile(dot, d) {
- return pwd, nil
+ return dir, nil
}
}
@@ -71,8 +71,8 @@ func Getwd() (pwd string, err error) {
// General algorithm: find name in parent
// and then find name of parent. Each iteration
- // adds /name to the beginning of pwd.
- pwd = ""
+ // adds /name to the beginning of dir.
+ dir = ""
for parent := ".."; ; parent = "../" + parent {
if len(parent) >= 1024 { // Sanity check
return "", syscall.ENAMETOOLONG
@@ -91,7 +91,7 @@ func Getwd() (pwd string, err error) {
for _, name := range names {
d, _ := Lstat(parent + "/" + name)
if SameFile(d, dot) {
- pwd = "/" + name + pwd
+ dir = "/" + name + dir
goto Found
}
}
@@ -112,8 +112,8 @@ func Getwd() (pwd string, err error) {
// Save answer as hint to avoid the expensive path next time.
getwdCache.Lock()
- getwdCache.dir = pwd
+ getwdCache.dir = dir
getwdCache.Unlock()
- return pwd, nil
+ return dir, nil
}
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 9462ebd42..16d5984e9 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -6,6 +6,7 @@ package os_test
import (
"bytes"
+ "errors"
"flag"
"fmt"
"io"
@@ -13,7 +14,9 @@ import (
. "os"
osexec "os/exec"
"path/filepath"
+ "reflect"
"runtime"
+ "sort"
"strings"
"syscall"
"testing"
@@ -382,6 +385,84 @@ func TestReaddirNValues(t *testing.T) {
}
}
+func touch(t *testing.T, name string) {
+ f, err := Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestReaddirStatFailures(t *testing.T) {
+ switch runtime.GOOS {
+ case "windows", "plan9":
+ // Windows and Plan 9 already do this correctly,
+ // but are structured with different syscalls such
+ // that they don't use Lstat, so the hook below for
+ // testing it wouldn't work.
+ t.Skipf("skipping test on %v", runtime.GOOS)
+ }
+ dir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer RemoveAll(dir)
+ touch(t, filepath.Join(dir, "good1"))
+ touch(t, filepath.Join(dir, "x")) // will disappear or have an error
+ touch(t, filepath.Join(dir, "good2"))
+ defer func() {
+ *LstatP = Lstat
+ }()
+ var xerr error // error to return for x
+ *LstatP = func(path string) (FileInfo, error) {
+ if xerr != nil && strings.HasSuffix(path, "x") {
+ return nil, xerr
+ }
+ return Lstat(path)
+ }
+ readDir := func() ([]FileInfo, error) {
+ d, err := Open(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer d.Close()
+ return d.Readdir(-1)
+ }
+ mustReadDir := func(testName string) []FileInfo {
+ fis, err := readDir()
+ if err != nil {
+ t.Fatalf("%s: Readdir: %v", testName, err)
+ }
+ return fis
+ }
+ names := func(fis []FileInfo) []string {
+ s := make([]string, len(fis))
+ for i, fi := range fis {
+ s[i] = fi.Name()
+ }
+ sort.Strings(s)
+ return s
+ }
+
+ if got, want := names(mustReadDir("inital readdir")),
+ []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("initial readdir got %q; want %q", got, want)
+ }
+
+ xerr = ErrNotExist
+ if got, want := names(mustReadDir("with x disappearing")),
+ []string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("with x disappearing, got %q; want %q", got, want)
+ }
+
+ xerr = errors.New("some real error")
+ if _, err := readDir(); err != xerr {
+ t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
+ }
+}
+
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows or Plan 9.
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
@@ -415,10 +496,10 @@ func TestHardLink(t *testing.T) {
}
}
-func TestSymLink(t *testing.T) {
- // Symlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+func TestSymlink(t *testing.T) {
+ switch runtime.GOOS {
+ case "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -478,9 +559,9 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- // Symlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ switch runtime.GOOS {
+ case "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -549,6 +630,10 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
}
func TestStartProcess(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
var dir, cmd string
var args []string
if runtime.GOOS == "windows" {
@@ -622,8 +707,10 @@ func TestFTruncate(t *testing.T) {
checkSize(t, f, 1024)
f.Truncate(0)
checkSize(t, f, 0)
- f.Write([]byte("surprise!"))
- checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ _, err := f.Write([]byte("surprise!"))
+ if err == nil {
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ }
}
func TestTruncate(t *testing.T) {
@@ -640,8 +727,10 @@ func TestTruncate(t *testing.T) {
checkSize(t, f, 1024)
Truncate(f.Name(), 0)
checkSize(t, f, 0)
- f.Write([]byte("surprise!"))
- checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ _, err := f.Write([]byte("surprise!"))
+ if err == nil {
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+ }
}
// Use TempDir() to make sure we're on a local file system,
@@ -676,13 +765,13 @@ func TestChtimes(t *testing.T) {
}
postStat := st
- /* Plan 9:
+ /* Plan 9, NaCl:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
contents are accessed; also, it is set whenever mtime is set.
*/
pat := Atime(postStat)
pmt := postStat.ModTime()
- if !pat.Before(at) && runtime.GOOS != "plan9" {
+ if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" {
t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
}
@@ -884,8 +973,9 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ switch runtime.GOOS {
+ case "windows", "plan9", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
// Check internal Hostname() against the output of /bin/hostname.
@@ -1144,6 +1234,10 @@ func TestReadAtEOF(t *testing.T) {
}
func testKillProcess(t *testing.T, processKiller func(p *Process)) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
@@ -1211,3 +1305,35 @@ func TestKillFindProcess(t *testing.T) {
}
})
}
+
+var nilFileMethodTests = []struct {
+ name string
+ f func(*File) error
+}{
+ {"Chdir", func(f *File) error { return f.Chdir() }},
+ {"Close", func(f *File) error { return f.Close() }},
+ {"Chmod", func(f *File) error { return f.Chmod(0) }},
+ {"Chown", func(f *File) error { return f.Chown(0, 0) }},
+ {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
+ {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
+ {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
+ {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
+ {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+ {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
+ {"Sync", func(f *File) error { return f.Sync() }},
+ {"Truncate", func(f *File) error { return f.Truncate(0) }},
+ {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
+ {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
+ {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
+}
+
+// Test that all File methods give ErrInvalid if the receiver is nil.
+func TestNilFileMethods(t *testing.T) {
+ for _, tt := range nilFileMethodTests {
+ var file *File
+ got := tt.f(file)
+ if got != ErrInvalid {
+ t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
+ }
+ }
+}
diff --git a/src/pkg/os/os_unix_test.go b/src/pkg/os/os_unix_test.go
index b0fc0256d..21d40ccaf 100644
--- a/src/pkg/os/os_unix_test.go
+++ b/src/pkg/os/os_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
@@ -74,41 +74,3 @@ func TestChown(t *testing.T) {
checkUidGid(t, f.Name(), int(sys.Uid), gid)
}
}
-
-func TestReaddirWithBadLstat(t *testing.T) {
- handle, err := Open(sfdir)
- failfile := sfdir + "/" + sfname
- if err != nil {
- t.Fatalf("Couldn't open %s: %s", sfdir, err)
- }
-
- *LstatP = func(file string) (FileInfo, error) {
- if file == failfile {
- var fi FileInfo
- return fi, ErrInvalid
- }
- return Lstat(file)
- }
- defer func() { *LstatP = Lstat }()
-
- dirs, err := handle.Readdir(-1)
- if err != nil {
- t.Fatalf("Expected Readdir to return no error, got %v", err)
- }
- foundfail := false
- for _, dir := range dirs {
- if dir.Name() == sfname {
- foundfail = true
- if dir.Sys() != nil {
- t.Errorf("Expected Readdir for %s should not contain Sys", failfile)
- }
- } else {
- if dir.Sys() == nil {
- t.Errorf("Readdir for every file other than %s should contain Sys, but %s/%s didn't either", failfile, sfdir, dir.Name())
- }
- }
- }
- if !foundfail {
- t.Fatalf("Expected %s from Readdir, but didn't find it", failfile)
- }
-}
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index 27abf5982..3af21cde9 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -167,8 +167,9 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- t.Skip("Skipping test: symlinks don't exist under Windows/Plan 9")
+ switch runtime.GOOS {
+ case "nacl", "plan9", "windows":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
index 3bf63bf80..0211107dd 100644
--- a/src/pkg/os/path_unix.go
+++ b/src/pkg/os/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
diff --git a/src/pkg/os/pipe_bsd.go b/src/pkg/os/pipe_bsd.go
index 73d35b4d5..3b81ed20f 100644
--- a/src/pkg/os/pipe_bsd.go
+++ b/src/pkg/os/pipe_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
package os
diff --git a/src/pkg/os/signal/example_test.go b/src/pkg/os/signal/example_test.go
index 600ed315d..079ee5070 100644
--- a/src/pkg/os/signal/example_test.go
+++ b/src/pkg/os/signal/example_test.go
@@ -1,3 +1,7 @@
+// 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 signal_test
import (
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
index 888823cf4..f860924aa 100644
--- a/src/pkg/os/signal/sig.s
+++ b/src/pkg/os/signal/sig.s
@@ -4,7 +4,7 @@
// Assembly to get into package runtime without using exported symbols.
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
#include "../../../cmd/ld/textflag.h"
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index 741f2a0ed..076fe3f93 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/os/signal/signal_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package signal
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
index 318488dc0..94b8ab3dd 100644
--- a/src/pkg/os/signal/signal_unix.go
+++ b/src/pkg/os/signal/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package signal
diff --git a/src/pkg/os/signal/signal_windows_test.go b/src/pkg/os/signal/signal_windows_test.go
index 26712f35b..f3e6706b7 100644
--- a/src/pkg/os/signal/signal_windows_test.go
+++ b/src/pkg/os/signal/signal_windows_test.go
@@ -6,6 +6,7 @@ package signal
import (
"bytes"
+ "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -55,9 +56,15 @@ func main() {
}
}
`
- name := filepath.Join(os.TempDir(), "ctlbreak")
+ tmp, err := ioutil.TempDir("", "TestCtrlBreak")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ // write ctrlbreak.go
+ name := filepath.Join(tmp, "ctlbreak")
src := name + ".go"
- defer os.Remove(src)
f, err := os.Create(src)
if err != nil {
t.Fatalf("Failed to create %v: %v", src, err)
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
new file mode 100644
index 000000000..a503b59fa
--- /dev/null
+++ b/src/pkg/os/stat_nacl.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ stat1 := fs1.sys.(*syscall.Stat_t)
+ stat2 := fs2.sys.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtime, st.MtimeNsec),
+ sys: st,
+ }
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(sec, nsec int64) time.Time {
+ return time.Unix(sec, nsec)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ st := fi.Sys().(*syscall.Stat_t)
+ return timespecToTime(st.Atime, st.AtimeNsec)
+}
diff --git a/src/pkg/os/stat_solaris.go b/src/pkg/os/stat_solaris.go
new file mode 100644
index 000000000..605c1d9b6
--- /dev/null
+++ b/src/pkg/os/stat_solaris.go
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ stat1 := fs1.sys.(*syscall.Stat_t)
+ stat2 := fs2.sys.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtim),
+ sys: st,
+ }
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
+}
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
index 9ad2f8546..8ad5e2183 100644
--- a/src/pkg/os/sys_bsd.go
+++ b/src/pkg/os/sys_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
// os code shared between *BSD systems including OS X (Darwin)
// and FreeBSD.
diff --git a/src/pkg/os/sys_darwin.go b/src/pkg/os/sys_darwin.go
new file mode 100644
index 000000000..7a8330abb
--- /dev/null
+++ b/src/pkg/os/sys_darwin.go
@@ -0,0 +1,31 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+ // Seems like kern.osreldate is veiled on latest OS X. We use
+ // kern.osrelease instead.
+ osver, err := syscall.Sysctl("kern.osrelease")
+ if err != nil {
+ return
+ }
+ var i int
+ for i = range osver {
+ if osver[i] != '.' {
+ continue
+ }
+ }
+ // The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin
+ // 11.0.0). See http://support.apple.com/kb/HT1633.
+ if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
+ supportsCloseOnExec = true
+ }
+}
diff --git a/src/pkg/os/sys_freebsd.go b/src/pkg/os/sys_freebsd.go
new file mode 100644
index 000000000..273c2df1c
--- /dev/null
+++ b/src/pkg/os/sys_freebsd.go
@@ -0,0 +1,23 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+ osrel, err := syscall.SysctlUint32("kern.osreldate")
+ if err != nil {
+ return
+ }
+ // The O_CLOEXEC flag was introduced in FreeBSD 8.3.
+ // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+ if osrel >= 803000 {
+ supportsCloseOnExec = true
+ }
+}
diff --git a/src/pkg/os/sys_nacl.go b/src/pkg/os/sys_nacl.go
new file mode 100644
index 000000000..07907c847
--- /dev/null
+++ b/src/pkg/os/sys_nacl.go
@@ -0,0 +1,9 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = false
diff --git a/src/pkg/os/sys_solaris.go b/src/pkg/os/sys_solaris.go
new file mode 100644
index 000000000..917e8f2b0
--- /dev/null
+++ b/src/pkg/os/sys_solaris.go
@@ -0,0 +1,11 @@
+// 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 os
+
+import "syscall"
+
+func hostname() (name string, err error) {
+ return syscall.Gethostname()
+}
diff --git a/src/pkg/os/sys_unix.go b/src/pkg/os/sys_unix.go
new file mode 100644
index 000000000..39c20dc73
--- /dev/null
+++ b/src/pkg/os/sys_unix.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly linux netbsd openbsd solaris
+
+package os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = true
diff --git a/src/pkg/os/user/lookup_unix.go b/src/pkg/os/user/lookup_unix.go
index 5459268fa..f2baf05bb 100644
--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/os/user/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// +build cgo
package user
diff --git a/src/pkg/path/filepath/export_test.go b/src/pkg/path/filepath/export_test.go
new file mode 100644
index 000000000..0cf9e3bca
--- /dev/null
+++ b/src/pkg/path/filepath/export_test.go
@@ -0,0 +1,7 @@
+// 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 filepath
+
+var LstatP = &lstat
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 3d84145d7..a9bcc103c 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -230,7 +230,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
//
func Glob(pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
- if _, err = os.Stat(pattern); err != nil {
+ if _, err = os.Lstat(pattern); err != nil {
return nil, nil
}
return []string{pattern}, nil
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
index 13108ce1e..382692eaa 100644
--- a/src/pkg/path/filepath/match_test.go
+++ b/src/pkg/path/filepath/match_test.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package filepath
+package filepath_test
import (
+ "io/ioutil"
+ "os"
+ . "path/filepath"
"runtime"
"strings"
"testing"
@@ -153,3 +156,51 @@ func TestGlobError(t *testing.T) {
t.Error("expected error for bad pattern; got none")
}
}
+
+var globSymlinkTests = []struct {
+ path, dest string
+ brokenLink bool
+}{
+ {"test1", "link1", false},
+ {"test2", "link2", true},
+}
+
+func TestGlobSymlink(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9", "windows":
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
+
+ tmpDir, err := ioutil.TempDir("", "globsymlink")
+ if err != nil {
+ t.Fatal("creating temp dir:", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ for _, tt := range globSymlinkTests {
+ path := Join(tmpDir, tt.path)
+ dest := Join(tmpDir, tt.dest)
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+ err = os.Symlink(path, dest)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if tt.brokenLink {
+ // Break the symlink.
+ os.Remove(path)
+ }
+ matches, err := Glob(dest)
+ if err != nil {
+ t.Errorf("GlobSymlink error for %q: %s", dest, err)
+ }
+ if !contains(matches, dest) {
+ t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest)
+ }
+ }
+}
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index f8c7e4b2f..71603cc59 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -67,7 +67,7 @@ const (
// along with the non-.. element that precedes it.
// 4. Eliminate .. elements that begin a rooted path:
// that is, replace "/.." by "/" at the beginning of a path,
-// assuming Separator is '/'.
+// assuming Separator is '/'.
//
// The returned path ends in a slash only if it represents a root directory,
// such as "/" on Unix or `C:\` on Windows.
@@ -336,6 +336,8 @@ var SkipDir = errors.New("skip this directory")
// the next file.
type WalkFunc func(path string, info os.FileInfo, err error) error
+var lstat = os.Lstat // for testing
+
// walk recursively descends path, calling w.
func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
err := walkFn(path, info, nil)
@@ -350,17 +352,25 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
return nil
}
- list, err := readDir(path)
+ names, err := readDirNames(path)
if err != nil {
return walkFn(path, info, err)
}
- for _, fileInfo := range list {
- err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn)
+ for _, name := range names {
+ filename := Join(path, name)
+ fileInfo, err := lstat(filename)
if err != nil {
- if !fileInfo.IsDir() || err != SkipDir {
+ if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
return err
}
+ } else {
+ err = walk(filename, fileInfo, walkFn)
+ if err != nil {
+ if !fileInfo.IsDir() || err != SkipDir {
+ return err
+ }
+ }
}
}
return nil
@@ -380,30 +390,22 @@ func Walk(root string, walkFn WalkFunc) error {
return walk(root, info, walkFn)
}
-// readDir reads the directory named by dirname and returns
+// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entries.
-// Copied from io/ioutil to avoid the circular import.
-func readDir(dirname string) ([]os.FileInfo, error) {
+func readDirNames(dirname string) ([]string, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
}
- list, err := f.Readdir(-1)
+ names, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return nil, err
}
- sort.Sort(byName(list))
- return list, nil
+ sort.Strings(names)
+ return names, nil
}
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path is empty, Base returns ".".
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index d32b70d6e..819bd217c 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -5,6 +5,7 @@
package filepath_test
import (
+ "errors"
"io/ioutil"
"os"
"path/filepath"
@@ -458,6 +459,63 @@ func TestWalk(t *testing.T) {
}
}
+func touch(t *testing.T, name string) {
+ f, err := os.Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestWalkFileError(t *testing.T) {
+ td, err := ioutil.TempDir("", "walktest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(td)
+
+ touch(t, filepath.Join(td, "foo"))
+ touch(t, filepath.Join(td, "bar"))
+ dir := filepath.Join(td, "dir")
+ if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
+ t.Fatal(err)
+ }
+ touch(t, filepath.Join(dir, "baz"))
+ touch(t, filepath.Join(dir, "stat-error"))
+ defer func() {
+ *filepath.LstatP = os.Lstat
+ }()
+ statErr := errors.New("some stat error")
+ *filepath.LstatP = func(path string) (os.FileInfo, error) {
+ if strings.HasSuffix(path, "stat-error") {
+ return nil, statErr
+ }
+ return os.Lstat(path)
+ }
+ got := map[string]error{}
+ err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error {
+ rel, _ := filepath.Rel(td, path)
+ got[filepath.ToSlash(rel)] = err
+ return nil
+ })
+ if err != nil {
+ t.Errorf("Walk error: %v", err)
+ }
+ want := map[string]error{
+ ".": nil,
+ "foo": nil,
+ "bar": nil,
+ "dir": nil,
+ "dir/baz": nil,
+ "dir/stat-error": statErr,
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("Walked %#v; want %#v", got, want)
+ }
+}
+
var basetests = []PathTest{
{"", "."},
{".", "."},
@@ -633,8 +691,9 @@ func simpleJoin(dir, path string) string {
}
func TestEvalSymlinks(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("Skipping test: symlinks don't exist under Plan 9")
+ switch runtime.GOOS {
+ case "nacl", "plan9":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
tmpDir, err := ioutil.TempDir("", "evalsymlink")
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index d927b342b..7aba0ab5b 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/path/filepath/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package filepath
diff --git a/src/pkg/path/filepath/path_windows_test.go b/src/pkg/path/filepath/path_windows_test.go
index d8926adde..8a9be8e89 100644
--- a/src/pkg/path/filepath/path_windows_test.go
+++ b/src/pkg/path/filepath/path_windows_test.go
@@ -1,3 +1,7 @@
+// 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 filepath_test
import (
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index e9a20963f..e9949012c 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -15,6 +15,7 @@ import (
. "reflect"
"runtime"
"sort"
+ "strings"
"sync"
"testing"
"time"
@@ -678,6 +679,7 @@ var deepEqualTests = []DeepEqualTest{
{1, nil, false},
{fn1, fn3, false},
{fn3, fn3, false},
+ {[][]int{[]int{1}}, [][]int{[]int{2}}, false},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
@@ -971,6 +973,31 @@ func TestMap(t *testing.T) {
}
}
+func TestNilMap(t *testing.T) {
+ var m map[string]int
+ mv := ValueOf(m)
+ keys := mv.MapKeys()
+ if len(keys) != 0 {
+ t.Errorf(">0 keys for nil map: %v", keys)
+ }
+
+ // Check that value for missing key is zero.
+ x := mv.MapIndex(ValueOf("hello"))
+ if x.Kind() != Invalid {
+ t.Errorf("m.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+ }
+
+ // Check big value too.
+ var mbig map[string][10 << 20]byte
+ x = ValueOf(mbig).MapIndex(ValueOf("hello"))
+ if x.Kind() != Invalid {
+ t.Errorf("mbig.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+ }
+
+ // Test that deletes from a nil map succeed.
+ mv.SetMapIndex(ValueOf("hi"), Value{})
+}
+
func TestChan(t *testing.T) {
for loop := 0; loop < 2; loop++ {
var c chan int
@@ -1434,6 +1461,46 @@ func TestFunc(t *testing.T) {
}
}
+type emptyStruct struct{}
+
+type nonEmptyStruct struct {
+ member int
+}
+
+func returnEmpty() emptyStruct {
+ return emptyStruct{}
+}
+
+func takesEmpty(e emptyStruct) {
+}
+
+func returnNonEmpty(i int) nonEmptyStruct {
+ return nonEmptyStruct{member: i}
+}
+
+func takesNonEmpty(n nonEmptyStruct) int {
+ return n.member
+}
+
+func TestCallWithStruct(t *testing.T) {
+ r := ValueOf(returnEmpty).Call(nil)
+ if len(r) != 1 || r[0].Type() != TypeOf(emptyStruct{}) {
+ t.Errorf("returning empty struct returned %#v instead", r)
+ }
+ r = ValueOf(takesEmpty).Call([]Value{ValueOf(emptyStruct{})})
+ if len(r) != 0 {
+ t.Errorf("takesEmpty returned values: %#v", r)
+ }
+ r = ValueOf(returnNonEmpty).Call([]Value{ValueOf(42)})
+ if len(r) != 1 || r[0].Type() != TypeOf(nonEmptyStruct{}) || r[0].Field(0).Int() != 42 {
+ t.Errorf("returnNonEmpty returned %#v", r)
+ }
+ r = ValueOf(takesNonEmpty).Call([]Value{ValueOf(nonEmptyStruct{member: 42})})
+ if len(r) != 1 || r[0].Type() != TypeOf(1) || r[0].Int() != 42 {
+ t.Errorf("takesNonEmpty returned %#v", r)
+ }
+}
+
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -1470,6 +1537,23 @@ func TestMakeFuncInterface(t *testing.T) {
}
}
+func TestMakeFuncVariadic(t *testing.T) {
+ // Test that variadic arguments are packed into a slice and passed as last arg
+ fn := func(_ int, is ...int) []int { return nil }
+ fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
+ ValueOf(&fn).Elem().Set(fv)
+
+ r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+
+ r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int)
+ if r[0] != 2 || r[1] != 3 {
+ t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+ }
+}
+
type Point struct {
x, y int
}
@@ -3616,3 +3700,142 @@ func (x *exhaustive) Choose(max int) int {
func (x *exhaustive) Maybe() bool {
return x.Choose(2) == 1
}
+
+func GCFunc(args []Value) []Value {
+ runtime.GC()
+ return []Value{}
+}
+
+func TestReflectFuncTraceback(t *testing.T) {
+ f := MakeFunc(TypeOf(func() {}), GCFunc)
+ f.Call([]Value{})
+}
+
+func (p Point) GCMethod(k int) int {
+ runtime.GC()
+ return k + p.x
+}
+
+func TestReflectMethodTraceback(t *testing.T) {
+ p := Point{3, 4}
+ m := ValueOf(p).MethodByName("GCMethod")
+ i := ValueOf(m.Interface()).Call([]Value{ValueOf(5)})[0].Int()
+ if i != 8 {
+ t.Errorf("Call returned %d; want 8", i)
+ }
+}
+
+func TestBigZero(t *testing.T) {
+ const size = 1 << 10
+ var v [size]byte
+ z := Zero(ValueOf(v).Type()).Interface().([size]byte)
+ for i := 0; i < size; i++ {
+ if z[i] != 0 {
+ t.Fatalf("Zero object not all zero, index %d", i)
+ }
+ }
+}
+
+func TestFieldByIndexNil(t *testing.T) {
+ type P struct {
+ F int
+ }
+ type T struct {
+ *P
+ }
+ v := ValueOf(T{})
+
+ v.FieldByName("P") // should be fine
+
+ defer func() {
+ if err := recover(); err == nil {
+ t.Fatalf("no error")
+ } else if !strings.Contains(fmt.Sprint(err), "nil pointer to embedded struct") {
+ t.Fatalf(`err=%q, wanted error containing "nil pointer to embedded struct"`, err)
+ }
+ }()
+ v.FieldByName("F") // should panic
+
+ t.Fatalf("did not panic")
+}
+
+// Given
+// type Outer struct {
+// *Inner
+// ...
+// }
+// the compiler generates the implementation of (*Outer).M dispatching to the embedded Inner.
+// The implementation is logically:
+// func (p *Outer) M() {
+// (p.Inner).M()
+// }
+// but since the only change here is the replacement of one pointer receiver with another,
+// the actual generated code overwrites the original receiver with the p.Inner pointer and
+// then jumps to the M method expecting the *Inner receiver.
+//
+// During reflect.Value.Call, we create an argument frame and the associated data structures
+// to describe it to the garbage collector, populate the frame, call reflect.call to
+// run a function call using that frame, and then copy the results back out of the frame.
+// The reflect.call function does a memmove of the frame structure onto the
+// stack (to set up the inputs), runs the call, and the memmoves the stack back to
+// the frame structure (to preserve the outputs).
+//
+// Originally reflect.call did not distinguish inputs from outputs: both memmoves
+// were for the full stack frame. However, in the case where the called function was
+// one of these wrappers, the rewritten receiver is almost certainly a different type
+// than the original receiver. This is not a problem on the stack, where we use the
+// program counter to determine the type information and understand that
+// during (*Outer).M the receiver is an *Outer while during (*Inner).M the receiver in the same
+// memory word is now an *Inner. But in the statically typed argument frame created
+// by reflect, the receiver is always an *Outer. Copying the modified receiver pointer
+// off the stack into the frame will store an *Inner there, and then if a garbage collection
+// happens to scan that argument frame before it is discarded, it will scan the *Inner
+// memory as if it were an *Outer. If the two have different memory layouts, the
+// collection will intepret the memory incorrectly.
+//
+// One such possible incorrect interpretation is to treat two arbitrary memory words
+// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
+// an interface requires dereferencing the itab word, the misinterpretation will try to
+// deference Inner.P1, causing a crash during garbage collection.
+//
+// This came up in a real program in issue 7725.
+
+type Outer struct {
+ *Inner
+ R io.Reader
+}
+
+type Inner struct {
+ X *Outer
+ P1 uintptr
+ P2 uintptr
+}
+
+func (pi *Inner) M() {
+ // Clear references to pi so that the only way the
+ // garbage collection will find the pointer is in the
+ // argument frame, typed as a *Outer.
+ pi.X.Inner = nil
+
+ // Set up an interface value that will cause a crash.
+ // P1 = 1 is a non-zero, so the interface looks non-nil.
+ // P2 = pi ensures that the data word points into the
+ // allocated heap; if not the collection skips the interface
+ // value as irrelevant, without dereferencing P1.
+ pi.P1 = 1
+ pi.P2 = uintptr(unsafe.Pointer(pi))
+}
+
+func TestCallMethodJump(t *testing.T) {
+ // In reflect.Value.Call, trigger a garbage collection after reflect.call
+ // returns but before the args frame has been discarded.
+ // This is a little clumsy but makes the failure repeatable.
+ *CallGC = true
+
+ p := &Outer{Inner: new(Inner)}
+ p.Inner.X = p
+ ValueOf(p).Method(0).Call(nil)
+
+ // Stop garbage collecting during reflect.call.
+ *CallGC = false
+}
diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s
new file mode 100644
index 000000000..75413c752
--- /dev/null
+++ b/src/pkg/reflect/asm_amd64p32.s
@@ -0,0 +1,27 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+ MOVL DX, 0(SP)
+ LEAL argframe+0(FP), CX
+ MOVL CX, 4(SP)
+ CALL ·callReflect(SB)
+ RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+ MOVL DX, 0(SP)
+ LEAL argframe+0(FP), CX
+ MOVL CX, 4(SP)
+ CALL ·callMethod(SB)
+ RET
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index e3bf3dcac..f63715c9a 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -62,9 +62,6 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
switch v1.Kind() {
case Array:
- if v1.Len() != v2.Len() {
- return false
- }
for i := 0; i < v1.Len(); i++ {
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
return false
diff --git a/src/pkg/reflect/export_test.go b/src/pkg/reflect/export_test.go
index cd8cf2cf2..0778ad37f 100644
--- a/src/pkg/reflect/export_test.go
+++ b/src/pkg/reflect/export_test.go
@@ -16,3 +16,4 @@ func IsRO(v Value) bool {
}
var ArrayOf = arrayOf
+var CallGC = &callGC
diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go
index e1608ea6c..0e61fdea7 100644
--- a/src/pkg/reflect/makefunc.go
+++ b/src/pkg/reflect/makefunc.go
@@ -56,7 +56,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
- return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
+ return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift}
}
// makeFuncStub is an assembly function that is the code half of
@@ -81,13 +81,13 @@ type methodValue struct {
// by code like Convert and Interface and Assign.
func makeMethodValue(op string, v Value) Value {
if v.flag&flagMethod == 0 {
- panic("reflect: internal error: invalid use of makePartialFunc")
+ panic("reflect: internal error: invalid use of makeMethodValue")
}
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(v.typ.Kind()) << flagKindShift
- rcvr := Value{v.typ, v.val, fl}
+ rcvr := Value{v.typ, v.ptr, v.scalar, fl}
// v.Type returns the actual type of the method value.
funcType := v.Type().(*rtype)
@@ -109,7 +109,7 @@ func makeMethodValue(op string, v Value) Value {
// but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method)
- return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+ return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift}
}
// methodValueCall is an assembly function that is the code half of
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 7afb7defe..40d76f99d 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,6 +16,7 @@
package reflect
import (
+ "runtime"
"strconv"
"sync"
"unsafe"
@@ -252,6 +253,7 @@ type rtype struct {
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
+ zero unsafe.Pointer // pointer to zero value
}
// Method on non-interface type
@@ -477,6 +479,8 @@ func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
+func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
+
func (t *rtype) common() *rtype { return t }
func (t *uncommonType) Method(i int) (m Method) {
@@ -495,7 +499,7 @@ func (t *uncommonType) Method(i int) (m Method) {
mt := p.typ
m.Type = mt
fn := unsafe.Pointer(&p.tfn)
- m.Func = Value{mt, fn, fl}
+ m.Func = Value{mt, fn, 0, fl}
m.Index = i
return
}
@@ -1089,6 +1093,7 @@ func (t *rtype) ptrTo() *rtype {
p.uncommonType = nil
p.ptrToThis = nil
+ p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
if t.kind&kindNoPointers != 0 {
@@ -1475,6 +1480,7 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.elem = typ
ch.uncommonType = nil
ch.ptrToThis = nil
+ ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
ch.gc = unsafe.Pointer(&chanGC{
width: ch.size,
@@ -1534,6 +1540,14 @@ func MapOf(key, elem Type) Type {
mt.hmap = hMapOf(mt.bucket)
mt.uncommonType = nil
mt.ptrToThis = nil
+ mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
+ mt.gc = unsafe.Pointer(&ptrGC{
+ width: unsafe.Sizeof(uintptr(0)),
+ op: _GC_PTR,
+ off: 0,
+ elemgc: mt.hmap.gc,
+ end: _GC_END,
+ })
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
@@ -1566,6 +1580,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
offset += ptrsize
+ if runtime.GOARCH == "amd64p32" {
+ offset += 4
+ }
+
// keys
if ktyp.kind&kindNoPointers == 0 {
gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
@@ -1709,6 +1727,7 @@ func SliceOf(t Type) Type {
slice.elem = typ
slice.uncommonType = nil
slice.ptrToThis = nil
+ slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
if typ.size == 0 {
slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
@@ -1778,6 +1797,7 @@ func arrayOf(count int, elem Type) Type {
// TODO: array.gc
array.uncommonType = nil
array.ptrToThis = nil
+ array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -1795,3 +1815,112 @@ func toType(t *rtype) Type {
}
return t
}
+
+type layoutKey struct {
+ t *rtype // function signature
+ rcvr *rtype // receiver type, or nil if none
+}
+
+type layoutType struct {
+ t *rtype
+ argSize uintptr // size of arguments
+ retOffset uintptr // offset of return values.
+}
+
+var layoutCache struct {
+ sync.RWMutex
+ m map[layoutKey]layoutType
+}
+
+// funcLayout computes a struct type representing the layout of the
+// function arguments and return values for the function type t.
+// If rcvr != nil, rcvr specifies the type of the receiver.
+// The returned type exists only for GC, so we only fill out GC relevant info.
+// Currently, that's just size and the GC program. We also fill in
+// the name for possible debugging use.
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
+ if t.Kind() != Func {
+ panic("reflect: funcLayout of non-func type")
+ }
+ if rcvr != nil && rcvr.Kind() == Interface {
+ panic("reflect: funcLayout with interface receiver " + rcvr.String())
+ }
+ k := layoutKey{t, rcvr}
+ layoutCache.RLock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.RUnlock()
+ return x.t, x.argSize, x.retOffset
+ }
+ layoutCache.RUnlock()
+ layoutCache.Lock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.Unlock()
+ return x.t, x.argSize, x.retOffset
+ }
+
+ tt := (*funcType)(unsafe.Pointer(t))
+
+ // compute gc program for arguments
+ gc := make([]uintptr, 1) // first entry is size, filled in at the end
+ offset := uintptr(0)
+ if rcvr != nil {
+ // Reflect uses the "interface" calling convention for
+ // methods, where receivers take one word of argument
+ // space no matter how big they actually are.
+ if rcvr.size > ptrSize {
+ // we pass a pointer to the receiver.
+ gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc))
+ } else if rcvr.pointers() {
+ // rcvr is a one-word pointer object. Its gc program
+ // is just what we need here.
+ gc = appendGCProgram(gc, rcvr)
+ }
+ offset += ptrSize
+ }
+ for _, arg := range tt.in {
+ offset = align(offset, uintptr(arg.align))
+ if arg.pointers() {
+ gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc))
+ }
+ offset += arg.size
+ }
+ argSize = offset
+ if runtime.GOARCH == "amd64p32" {
+ offset = align(offset, 8)
+ }
+ offset = align(offset, ptrSize)
+ retOffset = offset
+ for _, res := range tt.out {
+ offset = align(offset, uintptr(res.align))
+ if res.pointers() {
+ gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc))
+ }
+ offset += res.size
+ }
+ gc = append(gc, _GC_END)
+ gc[0] = offset
+
+ // build dummy rtype holding gc program
+ x := new(rtype)
+ x.size = offset
+ x.gc = unsafe.Pointer(&gc[0])
+ var s string
+ if rcvr != nil {
+ s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+ } else {
+ s = "funcargs(" + *t.string + ")"
+ }
+ x.string = &s
+
+ // cache result for future callers
+ if layoutCache.m == nil {
+ layoutCache.m = make(map[layoutKey]layoutType)
+ }
+ layoutCache.m[k] = layoutType{
+ t: x,
+ argSize: argSize,
+ retOffset: retOffset,
+ }
+ layoutCache.Unlock()
+ return x, argSize, retOffset
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index df549f5e1..576cbc398 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -62,14 +62,15 @@ type Value struct {
// typ holds the type of the value represented by a Value.
typ *rtype
- // val holds the 1-word representation of the value.
- // If flag's flagIndir bit is set, then val is a pointer to the data.
- // Otherwise val is a word holding the actual data.
- // When the data is smaller than a word, it begins at
- // the first byte (in the memory address sense) of val.
- // We use unsafe.Pointer so that the garbage collector
- // knows that val could be a pointer.
- val unsafe.Pointer
+ // Pointer-valued data or, if flagIndir is set, pointer to data.
+ // Valid when either flagIndir is set or typ.pointers() is true.
+ ptr unsafe.Pointer
+
+ // Non-pointer-valued data. When the data is smaller
+ // than a word, it begins at the first byte (in the memory
+ // address sense) of this field.
+ // Valid when flagIndir is not set and typ.pointers() is false.
+ scalar uintptr
// flag holds metadata about the value.
// The lowest bits are flag bits:
@@ -108,6 +109,78 @@ func (f flag) kind() Kind {
return Kind((f >> flagKindShift) & flagKindMask)
}
+// pointer returns the underlying pointer represented by v.
+// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+func (v Value) pointer() unsafe.Pointer {
+ if v.typ.size != ptrSize || !v.typ.pointers() {
+ panic("can't call pointer on a non-pointer Value")
+ }
+ if v.flag&flagIndir != 0 {
+ return *(*unsafe.Pointer)(v.ptr)
+ }
+ return v.ptr
+}
+
+// packEface converts v to the empty interface.
+func packEface(v Value) interface{} {
+ t := v.typ
+ var i interface{}
+ e := (*emptyInterface)(unsafe.Pointer(&i))
+ // First, fill in the data portion of the interface.
+ switch {
+ case t.size > ptrSize:
+ // Value is indirect, and so is the interface we're making.
+ ptr := v.ptr
+ if v.flag&flagAddr != 0 {
+ // TODO: pass safe boolean from valueInterface so
+ // we don't need to copy if safe==true?
+ c := unsafe_New(t)
+ memmove(c, ptr, t.size)
+ ptr = c
+ }
+ e.word = iword(ptr)
+ case v.flag&flagIndir != 0:
+ // Value is indirect, but interface is direct. We need
+ // to load the data at v.ptr into the interface data word.
+ if t.pointers() {
+ e.word = iword(*(*unsafe.Pointer)(v.ptr))
+ } else {
+ e.word = iword(loadScalar(v.ptr, t.size))
+ }
+ default:
+ // Value is direct, and so is the interface.
+ if t.pointers() {
+ e.word = iword(v.ptr)
+ } else {
+ e.word = iword(v.scalar)
+ }
+ }
+ // Now, fill in the type portion. We're very careful here not
+ // to have any operation between the e.word and e.typ assignments
+ // that would let the garbage collector observe the partially-built
+ // interface value.
+ e.typ = t
+ return i
+}
+
+// unpackEface converts the empty interface i to a Value.
+func unpackEface(i interface{}) Value {
+ e := (*emptyInterface)(unsafe.Pointer(&i))
+ // NOTE: don't read e.word until we know whether it is really a pointer or not.
+ t := e.typ
+ if t == nil {
+ return Value{}
+ }
+ f := flag(t.Kind()) << flagKindShift
+ if t.size > ptrSize {
+ return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
+ }
+ if t.pointers() {
+ return Value{t, unsafe.Pointer(e.word), 0, f}
+ }
+ return Value{t, nil, uintptr(e.word), f}
+}
+
// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
@@ -139,28 +212,21 @@ func methodName() string {
// bigger than a pointer, its word is a pointer to v's data.
// Otherwise, its word holds the data stored
// in its leading bytes (so is not a pointer).
-// Because the value sometimes holds a pointer, we use
-// unsafe.Pointer to represent it, so that if iword appears
-// in a struct, the garbage collector knows that might be
-// a pointer.
+// This type is very dangerous for the garbage collector because
+// it must be treated conservatively. We try to never expose it
+// to the GC here so that GC remains precise.
type iword unsafe.Pointer
-func (v Value) iword() iword {
- if v.flag&flagIndir != 0 && v.typ.size <= ptrSize {
- // Have indirect but want direct word.
- return loadIword(v.val, v.typ.size)
- }
- return iword(v.val)
-}
-
-// loadIword loads n bytes at p from memory into an iword.
-func loadIword(p unsafe.Pointer, n uintptr) iword {
+// loadScalar loads n bytes at p from memory into a uintptr
+// that forms the second word of an interface. The data
+// must be non-pointer in nature.
+func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
// Run the copy ourselves instead of calling memmove
// to avoid moving w to the heap.
- var w iword
+ var w uintptr
switch n {
default:
- panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
+ panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -182,13 +248,13 @@ func loadIword(p unsafe.Pointer, n uintptr) iword {
return w
}
-// storeIword stores n bytes from w into p.
-func storeIword(p unsafe.Pointer, w iword, n uintptr) {
+// storeScalar stores n bytes from w into p.
+func storeScalar(p unsafe.Pointer, w uintptr, n uintptr) {
// Run the copy ourselves instead of calling memmove
// to avoid moving w to the heap.
switch n {
default:
- panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
+ panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -278,7 +344,7 @@ func (v Value) Addr() Value {
if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+ return Value{v.typ.ptrTo(), v.ptr, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
}
// Bool returns v's underlying value.
@@ -286,9 +352,9 @@ func (v Value) Addr() Value {
func (v Value) Bool() bool {
v.mustBe(Bool)
if v.flag&flagIndir != 0 {
- return *(*bool)(v.val)
+ return *(*bool)(v.ptr)
}
- return *(*bool)(unsafe.Pointer(&v.val))
+ return *(*bool)(unsafe.Pointer(&v.scalar))
}
// Bytes returns v's underlying value.
@@ -299,7 +365,7 @@ func (v Value) Bytes() []byte {
panic("reflect.Value.Bytes of non-byte slice")
}
// Slice is always bigger than a word; assume flagIndir.
- return *(*[]byte)(v.val)
+ return *(*[]byte)(v.ptr)
}
// runes returns v's underlying value.
@@ -310,7 +376,7 @@ func (v Value) runes() []rune {
panic("reflect.Value.Bytes of non-rune slice")
}
// Slice is always bigger than a word; assume flagIndir.
- return *(*[]rune)(v.val)
+ return *(*[]rune)(v.ptr)
}
// CanAddr returns true if the value's address can be obtained with Addr.
@@ -358,19 +424,28 @@ func (v Value) CallSlice(in []Value) []Value {
return v.call("CallSlice", in)
}
+var callGC bool // for testing; see TestCallMethodJump
+
+var makeFuncStubFn = makeFuncStub
+var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
+var methodValueCallFn = methodValueCall
+var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn))
+
func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
var (
- fn unsafe.Pointer
- rcvr iword
+ fn unsafe.Pointer
+ rcvr Value
+ rcvrtype *rtype
)
if v.flag&flagMethod != 0 {
- t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
+ rcvr = v
+ rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
} else if v.flag&flagIndir != 0 {
- fn = *(*unsafe.Pointer)(v.val)
+ fn = *(*unsafe.Pointer)(v.ptr)
} else {
- fn = v.val
+ fn = v.ptr
}
if fn == nil {
@@ -434,23 +509,36 @@ func (v Value) call(op string, in []Value) []Value {
}
nout := t.NumOut()
- // Compute arg size & allocate.
- // This computation is 5g/6g/8g-dependent
- // and probably wrong for gccgo, but so
- // is most of this function.
- size, _, _, _ := frameSize(t, v.flag&flagMethod != 0)
-
- // Copy into args.
- //
- // TODO(rsc): This will need to be updated for any new garbage collector.
- // For now make everything look like a pointer by allocating
- // a []unsafe.Pointer.
- args := make([]unsafe.Pointer, size/ptrSize)
- ptr := unsafe.Pointer(&args[0])
+ // If target is makeFuncStub, short circuit the unpack onto stack /
+ // pack back into []Value for the args and return values. Just do the
+ // call directly.
+ // We need to do this here because otherwise we have a situation where
+ // reflect.callXX calls makeFuncStub, neither of which knows the
+ // layout of the args. That's bad for precise gc & stack copying.
+ x := (*makeFuncImpl)(fn)
+ if x.code == makeFuncStubCode {
+ return x.fn(in)
+ }
+
+ // If the target is methodValueCall, do its work here: add the receiver
+ // argument and call the real target directly.
+ // We need to do this here because otherwise we have a situation where
+ // reflect.callXX calls methodValueCall, neither of which knows the
+ // layout of the args. That's bad for precise gc & stack copying.
+ y := (*methodValue)(fn)
+ if y.fn == methodValueCallCode {
+ rcvr = y.rcvr
+ rcvrtype, t, fn = methodReceiver("call", rcvr, y.method)
+ }
+
+ // Compute frame type, allocate a chunk of memory for frame
+ frametype, _, retOffset := funcLayout(t, rcvrtype)
+ args := unsafe_New(frametype)
off := uintptr(0)
- if v.flag&flagMethod != 0 {
- // Hard-wired first argument.
- *(*iword)(ptr) = rcvr
+
+ // Copy inputs into args.
+ if rcvrtype != nil {
+ storeRcvr(rcvr, args)
off = ptrSize
}
for i, v := range in {
@@ -459,30 +547,35 @@ func (v Value) call(op string, in []Value) []Value {
a := uintptr(targ.align)
off = (off + a - 1) &^ (a - 1)
n := targ.size
- addr := unsafe.Pointer(uintptr(ptr) + off)
+ addr := unsafe.Pointer(uintptr(args) + off)
v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
- if v.flag&flagIndir == 0 {
- storeIword(addr, iword(v.val), n)
+ if v.flag&flagIndir != 0 {
+ memmove(addr, v.ptr, n)
+ } else if targ.pointers() {
+ *(*unsafe.Pointer)(addr) = v.ptr
} else {
- memmove(addr, v.val, n)
+ storeScalar(addr, v.scalar, n)
}
off += n
}
- off = (off + ptrSize - 1) &^ (ptrSize - 1)
// Call.
- call(fn, ptr, uint32(size))
+ call(fn, args, uint32(frametype.size), uint32(retOffset))
+
+ // For testing; see TestCallMethodJump.
+ if callGC {
+ runtime.GC()
+ }
// Copy return values out of args.
- //
- // TODO(rsc): revisit like above.
ret := make([]Value, nout)
+ off = retOffset
for i := 0; i < nout; i++ {
tv := t.Out(i)
a := uintptr(tv.Align())
off = (off + a - 1) &^ (a - 1)
fl := flagIndir | flag(tv.Kind())<<flagKindShift
- ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(ptr) + off), fl}
+ ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), 0, fl}
off += tv.Size()
}
@@ -512,18 +605,20 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
for _, arg := range ftyp.in {
typ := arg
off += -off & uintptr(typ.align-1)
- v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
- if typ.size <= ptrSize {
- // value fits in word.
- v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
- } else {
+ addr := unsafe.Pointer(uintptr(ptr) + off)
+ v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift}
+ if typ.size > ptrSize {
// value does not fit in word.
// Must make a copy, because f might keep a reference to it,
// and we cannot let f keep a reference to the stack frame
// after this function returns, not even a read-only reference.
- v.val = unsafe_New(typ)
- memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
+ v.ptr = unsafe_New(typ)
+ memmove(v.ptr, addr, typ.size)
v.flag |= flagIndir
+ } else if typ.pointers() {
+ v.ptr = *(*unsafe.Pointer)(addr)
+ } else {
+ v.scalar = loadScalar(addr, typ.size)
}
in = append(in, v)
off += typ.size
@@ -538,6 +633,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Copy results back into argument frame.
if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1)
+ if runtime.GOARCH == "amd64p32" {
+ off = align(off, 8)
+ }
for i, arg := range ftyp.out {
typ := arg
v := out[i]
@@ -552,10 +650,12 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
}
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
- if v.flag&flagIndir == 0 {
- storeIword(addr, iword(v.val), typ.size)
+ if v.flag&flagIndir != 0 {
+ memmove(addr, v.ptr, typ.size)
+ } else if typ.pointers() {
+ *(*unsafe.Pointer)(addr) = v.ptr
} else {
- memmove(addr, v.val, typ.size)
+ storeScalar(addr, v.scalar, typ.size)
}
off += typ.size
}
@@ -566,7 +666,10 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should
// not be used.
-func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer, rcvr iword) {
+// The return value rcvrtype gives the method's actual receiver type.
+// The return value t gives the method type signature (without the receiver).
+// The return value fn is a pointer to the method code.
+func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
i := methodIndex
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
@@ -577,14 +680,15 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
if m.pkgPath != nil {
panic("reflect: " + op + " of unexported method")
}
- t = m.typ
- iface := (*nonEmptyInterface)(v.val)
+ iface := (*nonEmptyInterface)(v.ptr)
if iface.itab == nil {
panic("reflect: " + op + " of method on nil interface value")
}
+ rcvrtype = iface.itab.typ
fn = unsafe.Pointer(&iface.itab.fun[i])
- rcvr = iface.word
+ t = m.typ
} else {
+ rcvrtype = v.typ
ut := v.typ.uncommon()
if ut == nil || i < 0 || i >= len(ut.methods) {
panic("reflect: internal error: invalid method index")
@@ -595,58 +699,41 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
}
fn = unsafe.Pointer(&m.ifn)
t = m.mtyp
- rcvr = v.iword()
}
return
}
+// v is a method receiver. Store at p the word which is used to
+// encode that receiver at the start of the argument list.
+// Reflect uses the "interface" calling convention for
+// methods, which always uses one word to record the receiver.
+func storeRcvr(v Value, p unsafe.Pointer) {
+ t := v.typ
+ if t.Kind() == Interface {
+ // the interface data word becomes the receiver word
+ iface := (*nonEmptyInterface)(v.ptr)
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
+ } else if v.flag&flagIndir != 0 {
+ if t.size > ptrSize {
+ *(*unsafe.Pointer)(p) = v.ptr
+ } else if t.pointers() {
+ *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
+ } else {
+ *(*uintptr)(p) = loadScalar(v.ptr, t.size)
+ }
+ } else if t.pointers() {
+ *(*unsafe.Pointer)(p) = v.ptr
+ } else {
+ *(*uintptr)(p) = v.scalar
+ }
+}
+
// align returns the result of rounding x up to a multiple of n.
// n must be a power of two.
func align(x, n uintptr) uintptr {
return (x + n - 1) &^ (n - 1)
}
-// frameSize returns the sizes of the argument and result frame
-// for a function of the given type. The rcvr bool specifies whether
-// a one-word receiver should be included in the total.
-func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
- if rcvr {
- // extra word for receiver interface word
- total += ptrSize
- }
-
- nin := t.NumIn()
- in = -total
- for i := 0; i < nin; i++ {
- tv := t.In(i)
- total = align(total, uintptr(tv.Align()))
- total += tv.Size()
- }
- in += total
- total = align(total, ptrSize)
- nout := t.NumOut()
- outOffset = total
- out = -total
- for i := 0; i < nout; i++ {
- tv := t.Out(i)
- total = align(total, uintptr(tv.Align()))
- total += tv.Size()
- }
- out += total
-
- // total must be > 0 in order for &args[0] to be valid.
- // the argument copying is going to round it up to
- // a multiple of ptrSize anyway, so make it ptrSize to begin with.
- if total < ptrSize {
- total = ptrSize
- }
-
- // round to pointer
- total = align(total, ptrSize)
-
- return
-}
-
// callMethod is the call implementation used by a function returned
// by makeMethodValue (used by v.Method(i).Interface()).
// It is a streamlined version of the usual reflect call: the caller has
@@ -659,24 +746,31 @@ func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
// so that the linker can make it work correctly for panic and recover.
// The gc compilers know to do that for the name "reflect.callMethod".
func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
- t, fn, rcvr := methodReceiver("call", ctxt.rcvr, ctxt.method)
- total, in, outOffset, out := frameSize(t, true)
-
- // Copy into args.
- //
- // TODO(rsc): This will need to be updated for any new garbage collector.
- // For now make everything look like a pointer by allocating
- // a []unsafe.Pointer.
- args := make([]unsafe.Pointer, total/ptrSize)
- args[0] = unsafe.Pointer(rcvr)
- base := unsafe.Pointer(&args[0])
- memmove(unsafe.Pointer(uintptr(base)+ptrSize), frame, in)
+ rcvr := ctxt.rcvr
+ rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
+ frametype, argSize, retOffset := funcLayout(t, rcvrtype)
+
+ // Make a new frame that is one word bigger so we can store the receiver.
+ args := unsafe_New(frametype)
+
+ // Copy in receiver and rest of args.
+ storeRcvr(rcvr, args)
+ memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
// Call.
- call(fn, unsafe.Pointer(&args[0]), uint32(total))
+ call(fn, args, uint32(frametype.size), uint32(retOffset))
- // Copy return values.
- memmove(unsafe.Pointer(uintptr(frame)+outOffset-ptrSize), unsafe.Pointer(uintptr(base)+outOffset), out)
+ // Copy return values. On amd64p32, the beginning of return values
+ // is 64-bit aligned, so the caller's frame layout (which doesn't have
+ // a receiver) is different from the layout of the fn call, which has
+ // a receiver.
+ // Ignore any changes to args and just copy return values.
+ callerRetOffset := retOffset - ptrSize
+ if runtime.GOARCH == "amd64p32" {
+ callerRetOffset = align(argSize-ptrSize, 8)
+ }
+ memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset),
+ unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset)
}
// funcName returns the name of f, for use in error messages.
@@ -697,10 +791,10 @@ func (v Value) Cap() int {
case Array:
return v.typ.Len()
case Chan:
- return int(chancap(v.iword()))
+ return int(chancap(v.pointer()))
case Slice:
// Slice is always bigger than a word; assume flagIndir.
- return (*SliceHeader)(v.val).Cap
+ return (*sliceHeader)(v.ptr).Cap
}
panic(&ValueError{"reflect.Value.Cap", k})
}
@@ -710,7 +804,7 @@ func (v Value) Cap() int {
func (v Value) Close() {
v.mustBe(Chan)
v.mustBeExported()
- chanclose(v.iword())
+ chanclose(v.pointer())
}
// Complex returns v's underlying value, as a complex128.
@@ -720,12 +814,12 @@ func (v Value) Complex() complex128 {
switch k {
case Complex64:
if v.flag&flagIndir != 0 {
- return complex128(*(*complex64)(v.val))
+ return complex128(*(*complex64)(v.ptr))
}
- return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
+ return complex128(*(*complex64)(unsafe.Pointer(&v.scalar)))
case Complex128:
// complex128 is always bigger than a word; assume flagIndir.
- return *(*complex128)(v.val)
+ return *(*complex128)(v.ptr)
}
panic(&ValueError{"reflect.Value.Complex", k})
}
@@ -738,48 +832,31 @@ func (v Value) Elem() Value {
k := v.kind()
switch k {
case Interface:
- var (
- typ *rtype
- val unsafe.Pointer
- )
+ var eface interface{}
if v.typ.NumMethod() == 0 {
- eface := (*emptyInterface)(v.val)
- if eface.typ == nil {
- // nil interface value
- return Value{}
- }
- typ = eface.typ
- val = unsafe.Pointer(eface.word)
+ eface = *(*interface{})(v.ptr)
} else {
- iface := (*nonEmptyInterface)(v.val)
- if iface.itab == nil {
- // nil interface value
- return Value{}
- }
- typ = iface.itab.typ
- val = unsafe.Pointer(iface.word)
- }
- fl := v.flag & flagRO
- fl |= flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
+ eface = (interface{})(*(*interface {
+ M()
+ })(v.ptr))
}
- return Value{typ, val, fl}
-
+ x := unpackEface(eface)
+ x.flag |= v.flag & flagRO
+ return x
case Ptr:
- val := v.val
+ ptr := v.ptr
if v.flag&flagIndir != 0 {
- val = *(*unsafe.Pointer)(val)
+ ptr = *(*unsafe.Pointer)(ptr)
}
// The returned value's address is v's value.
- if val == nil {
+ if ptr == nil {
return Value{}
}
tt := (*ptrType)(unsafe.Pointer(v.typ))
typ := tt.elem
fl := v.flag&flagRO | flagIndir | flagAddr
fl |= flag(typ.Kind() << flagKindShift)
- return Value{typ, val, fl}
+ return Value{typ, ptr, 0, fl}
}
panic(&ValueError{"reflect.Value.Elem", k})
}
@@ -803,20 +880,26 @@ func (v Value) Field(i int) Value {
}
fl |= flag(typ.Kind()) << flagKindShift
- var val unsafe.Pointer
+ var ptr unsafe.Pointer
+ var scalar uintptr
switch {
case fl&flagIndir != 0:
// Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + field.offset)
+ ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
+ case typ.pointers():
+ if field.offset != 0 {
+ panic("field access of ptr value isn't at offset 0")
+ }
+ ptr = v.ptr
case bigEndian:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+ // Must be scalar. Discard leading bytes.
+ scalar = v.scalar << (field.offset * 8)
default:
- // Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
+ // Must be scalar. Discard leading bytes.
+ scalar = v.scalar >> (field.offset * 8)
}
- return Value{typ, val, fl}
+ return Value{typ, ptr, scalar, fl}
}
// FieldByIndex returns the nested field corresponding to index.
@@ -825,7 +908,10 @@ func (v Value) FieldByIndex(index []int) Value {
v.mustBe(Struct)
for i, x := range index {
if i > 0 {
- if v.Kind() == Ptr && v.Elem().Kind() == Struct {
+ if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct {
+ if v.IsNil() {
+ panic("reflect: indirection through nil pointer to embedded struct")
+ }
v = v.Elem()
}
}
@@ -864,14 +950,14 @@ func (v Value) Float() float64 {
switch k {
case Float32:
if v.flag&flagIndir != 0 {
- return float64(*(*float32)(v.val))
+ return float64(*(*float32)(v.ptr))
}
- return float64(*(*float32)(unsafe.Pointer(&v.val)))
+ return float64(*(*float32)(unsafe.Pointer(&v.scalar)))
case Float64:
if v.flag&flagIndir != 0 {
- return *(*float64)(v.val)
+ return *(*float64)(v.ptr)
}
- return *(*float64)(unsafe.Pointer(&v.val))
+ return *(*float64)(unsafe.Pointer(&v.scalar))
}
panic(&ValueError{"reflect.Value.Float", k})
}
@@ -894,41 +980,48 @@ func (v Value) Index(i int) Value {
offset := uintptr(i) * typ.size
var val unsafe.Pointer
+ var scalar uintptr
switch {
case fl&flagIndir != 0:
// Indirect. Just bump pointer.
- val = unsafe.Pointer(uintptr(v.val) + offset)
+ val = unsafe.Pointer(uintptr(v.ptr) + offset)
+ case typ.pointers():
+ if offset != 0 {
+ panic("can't Index(i) with i!=0 on ptrLike value")
+ }
+ val = v.ptr
case bigEndian:
// Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+ scalar = v.scalar << (offset * 8)
default:
// Direct. Discard leading bytes.
- val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+ scalar = v.scalar >> (offset * 8)
}
- return Value{typ, val, fl}
+ return Value{typ, val, scalar, fl}
case Slice:
// Element flag same as Elem of Ptr.
// Addressable, indirect, possibly read-only.
fl := flagAddr | flagIndir | v.flag&flagRO
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
if i < 0 || i >= s.Len {
panic("reflect: slice index out of range")
}
tt := (*sliceType)(unsafe.Pointer(v.typ))
typ := tt.elem
fl |= flag(typ.Kind()) << flagKindShift
- val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
- return Value{typ, val, fl}
+ val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+ return Value{typ, val, 0, fl}
case String:
fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
- s := (*StringHeader)(v.val)
+ s := (*stringHeader)(v.ptr)
if i < 0 || i >= s.Len {
panic("reflect: string index out of range")
}
- val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
- return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
+ b := uintptr(0)
+ *(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i)))
+ return Value{uint8Type, nil, b, fl}
}
panic(&ValueError{"reflect.Value.Index", k})
}
@@ -939,11 +1032,11 @@ func (v Value) Int() int64 {
k := v.kind()
var p unsafe.Pointer
if v.flag&flagIndir != 0 {
- p = v.val
+ p = v.ptr
} else {
- // The escape analysis is good enough that &v.val
+ // The escape analysis is good enough that &v.scalar
// does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
+ p = unsafe.Pointer(&v.scalar)
}
switch k {
case Int:
@@ -991,51 +1084,42 @@ func valueInterface(v Value, safe bool) interface{} {
v = makeMethodValue("Interface", v)
}
- k := v.kind()
- if k == Interface {
+ if v.kind() == Interface {
// Special case: return the element inside the interface.
// Empty interface has one layout, all interfaces with
// methods have a second layout.
if v.NumMethod() == 0 {
- return *(*interface{})(v.val)
+ return *(*interface{})(v.ptr)
}
return *(*interface {
M()
- })(v.val)
- }
-
- // Non-interface value.
- var eface emptyInterface
- eface.typ = v.typ
- eface.word = v.iword()
-
- // Don't need to allocate if v is not addressable or fits in one word.
- if v.flag&flagAddr != 0 && v.typ.size > ptrSize {
- // eface.word is a pointer to the actual data,
- // which might be changed. We need to return
- // a pointer to unchanging data, so make a copy.
- ptr := unsafe_New(v.typ)
- memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
- eface.word = iword(ptr)
+ })(v.ptr)
}
- return *(*interface{})(unsafe.Pointer(&eface))
+ // TODO: pass safe to packEface so we don't need to copy if safe==true?
+ return packEface(v)
}
// InterfaceData returns the interface v's value as a uintptr pair.
// It panics if v's Kind is not Interface.
func (v Value) InterfaceData() [2]uintptr {
+ // TODO: deprecate this
v.mustBe(Interface)
// We treat this as a read operation, so we allow
// it even for unexported data, because the caller
// has to import "unsafe" to turn it into something
// that can be abused.
// Interface value is always bigger than a word; assume flagIndir.
- return *(*[2]uintptr)(v.val)
+ return *(*[2]uintptr)(v.ptr)
}
-// IsNil returns true if v is a nil value.
-// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
+// IsNil reports whether its argument v is nil. The argument must be
+// a chan, func, interface, map, pointer, or slice value; if it is
+// not, IsNil panics. Note that IsNil is not always equivalent to a
+// regular comparison with nil in Go. For example, if v was created
+// by calling ValueOf with an uninitialized interface variable i,
+// i==nil will be true but v.IsNil will panic as v will be the zero
+// Value.
func (v Value) IsNil() bool {
k := v.kind()
switch k {
@@ -1043,7 +1127,7 @@ func (v Value) IsNil() bool {
if v.flag&flagMethod != 0 {
return false
}
- ptr := v.val
+ ptr := v.ptr
if v.flag&flagIndir != 0 {
ptr = *(*unsafe.Pointer)(ptr)
}
@@ -1051,7 +1135,7 @@ func (v Value) IsNil() bool {
case Interface, Slice:
// Both interface and slice are nil if first word is 0.
// Both are always bigger than a word; assume flagIndir.
- return *(*unsafe.Pointer)(v.val) == nil
+ return *(*unsafe.Pointer)(v.ptr) == nil
}
panic(&ValueError{"reflect.Value.IsNil", k})
}
@@ -1080,15 +1164,15 @@ func (v Value) Len() int {
tt := (*arrayType)(unsafe.Pointer(v.typ))
return int(tt.len)
case Chan:
- return chanlen(v.iword())
+ return chanlen(v.pointer())
case Map:
- return maplen(v.iword())
+ return maplen(v.pointer())
case Slice:
// Slice is bigger than a word; assume flagIndir.
- return (*SliceHeader)(v.val).Len
+ return (*sliceHeader)(v.ptr).Len
case String:
// String is bigger than a word; assume flagIndir.
- return (*StringHeader)(v.val).Len
+ return (*stringHeader)(v.ptr).Len
}
panic(&ValueError{"reflect.Value.Len", k})
}
@@ -1110,17 +1194,32 @@ func (v Value) MapIndex(key Value) Value {
// of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
- word, ok := mapaccess(v.typ, v.iword(), key.iword())
- if !ok {
+ var k unsafe.Pointer
+ if key.flag&flagIndir != 0 {
+ k = key.ptr
+ } else if key.typ.pointers() {
+ k = unsafe.Pointer(&key.ptr)
+ } else {
+ k = unsafe.Pointer(&key.scalar)
+ }
+ e := mapaccess(v.typ, v.pointer(), k)
+ if e == nil {
return Value{}
}
typ := tt.elem
fl := (v.flag | key.flag) & flagRO
+ fl |= flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
- fl |= flagIndir
+ // Copy result so future changes to the map
+ // won't change the underlying value.
+ c := unsafe_New(typ)
+ memmove(c, e, typ.size)
+ return Value{typ, c, 0, fl | flagIndir}
+ } else if typ.pointers() {
+ return Value{typ, *(*unsafe.Pointer)(e), 0, fl}
+ } else {
+ return Value{typ, nil, loadScalar(e, typ.size), fl}
}
- fl |= flag(typ.Kind()) << flagKindShift
- return Value{typ, unsafe.Pointer(word), fl}
}
// MapKeys returns a slice containing all the keys present in the map,
@@ -1132,13 +1231,9 @@ func (v Value) MapKeys() []Value {
tt := (*mapType)(unsafe.Pointer(v.typ))
keyType := tt.key
- fl := v.flag & flagRO
- fl |= flag(keyType.Kind()) << flagKindShift
- if keyType.size > ptrSize {
- fl |= flagIndir
- }
+ fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift
- m := v.iword()
+ m := v.pointer()
mlen := int(0)
if m != nil {
mlen = maplen(m)
@@ -1147,11 +1242,24 @@ func (v Value) MapKeys() []Value {
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
- keyWord, ok := mapiterkey(it)
- if !ok {
+ key := mapiterkey(it)
+ if key == nil {
+ // Someone deleted an entry from the map since we
+ // called maplen above. It's a data race, but nothing
+ // we can do about it.
break
}
- a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
+ if keyType.size > ptrSize {
+ // Copy result so future changes to the map
+ // won't change the underlying value.
+ c := unsafe_New(keyType)
+ memmove(c, key, keyType.size)
+ a[i] = Value{keyType, c, 0, fl | flagIndir}
+ } else if keyType.pointers() {
+ a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl}
+ } else {
+ a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl}
+ }
mapiternext(it)
}
return a[:i]
@@ -1174,7 +1282,7 @@ func (v Value) Method(i int) Value {
fl := v.flag & (flagRO | flagIndir)
fl |= flag(Func) << flagKindShift
fl |= flag(i)<<flagMethodShift | flagMethod
- return Value{v.typ, v.val, fl}
+ return Value{v.typ, v.ptr, v.scalar, fl}
}
// NumMethod returns the number of methods in the value's method set.
@@ -1284,15 +1392,16 @@ func (v Value) OverflowUint(x uint64) bool {
// code pointer, but not necessarily enough to identify a
// single function uniquely. The only guarantee is that the
// result is zero if and only if v is a nil func Value.
+//
+// If v's Kind is Slice, the returned pointer is to the first
+// element of the slice. If the slice is nil the returned value
+// is 0. If the slice is empty but non-nil the return value is non-zero.
func (v Value) Pointer() uintptr {
+ // TODO: deprecate
k := v.kind()
switch k {
case Chan, Map, Ptr, UnsafePointer:
- p := v.val
- if v.flag&flagIndir != 0 {
- p = *(*unsafe.Pointer)(p)
- }
- return uintptr(p)
+ return uintptr(v.pointer())
case Func:
if v.flag&flagMethod != 0 {
// As the doc comment says, the returned pointer is an
@@ -1304,10 +1413,7 @@ func (v Value) Pointer() uintptr {
f := methodValueCall
return **(**uintptr)(unsafe.Pointer(&f))
}
- p := v.val
- if v.flag&flagIndir != 0 {
- p = *(*unsafe.Pointer)(p)
- }
+ p := v.pointer()
// Non-nil func value points at data block.
// First word of data block is actual code.
if p != nil {
@@ -1316,7 +1422,7 @@ func (v Value) Pointer() uintptr {
return uintptr(p)
case Slice:
- return (*SliceHeader)(v.val).Data
+ return (*SliceHeader)(v.ptr).Data
}
panic(&ValueError{"reflect.Value.Pointer", k})
}
@@ -1339,14 +1445,21 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect: recv on send-only channel")
}
- word, selected, ok := chanrecv(v.typ, v.iword(), nb)
- if selected {
- typ := tt.elem
- fl := flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
- }
- val = Value{typ, unsafe.Pointer(word), fl}
+ t := tt.elem
+ val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
+ var p unsafe.Pointer
+ if t.size > ptrSize {
+ p = unsafe_New(t)
+ val.ptr = p
+ val.flag |= flagIndir
+ } else if t.pointers() {
+ p = unsafe.Pointer(&val.ptr)
+ } else {
+ p = unsafe.Pointer(&val.scalar)
+ }
+ selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+ if !selected {
+ val = Value{}
}
return
}
@@ -1369,7 +1482,15 @@ func (v Value) send(x Value, nb bool) (selected bool) {
}
x.mustBeExported()
x = x.assignTo("reflect.Value.Send", tt.elem, nil)
- return chansend(v.typ, v.iword(), x.iword(), nb)
+ var p unsafe.Pointer
+ if x.flag&flagIndir != 0 {
+ p = x.ptr
+ } else if x.typ.pointers() {
+ p = unsafe.Pointer(&x.ptr)
+ } else {
+ p = unsafe.Pointer(&x.scalar)
+ }
+ return chansend(v.typ, v.pointer(), p, nb)
}
// Set assigns x to the value v.
@@ -1380,13 +1501,15 @@ func (v Value) Set(x Value) {
x.mustBeExported() // do not let unexported x leak
var target *interface{}
if v.kind() == Interface {
- target = (*interface{})(v.val)
+ target = (*interface{})(v.ptr)
}
x = x.assignTo("reflect.Set", v.typ, target)
if x.flag&flagIndir != 0 {
- memmove(v.val, x.val, v.typ.size)
+ memmove(v.ptr, x.ptr, v.typ.size)
+ } else if x.typ.pointers() {
+ *(*unsafe.Pointer)(v.ptr) = x.ptr
} else {
- storeIword(v.val, iword(x.val), v.typ.size)
+ memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size)
}
}
@@ -1395,7 +1518,7 @@ func (v Value) Set(x Value) {
func (v Value) SetBool(x bool) {
v.mustBeAssignable()
v.mustBe(Bool)
- *(*bool)(v.val) = x
+ *(*bool)(v.ptr) = x
}
// SetBytes sets v's underlying value.
@@ -1406,7 +1529,7 @@ func (v Value) SetBytes(x []byte) {
if v.typ.Elem().Kind() != Uint8 {
panic("reflect.Value.SetBytes of non-byte slice")
}
- *(*[]byte)(v.val) = x
+ *(*[]byte)(v.ptr) = x
}
// setRunes sets v's underlying value.
@@ -1417,7 +1540,7 @@ func (v Value) setRunes(x []rune) {
if v.typ.Elem().Kind() != Int32 {
panic("reflect.Value.setRunes of non-rune slice")
}
- *(*[]rune)(v.val) = x
+ *(*[]rune)(v.ptr) = x
}
// SetComplex sets v's underlying value to x.
@@ -1428,9 +1551,9 @@ func (v Value) SetComplex(x complex128) {
default:
panic(&ValueError{"reflect.Value.SetComplex", k})
case Complex64:
- *(*complex64)(v.val) = complex64(x)
+ *(*complex64)(v.ptr) = complex64(x)
case Complex128:
- *(*complex128)(v.val) = x
+ *(*complex128)(v.ptr) = x
}
}
@@ -1442,9 +1565,9 @@ func (v Value) SetFloat(x float64) {
default:
panic(&ValueError{"reflect.Value.SetFloat", k})
case Float32:
- *(*float32)(v.val) = float32(x)
+ *(*float32)(v.ptr) = float32(x)
case Float64:
- *(*float64)(v.val) = x
+ *(*float64)(v.ptr) = x
}
}
@@ -1456,15 +1579,15 @@ func (v Value) SetInt(x int64) {
default:
panic(&ValueError{"reflect.Value.SetInt", k})
case Int:
- *(*int)(v.val) = int(x)
+ *(*int)(v.ptr) = int(x)
case Int8:
- *(*int8)(v.val) = int8(x)
+ *(*int8)(v.ptr) = int8(x)
case Int16:
- *(*int16)(v.val) = int16(x)
+ *(*int16)(v.ptr) = int16(x)
case Int32:
- *(*int32)(v.val) = int32(x)
+ *(*int32)(v.ptr) = int32(x)
case Int64:
- *(*int64)(v.val) = x
+ *(*int64)(v.ptr) = x
}
}
@@ -1474,7 +1597,7 @@ func (v Value) SetInt(x int64) {
func (v Value) SetLen(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
if n < 0 || n > int(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
@@ -1487,7 +1610,7 @@ func (v Value) SetLen(n int) {
func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
if n < int(s.Len) || n > int(s.Cap) {
panic("reflect: slice capacity out of range in SetCap")
}
@@ -1497,6 +1620,7 @@ func (v Value) SetCap(n int) {
// SetMapIndex sets the value associated with key in the map v to val.
// It panics if v's Kind is not Map.
// If val is the zero Value, SetMapIndex deletes the key from the map.
+// Otherwise if v holds a nil map, SetMapIndex will panic.
// As in Go, key's value must be assignable to the map's key type,
// and val's value must be assignable to the map's value type.
func (v Value) SetMapIndex(key, val Value) {
@@ -1505,11 +1629,29 @@ func (v Value) SetMapIndex(key, val Value) {
key.mustBeExported()
tt := (*mapType)(unsafe.Pointer(v.typ))
key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
- if val.typ != nil {
- val.mustBeExported()
- val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ var k unsafe.Pointer
+ if key.flag&flagIndir != 0 {
+ k = key.ptr
+ } else if key.typ.pointers() {
+ k = unsafe.Pointer(&key.ptr)
+ } else {
+ k = unsafe.Pointer(&key.scalar)
+ }
+ if val.typ == nil {
+ mapdelete(v.typ, v.pointer(), k)
+ return
+ }
+ val.mustBeExported()
+ val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ var e unsafe.Pointer
+ if val.flag&flagIndir != 0 {
+ e = val.ptr
+ } else if val.typ.pointers() {
+ e = unsafe.Pointer(&val.ptr)
+ } else {
+ e = unsafe.Pointer(&val.scalar)
}
- mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil)
+ mapassign(v.typ, v.pointer(), k, e)
}
// SetUint sets v's underlying value to x.
@@ -1520,17 +1662,17 @@ func (v Value) SetUint(x uint64) {
default:
panic(&ValueError{"reflect.Value.SetUint", k})
case Uint:
- *(*uint)(v.val) = uint(x)
+ *(*uint)(v.ptr) = uint(x)
case Uint8:
- *(*uint8)(v.val) = uint8(x)
+ *(*uint8)(v.ptr) = uint8(x)
case Uint16:
- *(*uint16)(v.val) = uint16(x)
+ *(*uint16)(v.ptr) = uint16(x)
case Uint32:
- *(*uint32)(v.val) = uint32(x)
+ *(*uint32)(v.ptr) = uint32(x)
case Uint64:
- *(*uint64)(v.val) = x
+ *(*uint64)(v.ptr) = x
case Uintptr:
- *(*uintptr)(v.val) = uintptr(x)
+ *(*uintptr)(v.ptr) = uintptr(x)
}
}
@@ -1539,7 +1681,7 @@ func (v Value) SetUint(x uint64) {
func (v Value) SetPointer(x unsafe.Pointer) {
v.mustBeAssignable()
v.mustBe(UnsafePointer)
- *(*unsafe.Pointer)(v.val) = x
+ *(*unsafe.Pointer)(v.ptr) = x
}
// SetString sets v's underlying value to x.
@@ -1547,7 +1689,7 @@ func (v Value) SetPointer(x unsafe.Pointer) {
func (v Value) SetString(x string) {
v.mustBeAssignable()
v.mustBe(String)
- *(*string)(v.val) = x
+ *(*string)(v.ptr) = x
}
// Slice returns v[i:j].
@@ -1570,24 +1712,21 @@ func (v Value) Slice(i, j int) Value {
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len)
typ = (*sliceType)(unsafe.Pointer(tt.slice))
- base = v.val
+ base = v.ptr
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*SliceHeader)(v.val)
+ s := (*sliceHeader)(v.ptr)
base = unsafe.Pointer(s.Data)
cap = s.Cap
case String:
- s := (*StringHeader)(v.val)
+ s := (*stringHeader)(v.ptr)
if i < 0 || j < i || j > s.Len {
panic("reflect.Value.Slice: string slice index out of bounds")
}
- var x string
- val := (*StringHeader)(unsafe.Pointer(&x))
- val.Data = s.Data + uintptr(i)
- val.Len = j - i
- return Value{v.typ, unsafe.Pointer(&x), v.flag}
+ t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+ return Value{v.typ, unsafe.Pointer(&t), 0, v.flag}
}
if i < 0 || j < i || j > cap {
@@ -1597,14 +1736,14 @@ func (v Value) Slice(i, j int) Value {
// Declare slice so that gc can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+ // Reinterpret as *sliceHeader to edit.
+ s := (*sliceHeader)(unsafe.Pointer(&x))
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = cap - i
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), fl}
+ return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
}
// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
@@ -1622,17 +1761,17 @@ func (v Value) Slice3(i, j, k int) Value {
case Array:
if v.flag&flagAddr == 0 {
- panic("reflect.Value.Slice: slice of unaddressable array")
+ panic("reflect.Value.Slice3: slice of unaddressable array")
}
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len)
typ = (*sliceType)(unsafe.Pointer(tt.slice))
- base = v.val
+ base = v.ptr
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
- s := (*SliceHeader)(v.val)
- base = unsafe.Pointer(s.Data)
+ s := (*sliceHeader)(v.ptr)
+ base = s.Data
cap = s.Cap
}
@@ -1644,14 +1783,14 @@ func (v Value) Slice3(i, j, k int) Value {
// can see the base pointer in it.
var x []unsafe.Pointer
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+ // Reinterpret as *sliceHeader to edit.
+ s := (*sliceHeader)(unsafe.Pointer(&x))
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = k - i
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
- return Value{typ.common(), unsafe.Pointer(&x), fl}
+ return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
}
// String returns the string v's underlying value, as a string.
@@ -1663,7 +1802,7 @@ func (v Value) String() string {
case Invalid:
return "<invalid Value>"
case String:
- return *(*string)(v.val)
+ return *(*string)(v.ptr)
}
// If you call String on a reflect.Value of other type, it's better to
// print something than to panic. Useful in debugging.
@@ -1672,9 +1811,9 @@ func (v Value) String() string {
// TryRecv attempts to receive a value from the channel v but will not block.
// It panics if v's Kind is not Chan.
-// If the receive cannot finish without blocking, x is the zero Value.
-// The boolean ok is true if the value x corresponds to a send
-// on the channel, false if it is a zero value received because the channel is closed.
+// If the receive delivers a value, x is the transferred value and ok is true.
+// If the receive cannot finish without blocking, x is the zero Value and ok is false.
+// If the channel is closed, x is the zero value for the channel's element type and ok is false.
func (v Value) TryRecv() (x Value, ok bool) {
v.mustBe(Chan)
v.mustBeExported()
@@ -1729,11 +1868,11 @@ func (v Value) Uint() uint64 {
k := v.kind()
var p unsafe.Pointer
if v.flag&flagIndir != 0 {
- p = v.val
+ p = v.ptr
} else {
- // The escape analysis is good enough that &v.val
+ // The escape analysis is good enough that &v.scalar
// does not trigger a heap allocation.
- p = unsafe.Pointer(&v.val)
+ p = unsafe.Pointer(&v.scalar)
}
switch k {
case Uint:
@@ -1756,13 +1895,14 @@ func (v Value) Uint() uint64 {
// It is for advanced clients that also import the "unsafe" package.
// It panics if v is not addressable.
func (v Value) UnsafeAddr() uintptr {
+ // TODO: deprecate
if v.typ == nil {
panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
}
if v.flag&flagAddr == 0 {
panic("reflect.Value.UnsafeAddr of unaddressable value")
}
- return uintptr(v.val)
+ return uintptr(v.ptr)
}
// StringHeader is the runtime representation of a string.
@@ -1776,6 +1916,12 @@ type StringHeader struct {
Len int
}
+// stringHeader is a safe version of StringHeader used within this package.
+type stringHeader struct {
+ Data unsafe.Pointer
+ Len int
+}
+
// SliceHeader is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
@@ -1788,6 +1934,13 @@ type SliceHeader struct {
Cap int
}
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+ Data unsafe.Pointer
+ Len int
+ Cap int
+}
+
func typesMustMatch(what string, t1, t2 Type) {
if t1 != t2 {
panic(what + ": " + t1.String() + " != " + t2.String())
@@ -1876,6 +2029,8 @@ func Copy(dst, src Value) int {
// If sk is an in-line array, cannot take its address.
// Instead, copy element by element.
+ // TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar))
+ // if we teach the compiler that ptrs don't escape from memmove.
if src.flag&flagIndir == 0 {
for i := 0; i < n; i++ {
dst.Index(i).Set(src.Index(i))
@@ -1886,14 +2041,14 @@ func Copy(dst, src Value) int {
// Copy via memmove.
var da, sa unsafe.Pointer
if dk == Array {
- da = dst.val
+ da = dst.ptr
} else {
- da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
+ da = (*sliceHeader)(dst.ptr).Data
}
if sk == Array {
- sa = src.val
+ sa = src.ptr
} else {
- sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
+ sa = (*sliceHeader)(src.ptr).Data
}
memmove(da, sa, uintptr(n)*de.Size())
return n
@@ -1902,17 +2057,18 @@ func Copy(dst, src Value) int {
// A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/chan.c:/runtimeSelect
type runtimeSelect struct {
- dir uintptr // 0, SendDir, or RecvDir
- typ *rtype // channel type
- ch iword // interface word for channel
- val iword // interface word for value (for SendDir)
+ dir uintptr // 0, SendDir, or RecvDir
+ typ *rtype // channel type
+ ch unsafe.Pointer // channel
+ val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
}
-// rselect runs a select. It returns the index of the chosen case,
-// and if the case was a receive, the interface word of the received
-// value and the conventional OK bool to indicate whether the receive
-// corresponds to a sent value.
-func rselect([]runtimeSelect) (chosen int, recv iword, recvOK bool)
+// rselect runs a select. It returns the index of the chosen case.
+// If the case was a receive, val is filled in with the received value.
+// The conventional OK bool indicates whether the receive corresponds
+// to a sent value.
+//go:noescape
+func rselect([]runtimeSelect) (chosen int, recvOK bool)
// A SelectDir describes the communication direction of a select case.
type SelectDir int
@@ -1992,7 +2148,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
if ChanDir(tt.dir)&SendDir == 0 {
panic("reflect.Select: SendDir case using recv-only channel")
}
- rc.ch = ch.iword()
+ rc.ch = ch.pointer()
rc.typ = &tt.rtype
v := c.Send
if !v.IsValid() {
@@ -2000,7 +2156,13 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
}
v.mustBeExported()
v = v.assignTo("reflect.Select", tt.elem, nil)
- rc.val = v.iword()
+ if v.flag&flagIndir != 0 {
+ rc.val = v.ptr
+ } else if v.typ.pointers() {
+ rc.val = unsafe.Pointer(&v.ptr)
+ } else {
+ rc.val = unsafe.Pointer(&v.scalar)
+ }
case SelectRecv:
if c.Send.IsValid() {
@@ -2013,23 +2175,28 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
ch.mustBe(Chan)
ch.mustBeExported()
tt := (*chanType)(unsafe.Pointer(ch.typ))
- rc.typ = &tt.rtype
if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect.Select: RecvDir case using send-only channel")
}
- rc.ch = ch.iword()
+ rc.ch = ch.pointer()
+ rc.typ = &tt.rtype
+ rc.val = unsafe_New(tt.elem)
}
}
- chosen, word, recvOK := rselect(runcases)
+ chosen, recvOK = rselect(runcases)
if runcases[chosen].dir == uintptr(SelectRecv) {
tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
- typ := tt.elem
- fl := flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
+ t := tt.elem
+ p := runcases[chosen].val
+ fl := flag(t.Kind()) << flagKindShift
+ if t.size > ptrSize {
+ recv = Value{t, p, 0, fl | flagIndir}
+ } else if t.pointers() {
+ recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
+ } else {
+ recv = Value{t, nil, loadScalar(p, t.size), fl}
}
- recv = Value{typ, unsafe.Pointer(word), fl}
}
return chosen, recv, recvOK
}
@@ -2058,16 +2225,8 @@ func MakeSlice(typ Type, len, cap int) Value {
panic("reflect.MakeSlice: len > cap")
}
- // Declare slice so that gc can see the base pointer in it.
- var x []unsafe.Pointer
-
- // Reinterpret as *SliceHeader to edit.
- s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap))
- s.Len = len
- s.Cap = cap
-
- return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
+ s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+ return Value{typ.common(), unsafe.Pointer(&s), 0, flagIndir | flag(Slice)<<flagKindShift}
}
// MakeChan creates a new channel with the specified type and buffer size.
@@ -2082,7 +2241,7 @@ func MakeChan(typ Type, buffer int) Value {
panic("reflect.MakeChan: unidirectional channel type")
}
ch := makechan(typ.(*rtype), uint64(buffer))
- return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift}
+ return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift}
}
// MakeMap creates a new map of the specified type.
@@ -2091,7 +2250,7 @@ func MakeMap(typ Type) Value {
panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.(*rtype))
- return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
+ return Value{typ.common(), m, 0, flag(Map) << flagKindShift}
}
// Indirect returns the value that v points to.
@@ -2112,21 +2271,13 @@ func ValueOf(i interface{}) Value {
}
// TODO(rsc): Eliminate this terrible hack.
- // In the call to packValue, eface.typ doesn't escape,
- // and eface.word is an integer. So it looks like
- // i (= eface) doesn't escape. But really it does,
- // because eface.word is actually a pointer.
+ // In the call to unpackEface, i.typ doesn't escape,
+ // and i.word is an integer. So it looks like
+ // i doesn't escape. But really it does,
+ // because i.word is actually a pointer.
escapes(i)
- // For an interface value with the noAddr bit set,
- // the representation is identical to an empty interface.
- eface := *(*emptyInterface)(unsafe.Pointer(&i))
- typ := eface.typ
- fl := flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
- fl |= flagIndir
- }
- return Value{typ, unsafe.Pointer(eface.word), fl}
+ return unpackEface(i)
}
// Zero returns a Value representing the zero value for the specified type.
@@ -2141,27 +2292,27 @@ func Zero(typ Type) Value {
t := typ.common()
fl := flag(t.Kind()) << flagKindShift
if t.size <= ptrSize {
- return Value{t, nil, fl}
+ return Value{t, nil, 0, fl}
}
- return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
+ return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
}
// New returns a Value representing a pointer to a new zero value
-// for the specified type. That is, the returned Value's Type is PtrTo(t).
+// for the specified type. That is, the returned Value's Type is PtrTo(typ).
func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
}
ptr := unsafe_New(typ.(*rtype))
fl := flag(Ptr) << flagKindShift
- return Value{typ.common().ptrTo(), ptr, fl}
+ return Value{typ.common().ptrTo(), ptr, 0, fl}
}
// NewAt returns a Value representing a pointer to a value of the
// specified type, using p as that pointer.
func NewAt(typ Type, p unsafe.Pointer) Value {
fl := flag(Ptr) << flagKindShift
- return Value{typ.common().ptrTo(), p, fl}
+ return Value{typ.common().ptrTo(), p, 0, fl}
}
// assignTo returns a value v that can be assigned directly to typ.
@@ -2179,7 +2330,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
v.typ = dst
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(dst.Kind()) << flagKindShift
- return Value{dst, v.val, fl}
+ return Value{dst, v.ptr, v.scalar, fl}
case implements(dst, v.typ):
if target == nil {
@@ -2191,7 +2342,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
} else {
ifaceE2I(dst, x, unsafe.Pointer(target))
}
- return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+ return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift}
}
// Failed.
@@ -2303,20 +2454,20 @@ func makeInt(f flag, bits uint64, t Type) Value {
// Assume ptrSize >= 4, so this must be uint64.
ptr := unsafe_New(typ)
*(*uint64)(unsafe.Pointer(ptr)) = bits
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
- var w iword
+ var s uintptr
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
+ *(*uint8)(unsafe.Pointer(&s)) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
+ *(*uint16)(unsafe.Pointer(&s)) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
+ *(*uint32)(unsafe.Pointer(&s)) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
+ *(*uint64)(unsafe.Pointer(&s)) = uint64(bits)
}
- return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
// makeFloat returns a Value of type t equal to v (possibly truncated to float32),
@@ -2327,17 +2478,17 @@ func makeFloat(f flag, v float64, t Type) Value {
// Assume ptrSize >= 4, so this must be float64.
ptr := unsafe_New(typ)
*(*float64)(unsafe.Pointer(ptr)) = v
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
- var w iword
+ var s uintptr
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(&w)) = float32(v)
+ *(*float32)(unsafe.Pointer(&s)) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(&w)) = v
+ *(*float64)(unsafe.Pointer(&s)) = v
}
- return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
@@ -2352,13 +2503,13 @@ func makeComplex(f flag, v complex128, t Type) Value {
case 16:
*(*complex128)(unsafe.Pointer(ptr)) = v
}
- return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+ return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
// Assume ptrSize <= 8 so this must be complex64.
- var w iword
- *(*complex64)(unsafe.Pointer(&w)) = complex64(v)
- return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+ var s uintptr
+ *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+ return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
func makeString(f flag, v string, t Type) Value {
@@ -2461,15 +2612,15 @@ func cvtStringRunes(v Value, t Type) Value {
func cvtDirect(v Value, typ Type) Value {
f := v.flag
t := typ.common()
- val := v.val
+ ptr := v.ptr
if f&flagAddr != 0 {
// indirect, mutable word - make a copy
- ptr := unsafe_New(t)
- memmove(ptr, val, t.size)
- val = ptr
+ c := unsafe_New(t)
+ memmove(c, ptr, t.size)
+ ptr = c
f &^= flagAddr
}
- return Value{t, val, v.flag&flagRO | f}
+ return Value{t, ptr, v.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f?
}
// convertOp: concrete -> interface
@@ -2481,7 +2632,7 @@ func cvtT2I(v Value, typ Type) Value {
} else {
ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
}
- return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+ return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
}
// convertOp: interface -> interface
@@ -2495,22 +2646,27 @@ func cvtI2I(v Value, typ Type) Value {
}
// implemented in ../pkg/runtime
-func chancap(ch iword) int
-func chanclose(ch iword)
-func chanlen(ch iword) int
-func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
-func chansend(t *rtype, ch iword, val iword, nb bool) bool
-
-func makechan(typ *rtype, size uint64) (ch iword)
-func makemap(t *rtype) (m iword)
-func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
-func mapassign(t *rtype, m iword, key, val iword, ok bool)
-func mapiterinit(t *rtype, m iword) *byte
-func mapiterkey(it *byte) (key iword, ok bool)
-func mapiternext(it *byte)
-func maplen(m iword) int
-
-func call(fn, arg unsafe.Pointer, n uint32)
+func chancap(ch unsafe.Pointer) int
+func chanclose(ch unsafe.Pointer)
+func chanlen(ch unsafe.Pointer) int
+
+//go:noescape
+func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+
+//go:noescape
+func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
+
+func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
+func makemap(t *rtype) (m unsafe.Pointer)
+func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+func mapiternext(it unsafe.Pointer)
+func maplen(m unsafe.Pointer) int
+
+func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
// Dummy annotation marking that the value x escapes,
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index e914a7ccb..301a1dfcd 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -473,6 +473,11 @@ func TestSplit(t *testing.T) {
}
}
+// This ran out of stack before issue 7608 was fixed.
+func TestOnePassCutoff(t *testing.T) {
+ MustCompile(`^(?:x{1,1000}){1,1000}$`)
+}
+
func BenchmarkLiteral(b *testing.B) {
x := strings.Repeat("x", 50) + "y"
b.StopTimer()
@@ -578,3 +583,63 @@ func BenchmarkAnchoredLongMatch(b *testing.B) {
re.Match(x)
}
}
+
+func BenchmarkOnePassShortA(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile("^.bc(d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkNotOnePassShortA(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile(".bc(d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassShortB(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile("^.bc(?:d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkNotOnePassShortB(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcddddddeeeededd")
+ re := MustCompile(".bc(?:d|e)*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassLongPrefix(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^abcdefghijklmnopqrstuvwxyz.*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkOnePassLongNotPrefix(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^.bcdefghijklmnopqrstuvwxyz.*$")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
diff --git a/src/pkg/regexp/example_test.go b/src/pkg/regexp/example_test.go
index b0ad9d340..a4e0da8ea 100644
--- a/src/pkg/regexp/example_test.go
+++ b/src/pkg/regexp/example_test.go
@@ -1,3 +1,7 @@
+// 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 regexp_test
import (
diff --git a/src/pkg/regexp/exec.go b/src/pkg/regexp/exec.go
index 333ca2554..c4cb201f6 100644
--- a/src/pkg/regexp/exec.go
+++ b/src/pkg/regexp/exec.go
@@ -37,6 +37,7 @@ type thread struct {
type machine struct {
re *Regexp // corresponding Regexp
p *syntax.Prog // compiled program
+ op *onePassProg // compiled onepass program, or notOnePass
q0, q1 queue // two queues for runq, nextq
pool []*thread // pool of available threads
matched bool // whether a match was found
@@ -66,8 +67,8 @@ func (m *machine) newInputReader(r io.RuneReader) input {
}
// progMachine returns a new machine running the prog p.
-func progMachine(p *syntax.Prog) *machine {
- m := &machine{p: p}
+func progMachine(p *syntax.Prog, op *onePassProg) *machine {
+ m := &machine{p: p, op: op}
n := len(m.p.Inst)
m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
@@ -312,6 +313,105 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
return t
}
+// onepass runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) onepass(i input, pos int) bool {
+ startCond := m.re.cond
+ if startCond == ^syntax.EmptyOp(0) { // impossible
+ return false
+ }
+ m.matched = false
+ for i := range m.matchcap {
+ m.matchcap[i] = -1
+ }
+ r, r1 := endOfText, endOfText
+ width, width1 := 0, 0
+ r, width = i.step(pos)
+ if r != endOfText {
+ r1, width1 = i.step(pos + width)
+ }
+ var flag syntax.EmptyOp
+ if pos == 0 {
+ flag = syntax.EmptyOpContext(-1, r)
+ } else {
+ flag = i.context(pos)
+ }
+ pc := m.op.Start
+ inst := m.op.Inst[pc]
+ // If there is a simple literal prefix, skip over it.
+ if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 &&
+ len(m.re.prefix) > 0 && i.canCheckPrefix() {
+ // Match requires literal prefix; fast search for it.
+ if i.hasPrefix(m.re) {
+ pos += len(m.re.prefix)
+ r, width = i.step(pos)
+ r1, width1 = i.step(pos + width)
+ flag = i.context(pos)
+ pc = int(m.re.prefixEnd)
+ } else {
+ return m.matched
+ }
+ }
+ for {
+ inst = m.op.Inst[pc]
+ pc = int(inst.Out)
+ switch inst.Op {
+ default:
+ panic("bad inst")
+ case syntax.InstMatch:
+ m.matched = true
+ if len(m.matchcap) > 0 {
+ m.matchcap[0] = 0
+ m.matchcap[1] = pos
+ }
+ return m.matched
+ case syntax.InstRune:
+ if !inst.MatchRune(r) {
+ return m.matched
+ }
+ case syntax.InstRune1:
+ if r != inst.Rune[0] {
+ return m.matched
+ }
+ case syntax.InstRuneAny:
+ // Nothing
+ case syntax.InstRuneAnyNotNL:
+ if r == '\n' {
+ return m.matched
+ }
+ // peek at the input rune to see which branch of the Alt to take
+ case syntax.InstAlt, syntax.InstAltMatch:
+ pc = int(onePassNext(&inst, r))
+ continue
+ case syntax.InstFail:
+ return m.matched
+ case syntax.InstNop:
+ continue
+ case syntax.InstEmptyWidth:
+ if syntax.EmptyOp(inst.Arg)&^flag != 0 {
+ return m.matched
+ }
+ continue
+ case syntax.InstCapture:
+ if int(inst.Arg) < len(m.matchcap) {
+ m.matchcap[inst.Arg] = pos
+ }
+ continue
+ }
+ if width == 0 {
+ break
+ }
+ flag = syntax.EmptyOpContext(r, r1)
+ pos += width
+ r, width = r1, width1
+ if r != endOfText {
+ r1, width1 = i.step(pos + width)
+ }
+ }
+ return m.matched
+}
+
// empty is a non-nil 0-element slice,
// so doExecute can avoid an allocation
// when 0 captures are requested from a successful match.
@@ -329,16 +429,23 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
} else {
i = m.newInputString(s)
}
- m.init(ncap)
- if !m.match(i, pos) {
- re.put(m)
- return nil
+ if m.op != notOnePass {
+ if !m.onepass(i, pos) {
+ re.put(m)
+ return nil
+ }
+ } else {
+ m.init(ncap)
+ if !m.match(i, pos) {
+ re.put(m)
+ return nil
+ }
}
if ncap == 0 {
re.put(m)
return empty // empty but not nil
}
- cap := make([]int, ncap)
+ cap := make([]int, len(m.matchcap))
copy(cap, m.matchcap)
re.put(m)
return cap
diff --git a/src/pkg/regexp/onepass.go b/src/pkg/regexp/onepass.go
new file mode 100644
index 000000000..501fb28af
--- /dev/null
+++ b/src/pkg/regexp/onepass.go
@@ -0,0 +1,582 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+
+package regexp
+
+import (
+ "bytes"
+ "regexp/syntax"
+ "sort"
+ "unicode"
+)
+
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// "One-pass" regexp execution.
+// Some regexps can be analyzed to determine that they never need
+// backtracking: they are guaranteed to run in one pass over the string
+// without bothering to save all the usual NFA state.
+// Detect those and execute them more quickly.
+
+// A onePassProg is a compiled one-pass regular expression program.
+// It is the same as syntax.Prog except for the use of onePassInst.
+type onePassProg struct {
+ Inst []onePassInst
+ Start int // index of start instruction
+ NumCap int // number of InstCapture insts in re
+}
+
+// A onePassInst is a single instruction in a one-pass regular expression program.
+// It is the same as syntax.Inst except for the new 'Next' field.
+type onePassInst struct {
+ syntax.Inst
+ Next []uint32
+}
+
+// OnePassPrefix returns a literal string that all matches for the
+// regexp must start with. Complete is true if the prefix
+// is the entire match. Pc is the index of the last rune instruction
+// in the string. The OnePassPrefix skips over the mandatory
+// EmptyBeginText
+func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) {
+ i := &p.Inst[p.Start]
+ if i.Op != syntax.InstEmptyWidth || (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText == 0 {
+ return "", i.Op == syntax.InstMatch, uint32(p.Start)
+ }
+ pc = i.Out
+ i = &p.Inst[pc]
+ for i.Op == syntax.InstNop {
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ // Avoid allocation of buffer if prefix is empty.
+ if iop(i) != syntax.InstRune || len(i.Rune) != 1 {
+ return "", i.Op == syntax.InstMatch, uint32(p.Start)
+ }
+
+ // Have prefix; gather characters.
+ var buf bytes.Buffer
+ for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 {
+ buf.WriteRune(i.Rune[0])
+ pc, i = i.Out, &p.Inst[i.Out]
+ }
+ return buf.String(), i.Op == syntax.InstEmptyWidth && (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText != 0, pc
+}
+
+// OnePassNext selects the next actionable state of the prog, based on the input character.
+// It should only be called when i.Op == InstAlt or InstAltMatch, and from the one-pass machine.
+// One of the alternates may ultimately lead without input to end of line. If the instruction
+// is InstAltMatch the path to the InstMatch is in i.Out, the normal node in i.Next.
+func onePassNext(i *onePassInst, r rune) uint32 {
+ next := i.MatchRunePos(r)
+ if next >= 0 {
+ return i.Next[next]
+ }
+ if i.Op == syntax.InstAltMatch {
+ return i.Out
+ }
+ return 0
+}
+
+func iop(i *syntax.Inst) syntax.InstOp {
+ op := i.Op
+ switch op {
+ case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ op = syntax.InstRune
+ }
+ return op
+}
+
+// Sparse Array implementation is used as a queueOnePass.
+type queueOnePass struct {
+ sparse []uint32
+ dense []uint32
+ size, nextIndex uint32
+}
+
+func (q *queueOnePass) empty() bool {
+ return q.nextIndex >= q.size
+}
+
+func (q *queueOnePass) next() (n uint32) {
+ n = q.dense[q.nextIndex]
+ q.nextIndex++
+ return
+}
+
+func (q *queueOnePass) clear() {
+ q.size = 0
+ q.nextIndex = 0
+}
+
+func (q *queueOnePass) reset() {
+ q.nextIndex = 0
+}
+
+func (q *queueOnePass) contains(u uint32) bool {
+ if u >= uint32(len(q.sparse)) {
+ return false
+ }
+ return q.sparse[u] < q.size && q.dense[q.sparse[u]] == u
+}
+
+func (q *queueOnePass) insert(u uint32) {
+ if !q.contains(u) {
+ q.insertNew(u)
+ }
+}
+
+func (q *queueOnePass) insertNew(u uint32) {
+ if u >= uint32(len(q.sparse)) {
+ return
+ }
+ q.sparse[u] = q.size
+ q.dense[q.size] = u
+ q.size++
+}
+
+func newQueue(size int) (q *queueOnePass) {
+ return &queueOnePass{
+ sparse: make([]uint32, size),
+ dense: make([]uint32, size),
+ }
+}
+
+// mergeRuneSets merges two non-intersecting runesets, and returns the merged result,
+// and a NextIp array. The idea is that if a rune matches the OnePassRunes at index
+// i, NextIp[i/2] is the target. If the input sets intersect, an empty runeset and a
+// NextIp array with the single element mergeFailed is returned.
+// The code assumes that both inputs contain ordered and non-intersecting rune pairs.
+const mergeFailed = uint32(0xffffffff)
+
+var (
+ noRune = []rune{}
+ noNext = []uint32{mergeFailed}
+)
+
+func mergeRuneSets(leftRunes, rightRunes *[]rune, leftPC, rightPC uint32) ([]rune, []uint32) {
+ leftLen := len(*leftRunes)
+ rightLen := len(*rightRunes)
+ if leftLen&0x1 != 0 || rightLen&0x1 != 0 {
+ panic("mergeRuneSets odd length []rune")
+ }
+ var (
+ lx, rx int
+ )
+ merged := make([]rune, 0)
+ next := make([]uint32, 0)
+ ok := true
+ defer func() {
+ if !ok {
+ merged = nil
+ next = nil
+ }
+ }()
+
+ ix := -1
+ extend := func(newLow *int, newArray *[]rune, pc uint32) bool {
+ if ix > 0 && (*newArray)[*newLow] <= merged[ix] {
+ return false
+ }
+ merged = append(merged, (*newArray)[*newLow], (*newArray)[*newLow+1])
+ *newLow += 2
+ ix += 2
+ next = append(next, pc)
+ return true
+ }
+
+ for lx < leftLen || rx < rightLen {
+ switch {
+ case rx >= rightLen:
+ ok = extend(&lx, leftRunes, leftPC)
+ case lx >= leftLen:
+ ok = extend(&rx, rightRunes, rightPC)
+ case (*rightRunes)[rx] < (*leftRunes)[lx]:
+ ok = extend(&rx, rightRunes, rightPC)
+ default:
+ ok = extend(&lx, leftRunes, leftPC)
+ }
+ if !ok {
+ return noRune, noNext
+ }
+ }
+ return merged, next
+}
+
+// cleanupOnePass drops working memory, and restores certain shortcut instructions.
+func cleanupOnePass(prog *onePassProg, original *syntax.Prog) {
+ for ix, instOriginal := range original.Inst {
+ switch instOriginal.Op {
+ case syntax.InstAlt, syntax.InstAltMatch, syntax.InstRune:
+ case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop, syntax.InstMatch, syntax.InstFail:
+ prog.Inst[ix].Next = nil
+ case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ prog.Inst[ix].Next = nil
+ prog.Inst[ix] = onePassInst{Inst: instOriginal}
+ }
+ }
+}
+
+// onePassCopy creates a copy of the original Prog, as we'll be modifying it
+func onePassCopy(prog *syntax.Prog) *onePassProg {
+ p := &onePassProg{
+ Start: prog.Start,
+ NumCap: prog.NumCap,
+ }
+ for _, inst := range prog.Inst {
+ p.Inst = append(p.Inst, onePassInst{Inst: inst})
+ }
+
+ // rewrites one or more common Prog constructs that enable some otherwise
+ // non-onepass Progs to be onepass. A:BD (for example) means an InstAlt at
+ // ip A, that points to ips B & C.
+ // A:BC + B:DA => A:BC + B:CD
+ // A:BC + B:DC => A:DC + B:DC
+ for pc := range p.Inst {
+ switch p.Inst[pc].Op {
+ default:
+ continue
+ case syntax.InstAlt, syntax.InstAltMatch:
+ // A:Bx + B:Ay
+ p_A_Other := &p.Inst[pc].Out
+ p_A_Alt := &p.Inst[pc].Arg
+ // make sure a target is another Alt
+ instAlt := p.Inst[*p_A_Alt]
+ if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+ p_A_Alt, p_A_Other = p_A_Other, p_A_Alt
+ instAlt = p.Inst[*p_A_Alt]
+ if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+ continue
+ }
+ }
+ instOther := p.Inst[*p_A_Other]
+ // Analyzing both legs pointing to Alts is for another day
+ if instOther.Op == syntax.InstAlt || instOther.Op == syntax.InstAltMatch {
+ // too complicated
+ continue
+ }
+ // simple empty transition loop
+ // A:BC + B:DA => A:BC + B:DC
+ p_B_Alt := &p.Inst[*p_A_Alt].Out
+ p_B_Other := &p.Inst[*p_A_Alt].Arg
+ patch := false
+ if instAlt.Out == uint32(pc) {
+ patch = true
+ } else if instAlt.Arg == uint32(pc) {
+ patch = true
+ p_B_Alt, p_B_Other = p_B_Other, p_B_Alt
+ }
+ if patch {
+ *p_B_Alt = *p_A_Other
+ }
+
+ // empty transition to common target
+ // A:BC + B:DC => A:DC + B:DC
+ if *p_A_Other == *p_B_Alt {
+ *p_A_Alt = *p_B_Other
+ }
+ }
+ }
+ return p
+}
+
+// runeSlice exists to permit sorting the case-folded rune sets.
+type runeSlice []rune
+
+func (p runeSlice) Len() int { return len(p) }
+func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p runeSlice) Sort() {
+ sort.Sort(p)
+}
+
+var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
+var anyRune = []rune{0, unicode.MaxRune}
+
+// makeOnePass creates a onepass Prog, if possible. It is possible if at any alt,
+// the match engine can always tell which branch to take. The routine may modify
+// p if it is turned into a onepass Prog. If it isn't possible for this to be a
+// onepass Prog, the Prog notOnePass is returned. makeOnePass is recursive
+// to the size of the Prog.
+func makeOnePass(p *onePassProg) *onePassProg {
+ // If the machine is very long, it's not worth the time to check if we can use one pass.
+ if len(p.Inst) >= 1000 {
+ return notOnePass
+ }
+
+ var (
+ instQueue = newQueue(len(p.Inst))
+ visitQueue = newQueue(len(p.Inst))
+ build func(uint32, *queueOnePass)
+ check func(uint32, map[uint32]bool) bool
+ onePassRunes = make([][]rune, len(p.Inst))
+ )
+ build = func(pc uint32, q *queueOnePass) {
+ if q.contains(pc) {
+ return
+ }
+ inst := p.Inst[pc]
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ q.insert(inst.Out)
+ build(inst.Out, q)
+ q.insert(inst.Arg)
+ case syntax.InstMatch, syntax.InstFail:
+ default:
+ q.insert(inst.Out)
+ }
+ }
+
+ // check that paths from Alt instructions are unambiguous, and rebuild the new
+ // program as a onepass program
+ check = func(pc uint32, m map[uint32]bool) (ok bool) {
+ ok = true
+ inst := &p.Inst[pc]
+ if visitQueue.contains(pc) {
+ return
+ }
+ visitQueue.insert(pc)
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ ok = check(inst.Out, m) && check(inst.Arg, m)
+ // check no-input paths to InstMatch
+ matchOut := m[inst.Out]
+ matchArg := m[inst.Arg]
+ if matchOut && matchArg {
+ ok = false
+ break
+ }
+ // Match on empty goes in inst.Out
+ if matchArg {
+ inst.Out, inst.Arg = inst.Arg, inst.Out
+ matchOut, matchArg = matchArg, matchOut
+ }
+ if matchOut {
+ m[pc] = true
+ inst.Op = syntax.InstAltMatch
+ }
+
+ // build a dispatch operator from the two legs of the alt.
+ onePassRunes[pc], inst.Next = mergeRuneSets(
+ &onePassRunes[inst.Out], &onePassRunes[inst.Arg], inst.Out, inst.Arg)
+ if len(inst.Next) > 0 && inst.Next[0] == mergeFailed {
+ ok = false
+ break
+ }
+ case syntax.InstCapture, syntax.InstNop:
+ ok = check(inst.Out, m)
+ m[pc] = m[inst.Out]
+ // pass matching runes back through these no-ops.
+ onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ case syntax.InstEmptyWidth:
+ ok = check(inst.Out, m)
+ m[pc] = m[inst.Out]
+ onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ case syntax.InstMatch, syntax.InstFail:
+ m[pc] = inst.Op == syntax.InstMatch
+ break
+ case syntax.InstRune:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ if len(inst.Rune) == 0 {
+ onePassRunes[pc] = []rune{}
+ inst.Next = []uint32{inst.Out}
+ break
+ }
+ runes := make([]rune, 0)
+ if len(inst.Rune) == 1 && syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+ r0 := inst.Rune[0]
+ runes = append(runes, r0, r0)
+ for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+ runes = append(runes, r1, r1)
+ }
+ sort.Sort(runeSlice(runes))
+ } else {
+ runes = append(runes, inst.Rune...)
+ }
+ onePassRunes[pc] = runes
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ inst.Op = syntax.InstRune
+ case syntax.InstRune1:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ runes := []rune{}
+ // expand case-folded runes
+ if syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+ r0 := inst.Rune[0]
+ runes = append(runes, r0, r0)
+ for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+ runes = append(runes, r1, r1)
+ }
+ sort.Sort(runeSlice(runes))
+ } else {
+ runes = append(runes, inst.Rune[0], inst.Rune[0])
+ }
+ onePassRunes[pc] = runes
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ inst.Op = syntax.InstRune
+ case syntax.InstRuneAny:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ onePassRunes[pc] = append([]rune{}, anyRune...)
+ inst.Next = []uint32{inst.Out}
+ case syntax.InstRuneAnyNotNL:
+ ok = check(inst.Out, m)
+ m[pc] = false
+ if len(inst.Next) > 0 {
+ break
+ }
+ onePassRunes[pc] = append([]rune{}, anyRuneNotNL...)
+ inst.Next = []uint32{}
+ for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+ inst.Next = append(inst.Next, inst.Out)
+ }
+ }
+ return
+ }
+
+ instQueue.clear()
+ instQueue.insert(uint32(p.Start))
+ m := make(map[uint32]bool, len(p.Inst))
+ for !instQueue.empty() {
+ pc := instQueue.next()
+ inst := p.Inst[pc]
+ visitQueue.clear()
+ if !check(uint32(pc), m) {
+ p = notOnePass
+ break
+ }
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ instQueue.insert(inst.Out)
+ instQueue.insert(inst.Arg)
+ case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop:
+ instQueue.insert(inst.Out)
+ case syntax.InstMatch:
+ case syntax.InstFail:
+ case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ default:
+ }
+ }
+ if p != notOnePass {
+ for i, _ := range p.Inst {
+ p.Inst[i].Rune = onePassRunes[i]
+ }
+ }
+ return p
+}
+
+// walk visits each Inst in the prog once, and applies the argument
+// function(ip, next), in pre-order.
+func walk(prog *syntax.Prog, funcs ...func(ip, next uint32)) {
+ var walk1 func(uint32)
+ progQueue := newQueue(len(prog.Inst))
+ walk1 = func(ip uint32) {
+ if progQueue.contains(ip) {
+ return
+ }
+ progQueue.insert(ip)
+ inst := prog.Inst[ip]
+ switch inst.Op {
+ case syntax.InstAlt, syntax.InstAltMatch:
+ for _, f := range funcs {
+ f(ip, inst.Out)
+ f(ip, inst.Arg)
+ }
+ walk1(inst.Out)
+ walk1(inst.Arg)
+ default:
+ for _, f := range funcs {
+ f(ip, inst.Out)
+ }
+ walk1(inst.Out)
+ }
+ }
+ walk1(uint32(prog.Start))
+}
+
+// find returns the Insts that match the argument predicate function
+func find(prog *syntax.Prog, f func(*syntax.Prog, int) bool) (matches []uint32) {
+ matches = []uint32{}
+
+ for ip := range prog.Inst {
+ if f(prog, ip) {
+ matches = append(matches, uint32(ip))
+ }
+ }
+ return
+}
+
+var notOnePass *onePassProg = nil
+
+// compileOnePass returns a new *syntax.Prog suitable for onePass execution if the original Prog
+// can be recharacterized as a one-pass regexp program, or syntax.notOnePass if the
+// Prog cannot be converted. For a one pass prog, the fundamental condition that must
+// be true is: at any InstAlt, there must be no ambiguity about what branch to take.
+func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
+ if prog.Start == 0 {
+ return notOnePass
+ }
+ // onepass regexp is anchored
+ if prog.Inst[prog.Start].Op != syntax.InstEmptyWidth ||
+ syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
+ return notOnePass
+ }
+ // every instruction leading to InstMatch must be EmptyEndText
+ for _, inst := range prog.Inst {
+ opOut := prog.Inst[inst.Out].Op
+ switch inst.Op {
+ default:
+ if opOut == syntax.InstMatch {
+ return notOnePass
+ }
+ case syntax.InstAlt, syntax.InstAltMatch:
+ if opOut == syntax.InstMatch || prog.Inst[inst.Arg].Op == syntax.InstMatch {
+ return notOnePass
+ }
+ case syntax.InstEmptyWidth:
+ if opOut == syntax.InstMatch {
+ if syntax.EmptyOp(inst.Arg)&syntax.EmptyEndText == syntax.EmptyEndText {
+ continue
+ }
+ return notOnePass
+ }
+ }
+ }
+ // Creates a slightly optimized copy of the original Prog
+ // that cleans up some Prog idioms that block valid onepass programs
+ p = onePassCopy(prog)
+
+ // checkAmbiguity on InstAlts, build onepass Prog if possible
+ p = makeOnePass(p)
+
+ if p != notOnePass {
+ cleanupOnePass(p, prog)
+ }
+ return p
+}
diff --git a/src/pkg/regexp/onepass_test.go b/src/pkg/regexp/onepass_test.go
new file mode 100644
index 000000000..7b2beea67
--- /dev/null
+++ b/src/pkg/regexp/onepass_test.go
@@ -0,0 +1,208 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "reflect"
+ "regexp/syntax"
+ "testing"
+)
+
+var runeMergeTests = []struct {
+ left, right, merged []rune
+ next []uint32
+ leftPC, rightPC uint32
+}{
+ {
+ // empty rhs
+ []rune{69, 69},
+ []rune{},
+ []rune{69, 69},
+ []uint32{1},
+ 1, 2,
+ },
+ {
+ // identical runes, identical targets
+ []rune{69, 69},
+ []rune{69, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 1,
+ },
+ {
+ // identical runes, different targets
+ []rune{69, 69},
+ []rune{69, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // append right-first
+ []rune{69, 69},
+ []rune{71, 71},
+ []rune{69, 69, 71, 71},
+ []uint32{1, 2},
+ 1, 2,
+ },
+ {
+ // append, left-first
+ []rune{71, 71},
+ []rune{69, 69},
+ []rune{69, 69, 71, 71},
+ []uint32{2, 1},
+ 1, 2,
+ },
+ {
+ // successful interleave
+ []rune{60, 60, 71, 71, 101, 101},
+ []rune{69, 69, 88, 88},
+ []rune{60, 60, 69, 69, 71, 71, 88, 88, 101, 101},
+ []uint32{1, 2, 1, 2, 1},
+ 1, 2,
+ },
+ {
+ // left surrounds right
+ []rune{69, 74},
+ []rune{71, 71},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // right surrounds left
+ []rune{69, 74},
+ []rune{68, 75},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap at interval begin
+ []rune{69, 74},
+ []rune{74, 75},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap ar interval end
+ []rune{69, 74},
+ []rune{65, 69},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap from above
+ []rune{69, 74},
+ []rune{71, 74},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // overlap from below
+ []rune{69, 74},
+ []rune{65, 71},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+ {
+ // out of order []rune
+ []rune{69, 74, 60, 65},
+ []rune{66, 67},
+ []rune{},
+ []uint32{mergeFailed},
+ 1, 2,
+ },
+}
+
+func TestMergeRuneSet(t *testing.T) {
+ for ix, test := range runeMergeTests {
+ merged, next := mergeRuneSets(&test.left, &test.right, test.leftPC, test.rightPC)
+ if !reflect.DeepEqual(merged, test.merged) {
+ t.Errorf("mergeRuneSet :%d (%v, %v) merged\n have\n%v\nwant\n%v", ix, test.left, test.right, merged, test.merged)
+ }
+ if !reflect.DeepEqual(next, test.next) {
+ t.Errorf("mergeRuneSet :%d(%v, %v) next\n have\n%v\nwant\n%v", ix, test.left, test.right, next, test.next)
+ }
+ }
+}
+
+const noStr = `!`
+
+var onePass = &onePassProg{}
+
+var onePassTests = []struct {
+ re string
+ onePass *onePassProg
+ prog string
+}{
+ {`^(?:a|(?:a*))$`, notOnePass, noStr},
+ {`^(?:(a)|(?:a*))$`, notOnePass, noStr},
+ {`^(?:(?:(?:.(?:$))?))$`, onePass, `a`},
+ {`^abcd$`, onePass, `abcd`},
+ {`^abcd$`, onePass, `abcde`},
+ {`^(?:(?:a{0,})*?)$`, onePass, `a`},
+ {`^(?:(?:a+)*)$`, onePass, ``},
+ {`^(?:(?:a|(?:aa)))$`, onePass, ``},
+ {`^(?:[^\s\S])$`, onePass, ``},
+ {`^(?:(?:a{3,4}){0,})$`, notOnePass, `aaaaaa`},
+ {`^(?:(?:a+)*)$`, onePass, `a`},
+ {`^(?:(?:(?:a*)+))$`, onePass, noStr},
+ {`^(?:(?:a+)*)$`, onePass, ``},
+ {`^[a-c]+$`, onePass, `abc`},
+ {`^[a-c]*$`, onePass, `abcdabc`},
+ {`^(?:a*)$`, onePass, `aaaaaaa`},
+ {`^(?:(?:aa)|a)$`, onePass, `a`},
+ {`^[a-c]*`, notOnePass, `abcdabc`},
+ {`^[a-c]*$`, onePass, `abc`},
+ {`^...$`, onePass, ``},
+ {`^(?:a|(?:aa))$`, onePass, `a`},
+ {`^[a-c]*`, notOnePass, `abcabc`},
+ {`^a((b))c$`, onePass, noStr},
+ {`^a.[l-nA-Cg-j]?e$`, onePass, noStr},
+ {`^a((b))$`, onePass, noStr},
+ {`^a(?:(b)|(c))c$`, onePass, noStr},
+ {`^a(?:(b*)|(c))c$`, notOnePass, noStr},
+ {`^a(?:b|c)$`, onePass, noStr},
+ {`^a(?:b?|c)$`, onePass, noStr},
+ {`^a(?:b?|c?)$`, notOnePass, noStr},
+ {`^a(?:b?|c+)$`, onePass, noStr},
+ {`^a(?:b+|(bc))d$`, notOnePass, noStr},
+ {`^a(?:bc)+$`, onePass, noStr},
+ {`^a(?:[bcd])+$`, onePass, noStr},
+ {`^a((?:[bcd])+)$`, onePass, noStr},
+ {`^a(:?b|c)*d$`, onePass, `abbbccbbcbbd"`},
+ {`^.bc(d|e)*$`, onePass, `abcddddddeeeededd`},
+ {`^(?:(?:aa)|.)$`, notOnePass, `a`},
+ {`^(?:(?:a{1,2}){1,2})$`, notOnePass, `aaaa`},
+}
+
+func TestCompileOnePass(t *testing.T) {
+ var (
+ p *syntax.Prog
+ re *syntax.Regexp
+ err error
+ )
+ for _, test := range onePassTests {
+ if re, err = syntax.Parse(test.re, syntax.Perl); err != nil {
+ t.Errorf("Parse(%q) got err:%s, want success", test.re, err)
+ continue
+ }
+ // needs to be done before compile...
+ re = re.Simplify()
+ if p, err = syntax.Compile(re); err != nil {
+ t.Errorf("Compile(%q) got err:%s, want success", test.re, err)
+ continue
+ }
+ onePass = compileOnePass(p)
+ if (onePass == notOnePass) != (test.onePass == notOnePass) {
+ t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass)
+ }
+ }
+}
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 0046026ea..0b8336a04 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -11,6 +11,14 @@
// For an overview of the syntax, run
// godoc regexp/syntax
//
+// The regexp implementation provided by this package is
+// guaranteed to run in time linear in the size of the input.
+// (This is a property not guaranteed by most open source
+// implementations of regular expressions.) For more information
+// about this property, see
+// http://swtch.com/~rsc/regexp/regexp1.html
+// or any book about automata theory.
+//
// All characters are UTF-8-encoded code points.
//
// There are 16 methods of Regexp that match a regular expression and identify
@@ -70,16 +78,17 @@ import (
var debug = false
// Regexp is the representation of a compiled regular expression.
-// The public interface is entirely through methods.
// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
// read-only after Compile
expr string // as passed to Compile
prog *syntax.Prog // compiled program
+ onepass *onePassProg // onpass program or nil
prefix string // required prefix in unanchored matches
prefixBytes []byte // prefix, as a []byte
prefixComplete bool // prefix is the entire regexp
prefixRune rune // first rune in prefix
+ prefixEnd uint32 // pc for last rune in prefix
cond syntax.EmptyOp // empty-width conditions required at start of match
numSubexp int
subexpNames []string
@@ -156,12 +165,17 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
regexp := &Regexp{
expr: expr,
prog: prog,
+ onepass: compileOnePass(prog),
numSubexp: maxCap,
subexpNames: capNames,
cond: prog.StartCond(),
longest: longest,
}
- regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ if regexp.onepass == notOnePass {
+ regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ } else {
+ regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog)
+ }
if regexp.prefix != "" {
// TODO(rsc): Remove this allocation by adding
// IndexString to package bytes.
@@ -183,7 +197,7 @@ func (re *Regexp) get() *machine {
return z
}
re.mu.Unlock()
- z := progMachine(re.prog)
+ z := progMachine(re.prog, re.onepass)
z.re = re
return z
}
diff --git a/src/pkg/regexp/syntax/doc.go b/src/pkg/regexp/syntax/doc.go
index e52632ef7..8e72c90d3 100644
--- a/src/pkg/regexp/syntax/doc.go
+++ b/src/pkg/regexp/syntax/doc.go
@@ -46,6 +46,10 @@ Repetitions:
x{n,}? n or more x, prefer fewer
x{n}? exactly n x
+Implementation restriction: The counting forms x{n} etc. (but not the other
+forms x* etc.) have an upper limit of n=1000. Negative or higher explicit
+counts yield the parse error ErrInvalidRepeatSize.
+
Grouping:
(re) numbered capturing group (submatch)
(?P<name>re) named & numbered capturing group (submatch)
diff --git a/src/pkg/regexp/syntax/make_perl_groups.pl b/src/pkg/regexp/syntax/make_perl_groups.pl
index d024f5090..90040fcb4 100755
--- a/src/pkg/regexp/syntax/make_perl_groups.pl
+++ b/src/pkg/regexp/syntax/make_perl_groups.pl
@@ -92,6 +92,10 @@ sub PrintClasses($@) {
}
print <<EOF;
+// 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.
+
// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
// make_perl_groups.pl >perl_groups.go
diff --git a/src/pkg/regexp/syntax/parse.go b/src/pkg/regexp/syntax/parse.go
index 42d0bf4a1..cb25dca39 100644
--- a/src/pkg/regexp/syntax/parse.go
+++ b/src/pkg/regexp/syntax/parse.go
@@ -668,7 +668,6 @@ func Parse(s string, flags Flags) (*Regexp, error) {
c rune
op Op
lastRepeat string
- min, max int
)
p.flags = flags
p.wholeRegexp = s
@@ -740,7 +739,7 @@ func Parse(s string, flags Flags) (*Regexp, error) {
op = OpQuest
}
after := t[1:]
- if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
+ if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil {
return nil, err
}
repeat = before
diff --git a/src/pkg/regexp/syntax/parse_test.go b/src/pkg/regexp/syntax/parse_test.go
index 269d6c3b8..f3089294c 100644
--- a/src/pkg/regexp/syntax/parse_test.go
+++ b/src/pkg/regexp/syntax/parse_test.go
@@ -100,12 +100,12 @@ var parseTests = []parseTest{
{`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`\P{^Braille}`, `cc{0x2800-0x28ff}`},
- {`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`\pZ`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
{`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
{`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
{`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
- {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
{`\p{Lu}`, mkCharClass(unicode.IsUpper)},
{`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
{`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
diff --git a/src/pkg/regexp/syntax/perl_groups.go b/src/pkg/regexp/syntax/perl_groups.go
index 1a11ca62f..effe4e686 100644
--- a/src/pkg/regexp/syntax/perl_groups.go
+++ b/src/pkg/regexp/syntax/perl_groups.go
@@ -1,3 +1,7 @@
+// 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.
+
// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
// make_perl_groups.pl >perl_groups.go
diff --git a/src/pkg/regexp/syntax/prog.go b/src/pkg/regexp/syntax/prog.go
index a482a82f2..29bd282d0 100644
--- a/src/pkg/regexp/syntax/prog.go
+++ b/src/pkg/regexp/syntax/prog.go
@@ -37,6 +37,27 @@ const (
InstRuneAnyNotNL
)
+var instOpNames = []string{
+ "InstAlt",
+ "InstAltMatch",
+ "InstCapture",
+ "InstEmptyWidth",
+ "InstMatch",
+ "InstFail",
+ "InstNop",
+ "InstRune",
+ "InstRune1",
+ "InstRuneAny",
+ "InstRuneAnyNotNL",
+}
+
+func (i InstOp) String() string {
+ if uint(i) >= uint(len(instOpNames)) {
+ return ""
+ }
+ return instOpNames[i]
+}
+
// An EmptyOp specifies a kind or mixture of zero-width assertions.
type EmptyOp uint8
@@ -103,13 +124,13 @@ func (p *Prog) String() string {
// skipNop follows any no-op or capturing instructions
// and returns the resulting pc.
-func (p *Prog) skipNop(pc uint32) *Inst {
+func (p *Prog) skipNop(pc uint32) (*Inst, uint32) {
i := &p.Inst[pc]
for i.Op == InstNop || i.Op == InstCapture {
pc = i.Out
i = &p.Inst[pc]
}
- return i
+ return i, pc
}
// op returns i.Op but merges all the Rune special cases into InstRune
@@ -126,7 +147,7 @@ func (i *Inst) op() InstOp {
// regexp must start with. Complete is true if the prefix
// is the entire match.
func (p *Prog) Prefix() (prefix string, complete bool) {
- i := p.skipNop(uint32(p.Start))
+ i, _ := p.skipNop(uint32(p.Start))
// Avoid allocation of buffer if prefix is empty.
if i.op() != InstRune || len(i.Rune) != 1 {
@@ -137,7 +158,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
var buf bytes.Buffer
for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 {
buf.WriteRune(i.Rune[0])
- i = p.skipNop(i.Out)
+ i, _ = p.skipNop(i.Out)
}
return buf.String(), i.Op == InstMatch
}
@@ -166,35 +187,46 @@ Loop:
return flag
}
+const noMatch = -1
+
// MatchRune returns true if the instruction matches (and consumes) r.
// It should only be called when i.Op == InstRune.
func (i *Inst) MatchRune(r rune) bool {
+ return i.MatchRunePos(r) != noMatch
+}
+
+// MatchRunePos checks whether the instruction matches (and consumes) r.
+// If so, MatchRunePos returns the index of the matching rune pair
+// (or, when len(i.Rune) == 1, rune singleton).
+// If not, MatchRunePos returns -1.
+// MatchRunePos should only be called when i.Op == InstRune.
+func (i *Inst) MatchRunePos(r rune) int {
rune := i.Rune
// Special case: single-rune slice is from literal string, not char class.
if len(rune) == 1 {
r0 := rune[0]
if r == r0 {
- return true
+ return 0
}
if Flags(i.Arg)&FoldCase != 0 {
for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
if r == r1 {
- return true
+ return 0
}
}
}
- return false
+ return noMatch
}
// Peek at the first few pairs.
// Should handle ASCII well.
for j := 0; j < len(rune) && j <= 8; j += 2 {
if r < rune[j] {
- return false
+ return noMatch
}
if r <= rune[j+1] {
- return true
+ return j / 2
}
}
@@ -205,14 +237,14 @@ func (i *Inst) MatchRune(r rune) bool {
m := lo + (hi-lo)/2
if c := rune[2*m]; c <= r {
if r <= rune[2*m+1] {
- return true
+ return m
}
lo = m + 1
} else {
hi = m
}
}
- return false
+ return noMatch
}
// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
diff --git a/src/pkg/regexp/syntax/prog_test.go b/src/pkg/regexp/syntax/prog_test.go
index cd71abc2a..50bfa3d4b 100644
--- a/src/pkg/regexp/syntax/prog_test.go
+++ b/src/pkg/regexp/syntax/prog_test.go
@@ -4,9 +4,7 @@
package syntax
-import (
- "testing"
-)
+import "testing"
var compileTests = []struct {
Regexp string
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.goc
index c3a839695..f1b8d5982 100644
--- a/src/pkg/runtime/alg.c
+++ b/src/pkg/runtime/alg.goc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "type.h"
#include "../../cmd/ld/textflag.h"
@@ -20,7 +21,7 @@ runtime·memhash(uintptr *h, uintptr s, void *a)
{
byte *b;
uintptr hash;
- if(use_aeshash) {
+ if(!NaCl && use_aeshash) {
runtime·aeshash(h, s, a);
return;
}
@@ -464,11 +465,15 @@ runtime·algarray[] =
// Runtime helpers.
// used in asm_{386,amd64}.s
+#pragma dataflag NOPTR
byte runtime·aeskeysched[HashRandomBytes];
void
runtime·hashinit(void)
{
+ if(NaCl)
+ return;
+
// Install aes hash algorithm if we have the instructions we need
if((runtime·cpuid_ecx & (1 << 25)) != 0 && // aes (aesenc)
(runtime·cpuid_ecx & (1 << 9)) != 0 && // sse3 (pshufb)
@@ -505,37 +510,40 @@ void
runtime·equal(Type *t, ...)
{
byte *x, *y;
- uintptr ret;
+ bool *ret;
- x = (byte*)(&t+1);
+ x = (byte*)ROUND((uintptr)(&t+1), t->align);
y = x + t->size;
- ret = (uintptr)(y + t->size);
- ret = ROUND(ret, Structrnd);
- t->alg->equal((bool*)ret, t->size, x, y);
+ ret = (bool*)ROUND((uintptr)(y+t->size), Structrnd);
+ t->alg->equal(ret, t->size, x, y);
+}
+
+// Testing adapter for memclr
+func memclrBytes(s Slice) {
+ runtime·memclr(s.array, s.len);
}
// Testing adapters for hash quality tests (see hash_test.go)
-void runtime·haveGoodHash(bool res) {
+func haveGoodHash() (res bool) {
res = use_aeshash;
- FLUSH(&res);
}
-void runtime·stringHash(String s, uintptr seed, uintptr res) {
+
+func stringHash(s String, seed uintptr) (res uintptr) {
runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
res = seed;
- FLUSH(&res);
}
-void runtime·bytesHash(Slice s, uintptr seed, uintptr res) {
+
+func bytesHash(s Slice, seed uintptr) (res uintptr) {
runtime·algarray[AMEM].hash(&seed, s.len, s.array);
res = seed;
- FLUSH(&res);
}
-void runtime·int32Hash(uint32 i, uintptr seed, uintptr res) {
+
+func int32Hash(i uint32, seed uintptr) (res uintptr) {
runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
res = seed;
- FLUSH(&res);
}
-void runtime·int64Hash(uint64 i, uintptr seed, uintptr res) {
+
+func int64Hash(i uint64, seed uintptr) (res uintptr) {
runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
res = seed;
- FLUSH(&res);
}
diff --git a/src/pkg/runtime/append_test.go b/src/pkg/runtime/append_test.go
index 937c8259f..a67dc9b49 100644
--- a/src/pkg/runtime/append_test.go
+++ b/src/pkg/runtime/append_test.go
@@ -19,6 +19,25 @@ func BenchmarkAppend(b *testing.B) {
}
}
+func BenchmarkAppendGrowByte(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x []byte
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, byte(j))
+ }
+ }
+}
+
+func BenchmarkAppendGrowString(b *testing.B) {
+ var s string
+ for i := 0; i < b.N; i++ {
+ var x []string
+ for j := 0; j < 1<<20; j++ {
+ x = append(x, s)
+ }
+ }
+}
+
func benchmarkAppendBytes(b *testing.B, length int) {
b.StopTimer()
x := make([]byte, 0, N)
diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
index ebdb3ff4e..5c0a54f8c 100644
--- a/src/pkg/runtime/arch_386.h
+++ b/src/pkg/runtime/arch_386.h
@@ -7,5 +7,10 @@ enum {
BigEndian = 0,
CacheLineSize = 64,
RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+ PhysPageSize = 65536,
+#else
+ PhysPageSize = 4096,
+#endif
PCQuantum = 1
};
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
index 2bddf0796..c8a21847c 100644
--- a/src/pkg/runtime/arch_amd64.h
+++ b/src/pkg/runtime/arch_amd64.h
@@ -6,6 +6,15 @@ enum {
thechar = '6',
BigEndian = 0,
CacheLineSize = 64,
+#ifdef GOOS_solaris
+ RuntimeGogoBytes = 80,
+#else
+#ifdef GOOS_windows
+ RuntimeGogoBytes = 80,
+#else
RuntimeGogoBytes = 64,
+#endif // Windows
+#endif // Solaris
+ PhysPageSize = 4096,
PCQuantum = 1
};
diff --git a/src/pkg/runtime/arch_amd64p32.h b/src/pkg/runtime/arch_amd64p32.h
new file mode 100644
index 000000000..073a9e30e
--- /dev/null
+++ b/src/pkg/runtime/arch_amd64p32.h
@@ -0,0 +1,16 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+enum {
+ thechar = '6',
+ BigEndian = 0,
+ CacheLineSize = 64,
+ RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+ PhysPageSize = 65536,
+#else
+ PhysPageSize = 4096,
+#endif
+ PCQuantum = 1
+};
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
index e5da01c60..b9711289f 100644
--- a/src/pkg/runtime/arch_arm.h
+++ b/src/pkg/runtime/arch_arm.h
@@ -7,5 +7,6 @@ enum {
BigEndian = 0,
CacheLineSize = 32,
RuntimeGogoBytes = 80,
+ PhysPageSize = 4096,
PCQuantum = 4
};
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 5c642c0ed..95312089d 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -247,6 +247,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL $0, 0x1003 // crash if newstack returns
RET
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
+ MOVL $0, DX
+ JMP runtime·morestack(SB)
+
// Called from panic. Mimics morestack,
// reuses stack growth code to create a frame
// with the desired args running the desired function.
@@ -307,7 +311,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-12
JMP AX
// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-12
+TEXT reflect·call(SB), NOSPLIT, $0-16
MOVL argsize+8(FP), CX
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -339,8 +343,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-12
MOVL $runtime·badreflectcall(SB), AX
JMP AX
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVL argptr+4(FP), SI; \
MOVL argsize+8(FP), CX; \
@@ -348,11 +366,17 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
REP;MOVSB; \
/* call function */ \
MOVL f+0(FP), DX; \
- CALL (DX); \
+ MOVL (DX), AX; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
+ CALL AX; \
/* copy return values back */ \
MOVL argptr+4(FP), DI; \
MOVL argsize+8(FP), CX; \
+ MOVL retoffset+12(FP), BX; \
MOVL SP, SI; \
+ ADDL BX, DI; \
+ ADDL BX, SI; \
+ SUBL BX, CX; \
REP;MOVSB; \
RET
@@ -483,6 +507,12 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-8
XCHGL AX, 0(BX)
RET
+TEXT runtime·xchgp(SB), NOSPLIT, $0-8
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ XCHGL AX, 0(BX)
+ RET
+
TEXT runtime·procyield(SB),NOSPLIT,$0-0
MOVL 4(SP), AX
again:
@@ -646,7 +676,6 @@ havem:
// Save current sp in m->g0->sched.sp in preparation for
// switch back to m->curg stack.
// NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).
- // On Windows, the SEH is at 4(SP) and 8(SP).
MOVL m_g0(BP), SI
MOVL (g_sched+gobuf_sp)(SI), AX
MOVL AX, 0(SP)
@@ -747,21 +776,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
INT $3
RET
-TEXT runtime·memclr(SB),NOSPLIT,$0-8
- MOVL 4(SP), DI // arg 1 addr
- MOVL 8(SP), CX // arg 2 count
- MOVL CX, BX
- ANDL $3, BX
- SHRL $2, CX
- MOVL $0, AX
- CLD
- REP
- STOSL
- MOVL BX, CX
- REP
- STOSB
- RET
-
TEXT runtime·getcallerpc(SB),NOSPLIT,$0-4
MOVL x+0(FP),AX // addr of first arg
MOVL -4(AX),AX // get calling pc
@@ -1353,3 +1367,800 @@ cmp_allsame:
SETEQ CX // 1 if alen == blen
LEAL -1(CX)(AX*2), AX // 1,0,-1 result
RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/8g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ STOSL
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSL but
+// for some reason MOVSL is really slow.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ MOVL (SI),CX
+ ADDL $4,SI
+ MOVL CX,(DI)
+ ADDL $4,DI
+
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 2c2ffedd1..3c7eaf343 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -53,6 +53,9 @@ needtls:
// skip TLS setup on Plan 9
CMPL runtime·isplan9(SB), $1
JEQ ok
+ // skip TLS setup on Solaris
+ CMPL runtime·issolaris(SB), $1
+ JEQ ok
LEAQ runtime·tls0(SB), DI
CALL runtime·settls(SB)
@@ -286,7 +289,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
JMP AX
// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-20
+TEXT reflect·call(SB), NOSPLIT, $0-24
MOVLQZX argsize+16(FP), CX
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -318,8 +321,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-20
MOVQ $runtime·badreflectcall(SB), AX
JMP AX
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-24; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVQ argptr+8(FP), SI; \
MOVLQZX argsize+16(FP), CX; \
@@ -327,11 +344,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20; \
REP;MOVSB; \
/* call function */ \
MOVQ f+0(FP), DX; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
CALL (DX); \
/* copy return values back */ \
MOVQ argptr+8(FP), DI; \
MOVLQZX argsize+16(FP), CX; \
+ MOVLQZX retoffset+20(FP), BX; \
MOVQ SP, SI; \
+ ADDQ BX, DI; \
+ ADDQ BX, SI; \
+ SUBQ BX, CX; \
REP;MOVSB; \
RET
@@ -453,6 +475,46 @@ TEXT morestack<>(SB),NOSPLIT,$0
MOVQ $runtime·morestack(SB), AX
JMP AX
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack48(SB)
+
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
// if(*val == old){
@@ -546,6 +608,12 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-16
XCHGQ AX, 0(BX)
RET
+TEXT runtime·xchgp(SB), NOSPLIT, $0-16
+ MOVQ 8(SP), BX
+ MOVQ 16(SP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
TEXT runtime·procyield(SB),NOSPLIT,$0-0
MOVL 8(SP), AX
again:
@@ -614,10 +682,16 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16
MOVQ m_g0(BP), SI
MOVQ g(CX), DI
CMPQ SI, DI
- JEQ 4(PC)
+ JEQ nosave
+ MOVQ m_gsignal(BP), SI
+ CMPQ SI, DI
+ JEQ nosave
+
+ MOVQ m_g0(BP), SI
CALL gosave<>(SB)
MOVQ SI, g(CX)
MOVQ (g_sched+gobuf_sp)(SI), SP
+nosave:
// Now on a scheduling stack (a pthread-created stack).
// Make sure we have enough room for 4 stack-backed fast-call
@@ -779,21 +853,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
INT $3
RET
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
- MOVQ 8(SP), DI // arg 1 addr
- MOVQ 16(SP), CX // arg 2 count
- MOVQ CX, BX
- ANDQ $7, BX
- SHRQ $3, CX
- MOVQ $0, AX
- CLD
- REP
- STOSQ
- MOVQ BX, CX
- REP
- STOSB
- RET
-
TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
@@ -1340,3 +1399,801 @@ TEXT bytes·Equal(SB),NOSPLIT,$0-49
eqret:
MOVB AX, ret+48(FP)
RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ STOSQ
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSQ but
+// for some reason that is 3.5x slower than this code.
+// The STOSQ above seem fine, though.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ MOVQ (SI),CX
+ ADDQ $8,SI
+ MOVQ CX,(DI)
+ ADDQ $8,DI
+
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64p32.s b/src/pkg/runtime/asm_amd64p32.s
new file mode 100644
index 000000000..d47f12283
--- /dev/null
+++ b/src/pkg/runtime/asm_amd64p32.s
@@ -0,0 +1,1073 @@
+// 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.
+
+#include "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_go(SB),NOSPLIT,$0
+ // copy arguments forward on an even stack
+ MOVL argc+0(FP), AX
+ MOVL argv+4(FP), BX
+ MOVL SP, CX
+ SUBL $128, SP // plenty of scratch
+ ANDL $~15, CX
+ MOVL CX, SP
+
+ MOVL AX, 16(SP)
+ MOVL BX, 24(SP)
+
+ // create istack out of the given (operating system) stack.
+ MOVL $runtime·g0(SB), DI
+ LEAL (-64*1024+104)(SP), DI
+ MOVL BX, g_stackguard(DI)
+ MOVL BX, g_stackguard0(DI)
+ MOVL SP, g_stackbase(DI)
+
+ // find out information about the processor we're on
+ MOVQ $0, AX
+ CPUID
+ CMPQ AX, $0
+ JE nocpuinfo
+ MOVQ $1, AX
+ CPUID
+ MOVL CX, runtime·cpuid_ecx(SB)
+ MOVL DX, runtime·cpuid_edx(SB)
+nocpuinfo:
+
+needtls:
+ LEAL runtime·tls0(SB), DI
+ CALL runtime·settls(SB)
+
+ // store through it, to make sure it works
+ get_tls(BX)
+ MOVQ $0x123, g(BX)
+ MOVQ runtime·tls0(SB), AX
+ CMPQ AX, $0x123
+ JEQ 2(PC)
+ MOVL AX, 0 // abort
+ok:
+ // set the per-goroutine and per-mach "registers"
+ get_tls(BX)
+ LEAL runtime·g0(SB), CX
+ MOVL CX, g(BX)
+ LEAL runtime·m0(SB), AX
+ MOVL AX, m(BX)
+
+ // save m->g0 = g0
+ MOVL CX, m_g0(AX)
+
+ CLD // convention is D is always left cleared
+ CALL runtime·check(SB)
+
+ MOVL 16(SP), AX // copy argc
+ MOVL AX, 0(SP)
+ MOVL 24(SP), AX // copy argv
+ MOVL AX, 4(SP)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·hashinit(SB)
+ CALL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ MOVL $runtime·main·f(SB), AX // entry
+ MOVL $0, 0(SP)
+ MOVL AX, 4(SP)
+ ARGSIZE(8)
+ CALL runtime·newproc(SB)
+ ARGSIZE(-1)
+
+ // start this M
+ CALL runtime·mstart(SB)
+
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+DATA runtime·main·f+0(SB)/4,$runtime·main(SB)
+GLOBL runtime·main·f(SB),RODATA,$4
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
+ INT $3
+ RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$0-0
+ // No per-thread init.
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $0-4
+ MOVL b+0(FP), AX // gobuf
+ LEAL b+0(FP), BX // caller's SP
+ MOVL BX, gobuf_sp(AX)
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, gobuf_pc(AX)
+ MOVL $0, gobuf_ctxt(AX)
+ MOVQ $0, gobuf_ret(AX)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL BX, gobuf_g(AX)
+ RET
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), NOSPLIT, $0-4
+ MOVL b+0(FP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ MOVL 0(DX), CX // make sure g != nil
+ get_tls(CX)
+ MOVL DX, g(CX)
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_ctxt(BX), DX
+ MOVQ gobuf_ret(BX), AX
+ MOVL $0, gobuf_sp(BX) // clear to help garbage collector
+ MOVQ $0, gobuf_ret(BX)
+ MOVL $0, gobuf_ctxt(BX)
+ MOVL gobuf_pc(BX), BX
+ JMP BX
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), NOSPLIT, $0-4
+ MOVL fn+0(FP), DI
+
+ get_tls(CX)
+ MOVL g(CX), AX // save state in g->sched
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, (g_sched+gobuf_pc)(AX)
+ LEAL fn+0(FP), BX // caller's SP
+ MOVL BX, (g_sched+gobuf_sp)(AX)
+ MOVL AX, (g_sched+gobuf_g)(AX)
+
+ // switch to m->g0 & its stack, call fn
+ MOVL m(CX), BX
+ MOVL m_g0(BX), SI
+ CMPL SI, AX // if g == m->g0 call badmcall
+ JNE 3(PC)
+ MOVL $runtime·badmcall(SB), AX
+ JMP AX
+ MOVL SI, g(CX) // g = m->g0
+ MOVL (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp
+ PUSHQ AX
+ ARGSIZE(8)
+ CALL DI
+ POPQ AX
+ MOVL $runtime·badmcall2(SB), AX
+ JMP AX
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already done get_tls(CX); MOVQ m(CX), BX.
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$0-0
+ // Cannot grow scheduler stack (m->g0).
+ MOVL m_g0(BX), SI
+ CMPL g(CX), SI
+ JNE 2(PC)
+ MOVL 0, AX
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVL 8(SP), AX // f's caller's PC
+ MOVL AX, (m_morebuf+gobuf_pc)(BX)
+ LEAL 16(SP), AX // f's caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL AX, m_moreargp(BX)
+ get_tls(CX)
+ MOVL g(CX), SI
+ MOVL SI, (m_morebuf+gobuf_g)(BX)
+
+ // Set g->sched to context in f.
+ MOVL 0(SP), AX // f's PC
+ MOVL AX, (g_sched+gobuf_pc)(SI)
+ MOVL SI, (g_sched+gobuf_g)(SI)
+ LEAL 8(SP), AX // f's SP
+ MOVL AX, (g_sched+gobuf_sp)(SI)
+ MOVL DX, (g_sched+gobuf_ctxt)(SI)
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
+ MOVL $0, 0x1003 // crash if newstack returns
+ RET
+
+// Called from panic. Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// func call(fn *byte, arg *byte, argsize uint32).
+TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
+ get_tls(CX)
+ MOVL m(CX), BX
+
+ // Save our caller's state as the PC and SP to
+ // restore when returning from f.
+ MOVL 0(SP), AX // our caller's PC
+ MOVL AX, (m_morebuf+gobuf_pc)(BX)
+ LEAL 8(SP), AX // our caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL g(CX), AX
+ MOVL AX, (m_morebuf+gobuf_g)(BX)
+
+ // Save our own state as the PC and SP to restore
+ // if this goroutine needs to be restarted.
+ MOVL $runtime·newstackcall(SB), DI
+ MOVL DI, (g_sched+gobuf_pc)(AX)
+ MOVL SP, (g_sched+gobuf_sp)(AX)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to 1, as a hint to newstack
+ // that this is a call from runtime·newstackcall.
+ // If it turns out that f needs a larger frame than
+ // the default stack, f's usual stack growth prolog will
+ // allocate a new segment (and recopy the arguments).
+ MOVL 8(SP), AX // fn
+ MOVL 12(SP), DX // arg frame
+ MOVL 16(SP), CX // arg size
+
+ MOVQ AX, m_cret(BX) // f's PC
+ MOVL DX, m_moreargp(BX) // argument frame pointer
+ MOVL CX, m_moreargsize(BX) // f's argument size
+ MOVL $1, m_moreframesize(BX) // f's frame size
+
+ // Call newstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ get_tls(CX)
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
+ MOVL $0, 0x1103 // crash if newstack returns
+ RET
+
+// reflect·call: call a function with the given argument list
+// func call(f *FuncVal, arg *byte, argsize uint32).
+// we don't have variable-sized frames, so we use a small number
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+// Caution: ugly multiline assembly macros in your future!
+
+#define DISPATCH(NAME,MAXSIZE) \
+ CMPL CX, $MAXSIZE; \
+ JA 3(PC); \
+ MOVL $runtime·NAME(SB), AX; \
+ JMP AX
+// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
+
+TEXT reflect·call(SB), NOSPLIT, $0-20
+ MOVLQZX argsize+8(FP), CX
+ DISPATCH(call16, 16)
+ DISPATCH(call32, 32)
+ DISPATCH(call64, 64)
+ DISPATCH(call128, 128)
+ DISPATCH(call256, 256)
+ DISPATCH(call512, 512)
+ DISPATCH(call1024, 1024)
+ DISPATCH(call2048, 2048)
+ DISPATCH(call4096, 4096)
+ DISPATCH(call8192, 8192)
+ DISPATCH(call16384, 16384)
+ DISPATCH(call32768, 32768)
+ DISPATCH(call65536, 65536)
+ DISPATCH(call131072, 131072)
+ DISPATCH(call262144, 262144)
+ DISPATCH(call524288, 524288)
+ DISPATCH(call1048576, 1048576)
+ DISPATCH(call2097152, 2097152)
+ DISPATCH(call4194304, 4194304)
+ DISPATCH(call8388608, 8388608)
+ DISPATCH(call16777216, 16777216)
+ DISPATCH(call33554432, 33554432)
+ DISPATCH(call67108864, 67108864)
+ DISPATCH(call134217728, 134217728)
+ DISPATCH(call268435456, 268435456)
+ DISPATCH(call536870912, 536870912)
+ DISPATCH(call1073741824, 1073741824)
+ MOVL $runtime·badreflectcall(SB), AX
+ JMP AX
+
+#define CALLFN(NAME,MAXSIZE) \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ /* copy arguments to stack */ \
+ MOVL argptr+4(FP), SI; \
+ MOVL argsize+8(FP), CX; \
+ MOVL SP, DI; \
+ REP;MOVSB; \
+ /* call function */ \
+ MOVL f+0(FP), DX; \
+ MOVL (DX), AX; \
+ CALL AX; \
+ /* copy return values back */ \
+ MOVL argptr+4(FP), DI; \
+ MOVL argsize+8(FP), CX; \
+ MOVL retoffset+12(FP), BX; \
+ MOVL SP, SI; \
+ ADDL BX, DI; \
+ ADDL BX, SI; \
+ SUBL BX, CX; \
+ REP;MOVSB; \
+ RET
+
+CALLFN(call16, 16)
+CALLFN(call32, 32)
+CALLFN(call64, 64)
+CALLFN(call128, 128)
+CALLFN(call256, 256)
+CALLFN(call512, 512)
+CALLFN(call1024, 1024)
+CALLFN(call2048, 2048)
+CALLFN(call4096, 4096)
+CALLFN(call8192, 8192)
+CALLFN(call16384, 16384)
+CALLFN(call32768, 32768)
+CALLFN(call65536, 65536)
+CALLFN(call131072, 131072)
+CALLFN(call262144, 262144)
+CALLFN(call524288, 524288)
+CALLFN(call1048576, 1048576)
+CALLFN(call2097152, 2097152)
+CALLFN(call4194304, 4194304)
+CALLFN(call8388608, 8388608)
+CALLFN(call16777216, 16777216)
+CALLFN(call33554432, 33554432)
+CALLFN(call67108864, 67108864)
+CALLFN(call134217728, 134217728)
+CALLFN(call268435456, 268435456)
+CALLFN(call536870912, 536870912)
+CALLFN(call1073741824, 1073741824)
+
+// Return point when leaving stack.
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), NOSPLIT, $0-0
+ // Save return value in m->cret
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ AX, m_cret(BX) // MOVQ, to save all 64 bits
+
+ // Call oldstack on m->g0's stack.
+ MOVL m_g0(BX), BX
+ MOVL BX, g(CX)
+ MOVL (g_sched+gobuf_sp)(BX), SP
+ CALL runtime·oldstack(SB)
+ MOVL $0, 0x1004 // crash if oldstack returns
+ RET
+
+// morestack trampolines
+TEXT runtime·morestack00(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ $0, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack01(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ SHLQ $32, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack10(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVLQZX AX, AX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack11(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ MOVQ AX, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+// subcases of morestack01
+// with const of 8,16,...48
+TEXT runtime·morestack8(SB),NOSPLIT,$0
+ MOVQ $1, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack16(SB),NOSPLIT,$0
+ MOVQ $2, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack24(SB),NOSPLIT,$0
+ MOVQ $3, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack32(SB),NOSPLIT,$0
+ MOVQ $4, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack40(SB),NOSPLIT,$0
+ MOVQ $5, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT runtime·morestack48(SB),NOSPLIT,$0
+ MOVQ $6, R8
+ MOVL $morestack<>(SB), AX
+ JMP AX
+
+TEXT morestack<>(SB),NOSPLIT,$0
+ get_tls(CX)
+ MOVL m(CX), BX
+ SHLQ $35, R8
+ MOVQ R8, m_moreframesize(BX)
+ MOVL $runtime·morestack(SB), AX
+ JMP AX
+
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+ MOVL $0, DX
+ JMP runtime·morestack48(SB)
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·cas(SB), NOSPLIT, $0-12
+ MOVL val+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// bool runtime·cas64(uint64 *val, uint64 old, uint64 new)
+// Atomically:
+// if(*val == *old){
+// *val = new;
+// return 1;
+// } else {
+// return 0;
+// }
+TEXT runtime·cas64(SB), NOSPLIT, $0-24
+ MOVL val+0(FP), BX
+ MOVQ old+8(FP), AX
+ MOVQ new+16(FP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BX)
+ JNZ cas64_fail
+ MOVL $1, AX
+ RET
+cas64_fail:
+ MOVL $0, AX
+ RET
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT runtime·casp(SB), NOSPLIT, $0-12
+ MOVL val+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+// *val += delta;
+// return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-8
+ MOVL val+0(FP), BX
+ MOVL delta+4(FP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL CX, AX
+ RET
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-16
+ MOVL val+0(FP), BX
+ MOVQ delta+8(FP), AX
+ MOVQ AX, CX
+ LOCK
+ XADDQ AX, 0(BX)
+ ADDQ CX, AX
+ RET
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-8
+ MOVL val+0(FP), BX
+ MOVL new+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-16
+ MOVL val+0(FP), BX
+ MOVQ new+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+ MOVL val+0(FP), AX
+again:
+ PAUSE
+ SUBL $1, AX
+ JNZ again
+ RET
+
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+ MOVL ptr+0(FP), BX
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
+ MOVL fn+0(FP), DX
+ MOVL callersp+4(FP), BX
+ LEAL -8(BX), SP // caller sp after CALL
+ SUBL $5, (SP) // return to CALL again
+ MOVL 0(DX), BX
+ JMP BX // but first run the deferred function
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Not implemented.
+TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8
+ MOVL 0, AX
+ RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Not implemented.
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
+ MOVL 0, AX
+ RET
+
+// void setmg(M*, G*); set m and g. for use by needm.
+// Not implemented.
+TEXT runtime·setmg(SB), NOSPLIT, $0-8
+ MOVL 0, AX
+ RET
+
+// check that SP is in range [g->stackbase, g->stackguard)
+TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
+ get_tls(CX)
+ MOVL g(CX), AX
+ CMPL g_stackbase(AX), SP
+ JHI 2(PC)
+ MOVL 0, AX
+ CMPL SP, g_stackguard(AX)
+ JHI 2(PC)
+ MOVL 0, AX
+ RET
+
+TEXT runtime·memclr(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), DI
+ MOVL count+4(FP), CX
+ MOVQ CX, BX
+ ANDQ $7, BX
+ SHRQ $3, CX
+ MOVQ $0, AX
+ CLD
+ REP
+ STOSQ
+ MOVQ BX, CX
+ REP
+ STOSB
+ RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL -8(AX),AX // get calling pc
+ RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-16
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL pc+4(FP), BX // pc to set
+ MOVQ BX, -8(AX) // set calling pc
+ RET
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-8
+ MOVL sp+0(FP), AX
+ RET
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-0
+ RDTSC
+ SHLQ $32, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·stackguard(SB),NOSPLIT,$0-16
+ MOVL SP, DX
+ MOVL DX, sp+0(FP)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL g_stackguard(BX), DX
+ MOVL DX, limit+4(FP)
+ RET
+
+GLOBL runtime·tls0(SB), $64
+
+// hash function using AES hardware instructions
+// For now, our one amd64p32 system (NaCl) does not
+// support using AES instructions, so have not bothered to
+// write the implementations. Can copy and adjust the ones
+// in asm_amd64.s when the time comes.
+
+TEXT runtime·aeshash(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
+ RET
+
+TEXT runtime·memeq(SB),NOSPLIT,$0-12
+ MOVL a+0(FP), SI
+ MOVL b+4(FP), DI
+ MOVL count+8(FP), BX
+ JMP runtime·memeqbody(SB)
+
+// a in SI
+// b in DI
+// count in BX
+TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
+ XORQ AX, AX
+
+ CMPQ BX, $8
+ JB small
+
+ // 64 bytes at a time using xmm registers
+hugeloop:
+ CMPQ BX, $64
+ JB bigloop
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ MOVOU 16(SI), X2
+ MOVOU 16(DI), X3
+ MOVOU 32(SI), X4
+ MOVOU 32(DI), X5
+ MOVOU 48(SI), X6
+ MOVOU 48(DI), X7
+ PCMPEQB X1, X0
+ PCMPEQB X3, X2
+ PCMPEQB X5, X4
+ PCMPEQB X7, X6
+ PAND X2, X0
+ PAND X6, X4
+ PAND X4, X0
+ PMOVMSKB X0, DX
+ ADDQ $64, SI
+ ADDQ $64, DI
+ SUBQ $64, BX
+ CMPL DX, $0xffff
+ JEQ hugeloop
+ RET
+
+ // 8 bytes at a time using 64-bit register
+bigloop:
+ CMPQ BX, $8
+ JBE leftover
+ MOVQ (SI), CX
+ MOVQ (DI), DX
+ ADDQ $8, SI
+ ADDQ $8, DI
+ SUBQ $8, BX
+ CMPQ CX, DX
+ JEQ bigloop
+ RET
+
+ // remaining 0-8 bytes
+leftover:
+ ADDQ BX, SI
+ ADDQ BX, DI
+ MOVQ -8(SI), CX
+ MOVQ -8(DI), DX
+ CMPQ CX, DX
+ SETEQ AX
+ RET
+
+small:
+ CMPQ BX, $0
+ JEQ equal
+
+ LEAQ 0(BX*8), CX
+ NEGQ CX
+
+ CMPB SI, $0xf8
+ JA si_high
+
+ // load at SI won't cross a page boundary.
+ MOVQ (SI), SI
+ JMP si_finish
+si_high:
+ // address ends in 11111xxx. Load up to bytes we want, move to correct position.
+ MOVQ BX, DX
+ ADDQ SI, DX
+ MOVQ -8(DX), SI
+ SHRQ CX, SI
+si_finish:
+
+ // same for DI.
+ CMPB DI, $0xf8
+ JA di_high
+ MOVQ (DI), DI
+ JMP di_finish
+di_high:
+ MOVQ BX, DX
+ ADDQ DI, DX
+ MOVQ -8(DX), DI
+ SHRQ CX, DI
+di_finish:
+
+ SUBQ SI, DI
+ SHLQ CX, DI
+equal:
+ SETEQ AX
+ RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+ MOVL s1+0(FP), SI
+ MOVL s1+4(FP), BX
+ MOVL s2+8(FP), DI
+ MOVL s2+12(FP), DX
+ CALL runtime·cmpbody(SB)
+ MOVL AX, res+16(FP)
+ RET
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
+ MOVL s1+0(FP), SI
+ MOVL s1+4(FP), BX
+ MOVL s2+12(FP), DI
+ MOVL s2+16(FP), DX
+ CALL runtime·cmpbody(SB)
+ MOVQ AX, res+24(FP)
+ RET
+
+// input:
+// SI = a
+// DI = b
+// BX = alen
+// DX = blen
+// output:
+// AX = 1/0/-1
+TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
+ CMPQ SI, DI
+ JEQ cmp_allsame
+ CMPQ BX, DX
+ MOVQ DX, R8
+ CMOVQLT BX, R8 // R8 = min(alen, blen) = # of bytes to compare
+ CMPQ R8, $8
+ JB cmp_small
+
+cmp_loop:
+ CMPQ R8, $16
+ JBE cmp_0through16
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ PCMPEQB X0, X1
+ PMOVMSKB X1, AX
+ XORQ $0xffff, AX // convert EQ to NE
+ JNE cmp_diff16 // branch if at least one byte is not equal
+ ADDQ $16, SI
+ ADDQ $16, DI
+ SUBQ $16, R8
+ JMP cmp_loop
+
+ // AX = bit mask of differences
+cmp_diff16:
+ BSFQ AX, BX // index of first byte that differs
+ XORQ AX, AX
+ ADDQ BX, SI
+ MOVB (SI), CX
+ ADDQ BX, DI
+ CMPB CX, (DI)
+ SETHI AX
+ LEAQ -1(AX*2), AX // convert 1/0 to +1/-1
+ RET
+
+ // 0 through 16 bytes left, alen>=8, blen>=8
+cmp_0through16:
+ CMPQ R8, $8
+ JBE cmp_0through8
+ MOVQ (SI), AX
+ MOVQ (DI), CX
+ CMPQ AX, CX
+ JNE cmp_diff8
+cmp_0through8:
+ ADDQ R8, SI
+ ADDQ R8, DI
+ MOVQ -8(SI), AX
+ MOVQ -8(DI), CX
+ CMPQ AX, CX
+ JEQ cmp_allsame
+
+ // AX and CX contain parts of a and b that differ.
+cmp_diff8:
+ BSWAPQ AX // reverse order of bytes
+ BSWAPQ CX
+ XORQ AX, CX
+ BSRQ CX, CX // index of highest bit difference
+ SHRQ CX, AX // move a's bit to bottom
+ ANDQ $1, AX // mask bit
+ LEAQ -1(AX*2), AX // 1/0 => +1/-1
+ RET
+
+ // 0-7 bytes in common
+cmp_small:
+ LEAQ (R8*8), CX // bytes left -> bits left
+ NEGQ CX // - bits lift (== 64 - bits left mod 64)
+ JEQ cmp_allsame
+
+ // load bytes of a into high bytes of AX
+ CMPB SI, $0xf8
+ JA cmp_si_high
+ MOVQ (SI), SI
+ JMP cmp_si_finish
+cmp_si_high:
+ ADDQ R8, SI
+ MOVQ -8(SI), SI
+ SHRQ CX, SI
+cmp_si_finish:
+ SHLQ CX, SI
+
+ // load bytes of b in to high bytes of BX
+ CMPB DI, $0xf8
+ JA cmp_di_high
+ MOVQ (DI), DI
+ JMP cmp_di_finish
+cmp_di_high:
+ ADDQ R8, DI
+ MOVQ -8(DI), DI
+ SHRQ CX, DI
+cmp_di_finish:
+ SHLQ CX, DI
+
+ BSWAPQ SI // reverse order of bytes
+ BSWAPQ DI
+ XORQ SI, DI // find bit differences
+ JEQ cmp_allsame
+ BSRQ DI, CX // index of highest bit difference
+ SHRQ CX, SI // move a's bit to bottom
+ ANDQ $1, SI // mask bit
+ LEAQ -1(SI*2), AX // 1/0 => +1/-1
+ RET
+
+cmp_allsame:
+ XORQ AX, AX
+ XORQ CX, CX
+ CMPQ BX, DX
+ SETGT AX // 1 if alen > blen
+ SETEQ CX // 1 if alen == blen
+ LEAQ -1(CX)(AX*2), AX // 1,0,-1 result
+ RET
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
+ MOVL s+0(FP), SI
+ MOVL s_len+4(FP), BX
+ MOVB c+12(FP), AL
+ CALL runtime·indexbytebody(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0
+ MOVL s+0(FP), SI
+ MOVL s_len+4(FP), BX
+ MOVB c+8(FP), AL
+ CALL runtime·indexbytebody(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+// input:
+// SI: data
+// BX: data len
+// AL: byte sought
+// output:
+// AX
+TEXT runtime·indexbytebody(SB),NOSPLIT,$0
+ MOVL SI, DI
+
+ CMPL BX, $16
+ JLT indexbyte_small
+
+ // round up to first 16-byte boundary
+ TESTL $15, SI
+ JZ aligned
+ MOVL SI, CX
+ ANDL $~15, CX
+ ADDL $16, CX
+
+ // search the beginning
+ SUBL SI, CX
+ REPN; SCASB
+ JZ success
+
+// DI is 16-byte aligned; get ready to search using SSE instructions
+aligned:
+ // round down to last 16-byte boundary
+ MOVL BX, R11
+ ADDL SI, R11
+ ANDL $~15, R11
+
+ // shuffle X0 around so that each byte contains c
+ MOVD AX, X0
+ PUNPCKLBW X0, X0
+ PUNPCKLBW X0, X0
+ PSHUFL $0, X0, X0
+ JMP condition
+
+sse:
+ // move the next 16-byte chunk of the buffer into X1
+ MOVO (DI), X1
+ // compare bytes in X0 to X1
+ PCMPEQB X0, X1
+ // take the top bit of each byte in X1 and put the result in DX
+ PMOVMSKB X1, DX
+ TESTL DX, DX
+ JNZ ssesuccess
+ ADDL $16, DI
+
+condition:
+ CMPL DI, R11
+ JLT sse
+
+ // search the end
+ MOVL SI, CX
+ ADDL BX, CX
+ SUBL R11, CX
+ // if CX == 0, the zero flag will be set and we'll end up
+ // returning a false success
+ JZ failure
+ REPN; SCASB
+ JZ success
+
+failure:
+ MOVL $-1, AX
+ RET
+
+// handle for lengths < 16
+indexbyte_small:
+ MOVL BX, CX
+ REPN; SCASB
+ JZ success
+ MOVL $-1, AX
+ RET
+
+// we've found the chunk containing the byte
+// now just figure out which specific byte it is
+ssesuccess:
+ // get the index of the least significant set bit
+ BSFW DX, DX
+ SUBL SI, DI
+ ADDL DI, DX
+ MOVL DX, AX
+ RET
+
+success:
+ SUBL SI, DI
+ SUBL $1, DI
+ MOVL DI, AX
+ RET
+
+TEXT bytes·Equal(SB),NOSPLIT,$0-25
+ MOVL a_len+4(FP), BX
+ MOVL b_len+16(FP), CX
+ XORL AX, AX
+ CMPL BX, CX
+ JNE eqret
+ MOVL a+0(FP), SI
+ MOVL b+12(FP), DI
+ CALL runtime·memeqbody(SB)
+eqret:
+ MOVB AX, ret+24(FP)
+ RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ JMP time·now(SB)
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index f483e6fc8..1aea9036a 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -89,11 +89,9 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
WORD $0xe1200071 // BKPT 0x0001
RET
-GLOBL runtime·goarm(SB), $4
-
TEXT runtime·asminit(SB),NOSPLIT,$0-0
// disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
- MOVW runtime·goarm(SB), R11
+ MOVB runtime·goarm(SB), R11
CMP $5, R11
BLE 4(PC)
WORD $0xeef1ba10 // vmrs r11, fpscr
@@ -215,6 +213,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
// is still in this function, and not the beginning of the next.
RET
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
+ MOVW $0, R7
+ B runtime·morestack(SB)
+
// Called from panic. Mimics morestack,
// reuses stack growth code to create a frame
// with the desired args running the desired function.
@@ -267,7 +269,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $-4-12
MOVW $runtime·NAME(SB), R1; \
B (R1)
-TEXT reflect·call(SB), NOSPLIT, $-4-12
+TEXT reflect·call(SB), NOSPLIT, $-4-16
MOVW argsize+8(FP), R0
DISPATCH(call16, 16)
DISPATCH(call32, 32)
@@ -299,8 +301,22 @@ TEXT reflect·call(SB), NOSPLIT, $-4-12
MOVW $runtime·badreflectcall(SB), R1
B (R1)
+// Argument map for the callXX frames. Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
@@ -314,11 +330,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12; \
/* call function */ \
MOVW f+0(FP), R7; \
MOVW (R7), R0; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
BL (R0); \
/* copy return values back */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
+ MOVW retoffset+12(FP), R3; \
ADD $4, SP, R1; \
+ ADD R3, R1; \
+ ADD R3, R0; \
+ SUB R3, R2; \
CMP $0, R2; \
RET.EQ ; \
MOVBU.P 1(R1), R5; \
@@ -373,6 +394,10 @@ TEXT runtime·lessstack(SB), NOSPLIT, $-4-0
// 1. grab stored LR for caller
// 2. sub 4 bytes to get back to BL deferreturn
// 3. B to fn
+// TODO(rsc): Push things on stack and then use pop
+// to load all registers simultaneously, so that a profiling
+// interrupt can never see mismatched SP/LR/PC.
+// (And double-check that pop is atomic in that way.)
TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
@@ -629,17 +654,33 @@ _next:
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
-// g (R10) at 8(TP), m (R9) at 12(TP)
+// save_gm saves the g and m registers into pthread-provided
+// thread-local memory, so that we can call externally compiled
+// ARM code that will overwrite those registers.
+// NOTE: runtime.gogo assumes that R1 is preserved by this function.
TEXT runtime·save_gm(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
- MOVW g, 8(R0)
- MOVW m, 12(R0)
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsgm(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g and m.
+ MOVW $runtime·tlsgm(SB), R11
+ ADD R11, R0
+ MOVW g, 0(R0)
+ MOVW m, 4(R0)
RET
+// load_gm loads the g and m registers from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// ARM code that overwrote those registers.
TEXT runtime·load_gm(SB),NOSPLIT,$0
- MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
- MOVW 8(R0), g
- MOVW 12(R0), m
+ MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ // $runtime.tlsgm(SB) is a special linker symbol.
+ // It is the offset from the TLS base pointer to our
+ // thread-local storage for g and m.
+ MOVW $runtime·tlsgm(SB), R11
+ ADD R11, R0
+ MOVW 0(R0), g
+ MOVW 4(R0), m
RET
// void setmg_gcc(M*, G*); set m and g called from gcc.
@@ -648,7 +689,6 @@ TEXT setmg_gcc<>(SB),NOSPLIT,$0
MOVW R1, g
B runtime·save_gm(SB)
-
// TODO: share code with memeq?
TEXT bytes·Equal(SB),NOSPLIT,$0
MOVW a_len+4(FP), R1
@@ -726,3 +766,414 @@ _sib_notfound:
MOVW $-1, R0
MOVW R0, ret+12(FP)
RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+ B time·now(SB)
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory. Do not
+// change this code without also changing the code
+// in ../../cmd/5g/ggen.c:clearfat.
+// R0: zero
+// R1: ptr to memory to be zeroed
+// R1 is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ MOVW.P R0, 4(R1)
+ RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory. Source
+// and destination must not overlap. Do not
+// change this code without also changing the code
+// in ../../cmd/5g/cgen.c:sgen.
+// R0: scratch space
+// R1: ptr to source memory
+// R2: ptr to destination memory
+// R1 and R2 are updated as a side effect
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ RET
diff --git a/src/pkg/runtime/atomic_amd64.c b/src/pkg/runtime/atomic_amd64x.c
index 0bd4d906b..11b578936 100644
--- a/src/pkg/runtime/atomic_amd64.c
+++ b/src/pkg/runtime/atomic_amd64x.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build amd64 amd64p32
+
#include "runtime.h"
#include "../../cmd/ld/textflag.h"
diff --git a/src/pkg/runtime/atomic_arm.c b/src/pkg/runtime/atomic_arm.c
index b1e97b27d..d914475c7 100644
--- a/src/pkg/runtime/atomic_arm.c
+++ b/src/pkg/runtime/atomic_arm.c
@@ -42,6 +42,19 @@ runtime·xchg(uint32 volatile* addr, uint32 v)
}
#pragma textflag NOSPLIT
+void*
+runtime·xchgp(void* volatile* addr, void* v)
+{
+ void *old;
+
+ for(;;) {
+ old = *addr;
+ if(runtime·casp(addr, old, v))
+ return old;
+ }
+}
+
+#pragma textflag NOSPLIT
void
runtime·procyield(uint32 cnt)
{
diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c
index 88ee53bb5..285678fba 100644
--- a/src/pkg/runtime/callback_windows.c
+++ b/src/pkg/runtime/callback_windows.c
@@ -49,7 +49,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
runtime·cbctxts = &(cbs.ctxt[0]);
n = cbs.n;
for(i=0; i<n; i++) {
- if(cbs.ctxt[i]->gobody == fn.data) {
+ if(cbs.ctxt[i]->gobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) {
runtime·unlock(&cbs);
// runtime·callbackasm is just a series of CALL instructions
// (each is 5 bytes long), and we want callback to arrive at
@@ -63,6 +63,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
c = runtime·mal(sizeof *c);
c->gobody = fn.data;
c->argsize = argsize;
+ c->cleanstack = cleanstack;
if(cleanstack && argsize!=0)
c->restorestack = argsize;
else
diff --git a/src/pkg/runtime/cgo/asm_nacl_amd64p32.s b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
new file mode 100644
index 000000000..377cf72a3
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
@@ -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.
+
+#include "../../../cmd/ld/textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$0
+ INT $3
+ RET
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_386.c b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
index 6797824c6..695c16634 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_386.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
index eb342a2ff..a46c121ad 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index 6797824c6..695c16634 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index eb342a2ff..a46c121ad 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
SIGFILLSET(ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_arm.c b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
index 211dca75c..6175e1d9c 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
@@ -4,7 +4,9 @@
#include <sys/types.h>
#include <machine/sysarch.h>
+#include <sys/signalvar.h>
#include <pthread.h>
+#include <signal.h>
#include <string.h>
#include "libcgo.h"
@@ -39,10 +41,14 @@ void
_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ SIGFILLSET(ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -52,6 +58,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index c25c7b70f..0a46c9b7a 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -34,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
@@ -46,7 +46,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index bd7c88d99..c530183b7 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -34,14 +34,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c
index 9a6e58594..032568155 100644
--- a/src/pkg/runtime/cgo/gcc_linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <string.h>
+#include <signal.h>
#include "libcgo.h"
static void *threadentry(void*);
@@ -28,10 +29,14 @@ void
_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -41,6 +46,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_386.c b/src/pkg/runtime/cgo/gcc_netbsd_386.c
index b399e16dc..28690ccbd 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_386.c
@@ -35,14 +35,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
index f27e142ce..6e0482d5b 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_arm.c b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
index 68c8b6e71..ba2ae2568 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c
index 6422d1b93..e682c3725 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -122,14 +122,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = sys_pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
index 5a5a17114..64d29a935 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
@@ -122,7 +122,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
int err;
sigfillset(&ign);
- sigprocmask(SIG_SETMASK, &ign, &oset);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
@@ -130,7 +130,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
ts->g->stackguard = size;
err = sys_pthread_create(&p, &attr, threadentry, ts);
- sigprocmask(SIG_SETMASK, &oset, nil);
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c
index 02eab12e5..cdc866468 100644
--- a/src/pkg/runtime/cgo/gcc_windows_386.c
+++ b/src/pkg/runtime/cgo/gcc_windows_386.c
@@ -5,6 +5,8 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "libcgo.h"
static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
void
_cgo_sys_thread_start(ThreadStart *ts)
{
- _beginthread(threadentry, 0, ts);
+ uintptr_t thandle;
+
+ thandle = _beginthread(threadentry, 0, ts);
+ if(thandle == -1) {
+ fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+ abort();
+ }
}
static void
threadentry(void *v)
{
ThreadStart ts;
- void *tls0;
ts = *(ThreadStart*)v;
free(v);
@@ -43,16 +50,13 @@ threadentry(void *v)
/*
* Set specific keys in thread local storage.
*/
- tls0 = (void*)LocalAlloc(LPTR, 32);
asm volatile (
"movl %0, %%fs:0x14\n" // MOVL tls0, 0x14(FS)
"movl %%fs:0x14, %%eax\n" // MOVL 0x14(FS), tmp
"movl %1, 0(%%eax)\n" // MOVL g, 0(FS)
"movl %2, 4(%%eax)\n" // MOVL m, 4(FS)
- :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
+ :: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%eax"
);
crosscall_386(ts.fn);
-
- LocalFree(tls0);
}
diff --git a/src/pkg/runtime/cgo/gcc_windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c
index f7695a1cc..d8dd69b4a 100644
--- a/src/pkg/runtime/cgo/gcc_windows_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c
@@ -5,6 +5,8 @@
#define WIN64_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "libcgo.h"
static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
void
_cgo_sys_thread_start(ThreadStart *ts)
{
- _beginthread(threadentry, 0, ts);
+ uintptr_t thandle;
+
+ thandle = _beginthread(threadentry, 0, ts);
+ if(thandle == -1) {
+ fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+ abort();
+ }
}
static void
threadentry(void *v)
{
ThreadStart ts;
- void *tls0;
ts = *(ThreadStart*)v;
free(v);
@@ -43,13 +50,12 @@ threadentry(void *v)
/*
* Set specific keys in thread local storage.
*/
- tls0 = (void*)LocalAlloc(LPTR, 64);
asm volatile (
"movq %0, %%gs:0x28\n" // MOVL tls0, 0x28(GS)
"movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp
"movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
"movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
- :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
+ :: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%rax"
);
crosscall_amd64(ts.fn);
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index 41a371c27..65ea3f372 100644
--- a/src/pkg/runtime/cgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -34,6 +34,7 @@ struct ThreadStart
{
uintptr m;
G *g;
+ uintptr *tls;
void (*fn)(void);
};
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 2a04453fd..7b2ec26f3 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -99,12 +99,7 @@ runtime·cgocall(void (*fn)(void*), void *arg)
{
Defer d;
- if(m->racecall) {
- runtime·asmcgocall(fn, arg);
- return;
- }
-
- if(!runtime·iscgo && !Windows)
+ if(!runtime·iscgo && !Solaris && !Windows)
runtime·throw("cgocall unavailable");
if(fn == 0)
@@ -127,11 +122,10 @@ runtime·cgocall(void (*fn)(void*), void *arg)
d.fn = &endcgoV;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1; // unused because unlockm never recovers
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
-
+
m->ncgo++;
/*
@@ -171,17 +165,6 @@ endcgo(void)
runtime·raceacquire(&cgosync);
}
-void
-runtime·NumCgoCall(int64 ret)
-{
- M *mp;
-
- ret = 0;
- for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
- ret += mp->ncgocall;
- FLUSH(&ret);
-}
-
// Helper functions for cgo code.
void (*_cgo_malloc)(void*);
@@ -235,6 +218,11 @@ struct CallbackArgs
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
#endif
+// Unimplemented on amd64p32
+#ifdef GOARCH_amd64p32
+#define CBARGS (CallbackArgs*)(nil)
+#endif
+
// On 386, stack frame is three words, plus caller PC.
#ifdef GOARCH_386
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
@@ -251,21 +239,9 @@ runtime·cgocallbackg(void)
runtime·exit(2);
}
- if(m->racecall) {
- // We were not in syscall, so no need to call runtime·exitsyscall.
- // However we must set m->locks for the following reason.
- // Race detector runtime makes __tsan_symbolize cgo callback
- // holding internal mutexes. The mutexes are not cooperative with Go scheduler.
- // So if we deschedule a goroutine that holds race detector internal mutex
- // (e.g. preempt it), another goroutine will deadlock trying to acquire the same mutex.
- m->locks++;
- runtime·cgocallbackg1();
- m->locks--;
- } else {
- runtime·exitsyscall(); // coming out of cgo call
- runtime·cgocallbackg1();
- runtime·entersyscall(); // going back to cgo call
- }
+ runtime·exitsyscall(); // coming out of cgo call
+ runtime·cgocallbackg1();
+ runtime·entersyscall(); // going back to cgo call
}
void
@@ -283,19 +259,18 @@ runtime·cgocallbackg1(void)
d.fn = &unwindmf;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1; // unused because unwindm never recovers
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
- if(raceenabled && !m->racecall)
+ if(raceenabled)
runtime·raceacquire(&cgosync);
// Invoke callback.
cb = CBARGS;
runtime·newstackcall(cb->fn, cb->arg, cb->argsize);
- if(raceenabled && !m->racecall)
+ if(raceenabled)
runtime·racereleasemerge(&cgosync);
// Pop defer.
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.goc
index 48cc41e20..7a584717b 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.goc
@@ -2,96 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "type.h"
#include "race.h"
#include "malloc.h"
+#include "chan.h"
#include "../../cmd/ld/textflag.h"
-#define MAXALIGN 8
-#define NOSELGEN 1
-
-typedef struct WaitQ WaitQ;
-typedef struct SudoG SudoG;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-struct SudoG
-{
- G* g; // g and selgen constitute
- uint32 selgen; // a weak pointer to g
- SudoG* link;
- int64 releasetime;
- byte* elem; // data element
-};
-
-struct WaitQ
-{
- SudoG* first;
- SudoG* last;
-};
-
-// The garbage collector is assuming that Hchan can only contain pointers into the stack
-// and cannot contain pointers into the heap.
-struct Hchan
-{
- uintgo qcount; // total data in the q
- uintgo dataqsiz; // size of the circular q
- uint16 elemsize;
- uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
- bool closed;
- Alg* elemalg; // interface for element type
- uintgo sendx; // send index
- uintgo recvx; // receive index
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- Lock;
-};
-
uint32 runtime·Hchansize = sizeof(Hchan);
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
-
-enum
-{
- debug = 0,
-
- // Scase.kind
- CaseRecv,
- CaseSend,
- CaseDefault,
-};
-
-struct Scase
-{
- SudoG sg; // must be first member (cast to Scase)
- Hchan* chan; // chan
- byte* pc; // return pc
- uint16 kind;
- uint16 so; // vararg of selected bool
- bool* receivedp; // pointer to received bool (recv2)
-};
-
-struct Select
-{
- uint16 tcase; // total count of scase[]
- uint16 ncase; // currently filled scase[]
- uint16* pollorder; // case poll order
- Hchan** lockorder; // channel lock order
- Scase scase[1]; // one per case (in order of appearance)
-};
-
static void dequeueg(WaitQ*);
static SudoG* dequeue(WaitQ*);
static void enqueue(WaitQ*, SudoG*);
static void destroychan(Hchan*);
static void racesync(Hchan*, SudoG*);
-Hchan*
-runtime·makechan_c(ChanType *t, int64 hint)
+static Hchan*
+makechan(ChanType *t, int64 hint)
{
Hchan *c;
Type *elem;
@@ -104,13 +33,13 @@ runtime·makechan_c(ChanType *t, int64 hint)
if((sizeof(*c)%MAXALIGN) != 0 || elem->align > MAXALIGN)
runtime·throw("makechan: bad alignment");
- if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem / elem->size))
+ if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > (MaxMem - sizeof(*c)) / elem->size))
runtime·panicstring("makechan: size out of range");
// allocate memory in one call
c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0);
c->elemsize = elem->size;
- c->elemalg = elem->alg;
+ c->elemtype = elem;
c->dataqsiz = hint;
if(debug)
@@ -120,21 +49,12 @@ runtime·makechan_c(ChanType *t, int64 hint)
return c;
}
-// For reflect
-// func makechan(typ *ChanType, size uint64) (chan)
-void
-reflect·makechan(ChanType *t, uint64 size, Hchan *c)
-{
- c = runtime·makechan_c(t, size);
- FLUSH(&c);
+func reflect·makechan(t *ChanType, size uint64) (c *Hchan) {
+ c = makechan(t, size);
}
-// makechan(t *ChanType, hint int64) (hchan *chan any);
-void
-runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
-{
- ret = runtime·makechan_c(t, hint);
- FLUSH(&ret);
+func makechan(t *ChanType, size int64) (c *Hchan) {
+ c = makechan(t, size);
}
/*
@@ -151,27 +71,28 @@ runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
* been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed.
*/
-void
-runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
+static bool
+chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc)
{
SudoG *sg;
SudoG mysg;
G* gp;
int64 t0;
+ if(raceenabled)
+ runtime·racereadobjectpc(ep, t->elem, runtime·getcallerpc(&t), chansend);
+
if(c == nil) {
USED(t);
- if(pres != nil) {
- *pres = false;
- return;
- }
+ if(!block)
+ return false;
runtime·park(nil, nil, "chan send (nil chan)");
- return; // not reached
+ return false; // not reached
}
if(debug) {
runtime·printf("chansend: chan=%p; elem=", c);
- c->elemalg->print(c->elemsize, ep);
+ c->elemtype->alg->print(c->elemsize, ep);
runtime·prints("\n");
}
@@ -184,7 +105,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
runtime·lock(c);
if(raceenabled)
- runtime·racereadpc(c, pc, runtime·chansend);
+ runtime·racereadpc(c, pc, chansend);
if(c->closed)
goto closed;
@@ -200,28 +121,24 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
gp = sg->g;
gp->param = sg;
if(sg->elem != nil)
- c->elemalg->copy(c->elemsize, sg->elem, ep);
+ c->elemtype->alg->copy(c->elemsize, sg->elem, ep);
if(sg->releasetime)
sg->releasetime = runtime·cputicks();
runtime·ready(gp);
-
- if(pres != nil)
- *pres = true;
- return;
+ return true;
}
- if(pres != nil) {
+ if(!block) {
runtime·unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->sendq, &mysg);
- runtime·park(runtime·unlock, c, "chan send");
+ runtime·parkunlock(c, "chan send");
if(g->param == nil) {
runtime·lock(c);
@@ -233,32 +150,33 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->closed)
goto closed;
if(c->qcount >= c->dataqsiz) {
- if(pres != nil) {
+ if(!block) {
runtime·unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->sendq, &mysg);
- runtime·park(runtime·unlock, c, "chan send");
+ runtime·parkunlock(c, "chan send");
runtime·lock(c);
goto asynch;
}
- if(raceenabled)
+ if(raceenabled) {
+ runtime·raceacquire(chanbuf(c, c->sendx));
runtime·racerelease(chanbuf(c, c->sendx));
+ }
- c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
c->qcount++;
@@ -272,37 +190,36 @@ asynch:
runtime·ready(gp);
} else
runtime·unlock(c);
- if(pres != nil)
- *pres = true;
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
runtime·unlock(c);
runtime·panicstring("send on closed channel");
+ return false; // not reached
}
-void
-runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
+static bool
+chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received)
{
SudoG *sg;
SudoG mysg;
G *gp;
int64 t0;
+ // raceenabled: don't need to check ep, as it is always on the stack.
+
if(debug)
runtime·printf("chanrecv: chan=%p\n", c);
if(c == nil) {
USED(t);
- if(selected != nil) {
- *selected = false;
- return;
- }
+ if(!block)
+ return false;
runtime·park(nil, nil, "chan receive (nil chan)");
- return; // not reached
+ return false; // not reached
}
t0 = 0;
@@ -326,32 +243,29 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
runtime·unlock(c);
if(ep != nil)
- c->elemalg->copy(c->elemsize, ep, sg->elem);
+ c->elemtype->alg->copy(c->elemsize, ep, sg->elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
sg->releasetime = runtime·cputicks();
runtime·ready(gp);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
- return;
+ return true;
}
- if(selected != nil) {
+ if(!block) {
runtime·unlock(c);
- *selected = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->recvq, &mysg);
- runtime·park(runtime·unlock, c, "chan receive");
+ runtime·parkunlock(c, "chan receive");
if(g->param == nil) {
runtime·lock(c);
@@ -364,36 +278,37 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
*received = true;
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->qcount <= 0) {
if(c->closed)
goto closed;
- if(selected != nil) {
+ if(!block) {
runtime·unlock(c);
- *selected = false;
if(received != nil)
*received = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->recvq, &mysg);
- runtime·park(runtime·unlock, c, "chan receive");
+ runtime·parkunlock(c, "chan receive");
runtime·lock(c);
goto asynch;
}
- if(raceenabled)
+ if(raceenabled) {
runtime·raceacquire(chanbuf(c, c->recvx));
+ runtime·racerelease(chanbuf(c, c->recvx));
+ }
if(ep != nil)
- c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ c->elemtype->alg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz)
c->recvx = 0;
c->qcount--;
@@ -408,19 +323,15 @@ asynch:
} else
runtime·unlock(c);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
if(ep != nil)
- c->elemalg->copy(c->elemsize, ep, nil);
- if(selected != nil)
- *selected = true;
+ c->elemtype->alg->copy(c->elemsize, ep, nil);
if(received != nil)
*received = false;
if(raceenabled)
@@ -428,38 +339,25 @@ closed:
runtime·unlock(c);
if(mysg.releasetime > 0)
runtime·blockevent(mysg.releasetime - t0, 2);
+ return true;
}
-// chansend1(hchan *chan any, elem any);
#pragma textflag NOSPLIT
-void
-runtime·chansend1(ChanType *t, Hchan* c, ...)
-{
- runtime·chansend(t, c, (byte*)(&c+1), nil, runtime·getcallerpc(&t));
+func chansend1(t *ChanType, c *Hchan, elem *byte) {
+ chansend(t, c, elem, true, runtime·getcallerpc(&t));
}
-// chanrecv1(hchan *chan any) (elem any);
#pragma textflag NOSPLIT
-void
-runtime·chanrecv1(ChanType *t, Hchan* c, ...)
-{
- runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil);
+func chanrecv1(t *ChanType, c *Hchan, elem *byte) {
+ chanrecv(t, c, elem, true, nil);
}
-// chanrecv2(hchan *chan any) (elem any, received bool);
+// chanrecv2(hchan *chan any, elem *any) (received bool);
#pragma textflag NOSPLIT
-void
-runtime·chanrecv2(ChanType *t, Hchan* c, ...)
-{
- byte *ae, *ap;
-
- ae = (byte*)(&c+1);
- ap = ae + t->elem->size;
- runtime·chanrecv(t, c, ae, nil, ap);
+func chanrecv2(t *ChanType, c *Hchan, elem *byte) (received bool) {
+ chanrecv(t, c, elem, true, &received);
}
-// func selectnbsend(c chan any, elem any) bool
-//
// compiler implements
//
// select {
@@ -478,18 +376,10 @@ runtime·chanrecv2(ChanType *t, Hchan* c, ...)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbsend(ChanType *t, Hchan *c, ...)
-{
- byte *ae, *ap;
-
- ae = (byte*)(&c + 1);
- ap = ae + ROUND(t->elem->size, Structrnd);
- runtime·chansend(t, c, ae, ap, runtime·getcallerpc(&t));
+func selectnbsend(t *ChanType, c *Hchan, elem *byte) (selected bool) {
+ selected = chansend(t, c, elem, false, runtime·getcallerpc(&t));
}
-// func selectnbrecv(elem *any, c chan any) bool
-//
// compiler implements
//
// select {
@@ -508,14 +398,10 @@ runtime·selectnbsend(ChanType *t, Hchan *c, ...)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
-{
- runtime·chanrecv(t, c, v, &selected, nil);
+func selectnbrecv(t *ChanType, elem *byte, c *Hchan) (selected bool) {
+ selected = chanrecv(t, c, elem, false, nil);
}
-// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
-//
// compiler implements
//
// select {
@@ -534,89 +420,29 @@ runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
// }
//
#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected)
-{
- runtime·chanrecv(t, c, v, &selected, received);
+func selectnbrecv2(t *ChanType, elem *byte, received *bool, c *Hchan) (selected bool) {
+ selected = chanrecv(t, c, elem, false, received);
}
-// For reflect:
-// func chansend(c chan, val iword, nb bool) (selected bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-//
-// The "uintptr selected" is really "bool selected" but saying
-// uintptr gets us the right alignment for the output parameter block.
#pragma textflag NOSPLIT
-void
-reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
-{
- bool *sp;
- byte *vp;
-
- if(nb) {
- selected = false;
- sp = (bool*)&selected;
- } else {
- *(bool*)&selected = true;
- FLUSH(&selected);
- sp = nil;
- }
- if(t->elem->size <= sizeof(val))
- vp = (byte*)&val;
- else
- vp = (byte*)val;
- runtime·chansend(t, c, vp, sp, runtime·getcallerpc(&t));
+func reflect·chansend(t *ChanType, c *Hchan, elem *byte, nb bool) (selected bool) {
+ selected = chansend(t, c, elem, !nb, runtime·getcallerpc(&t));
}
-// For reflect:
-// func chanrecv(c chan, nb bool) (val iword, selected, received bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
-{
- byte *vp;
- bool *sp;
-
- if(nb) {
- selected = false;
- sp = &selected;
- } else {
- selected = true;
- FLUSH(&selected);
- sp = nil;
- }
+func reflect·chanrecv(t *ChanType, c *Hchan, nb bool, elem *byte) (selected bool, received bool) {
received = false;
- FLUSH(&received);
- if(t->elem->size <= sizeof(val)) {
- val = 0;
- vp = (byte*)&val;
- } else {
- vp = runtime·mal(t->elem->size);
- val = (uintptr)vp;
- FLUSH(&val);
- }
- runtime·chanrecv(t, c, vp, sp, &received);
+ selected = chanrecv(t, c, elem, !nb, &received);
}
-static void newselect(int32, Select**);
+static Select* newselect(int32);
-// newselect(size uint32) (sel *byte);
#pragma textflag NOSPLIT
-void
-runtime·newselect(int32 size, ...)
-{
- int32 o;
- Select **selp;
-
- o = ROUND(sizeof(size), Structrnd);
- selp = (Select**)((byte*)&size + o);
- newselect(size, selp);
+func newselect(size int32) (sel *byte) {
+ sel = (byte*)newselect(size);
}
-static void
-newselect(int32 size, Select **selp)
+static Select*
+newselect(int32 size)
{
int32 n;
Select *sel;
@@ -638,28 +464,22 @@ newselect(int32 size, Select **selp)
sel->ncase = 0;
sel->lockorder = (void*)(sel->scase + size);
sel->pollorder = (void*)(sel->lockorder + size);
- *selp = sel;
if(debug)
runtime·printf("newselect s=%p size=%d\n", sel, size);
+ return sel;
}
// cut in half to give stack a chance to split
static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
-// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
-{
+func selectsend(sel *Select, c *Hchan, elem *byte) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
}
static void
@@ -688,34 +508,22 @@ selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
// cut in half to give stack a chance to split
static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so);
-// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
-{
+func selectrecv(sel *Select, c *Hchan, elem *byte) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
}
-// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
-{
+func selectrecv2(sel *Select, c *Hchan, elem *byte, received *bool) (selected bool) {
selected = false;
- FLUSH(&selected);
// nil cases do not compete
- if(c == nil)
- return;
-
- selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
+ if(c != nil)
+ selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
}
static void
@@ -745,14 +553,9 @@ selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so
// cut in half to give stack a chance to split
static void selectdefault(Select*, void*, int32);
-// selectdefault(sel *byte) (selected bool);
#pragma textflag NOSPLIT
-void
-runtime·selectdefault(Select *sel, bool selected)
-{
+func selectdefault(sel *Select) (selected bool) {
selected = false;
- FLUSH(&selected);
-
selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
}
@@ -821,9 +624,15 @@ selunlock(Select *sel)
}
}
-void
-runtime·block(void)
+static bool
+selparkcommit(G *gp, void *sel)
{
+ USED(gp);
+ selunlock(sel);
+ return true;
+}
+
+func block() {
runtime·park(nil, nil, "select (no cases)"); // forever
}
@@ -834,9 +643,7 @@ static void* selectgo(Select**);
// overwrites return pc on stack to signal which case of the select
// to run, so cannot appear at the top of a split stack.
#pragma textflag NOSPLIT
-void
-runtime·selectgo(Select *sel)
-{
+func selectgo(sel *Select) {
runtime·setcallerpc(&sel, selectgo(&sel));
}
@@ -844,7 +651,7 @@ static void*
selectgo(Select **selp)
{
Select *sel;
- uint32 o, i, j, k;
+ uint32 o, i, j, k, done;
int64 t0;
Scase *cas, *dfl;
Hchan *c;
@@ -946,7 +753,7 @@ loop:
case CaseSend:
if(raceenabled)
- runtime·racereadpc(c, cas->pc, runtime·chansend);
+ runtime·racereadpc(c, cas->pc, chansend);
if(c->closed)
goto sclose;
if(c->dataqsiz > 0) {
@@ -973,13 +780,14 @@ loop:
// pass 2 - enqueue on all chans
+ done = 0;
for(i=0; i<sel->ncase; i++) {
o = sel->pollorder[i];
cas = &sel->scase[o];
c = cas->chan;
sg = &cas->sg;
sg->g = g;
- sg->selgen = g->selgen;
+ sg->selectdone = &done;
switch(cas->kind) {
case CaseRecv:
@@ -993,7 +801,7 @@ loop:
}
g->param = nil;
- runtime·park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
+ runtime·park(selparkcommit, sel, "select");
sellock(sel);
sg = g->param;
@@ -1029,18 +837,29 @@ loop:
*cas->receivedp = true;
}
+ if(raceenabled) {
+ if(cas->kind == CaseRecv && cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
+ else if(cas->kind == CaseSend)
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+ }
+
selunlock(sel);
goto retc;
asyncrecv:
// can receive from buffer
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
runtime·raceacquire(chanbuf(c, c->recvx));
+ runtime·racerelease(chanbuf(c, c->recvx));
+ }
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
if(++c->recvx == c->dataqsiz)
c->recvx = 0;
c->qcount--;
@@ -1058,9 +877,12 @@ asyncrecv:
asyncsend:
// can send to buffer
- if(raceenabled)
+ if(raceenabled) {
+ runtime·raceacquire(chanbuf(c, c->sendx));
runtime·racerelease(chanbuf(c, c->sendx));
- c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+ }
+ c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
c->qcount++;
@@ -1078,15 +900,18 @@ asyncsend:
syncrecv:
// can receive from sleeping sender (sg)
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, sg->elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
@@ -1100,20 +925,22 @@ rclose:
if(cas->receivedp != nil)
*cas->receivedp = false;
if(cas->sg.elem != nil)
- c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
+ c->elemtype->alg->copy(c->elemsize, cas->sg.elem, nil);
if(raceenabled)
runtime·raceacquire(c);
goto retc;
syncsend:
// can send to sleeping receiver (sg)
- if(raceenabled)
+ if(raceenabled) {
+ runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(sg->elem != nil)
- c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
+ c->elemtype->alg->copy(c->elemsize, sg->elem, cas->sg.elem);
gp = sg->g;
gp->param = sg;
if(sg->releasetime)
@@ -1150,7 +977,7 @@ struct runtimeSelect
uintptr dir;
ChanType *typ;
Hchan *ch;
- uintptr val;
+ byte *val;
};
// This enum must match ../reflect/value.go:/SelectDir.
@@ -1160,34 +987,17 @@ enum SelectDir {
SelectDefault,
};
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
-void
-reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
-{
+func reflect·rselect(cases Slice) (chosen int, recvOK bool) {
int32 i;
Select *sel;
runtimeSelect* rcase, *rc;
- void *elem;
- void *recvptr;
- uintptr maxsize;
chosen = -1;
- word = 0;
recvOK = false;
- maxsize = 0;
rcase = (runtimeSelect*)cases.array;
- for(i=0; i<cases.len; i++) {
- rc = &rcase[i];
- if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->elem->size)
- maxsize = rc->typ->elem->size;
- }
-
- recvptr = nil;
- if(maxsize > sizeof(void*))
- recvptr = runtime·mal(maxsize);
- newselect(cases.len, &sel);
+ sel = newselect(cases.len);
for(i=0; i<cases.len; i++) {
rc = &rcase[i];
switch(rc->dir) {
@@ -1197,49 +1007,28 @@ reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
case SelectSend:
if(rc->ch == nil)
break;
- if(rc->typ->elem->size > sizeof(void*))
- elem = (void*)rc->val;
- else
- elem = (void*)&rc->val;
- selectsend(sel, rc->ch, (void*)i, elem, 0);
+ selectsend(sel, rc->ch, (void*)i, rc->val, 0);
break;
case SelectRecv:
if(rc->ch == nil)
break;
- if(rc->typ->elem->size > sizeof(void*))
- elem = recvptr;
- else
- elem = &word;
- selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0);
+ selectrecv(sel, rc->ch, (void*)i, rc->val, &recvOK, 0);
break;
}
}
chosen = (intgo)(uintptr)selectgo(&sel);
- if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > sizeof(void*))
- word = (uintptr)recvptr;
-
- FLUSH(&chosen);
- FLUSH(&word);
- FLUSH(&recvOK);
}
static void closechan(Hchan *c, void *pc);
-// closechan(sel *byte);
#pragma textflag NOSPLIT
-void
-runtime·closechan(Hchan *c)
-{
+func closechan(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
-// For reflect
-// func chanclose(c chan)
#pragma textflag NOSPLIT
-void
-reflect·chanclose(Hchan *c)
-{
+func reflect·chanclose(c *Hchan) {
closechan(c, runtime·getcallerpc(&c));
}
@@ -1292,28 +1081,18 @@ closechan(Hchan *c, void *pc)
runtime·unlock(c);
}
-// For reflect
-// func chanlen(c chan) (len int)
-void
-reflect·chanlen(Hchan *c, intgo len)
-{
+func reflect·chanlen(c *Hchan) (len int) {
if(c == nil)
len = 0;
else
len = c->qcount;
- FLUSH(&len);
}
-// For reflect
-// func chancap(c chan) int
-void
-reflect·chancap(Hchan *c, intgo cap)
-{
+func reflect·chancap(c *Hchan) (cap int) {
if(c == nil)
cap = 0;
else
cap = c->dataqsiz;
- FLUSH(&cap);
}
static SudoG*
@@ -1327,12 +1106,11 @@ loop:
return nil;
q->first = sgp->link;
- // if sgp is stale, ignore it
- if(sgp->selgen != NOSELGEN &&
- (sgp->selgen != sgp->g->selgen ||
- !runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
- //prints("INVALID PSEUDOG POINTER\n");
- goto loop;
+ // if sgp participates in a select and is already signaled, ignore it
+ if(sgp->selectdone != nil) {
+ // claim the right to signal
+ if(*sgp->selectdone != 0 || !runtime·cas(sgp->selectdone, 0, 1))
+ goto loop;
}
return sgp;
diff --git a/src/pkg/runtime/chan.h b/src/pkg/runtime/chan.h
new file mode 100644
index 000000000..ce2eb9f4e
--- /dev/null
+++ b/src/pkg/runtime/chan.h
@@ -0,0 +1,75 @@
+// 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.
+
+#define MAXALIGN 8
+
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
+
+struct SudoG
+{
+ G* g;
+ uint32* selectdone;
+ SudoG* link;
+ int64 releasetime;
+ byte* elem; // data element
+};
+
+struct WaitQ
+{
+ SudoG* first;
+ SudoG* last;
+};
+
+// The garbage collector is assuming that Hchan can only contain pointers into the stack
+// and cannot contain pointers into the heap.
+struct Hchan
+{
+ uintgo qcount; // total data in the q
+ uintgo dataqsiz; // size of the circular q
+ uint16 elemsize;
+ uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
+ bool closed;
+ Type* elemtype; // element type
+ uintgo sendx; // send index
+ uintgo recvx; // receive index
+ WaitQ recvq; // list of recv waiters
+ WaitQ sendq; // list of send waiters
+ Lock;
+};
+
+// Buffer follows Hchan immediately in memory.
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
+
+enum
+{
+ debug = 0,
+
+ // Scase.kind
+ CaseRecv,
+ CaseSend,
+ CaseDefault,
+};
+
+struct Scase
+{
+ SudoG sg; // must be first member (cast to Scase)
+ Hchan* chan; // chan
+ byte* pc; // return pc
+ uint16 kind;
+ uint16 so; // vararg of selected bool
+ bool* receivedp; // pointer to received bool (recv2)
+};
+
+struct Select
+{
+ uint16 tcase; // total count of scase[]
+ uint16 ncase; // currently filled scase[]
+ uint16* pollorder; // case poll order
+ Hchan** lockorder; // channel lock order
+ Scase scase[1]; // one per case (in order of appearance)
+};
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
index eb2c7c60d..ce4b39627 100644
--- a/src/pkg/runtime/chan_test.go
+++ b/src/pkg/runtime/chan_test.go
@@ -9,8 +9,327 @@ import (
"sync"
"sync/atomic"
"testing"
+ "time"
)
+func TestChan(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := 200
+ if testing.Short() {
+ N = 20
+ }
+ for chanCap := 0; chanCap < N; chanCap++ {
+ {
+ // Ensure that receive from empty chan blocks.
+ c := make(chan int, chanCap)
+ recv1 := false
+ go func() {
+ _ = <-c
+ recv1 = true
+ }()
+ recv2 := false
+ go func() {
+ _, _ = <-c
+ recv2 = true
+ }()
+ time.Sleep(time.Millisecond)
+ if recv1 || recv2 {
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ }
+ // Ensure that non-blocking receive does not block.
+ select {
+ case _ = <-c:
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ default:
+ }
+ select {
+ case _, _ = <-c:
+ t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+ default:
+ }
+ c <- 0
+ c <- 0
+ }
+
+ {
+ // Ensure that send to full chan blocks.
+ c := make(chan int, chanCap)
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ sent := uint32(0)
+ go func() {
+ c <- 0
+ atomic.StoreUint32(&sent, 1)
+ }()
+ time.Sleep(time.Millisecond)
+ if atomic.LoadUint32(&sent) != 0 {
+ t.Fatalf("chan[%d]: send to full chan", chanCap)
+ }
+ // Ensure that non-blocking send does not block.
+ select {
+ case c <- 0:
+ t.Fatalf("chan[%d]: send to full chan", chanCap)
+ default:
+ }
+ <-c
+ }
+
+ {
+ // Ensure that we receive 0 from closed chan.
+ c := make(chan int, chanCap)
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ close(c)
+ for i := 0; i < chanCap; i++ {
+ v := <-c
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+ if v := <-c; v != 0 {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
+ }
+ if v, ok := <-c; v != 0 || ok {
+ t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
+ }
+ }
+
+ {
+ // Ensure that close unblocks receive.
+ c := make(chan int, chanCap)
+ done := make(chan bool)
+ go func() {
+ v, ok := <-c
+ done <- v == 0 && ok == false
+ }()
+ time.Sleep(time.Millisecond)
+ close(c)
+ if !<-done {
+ t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
+ }
+ }
+
+ {
+ // Send 100 integers,
+ // ensure that we receive them non-corrupted in FIFO order.
+ c := make(chan int, chanCap)
+ go func() {
+ for i := 0; i < 100; i++ {
+ c <- i
+ }
+ }()
+ for i := 0; i < 100; i++ {
+ v := <-c
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+
+ // Same, but using recv2.
+ go func() {
+ for i := 0; i < 100; i++ {
+ c <- i
+ }
+ }()
+ for i := 0; i < 100; i++ {
+ v, ok := <-c
+ if !ok {
+ t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
+ }
+ if v != i {
+ t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+ }
+ }
+
+ // Send 1000 integers in 4 goroutines,
+ // ensure that we receive what we send.
+ const P = 4
+ const L = 1000
+ for p := 0; p < P; p++ {
+ go func() {
+ for i := 0; i < L; i++ {
+ c <- i
+ }
+ }()
+ }
+ done := make(chan map[int]int)
+ for p := 0; p < P; p++ {
+ go func() {
+ recv := make(map[int]int)
+ for i := 0; i < L; i++ {
+ v := <-c
+ recv[v] = recv[v] + 1
+ }
+ done <- recv
+ }()
+ }
+ recv := make(map[int]int)
+ for p := 0; p < P; p++ {
+ for k, v := range <-done {
+ recv[k] = recv[k] + v
+ }
+ }
+ if len(recv) != L {
+ t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
+ }
+ for _, v := range recv {
+ if v != P {
+ t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
+ }
+ }
+ }
+
+ {
+ // Test len/cap.
+ c := make(chan int, chanCap)
+ if len(c) != 0 || cap(c) != chanCap {
+ t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
+ }
+ for i := 0; i < chanCap; i++ {
+ c <- i
+ }
+ if len(c) != chanCap || cap(c) != chanCap {
+ t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
+ }
+ }
+
+ }
+}
+
+func TestSelfSelect(t *testing.T) {
+ // Ensure that send/recv on the same chan in select
+ // does not crash nor deadlock.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+ for _, chanCap := range []int{0, 10} {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ c := make(chan int, chanCap)
+ for p := 0; p < 2; p++ {
+ p := p
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 1000; i++ {
+ if p == 0 || i%2 == 0 {
+ select {
+ case c <- p:
+ case v := <-c:
+ if chanCap == 0 && v == p {
+ t.Fatalf("self receive")
+ }
+ }
+ } else {
+ select {
+ case v := <-c:
+ if chanCap == 0 && v == p {
+ t.Fatalf("self receive")
+ }
+ case c <- p:
+ }
+ }
+ }
+ }()
+ }
+ wg.Wait()
+ }
+}
+
+func TestSelectStress(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
+ var c [4]chan int
+ c[0] = make(chan int)
+ c[1] = make(chan int)
+ c[2] = make(chan int, 2)
+ c[3] = make(chan int, 3)
+ N := int(1e5)
+ if testing.Short() {
+ N /= 10
+ }
+ // There are 4 goroutines that send N values on each of the chans,
+ // + 4 goroutines that receive N values on each of the chans,
+ // + 1 goroutine that sends N values on each of the chans in a single select,
+ // + 1 goroutine that receives N values on each of the chans in a single select.
+ // All these sends, receives and selects interact chaotically at runtime,
+ // but we are careful that this whole construct does not deadlock.
+ var wg sync.WaitGroup
+ wg.Add(10)
+ for k := 0; k < 4; k++ {
+ k := k
+ go func() {
+ for i := 0; i < N; i++ {
+ c[k] <- 0
+ }
+ wg.Done()
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ <-c[k]
+ }
+ wg.Done()
+ }()
+ }
+ go func() {
+ var n [4]int
+ c1 := c
+ for i := 0; i < 4*N; i++ {
+ select {
+ case c1[3] <- 0:
+ n[3]++
+ if n[3] == N {
+ c1[3] = nil
+ }
+ case c1[2] <- 0:
+ n[2]++
+ if n[2] == N {
+ c1[2] = nil
+ }
+ case c1[0] <- 0:
+ n[0]++
+ if n[0] == N {
+ c1[0] = nil
+ }
+ case c1[1] <- 0:
+ n[1]++
+ if n[1] == N {
+ c1[1] = nil
+ }
+ }
+ }
+ wg.Done()
+ }()
+ go func() {
+ var n [4]int
+ c1 := c
+ for i := 0; i < 4*N; i++ {
+ select {
+ case <-c1[0]:
+ n[0]++
+ if n[0] == N {
+ c1[0] = nil
+ }
+ case <-c1[1]:
+ n[1]++
+ if n[1] == N {
+ c1[1] = nil
+ }
+ case <-c1[2]:
+ n[2]++
+ if n[2] == N {
+ c1[2] = nil
+ }
+ case <-c1[3]:
+ n[3]++
+ if n[3] == N {
+ c1[3] = nil
+ }
+ }
+ }
+ wg.Done()
+ }()
+ wg.Wait()
+}
+
func TestChanSendInterface(t *testing.T) {
type mt struct{}
m := &mt{}
@@ -29,34 +348,35 @@ func TestChanSendInterface(t *testing.T) {
func TestPseudoRandomSend(t *testing.T) {
n := 100
- c := make(chan int)
- l := make([]int, n)
- var m sync.Mutex
- m.Lock()
- go func() {
+ for _, chanCap := range []int{0, n} {
+ c := make(chan int, chanCap)
+ l := make([]int, n)
+ var m sync.Mutex
+ m.Lock()
+ go func() {
+ for i := 0; i < n; i++ {
+ runtime.Gosched()
+ l[i] = <-c
+ }
+ m.Unlock()
+ }()
for i := 0; i < n; i++ {
- runtime.Gosched()
- l[i] = <-c
+ select {
+ case c <- 1:
+ case c <- 0:
+ }
}
- m.Unlock()
- }()
- for i := 0; i < n; i++ {
- select {
- case c <- 0:
- case c <- 1:
+ m.Lock() // wait
+ n0 := 0
+ n1 := 0
+ for _, i := range l {
+ n0 += (i + 1) % 2
+ n1 += i
}
- }
- m.Lock() // wait
- n0 := 0
- n1 := 0
- for _, i := range l {
- n0 += (i + 1) % 2
- n1 += i
- if n0 > n/10 && n1 > n/10 {
- return
+ if n0 <= n/10 || n1 <= n/10 {
+ t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
}
}
- t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
}
func TestMultiConsumer(t *testing.T) {
@@ -110,147 +430,106 @@ func TestMultiConsumer(t *testing.T) {
}
}
+func BenchmarkChanNonblocking(b *testing.B) {
+ myc := make(chan int)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ select {
+ case <-myc:
+ default:
+ }
+ }
+ })
+}
+
func BenchmarkSelectUncontended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- myc1 := make(chan int, 1)
- myc2 := make(chan int, 1)
- myc1 <- 0
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- myc2 <- 0
- case <-myc2:
- myc1 <- 0
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ myc1 := make(chan int, 1)
+ myc2 := make(chan int, 1)
+ myc1 <- 0
+ for pb.Next() {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ })
}
func BenchmarkSelectContended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
+ procs := runtime.GOMAXPROCS(0)
myc1 := make(chan int, procs)
myc2 := make(chan int, procs)
- for p := 0; p < procs; p++ {
+ b.RunParallel(func(pb *testing.PB) {
myc1 <- 0
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- myc2 <- 0
- case <-myc2:
- myc1 <- 0
- }
- }
+ for pb.Next() {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ })
}
func BenchmarkSelectNonblock(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- myc1 := make(chan int)
- myc2 := make(chan int)
- myc3 := make(chan int, 1)
- myc4 := make(chan int, 1)
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- select {
- case <-myc1:
- default:
- }
- select {
- case myc2 <- 0:
- default:
- }
- select {
- case <-myc3:
- default:
- }
- select {
- case myc4 <- 0:
- default:
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int, 1)
+ myc4 := make(chan int, 1)
+ for pb.Next() {
+ select {
+ case <-myc1:
+ default:
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ select {
+ case myc2 <- 0:
+ default:
+ }
+ select {
+ case <-myc3:
+ default:
+ }
+ select {
+ case myc4 <- 0:
+ default:
+ }
+ }
+ })
}
func BenchmarkChanUncontended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- myc := make(chan int, CallsPerSched)
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- myc <- 0
- }
- for g := 0; g < CallsPerSched; g++ {
- <-myc
- }
+ const C = 100
+ b.RunParallel(func(pb *testing.PB) {
+ myc := make(chan int, C)
+ for pb.Next() {
+ for i := 0; i < C; i++ {
+ myc <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ for i := 0; i < C; i++ {
+ <-myc
+ }
+ }
+ })
}
func BenchmarkChanContended(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- myc := make(chan int, procs*CallsPerSched)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- for g := 0; g < CallsPerSched; g++ {
- myc <- 0
- }
- for g := 0; g < CallsPerSched; g++ {
- <-myc
- }
+ const C = 100
+ myc := make(chan int, C*runtime.GOMAXPROCS(0))
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ for i := 0; i < C; i++ {
+ myc <- 0
}
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ for i := 0; i < C; i++ {
+ <-myc
+ }
+ }
+ })
}
func BenchmarkChanSync(b *testing.B) {
@@ -350,33 +629,83 @@ func BenchmarkChanProdConsWork100(b *testing.B) {
benchmarkChanProdCons(b, 100, 100)
}
-func BenchmarkChanCreation(b *testing.B) {
+func BenchmarkSelectProdCons(b *testing.B) {
const CallsPerSched = 1000
procs := runtime.GOMAXPROCS(-1)
N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
+ c := make(chan bool, 2*procs)
+ myc := make(chan int, 128)
+ myclose := make(chan bool)
for p := 0; p < procs; p++ {
go func() {
+ // Producer: sends to myc.
+ foo := 0
+ // Intended to not fire during benchmarking.
+ mytimer := time.After(time.Hour)
for atomic.AddInt32(&N, -1) >= 0 {
for g := 0; g < CallsPerSched; g++ {
- myc := make(chan int, 1)
- myc <- 0
- <-myc
+ // Model some local work.
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ select {
+ case myc <- 1:
+ case <-mytimer:
+ case <-myclose:
+ }
}
}
- c <- true
+ myc <- 0
+ c <- foo == 42
+ }()
+ go func() {
+ // Consumer: receives from myc.
+ foo := 0
+ // Intended to not fire during benchmarking.
+ mytimer := time.After(time.Hour)
+ loop:
+ for {
+ select {
+ case v := <-myc:
+ if v == 0 {
+ break loop
+ }
+ case <-mytimer:
+ case <-myclose:
+ }
+ // Model some local work.
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ c <- foo == 42
}()
}
for p := 0; p < procs; p++ {
<-c
+ <-c
}
}
+func BenchmarkChanCreation(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ myc := make(chan int, 1)
+ myc <- 0
+ <-myc
+ }
+ })
+}
+
func BenchmarkChanSem(b *testing.B) {
type Empty struct{}
- c := make(chan Empty, 1)
- for i := 0; i < b.N; i++ {
- c <- Empty{}
- <-c
- }
+ myc := make(chan Empty, runtime.GOMAXPROCS(0))
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ myc <- Empty{}
+ <-myc
+ }
+ })
}
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.goc
index 395e70fe3..40935cf1c 100644
--- a/src/pkg/runtime/complex.c
+++ b/src/pkg/runtime/complex.goc
@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
-typedef struct Complex128 Complex128;
-
-void
-runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
-{
+func complex128div(n Complex128, d Complex128) (q Complex128) {
int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom;
@@ -58,5 +55,4 @@ runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
q.imag = (n.imag - n.real*ratio) / denom;
}
}
- FLUSH(&q);
}
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.goc
index 1c34b9e6f..faaea2943 100644
--- a/src/pkg/runtime/cpuprof.c
+++ b/src/pkg/runtime/cpuprof.goc
@@ -48,6 +48,7 @@
// in order to let the log closer set the high bit to indicate "EOF" safely
// in the situation when normally the goroutine "owns" handoff.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
@@ -80,7 +81,6 @@ struct Profile {
uintptr count; // tick count
uintptr evicts; // eviction count
uintptr lost; // lost ticks that need to be logged
- uintptr totallost; // total lost ticks
// Active recent stack traces.
Bucket hash[HashSize];
@@ -168,7 +168,7 @@ runtime·SetCPUProfileRate(intgo hz)
runtime·noteclear(&prof->wait);
runtime·setcpuprofilerate(tick, hz);
- } else if(prof->on) {
+ } else if(prof != nil && prof->on) {
runtime·setcpuprofilerate(nil, 0);
prof->on = false;
@@ -243,7 +243,6 @@ add(Profile *p, uintptr *pc, int32 n)
if(!evict(p, e)) {
// Could not evict entry. Record lost stack.
p->lost++;
- p->totallost++;
return;
}
p->evicts++;
@@ -307,6 +306,7 @@ flushlog(Profile *p)
*q++ = p->lost;
*q++ = 1;
*q++ = (uintptr)LostProfileData;
+ p->lost = 0;
}
p->nlog = q - log;
return true;
@@ -428,9 +428,6 @@ breakflush:
// CPUProfile returns the next cpu profile block as a []byte.
// The user documentation is in debug.go.
-void
-runtime·CPUProfile(Slice ret)
-{
+func CPUProfile() (ret Slice) {
ret = getprofile(prof);
- FLUSH(&ret);
}
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
index 5476924bb..b0277f293 100644
--- a/src/pkg/runtime/crash_test.go
+++ b/src/pkg/runtime/crash_test.go
@@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"testing"
"text/template"
@@ -31,6 +32,10 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
}
func executeTest(t *testing.T, templ string, data interface{}) string {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
checkStaleRuntime(t)
st := template.Must(template.New("crashSource").Parse(templ))
@@ -111,8 +116,9 @@ func TestLockedDeadlock2(t *testing.T) {
func TestGoexitDeadlock(t *testing.T) {
output := executeTest(t, goexitDeadlockSource, nil)
- if output != "" {
- t.Fatalf("expected no output, got:\n%s", output)
+ want := "no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
}
}
@@ -132,6 +138,34 @@ func TestThreadExhaustion(t *testing.T) {
}
}
+func TestRecursivePanic(t *testing.T) {
+ output := executeTest(t, recursivePanicSource, nil)
+ want := `wrap: bad
+panic: again
+
+`
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+
+}
+
+func TestGoexitCrash(t *testing.T) {
+ output := executeTest(t, goexitExitSource, nil)
+ want := "no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+ }
+}
+
+func TestGoNil(t *testing.T) {
+ output := executeTest(t, goNilSource, nil)
+ want := "go of nil func value"
+ if !strings.Contains(output, want) {
+ t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+ }
+}
+
const crashSource = `
package main
@@ -272,3 +306,61 @@ func main() {
}
}
`
+
+const recursivePanicSource = `
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ func() {
+ defer func() {
+ fmt.Println(recover())
+ }()
+ var x [8192]byte
+ func(x [8192]byte) {
+ defer func() {
+ if err := recover(); err != nil {
+ panic("wrap: " + err.(string))
+ }
+ }()
+ panic("bad")
+ }(x)
+ }()
+ panic("again")
+}
+`
+
+const goexitExitSource = `
+package main
+
+import (
+ "runtime"
+ "time"
+)
+
+func main() {
+ go func() {
+ time.Sleep(time.Millisecond)
+ }()
+ i := 0
+ runtime.SetFinalizer(&i, func(p *int) {})
+ runtime.GC()
+ runtime.Goexit()
+}
+`
+
+const goNilSource = `
+package main
+
+func main() {
+ defer func() {
+ recover()
+ }()
+ var f func()
+ go f()
+ select{}
+}
+`
diff --git a/src/pkg/runtime/debug/garbage.go b/src/pkg/runtime/debug/garbage.go
index 8337d5d5b..edb364387 100644
--- a/src/pkg/runtime/debug/garbage.go
+++ b/src/pkg/runtime/debug/garbage.go
@@ -91,7 +91,9 @@ func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
// at startup, or 100 if the variable is not set.
// A negative percentage disables garbage collection.
func SetGCPercent(percent int) int {
- return setGCPercent(percent)
+ old := setGCPercent(percent)
+ runtime.GC()
+ return old
}
// FreeOSMemory forces a garbage collection followed by an
@@ -133,3 +135,19 @@ func SetMaxStack(bytes int) int {
func SetMaxThreads(threads int) int {
return setMaxThreads(threads)
}
+
+// SetPanicOnFault controls the runtime's behavior when a program faults
+// at an unexpected (non-nil) address. Such faults are typically caused by
+// bugs such as runtime memory corruption, so the default response is to crash
+// the program. Programs working with memory-mapped files or unsafe
+// manipulation of memory may cause faults at non-nil addresses in less
+// dramatic situations; SetPanicOnFault allows such programs to request
+// that the runtime trigger only a panic, not a crash.
+// SetPanicOnFault applies only to the current goroutine.
+// It returns the previous setting.
+func SetPanicOnFault(enabled bool) bool
+
+// WriteHeapDump writes a description of the heap and the objects in
+// it to the given file descriptor.
+// The heap dump format is defined at http://golang.org/s/go13heapdump.
+func WriteHeapDump(fd uintptr)
diff --git a/src/pkg/runtime/debug/heapdump_test.go b/src/pkg/runtime/debug/heapdump_test.go
new file mode 100644
index 000000000..920190115
--- /dev/null
+++ b/src/pkg/runtime/debug/heapdump_test.go
@@ -0,0 +1,33 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package debug
+
+import (
+ "io/ioutil"
+ "os"
+ "runtime"
+ "testing"
+)
+
+func TestWriteHeapDumpNonempty(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("WriteHeapDump is not available on NaCl.")
+ }
+ f, err := ioutil.TempFile("", "heapdumptest")
+ if err != nil {
+ t.Fatalf("TempFile failed: %v", err)
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ WriteHeapDump(f.Fd())
+ fi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ const minSize = 1
+ if size := fi.Size(); size < minSize {
+ t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
+ }
+}
diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
index 2896b2141..c29b0a226 100644
--- a/src/pkg/runtime/debug/stack.go
+++ b/src/pkg/runtime/debug/stack.go
@@ -18,6 +18,7 @@ var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
+ slash = []byte("/")
)
// PrintStack prints to standard error the stack trace returned by Stack.
@@ -84,6 +85,11 @@ func function(pc uintptr) []byte {
// runtime/debug.*T·ptrmethod
// and want
// *T.ptrmethod
+ // Since the package path might contains dots (e.g. code.google.com/...),
+ // we first remove the path prefix if there is one.
+ if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
+ name = name[lastslash+1:]
+ }
if period := bytes.Index(name, dot); period >= 0 {
name = name[period+1:]
}
diff --git a/src/pkg/runtime/defs.c b/src/pkg/runtime/defs.c
new file mode 100644
index 000000000..1c76198fc
--- /dev/null
+++ b/src/pkg/runtime/defs.c
@@ -0,0 +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.
+
+// This file is compiled by cmd/dist to obtain debug information
+// about the given header files.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "type.h"
+#include "race.h"
+#include "hashmap.h"
+#include "chan.h"
diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go
index dad20f16d..2832583e0 100644
--- a/src/pkg/runtime/defs_freebsd.go
+++ b/src/pkg/runtime/defs_freebsd.go
@@ -49,8 +49,10 @@ const (
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
- UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
- UMTX_OP_WAKE = C.UMTX_OP_WAKE
+ UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
+ UMTX_OP_WAIT_UINT_PRIVATE = C.UMTX_OP_WAIT_UINT_PRIVATE
+ UMTX_OP_WAKE = C.UMTX_OP_WAKE
+ UMTX_OP_WAKE_PRIVATE = C.UMTX_OP_WAKE_PRIVATE
SIGHUP = C.SIGHUP
SIGINT = C.SIGINT
diff --git a/src/pkg/runtime/defs_freebsd_386.h b/src/pkg/runtime/defs_freebsd_386.h
index cf9c76eb1..fab938526 100644
--- a/src/pkg/runtime/defs_freebsd_386.h
+++ b/src/pkg/runtime/defs_freebsd_386.h
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_amd64.h b/src/pkg/runtime/defs_freebsd_amd64.h
index 3fb33f38a..c1db91803 100644
--- a/src/pkg/runtime/defs_freebsd_amd64.h
+++ b/src/pkg/runtime/defs_freebsd_amd64.h
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_arm.h b/src/pkg/runtime/defs_freebsd_arm.h
index d321f4249..4fc452e45 100644
--- a/src/pkg/runtime/defs_freebsd_arm.h
+++ b/src/pkg/runtime/defs_freebsd_arm.h
@@ -4,7 +4,7 @@
enum {
EINTR = 0x4,
- EFAULT = 0xe,
+ EFAULT = 0xe,
PROT_NONE = 0x0,
PROT_READ = 0x1,
@@ -21,8 +21,10 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT_UINT = 0xb,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAIT_UINT_PRIVATE = 0xf,
+ UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAKE_PRIVATE = 0x10,
SIGHUP = 0x1,
SIGINT = 0x2,
@@ -76,13 +78,13 @@ enum {
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
- EV_ADD = 0x1,
- EV_DELETE = 0x2,
- EV_CLEAR = 0x20,
- EV_RECEIPT = 0x40,
- EV_ERROR = 0x4000,
- EVFILT_READ = -0x1,
- EVFILT_WRITE = -0x2,
+ EV_ADD = 0x1,
+ EV_DELETE = 0x2,
+ EV_CLEAR = 0x20,
+ EV_RECEIPT = 0x40,
+ EV_ERROR = 0x4000,
+ EVFILT_READ = -0x1,
+ EVFILT_WRITE = -0x2,
};
typedef struct Rtprio Rtprio;
@@ -159,10 +161,12 @@ struct Ucontext {
struct Timespec {
int64 tv_sec;
int32 tv_nsec;
+ byte Pad_cgo_0[4];
};
struct Timeval {
int64 tv_sec;
int32 tv_usec;
+ byte Pad_cgo_0[4];
};
struct Itimerval {
Timeval it_interval;
@@ -170,12 +174,12 @@ struct Itimerval {
};
struct Kevent {
- uint32 ident;
- int16 filter;
- uint16 flags;
- uint32 fflags;
- int32 data;
- byte *udata;
+ uint32 ident;
+ int16 filter;
+ uint16 flags;
+ uint32 fflags;
+ int32 data;
+ byte *udata;
};
diff --git a/src/pkg/runtime/defs_nacl_386.h b/src/pkg/runtime/defs_nacl_386.h
new file mode 100644
index 000000000..e8fbb38e1
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_386.h
@@ -0,0 +1,63 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ SIGSEGV = 11,
+ SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+ int64 tv_sec;
+ int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+
+struct ExcRegs386
+{
+ uint32 eax;
+ uint32 ecx;
+ uint32 edx;
+ uint32 ebx;
+ uint32 esp;
+ uint32 ebp;
+ uint32 esi;
+ uint32 edi;
+ uint32 eip;
+ uint32 eflags;
+};
+
+struct ExcContext
+{
+ uint32 size;
+ uint32 portable_context_offset;
+ uint32 portable_context_size;
+ uint32 arch;
+ uint32 regs_size;
+ uint32 reserved[11];
+ ExcRegs386 regs;
+};
+
+struct ExcPortableContext
+{
+ uint32 pc;
+ uint32 sp;
+ uint32 fp;
+};
diff --git a/src/pkg/runtime/defs_nacl_amd64p32.h b/src/pkg/runtime/defs_nacl_amd64p32.h
new file mode 100644
index 000000000..8d3068bf8
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_amd64p32.h
@@ -0,0 +1,90 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+ // These values are referred to in the source code
+ // but really don't matter. Even so, use the standard numbers.
+ SIGSEGV = 11,
+ SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+ int64 tv_sec;
+ int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+typedef struct ExcRegsAmd64 ExcRegsAmd64;
+
+struct ExcRegs386
+{
+ uint32 eax;
+ uint32 ecx;
+ uint32 edx;
+ uint32 ebx;
+ uint32 esp;
+ uint32 ebp;
+ uint32 esi;
+ uint32 edi;
+ uint32 eip;
+ uint32 eflags;
+};
+
+struct ExcRegsAmd64
+{
+ uint64 rax;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rbx;
+ uint64 rsp;
+ uint64 rbp;
+ uint64 rsi;
+ uint64 rdi;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint32 rflags;
+};
+
+struct ExcContext
+{
+ uint32 size;
+ uint32 portable_context_offset;
+ uint32 portable_context_size;
+ uint32 arch;
+ uint32 regs_size;
+ uint32 reserved[11];
+ union {
+ ExcRegs386 regs;
+ ExcRegsAmd64 regs64;
+ };
+};
+
+struct ExcPortableContext
+{
+ uint32 pc;
+ uint32 sp;
+ uint32 fp;
+};
diff --git a/src/pkg/runtime/defs_openbsd_386.h b/src/pkg/runtime/defs_openbsd_386.h
index a5b7f04b5..b8f993e2b 100644
--- a/src/pkg/runtime/defs_openbsd_386.h
+++ b/src/pkg/runtime/defs_openbsd_386.h
@@ -121,7 +121,7 @@ struct Sigcontext {
int32 sc_eflags;
int32 sc_esp;
int32 sc_ss;
- int32 sc_onstack;
+ int32 __sc_unused;
int32 sc_mask;
int32 sc_trapno;
int32 sc_err;
@@ -143,11 +143,11 @@ struct StackT {
};
struct Timespec {
- int32 tv_sec;
+ int64 tv_sec;
int32 tv_nsec;
};
struct Timeval {
- int32 tv_sec;
+ int64 tv_sec;
int32 tv_usec;
};
struct Itimerval {
@@ -160,7 +160,7 @@ struct Kevent {
int16 filter;
uint16 flags;
uint32 fflags;
- int32 data;
+ int64 data;
byte *udata;
};
diff --git a/src/pkg/runtime/defs_openbsd_amd64.h b/src/pkg/runtime/defs_openbsd_amd64.h
index eb47ec892..a1ae2ef65 100644
--- a/src/pkg/runtime/defs_openbsd_amd64.h
+++ b/src/pkg/runtime/defs_openbsd_amd64.h
@@ -133,7 +133,7 @@ struct Sigcontext {
int64 sc_rsp;
int64 sc_ss;
void *sc_fpstate;
- int32 sc_onstack;
+ int32 __sc_unused;
int32 sc_mask;
};
struct Siginfo {
@@ -154,8 +154,7 @@ struct StackT {
};
struct Timespec {
- int32 tv_sec;
- byte Pad_cgo_0[4];
+ int64 tv_sec;
int64 tv_nsec;
};
struct Timeval {
@@ -168,11 +167,11 @@ struct Itimerval {
};
struct Kevent {
- uint32 ident;
+ uint64 ident;
int16 filter;
uint16 flags;
uint32 fflags;
- int32 data;
+ int64 data;
byte *udata;
};
diff --git a/src/pkg/runtime/defs_solaris.go b/src/pkg/runtime/defs_solaris.go
new file mode 100644
index 000000000..8dcbb08b7
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris.go
@@ -0,0 +1,156 @@
+// 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
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/siginfo.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ucontext.h>
+#include <sys/regset.h>
+#include <sys/unistd.h>
+#include <sys/fork.h>
+#include <sys/port.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <netdb.h>
+*/
+import "C"
+
+const (
+ EINTR = C.EINTR
+ EBADF = C.EBADF
+ EFAULT = C.EFAULT
+ EAGAIN = C.EAGAIN
+ ETIMEDOUT = C.ETIMEDOUT
+ EWOULDBLOCK = C.EWOULDBLOCK
+ EINPROGRESS = C.EINPROGRESS
+
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_FREE = C.MADV_FREE
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+
+ _SC_NPROCESSORS_ONLN = C._SC_NPROCESSORS_ONLN
+
+ PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED
+
+ FORK_NOSIGCHLD = C.FORK_NOSIGCHLD
+ FORK_WAITPID = C.FORK_WAITPID
+
+ MAXHOSTNAMELEN = C.MAXHOSTNAMELEN
+
+ O_NONBLOCK = C.O_NONBLOCK
+ FD_CLOEXEC = C.FD_CLOEXEC
+ F_GETFL = C.F_GETFL
+ F_SETFL = C.F_SETFL
+ F_SETFD = C.F_SETFD
+
+ POLLIN = C.POLLIN
+ POLLOUT = C.POLLOUT
+ POLLHUP = C.POLLHUP
+ POLLERR = C.POLLERR
+
+ PORT_SOURCE_FD = C.PORT_SOURCE_FD
+)
+
+type SemT C.sem_t
+
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.sigset_t
+type StackT C.stack_t
+
+type Siginfo C.siginfo_t
+type Sigaction C.struct_sigaction
+
+type Fpregset C.fpregset_t
+type Mcontext C.mcontext_t
+type Ucontext C.ucontext_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+type PortEvent C.port_event_t
+type Pthread C.pthread_t
+type PthreadAttr C.pthread_attr_t
+
+// depends on Timespec, must appear below
+type Stat C.struct_stat
diff --git a/src/pkg/runtime/defs_solaris_amd64.go b/src/pkg/runtime/defs_solaris_amd64.go
new file mode 100644
index 000000000..049317888
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.go
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go defs_solaris_amd64.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/regset.h>
+*/
+import "C"
+
+const (
+ REG_RDI = C.REG_RDI
+ REG_RSI = C.REG_RSI
+ REG_RDX = C.REG_RDX
+ REG_RCX = C.REG_RCX
+ REG_R8 = C.REG_R8
+ REG_R9 = C.REG_R9
+ REG_R10 = C.REG_R10
+ REG_R11 = C.REG_R11
+ REG_R12 = C.REG_R12
+ REG_R13 = C.REG_R13
+ REG_R14 = C.REG_R14
+ REG_R15 = C.REG_R15
+ REG_RBP = C.REG_RBP
+ REG_RBX = C.REG_RBX
+ REG_RAX = C.REG_RAX
+ REG_GS = C.REG_GS
+ REG_FS = C.REG_FS
+ REG_ES = C.REG_ES
+ REG_DS = C.REG_DS
+ REG_TRAPNO = C.REG_TRAPNO
+ REG_ERR = C.REG_ERR
+ REG_RIP = C.REG_RIP
+ REG_CS = C.REG_CS
+ REG_RFLAGS = C.REG_RFL
+ REG_RSP = C.REG_RSP
+ REG_SS = C.REG_SS
+)
diff --git a/src/pkg/runtime/defs_solaris_amd64.h b/src/pkg/runtime/defs_solaris_amd64.h
new file mode 100644
index 000000000..799724fad
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.h
@@ -0,0 +1,254 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+ EINTR = 0x4,
+ EBADF = 0x9,
+ EFAULT = 0xe,
+ EAGAIN = 0xb,
+ ETIMEDOUT = 0x91,
+ EWOULDBLOCK = 0xb,
+ EINPROGRESS = 0x96,
+
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x100,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_FREE = 0x5,
+
+ SA_SIGINFO = 0x8,
+ SA_RESTART = 0x4,
+ SA_ONSTACK = 0x1,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x15,
+ SIGSTOP = 0x17,
+ SIGTSTP = 0x18,
+ SIGCONT = 0x19,
+ SIGCHLD = 0x12,
+ SIGTTIN = 0x1a,
+ SIGTTOU = 0x1b,
+ SIGIO = 0x16,
+ SIGXCPU = 0x1e,
+ SIGXFSZ = 0x1f,
+ SIGVTALRM = 0x1c,
+ SIGPROF = 0x1d,
+ SIGWINCH = 0x14,
+ SIGUSR1 = 0x10,
+ SIGUSR2 = 0x11,
+
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+
+ _SC_NPROCESSORS_ONLN = 0xf,
+
+ PTHREAD_CREATE_DETACHED = 0x40,
+
+ FORK_NOSIGCHLD = 0x1,
+ FORK_WAITPID = 0x2,
+
+ MAXHOSTNAMELEN = 0x100,
+
+ O_NONBLOCK = 0x80,
+ FD_CLOEXEC = 0x1,
+ F_GETFL = 0x3,
+ F_SETFL = 0x4,
+ F_SETFD = 0x2,
+
+ POLLIN = 0x1,
+ POLLOUT = 0x4,
+ POLLHUP = 0x10,
+ POLLERR = 0x8,
+
+ PORT_SOURCE_FD = 0x4,
+};
+
+typedef struct SemT SemT;
+typedef struct Sigaltstack Sigaltstack;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Sigaction Sigaction;
+typedef struct Fpregset Fpregset;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct PortEvent PortEvent;
+typedef struct PthreadAttr PthreadAttr;
+typedef struct Stat Stat;
+
+#pragma pack on
+
+struct SemT {
+ uint32 sem_count;
+ uint16 sem_type;
+ uint16 sem_magic;
+ uint64 sem_pad1[3];
+ uint64 sem_pad2[2];
+};
+
+struct Sigaltstack {
+ byte *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+};
+struct Sigset {
+ uint32 __sigbits[4];
+};
+struct StackT {
+ byte *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+};
+
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ int32 si_pad;
+ byte __data[240];
+};
+struct Sigaction {
+ int32 sa_flags;
+ byte Pad_cgo_0[4];
+ byte _funcptr[8];
+ Sigset sa_mask;
+};
+
+struct Fpregset {
+ byte fp_reg_set[528];
+};
+struct Mcontext {
+ int64 gregs[28];
+ Fpregset fpregs;
+};
+struct Ucontext {
+ uint64 uc_flags;
+ Ucontext *uc_link;
+ Sigset uc_sigmask;
+ StackT uc_stack;
+ byte Pad_cgo_0[8];
+ Mcontext uc_mcontext;
+ int64 uc_filler[5];
+ byte Pad_cgo_1[8];
+};
+
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+struct PortEvent {
+ int32 portev_events;
+ uint16 portev_source;
+ uint16 portev_pad;
+ uint64 portev_object;
+ byte *portev_user;
+};
+typedef uint32 Pthread;
+struct PthreadAttr {
+ byte *__pthread_attrp;
+};
+
+struct Stat {
+ uint64 st_dev;
+ uint64 st_ino;
+ uint32 st_mode;
+ uint32 st_nlink;
+ uint32 st_uid;
+ uint32 st_gid;
+ uint64 st_rdev;
+ int64 st_size;
+ Timespec st_atim;
+ Timespec st_mtim;
+ Timespec st_ctim;
+ int32 st_blksize;
+ byte Pad_cgo_0[4];
+ int64 st_blocks;
+ int8 st_fstype[16];
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+ REG_RDI = 0x8,
+ REG_RSI = 0x9,
+ REG_RDX = 0xc,
+ REG_RCX = 0xd,
+ REG_R8 = 0x7,
+ REG_R9 = 0x6,
+ REG_R10 = 0x5,
+ REG_R11 = 0x4,
+ REG_R12 = 0x3,
+ REG_R13 = 0x2,
+ REG_R14 = 0x1,
+ REG_R15 = 0x0,
+ REG_RBP = 0xa,
+ REG_RBX = 0xb,
+ REG_RAX = 0xe,
+ REG_GS = 0x17,
+ REG_FS = 0x16,
+ REG_ES = 0x18,
+ REG_DS = 0x19,
+ REG_TRAPNO = 0xf,
+ REG_ERR = 0x10,
+ REG_RIP = 0x11,
+ REG_CS = 0x12,
+ REG_RFLAGS = 0x13,
+ REG_RSP = 0x14,
+ REG_SS = 0x15,
+};
+
diff --git a/src/pkg/runtime/env_plan9.c b/src/pkg/runtime/env_plan9.c
index 599319c75..f732c9f29 100644
--- a/src/pkg/runtime/env_plan9.c
+++ b/src/pkg/runtime/env_plan9.c
@@ -12,6 +12,7 @@ runtime·getenv(int8 *s)
intgo len;
byte file[128];
byte *p;
+ static byte b[128];
len = runtime·findnull((byte*)s);
if(len > sizeof file-6)
@@ -25,7 +26,14 @@ runtime·getenv(int8 *s)
if(fd < 0)
return nil;
n = runtime·seek(fd, 0, 2);
- p = runtime·malloc(n+1);
+ if(runtime·strcmp((byte*)s, (byte*)"GOTRACEBACK") == 0){
+ // should not call malloc
+ if(n >= sizeof b)
+ return nil;
+ runtime·memclr(b, sizeof b);
+ p = b;
+ }else
+ p = runtime·malloc(n+1);
r = runtime·pread(fd, p, n, 0);
runtime·close(fd);
if(r < 0)
diff --git a/src/pkg/runtime/env_posix.c b/src/pkg/runtime/env_posix.c
index 00ce577d0..4c8288f6b 100644
--- a/src/pkg/runtime/env_posix.c
+++ b/src/pkg/runtime/env_posix.c
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
Slice syscall·envs;
@@ -44,15 +46,24 @@ void
syscall·setenv_c(String k, String v)
{
byte *arg[2];
+ uintptr len;
if(_cgo_setenv == nil)
return;
- arg[0] = runtime·malloc(k.len + 1);
+ // Objects that are explicitly freed must be at least 16 bytes in size,
+ // so that they are not allocated using tiny alloc.
+ len = k.len + 1;
+ if(len < TinySize)
+ len = TinySize;
+ arg[0] = runtime·malloc(len);
runtime·memmove(arg[0], k.str, k.len);
arg[0][k.len] = 0;
- arg[1] = runtime·malloc(v.len + 1);
+ len = v.len + 1;
+ if(len < TinySize)
+ len = TinySize;
+ arg[1] = runtime·malloc(len);
runtime·memmove(arg[1], v.str, v.len);
arg[1][v.len] = 0;
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index bd7090883..e704ff872 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -75,19 +75,20 @@ func newErrorString(s string, ret *interface{}) {
}
// An errorCString represents a runtime error described by a single C string.
-type errorCString uintptr
+// Not "type errorCString uintptr" because of http://golang.org/issue/7084.
+type errorCString struct{ cstr uintptr }
func (e errorCString) RuntimeError() {}
func cstringToGo(uintptr) string
func (e errorCString) Error() string {
- return "runtime error: " + cstringToGo(uintptr(e))
+ return "runtime error: " + cstringToGo(e.cstr)
}
// For calling from C.
func newErrorCString(s uintptr, ret *interface{}) {
- *ret = errorCString(s)
+ *ret = errorCString{s}
}
type stringer interface {
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index d170fa72a..7a31b63b3 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -31,11 +31,11 @@ type LFNode struct {
Pushcnt uintptr
}
-func lfstackpush(head *uint64, node *LFNode)
-func lfstackpop2(head *uint64) *LFNode
+func lfstackpush_go(head *uint64, node *LFNode)
+func lfstackpop_go(head *uint64) *LFNode
-var LFStackPush = lfstackpush
-var LFStackPop = lfstackpop2
+var LFStackPush = lfstackpush_go
+var LFStackPop = lfstackpop_go
type ParFor struct {
body *byte
@@ -48,17 +48,17 @@ type ParFor struct {
wait bool
}
-func parforalloc2(nthrmax uint32) *ParFor
-func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-func parfordo(desc *ParFor)
-func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+func newParFor(nthrmax uint32) *ParFor
+func parForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
+func parForDo(desc *ParFor)
+func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr)
-var NewParFor = parforalloc2
-var ParForSetup = parforsetup2
-var ParForDo = parfordo
+var NewParFor = newParFor
+var ParForSetup = parForSetup
+var ParForDo = parForDo
func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
- begin, end := parforiters(desc, uintptr(tid))
+ begin, end := parForIters(desc, uintptr(tid))
return uint32(begin), uint32(end)
}
@@ -80,7 +80,13 @@ var BytesHash = bytesHash
var Int32Hash = int32Hash
var Int64Hash = int64Hash
-func GogoBytes() int32
-
var hashLoad float64 // declared in hashmap.c
var HashLoad = &hashLoad
+
+func memclrBytes(b []byte)
+
+var MemclrBytes = memclrBytes
+
+func gogoBytes() int32
+
+var GogoBytes = gogoBytes
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index 527e9cdf8..053dc1014 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -24,18 +24,28 @@ percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
The GODEBUG variable controls debug output from the runtime. GODEBUG value is
a comma-separated list of name=val pairs. Supported names are:
+ allocfreetrace: setting allocfreetrace=1 causes every allocation to be
+ profiled and a stack trace printed on each object's allocation and free.
+
+ efence: setting efence=1 causes the allocator to run in a mode
+ where each object is allocated on a unique page and addresses are
+ never recycled.
+
gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard
error at each collection, summarizing the amount of memory collected and the
length of the pause. Setting gctrace=2 emits the same summary but also
repeats each collection.
- schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
- error every X milliseconds, summarizing the scheduler state.
+ gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
+ that it thinks are dead.
scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
detailed multiline info every X milliseconds, describing state of the scheduler,
processors, threads and goroutines.
+ schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
+ error every X milliseconds, summarizing the scheduler state.
+
The GOMAXPROCS variable limits the number of operating system threads that
can execute user-level Go code simultaneously. There is no limit to the number of threads
that can be blocked in system calls on behalf of Go code; those do not count against
@@ -69,6 +79,11 @@ func Gosched()
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
+//
+// Calling Goexit from the main goroutine terminates that goroutine
+// without func main returning. Since func main has not returned,
+// the program continues execution of other goroutines.
+// If all other goroutines exit, the program crashes.
func Goexit()
// Caller reports file and line number information about function invocations on
@@ -153,6 +168,9 @@ func funcentry_go(*Func) uintptr
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
+// It is not guaranteed that a finalizer will run if the size of *x is
+// zero bytes.
+//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
@@ -172,10 +190,8 @@ func GOROOT() string {
}
// Version returns the Go tree's version string.
-// It is either a sequence number or, when possible,
-// a release tag like "release.2010-03-04".
-// A trailing + indicates that the tree had local modifications
-// at the time of the build.
+// It is either the commit hash and date at the time of the build or,
+// when possible, a release tag like "go1.3".
func Version() string {
return theVersion
}
diff --git a/src/pkg/runtime/funcdata.h b/src/pkg/runtime/funcdata.h
index 166263ef9..e20b6ae25 100644
--- a/src/pkg/runtime/funcdata.h
+++ b/src/pkg/runtime/funcdata.h
@@ -8,9 +8,11 @@
// as well as the compilers.
#define PCDATA_ArgSize 0 /* argument size at CALL instruction */
+#define PCDATA_StackMapIndex 1
-#define FUNCDATA_GCArgs 0 /* garbage collector blocks */
-#define FUNCDATA_GCLocals 1
+#define FUNCDATA_ArgsPointerMaps 2 /* garbage collector blocks */
+#define FUNCDATA_LocalsPointerMaps 3
+#define FUNCDATA_DeadValueMaps 4
// To be used in assembly.
#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
diff --git a/src/pkg/runtime/futex_test.go b/src/pkg/runtime/futex_test.go
index f4054b7e7..f57fc52b8 100644
--- a/src/pkg/runtime/futex_test.go
+++ b/src/pkg/runtime/futex_test.go
@@ -2,33 +2,76 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Futex is only available on Dragonfly, FreeBSD and Linux.
-// The race detector emits calls to split stack functions so it breaks the test.
+// Futex is only available on DragonFly BSD, FreeBSD and Linux.
+// The race detector emits calls to split stack functions so it breaks
+// the test.
+
// +build dragonfly freebsd linux
// +build !race
package runtime_test
import (
- . "runtime"
+ "runtime"
"testing"
"time"
)
+type futexsleepTest struct {
+ mtx uint32
+ ns int64
+ msg string
+ ch chan futexsleepTest
+}
+
+var futexsleepTests = []futexsleepTest{
+ beforeY2038: {mtx: 0, ns: 86400 * 1e9, msg: "before the year 2038", ch: make(chan futexsleepTest, 1)},
+ afterY2038: {mtx: 0, ns: (1<<31 + 100) * 1e9, msg: "after the year 2038", ch: make(chan futexsleepTest, 1)},
+}
+
+const (
+ beforeY2038 = iota
+ afterY2038
+)
+
func TestFutexsleep(t *testing.T) {
- ch := make(chan bool, 1)
- var dummy uint32
+ if runtime.GOMAXPROCS(0) > 1 {
+ // futexsleep doesn't handle EINTR or other signals,
+ // so spurious wakeups may happen.
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
start := time.Now()
- go func() {
- Entersyscall()
- Futexsleep(&dummy, 0, (1<<31+100)*1e9)
- Exitsyscall()
- ch <- true
- }()
- select {
- case <-ch:
- t.Errorf("futexsleep finished early after %s!", time.Since(start))
- case <-time.After(time.Second):
- Futexwakeup(&dummy, 1)
+ for _, tt := range futexsleepTests {
+ go func(tt futexsleepTest) {
+ runtime.Entersyscall()
+ runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
+ runtime.Exitsyscall()
+ tt.ch <- tt
+ }(tt)
+ }
+loop:
+ for {
+ select {
+ case tt := <-futexsleepTests[beforeY2038].ch:
+ t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+ break loop
+ case tt := <-futexsleepTests[afterY2038].ch:
+ // Looks like FreeBSD 10 kernel has changed
+ // the semantics of timedwait on userspace
+ // mutex to make broken stuff look broken.
+ switch {
+ case runtime.GOOS == "freebsd" && runtime.GOARCH == "386":
+ t.Log("freebsd/386 may not work correctly after the year 2038, see golang.org/issue/7194")
+ default:
+ t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+ break loop
+ }
+ case <-time.After(time.Second):
+ break loop
+ }
+ }
+ for _, tt := range futexsleepTests {
+ runtime.Futexwakeup(&tt.mtx, 1)
}
}
diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go
index dbd68c1c7..58717ecf7 100644
--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -9,6 +9,7 @@ import (
"runtime"
"runtime/debug"
"testing"
+ "time"
)
func TestGcSys(t *testing.T) {
@@ -151,3 +152,85 @@ func TestGcRescan(t *testing.T) {
}
}
}
+
+func TestGcLastTime(t *testing.T) {
+ ms := new(runtime.MemStats)
+ t0 := time.Now().UnixNano()
+ runtime.GC()
+ t1 := time.Now().UnixNano()
+ runtime.ReadMemStats(ms)
+ last := int64(ms.LastGC)
+ if t0 > last || last > t1 {
+ t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1)
+ }
+}
+
+func BenchmarkSetTypeNoPtr1(b *testing.B) {
+ type NoPtr1 struct {
+ p uintptr
+ }
+ var p *NoPtr1
+ for i := 0; i < b.N; i++ {
+ p = &NoPtr1{}
+ }
+ _ = p
+}
+func BenchmarkSetTypeNoPtr2(b *testing.B) {
+ type NoPtr2 struct {
+ p, q uintptr
+ }
+ var p *NoPtr2
+ for i := 0; i < b.N; i++ {
+ p = &NoPtr2{}
+ }
+ _ = p
+}
+func BenchmarkSetTypePtr1(b *testing.B) {
+ type Ptr1 struct {
+ p *byte
+ }
+ var p *Ptr1
+ for i := 0; i < b.N; i++ {
+ p = &Ptr1{}
+ }
+ _ = p
+}
+func BenchmarkSetTypePtr2(b *testing.B) {
+ type Ptr2 struct {
+ p, q *byte
+ }
+ var p *Ptr2
+ for i := 0; i < b.N; i++ {
+ p = &Ptr2{}
+ }
+ _ = p
+}
+
+func BenchmarkAllocation(b *testing.B) {
+ type T struct {
+ x, y *byte
+ }
+ ngo := runtime.GOMAXPROCS(0)
+ work := make(chan bool, b.N+ngo)
+ result := make(chan *T)
+ for i := 0; i < b.N; i++ {
+ work <- true
+ }
+ for i := 0; i < ngo; i++ {
+ work <- false
+ }
+ for i := 0; i < ngo; i++ {
+ go func() {
+ var x *T
+ for <-work {
+ for i := 0; i < 1000; i++ {
+ x = &T{}
+ }
+ }
+ result <- x
+ }()
+ }
+ for i := 0; i < ngo; i++ {
+ <-result
+ }
+}
diff --git a/src/pkg/runtime/hash_test.go b/src/pkg/runtime/hash_test.go
index 312c4be8e..1c11e0538 100644
--- a/src/pkg/runtime/hash_test.go
+++ b/src/pkg/runtime/hash_test.go
@@ -397,10 +397,10 @@ func avalancheTest1(t *testing.T, k Key) {
// all sums inside those bounds with 99% probability.
N := n * hashSize
var c float64
- // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .99
- for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .99; c += .1 {
+ // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .9999
+ for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .9999; c += .1 {
}
- c *= 2.0 // allowed slack - we don't need to be perfectly random
+ c *= 4.0 // allowed slack - we don't need to be perfectly random
mean := .5 * REP
stddev := .5 * math.Sqrt(REP)
low := int(mean - c*stddev)
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.goc
index 6d2ab2168..3327bed65 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.goc
@@ -2,125 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "type.h"
#include "race.h"
+#include "hashmap.h"
+#include "typekind.h"
#include "../../cmd/ld/textflag.h"
-// This file contains the implementation of Go's map type.
-//
-// The map is just a hash table. The data is arranged
-// into an array of buckets. Each bucket contains up to
-// 8 key/value pairs. The low-order bits of the hash are
-// used to select a bucket. Each bucket contains a few
-// high-order bits of each hash to distinguish the entries
-// within a single bucket.
-//
-// If more than 8 keys hash to a bucket, we chain on
-// extra buckets.
-//
-// When the hashtable grows, we allocate a new array
-// of buckets twice as big. Buckets are incrementally
-// copied from the old bucket array to the new bucket array.
-//
-// Map iterators walk through the array of buckets and
-// return the keys in walk order (bucket #, then overflow
-// chain order, then bucket index). To maintain iteration
-// semantics, we never move keys within their bucket (if
-// we did, keys might be returned 0 or 2 times). When
-// growing the table, iterators remain iterating through the
-// old table and must check the new table if the bucket
-// they are iterating through has been moved ("evacuated")
-// to the new table.
-
-// Maximum number of key/value pairs a bucket can hold.
-#define BUCKETSIZE 8
-
-// Maximum average load of a bucket that triggers growth.
-#define LOAD 6.5
-
-// Picking LOAD: too large and we have lots of overflow
-// buckets, too small and we waste a lot of space. I wrote
-// a simple program to check some stats for different loads:
-// (64-bit, 8 byte keys and values)
-// LOAD %overflow bytes/entry hitprobe missprobe
-// 4.00 2.13 20.77 3.00 4.00
-// 4.50 4.05 17.30 3.25 4.50
-// 5.00 6.85 14.77 3.50 5.00
-// 5.50 10.55 12.94 3.75 5.50
-// 6.00 15.27 11.67 4.00 6.00
-// 6.50 20.90 10.79 4.25 6.50
-// 7.00 27.14 10.15 4.50 7.00
-// 7.50 34.03 9.73 4.75 7.50
-// 8.00 41.10 9.40 5.00 8.00
-//
-// %overflow = percentage of buckets which have an overflow bucket
-// bytes/entry = overhead bytes used per key/value pair
-// hitprobe = # of entries to check when looking up a present key
-// missprobe = # of entries to check when looking up an absent key
-//
-// Keep in mind this data is for maximally loaded tables, i.e. just
-// before the table grows. Typical tables will be somewhat less loaded.
-
-// Maximum key or value size to keep inline (instead of mallocing per element).
-// Must fit in a uint8.
-// Fast versions cannot handle big values - the cutoff size for
-// fast versions in ../../cmd/gc/walk.c must be at most this value.
-#define MAXKEYSIZE 128
-#define MAXVALUESIZE 128
-
-typedef struct Bucket Bucket;
-struct Bucket
-{
- // Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
- // ../reflect/type.go. Don't change this structure without also changing that code!
- uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (0 = empty)
- Bucket *overflow; // overflow bucket, if any
- byte data[1]; // BUCKETSIZE keys followed by BUCKETSIZE values
-};
-// NOTE: packing all the keys together and then all the values together makes the
-// code a bit more complicated than alternating key/value/key/value/... but it allows
-// us to eliminate padding which would be needed for, e.g., map[int64]int8.
-
-// Low-order bit of overflow field is used to mark a bucket as already evacuated
-// without destroying the overflow pointer.
-// Only buckets in oldbuckets will be marked as evacuated.
-// Evacuated bit will be set identically on the base bucket and any overflow buckets.
-#define evacuated(b) (((uintptr)(b)->overflow & 1) != 0)
-#define overflowptr(b) ((Bucket*)((uintptr)(b)->overflow & ~(uintptr)1))
-
-struct Hmap
-{
- // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
- // ../reflect/type.go. Don't change this structure without also changing that code!
- uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
- uint32 flags;
- uint32 hash0; // hash seed
- uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
- uint8 keysize; // key size in bytes
- uint8 valuesize; // value size in bytes
- uint16 bucketsize; // bucket size in bytes
-
- byte *buckets; // array of 2^B Buckets. may be nil if count==0.
- byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
- uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
-};
-
-// possible flags
-enum
-{
- IndirectKey = 1, // storing pointers to keys
- IndirectValue = 2, // storing pointers to values
- Iterator = 4, // there may be an iterator using buckets
- OldIterator = 8, // there may be an iterator using oldbuckets
-};
-
-// Macros for dereferencing indirect keys
-#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
-#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
-
enum
{
docheck = 0, // check invariants before and after every op. Slow!!!
@@ -143,16 +34,12 @@ check(MapType *t, Hmap *h)
// check buckets
for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
- if(h->oldbuckets != nil) {
- oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
- b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if(!evacuated(b))
- continue; // b is still uninitialized
- }
for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == Empty)
continue;
+ if(b->tophash[i] > Empty && b->tophash[i] < MinTopHash)
+ runtime·throw("evacuated cell in buckets");
cnt++;
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
if(!eq)
@@ -160,8 +47,8 @@ check(MapType *t, Hmap *h)
hash = h->hash0;
t->key->alg->hash(&hash, t->key->size, IK(h, k));
top = hash >> (8*sizeof(uintptr) - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
if(top != b->tophash[i])
runtime·throw("bad hash");
}
@@ -172,14 +59,12 @@ check(MapType *t, Hmap *h)
if(h->oldbuckets != nil) {
for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if(evacuated(b))
- continue;
- if(oldbucket < h->nevacuate)
- runtime·throw("bucket became unevacuated");
- for(; b != nil; b = overflowptr(b)) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ for(; b != nil; b = b->overflow) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] < MinTopHash)
continue;
+ if(oldbucket < h->nevacuate)
+ runtime·throw("unevacuated entry in an evacuated bucket");
cnt++;
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
if(!eq)
@@ -187,8 +72,8 @@ check(MapType *t, Hmap *h)
hash = h->hash0;
t->key->alg->hash(&hash, t->key->size, IK(h, k));
top = hash >> (8*sizeof(uintptr) - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
if(top != b->tophash[i])
runtime·throw("bad hash (old)");
}
@@ -224,6 +109,10 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
valuesize = sizeof(byte*);
}
bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
+ if(bucketsize != t->bucket->size) {
+ runtime·printf("runtime: bucketsize=%p but t->bucket->size=%p; t=%S\n", bucketsize, t->bucket->size, *t->string);
+ runtime·throw("bucketsize wrong");
+ }
// invariants we depend on. We should probably check these at compile time
// somewhere, but for now we'll do it here.
@@ -237,9 +126,9 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
runtime·throw("value size not a multiple of value align");
if(BUCKETSIZE < 8)
runtime·throw("bucketsize too small for proper alignment");
- if(sizeof(void*) == 4 && t->key->align > 4)
+ if((offsetof(Bucket, data[0]) & (t->key->align-1)) != 0)
runtime·throw("need padding in bucket (key)");
- if(sizeof(void*) == 4 && t->elem->align > 4)
+ if((offsetof(Bucket, data[0]) & (t->elem->align-1)) != 0)
runtime·throw("need padding in bucket (value)");
// find size parameter which will hold the requested # of elements
@@ -273,13 +162,12 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
}
// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
-// We leave the original bucket intact, except for the evacuated marks, so that
-// iterators can still iterate through the old buckets.
+// We leave the original bucket intact, except for marking the topbits
+// entries as evacuated, so that iterators can still iterate through the old buckets.
static void
evacuate(MapType *t, Hmap *h, uintptr oldbucket)
{
Bucket *b;
- Bucket *nextb;
Bucket *x, *y;
Bucket *newx, *newy;
uintptr xi, yi;
@@ -302,15 +190,19 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
xi = 0;
yi = 0;
- xk = x->data;
- yk = y->data;
+ xk = (byte*)x->data;
+ yk = (byte*)y->data;
xv = xk + h->keysize * BUCKETSIZE;
yv = yk + h->keysize * BUCKETSIZE;
- do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(; b != nil; b = b->overflow) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
top = b->tophash[i];
- if(top == 0)
+ if(top == Empty) {
+ b->tophash[i] = EvacuatedEmpty;
continue;
+ }
+ if(top < MinTopHash)
+ runtime·throw("bad state");
// Compute hash to make our evacuation decision (whether we need
// to send this key/value to bucket x or bucket y).
@@ -335,19 +227,20 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
else
hash &= ~newbit;
top = hash >> (8*sizeof(uintptr)-8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
}
}
if((hash & newbit) == 0) {
+ b->tophash[i] = EvacuatedX;
if(xi == BUCKETSIZE) {
if(checkgc) mstats.next_gc = mstats.heap_alloc;
newx = runtime·cnew(t->bucket);
x->overflow = newx;
x = newx;
xi = 0;
- xk = x->data;
+ xk = (byte*)x->data;
xv = xk + h->keysize * BUCKETSIZE;
}
x->tophash[xi] = top;
@@ -365,13 +258,14 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
xk += h->keysize;
xv += h->valuesize;
} else {
+ b->tophash[i] = EvacuatedY;
if(yi == BUCKETSIZE) {
if(checkgc) mstats.next_gc = mstats.heap_alloc;
newy = runtime·cnew(t->bucket);
y->overflow = newy;
y = newy;
yi = 0;
- yk = y->data;
+ yk = (byte*)y->data;
yv = yk + h->keysize * BUCKETSIZE;
}
y->tophash[yi] = top;
@@ -390,26 +284,21 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
yv += h->valuesize;
}
}
+ }
- // mark as evacuated so we don't do it again.
- // this also tells any iterators that this data isn't golden anymore.
- nextb = b->overflow;
- b->overflow = (Bucket*)((uintptr)nextb + 1);
-
- b = nextb;
- } while(b != nil);
-
- // Unlink the overflow buckets to help GC.
- b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
- if((h->flags & OldIterator) == 0)
- b->overflow = (Bucket*)1;
+ // Unlink the overflow buckets & clear key/value to help GC.
+ if((h->flags & OldIterator) == 0) {
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ b->overflow = nil;
+ runtime·memclr((byte*)b->data, h->bucketsize - offsetof(Bucket, data[0]));
+ }
}
- // advance evacuation mark
+ // Advance evacuation mark
if(oldbucket == h->nevacuate) {
h->nevacuate = oldbucket + 1;
if(oldbucket + 1 == newbit) // newbit == # of oldbuckets
- // free main bucket array
+ // Growing is all done. Free old main bucket array.
h->oldbuckets = nil;
}
if(docheck)
@@ -443,7 +332,6 @@ hash_grow(MapType *t, Hmap *h)
if(h->oldbuckets != nil)
runtime·throw("evacuation not done in time");
old_buckets = h->buckets;
- // NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
if(checkgc) mstats.next_gc = mstats.heap_alloc;
new_buckets = runtime·cnewarray(t->bucket, (uintptr)1 << (h->B + 1));
flags = (h->flags & ~(Iterator | OldIterator));
@@ -495,10 +383,10 @@ hash_lookup(MapType *t, Hmap *h, byte **keyp)
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] == top) {
k2 = IK(h, k);
t->key->alg->equal(&eq, t->key->size, key, k2);
@@ -513,10 +401,6 @@ hash_lookup(MapType *t, Hmap *h, byte **keyp)
return nil;
}
-// When an item is not found, fast versions return a pointer to this zeroed memory.
-#pragma dataflag RODATA
-static uint8 empty_value[MAXVALUESIZE];
-
// Specialized versions of mapaccess1 for specific types.
// See ./hashmap_fast.c and ../../cmd/gc/walk.c.
#define HASH_LOOKUP1 runtime·mapaccess1_fast32
@@ -564,6 +448,9 @@ static uint8 empty_value[MAXVALUESIZE];
#ifdef GOARCH_amd64
#define CHECKTYPE uint64
#endif
+#ifdef GOARCH_amd64p32
+#define CHECKTYPE uint32
+#endif
#ifdef GOARCH_386
#define CHECKTYPE uint32
#endif
@@ -612,15 +499,15 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
grow_work(t, h, bucket);
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
inserti = nil;
insertk = nil;
insertv = nil;
while(true) {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] != top) {
- if(b->tophash[i] == 0 && inserti == nil) {
+ if(b->tophash[i] == Empty && inserti == nil) {
inserti = &b->tophash[i];
insertk = k;
insertv = v;
@@ -654,7 +541,7 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
newb = runtime·cnew(t->bucket);
b->overflow = newb;
inserti = newb->tophash;
- insertk = newb->data;
+ insertk = (byte*)newb->data;
insertv = insertk + h->keysize * BUCKETSIZE;
}
@@ -701,10 +588,10 @@ hash_remove(MapType *t, Hmap *h, void *key)
grow_work(t, h, bucket);
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
top = hash >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
do {
- for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
if(b->tophash[i] != top)
continue;
t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
@@ -722,7 +609,7 @@ hash_remove(MapType *t, Hmap *h, void *key)
t->elem->alg->copy(t->elem->size, v, nil);
}
- b->tophash[i] = 0;
+ b->tophash[i] = Empty;
h->count--;
// TODO: consolidate buckets if they are mostly empty
@@ -737,42 +624,17 @@ hash_remove(MapType *t, Hmap *h, void *key)
// TODO: shrink the map, the same way we grow it.
-// If you modify hash_iter, also change cmd/gc/range.c to indicate
-// the size of this structure.
-struct hash_iter
-{
- uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
- uint8* value;
-
- MapType *t;
- Hmap *h;
-
- // end point for iteration
- uintptr endbucket;
- bool wrapped;
-
- // state of table at time iterator is initialized
- uint8 B;
- byte *buckets;
-
- // iter state
- uintptr bucket;
- struct Bucket *bptr;
- uintptr i;
- intptr check_bucket;
-};
-
// iterator state:
// bucket: the current bucket ID
// b: the current Bucket in the chain
// i: the next offset to check in the current bucket
static void
-hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
+hash_iter_init(MapType *t, Hmap *h, Hiter *it)
{
uint32 old;
- if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
- runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
+ if(sizeof(Hiter) / sizeof(uintptr) != 10) {
+ runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/reflect.c
}
it->t = t;
it->h = h;
@@ -782,8 +644,9 @@ hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
it->buckets = h->buckets;
// iterator state
- it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
- it->wrapped = false;
+ it->bucket = 0;
+ it->offset = runtime·fastrand1() & (BUCKETSIZE - 1);
+ it->done = false;
it->bptr = nil;
// Remember we have an iterator.
@@ -798,22 +661,22 @@ hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
if(h->buckets == nil) {
// Empty map. Force next hash_next to exit without
- // evalulating h->bucket.
- it->wrapped = true;
+ // evaluating h->bucket.
+ it->done = true;
}
}
// initializes it->key and it->value to the next key/value pair
// in the iteration, or nil if we've reached the end.
static void
-hash_next(struct hash_iter *it)
+hash_next(Hiter *it)
{
Hmap *h;
MapType *t;
uintptr bucket, oldbucket;
uintptr hash;
Bucket *b;
- uintptr i;
+ uintptr i, offi;
intptr check_bucket;
bool eq;
byte *k, *v;
@@ -828,7 +691,7 @@ hash_next(struct hash_iter *it)
next:
if(b == nil) {
- if(bucket == it->endbucket && it->wrapped) {
+ if(it->done) {
// end of iteration
it->key = nil;
it->value = nil;
@@ -854,18 +717,20 @@ next:
bucket++;
if(bucket == ((uintptr)1 << it->B)) {
bucket = 0;
- it->wrapped = true;
+ it->done = true;
}
i = 0;
}
- k = b->data + h->keysize * i;
- v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
- for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
- if(b->tophash[i] != 0) {
+ for(; i < BUCKETSIZE; i++) {
+ offi = (i + it->offset) & (BUCKETSIZE - 1);
+ k = (byte*)b->data + h->keysize * offi;
+ v = (byte*)b->data + h->keysize * BUCKETSIZE + h->valuesize * offi;
+ if(b->tophash[offi] != Empty && b->tophash[offi] != EvacuatedEmpty) {
if(check_bucket >= 0) {
// Special case: iterator was started during a grow and the
// grow is not done yet. We're working on a bucket whose
- // oldbucket has not been evacuated yet. So we're iterating
+ // oldbucket has not been evacuated yet. Or at least, it wasn't
+ // evacuated when we started the bucket. So we're iterating
// through the oldbucket, skipping any keys that will go
// to the other new bucket (each oldbucket expands to two
// buckets during a grow).
@@ -883,12 +748,15 @@ next:
// repeatable and randomish choice of which direction
// to send NaNs during evacuation. We'll use the low
// bit of tophash to decide which way NaNs go.
- if(check_bucket >> (it->B - 1) != (b->tophash[i] & 1)) {
+ // NOTE: this case is why we need two evacuate tophash
+ // values, evacuatedX and evacuatedY, that differ in
+ // their low bit.
+ if(check_bucket >> (it->B - 1) != (b->tophash[offi] & 1)) {
continue;
}
}
}
- if(!evacuated(b)) {
+ if(b->tophash[offi] != EvacuatedX && b->tophash[offi] != EvacuatedY) {
// this is the golden data, we can return it.
it->key = IK(h, k);
it->value = IV(h, v);
@@ -924,7 +792,7 @@ next:
return;
}
}
- b = overflowptr(b);
+ b = b->overflow;
i = 0;
goto next;
}
@@ -933,15 +801,12 @@ next:
/// interfaces to go runtime
//
-void
-reflect·ismapkey(Type *typ, bool ret)
-{
+func reflect·ismapkey(typ *Type) (ret bool) {
ret = typ != nil && typ->alg->hash != runtime·nohash;
- FLUSH(&ret);
}
-Hmap*
-runtime·makemap_c(MapType *typ, int64 hint)
+static Hmap*
+makemap_c(MapType *typ, int64 hint)
{
Hmap *h;
Type *key;
@@ -971,235 +836,186 @@ runtime·makemap_c(MapType *typ, int64 hint)
return h;
}
-// makemap(key, val *Type, hint int64) (hmap *map[any]any);
-void
-runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
-{
- ret = runtime·makemap_c(typ, hint);
- FLUSH(&ret);
+func makemap(typ *MapType, hint int64) (ret *Hmap) {
+ ret = makemap_c(typ, hint);
}
-// For reflect:
-// func makemap(Type *mapType) (hmap *map)
-void
-reflect·makemap(MapType *t, Hmap *ret)
-{
- ret = runtime·makemap_c(t, 0);
- FLUSH(&ret);
+func reflect·makemap(t *MapType) (ret *Hmap) {
+ ret = makemap_c(t, 0);
}
-void
-runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
-{
- byte *res;
- Type *elem;
-
- elem = t->elem;
- if(h == nil || h->count == 0) {
- elem->alg->copy(elem->size, av, nil);
- *pres = false;
- return;
- }
-
- res = hash_lookup(t, h, &ak);
-
- if(res != nil) {
- *pres = true;
- elem->alg->copy(elem->size, av, res);
- } else {
- *pres = false;
- elem->alg->copy(elem->size, av, nil);
- }
-}
-
-// mapaccess1(hmap *map[any]any, key any) (val any);
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
#pragma textflag NOSPLIT
-void
-runtime·mapaccess1(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av;
- byte *res;
-
- if(raceenabled && h != nil)
+func mapaccess1(t *MapType, h *Hmap, key *byte) (val *byte) {
+ if(raceenabled && h != nil) {
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
-
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, Structrnd);
-
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess1);
+ }
if(h == nil || h->count == 0) {
- t->elem->alg->copy(t->elem->size, av, nil);
+ val = t->elem->zero;
} else {
- res = hash_lookup(t, h, &ak);
- t->elem->alg->copy(t->elem->size, av, res);
+ val = hash_lookup(t, h, &key);
+ if(val == nil)
+ val = t->elem->zero;
}
if(debug) {
runtime·prints("runtime.mapaccess1: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- t->elem->alg->print(t->elem->size, av);
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
+// NOTE: The returned pointer keeps the whole map live, so don't
+// hold onto it for very long.
#pragma textflag NOSPLIT
-void
-runtime·mapaccess2(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av, *ap;
-
- if(raceenabled && h != nil)
+func mapaccess2(t *MapType, h *Hmap, key *byte) (val *byte, pres bool) {
+ if(raceenabled && h != nil) {
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess2);
+ }
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, Structrnd);
- ap = av + t->elem->size;
-
- runtime·mapaccess(t, h, ak, av, ap);
+ if(h == nil || h->count == 0) {
+ val = t->elem->zero;
+ pres = false;
+ } else {
+ val = hash_lookup(t, h, &key);
+ if(val == nil) {
+ val = t->elem->zero;
+ pres = false;
+ } else {
+ pres = true;
+ }
+ }
if(debug) {
runtime·prints("runtime.mapaccess2: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- t->elem->alg->print(t->elem->size, av);
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("; pres=");
- runtime·printbool(*ap);
+ runtime·printbool(pres);
runtime·prints("\n");
}
}
-// For reflect:
-// func mapaccess(t type, h map, key iword) (val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
- byte *ak, *av;
-
- if(raceenabled && h != nil)
- runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
-
- if(t->key->size <= sizeof(key))
- ak = (byte*)&key;
- else
- ak = (byte*)key;
- val = 0;
- pres = false;
- if(t->elem->size <= sizeof(val))
- av = (byte*)&val;
+#pragma textflag NOSPLIT
+func reflect·mapaccess(t *MapType, h *Hmap, key *byte) (val *byte) {
+ if(h == nil)
+ val = nil;
else {
- av = runtime·mal(t->elem->size);
- val = (uintptr)av;
+ if(raceenabled) {
+ runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapaccess);
+ }
+ val = hash_lookup(t, h, &key);
}
- runtime·mapaccess(t, h, ak, av, &pres);
- FLUSH(&val);
- FLUSH(&pres);
}
-void
-runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
-{
+#pragma textflag NOSPLIT
+func mapassign1(t *MapType, h *Hmap, key *byte, val *byte) {
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
- if(av == nil) {
- hash_remove(t, h, ak);
- } else {
- hash_insert(t, h, ak, av);
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapassign1);
+ runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), runtime·mapassign1);
}
+ hash_insert(t, h, key, val);
+
if(debug) {
- runtime·prints("mapassign: map=");
+ runtime·prints("mapassign1: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
runtime·prints("; val=");
- if(av)
- t->elem->alg->print(t->elem->size, av);
- else
- runtime·prints("nil");
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
#pragma textflag NOSPLIT
-void
-runtime·mapassign1(MapType *t, Hmap *h, ...)
-{
- byte *ak, *av;
-
+func mapdelete(t *MapType, h *Hmap, key *byte) {
if(h == nil)
- runtime·panicstring("assignment to entry in nil map");
+ return;
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
- ak = (byte*)(&h + 1);
- av = ak + ROUND(t->key->size, t->elem->align);
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapdelete);
+ }
+
+ hash_remove(t, h, key);
- runtime·mapassign(t, h, ak, av);
+ if(debug) {
+ runtime·prints("mapdelete: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("\n");
+ }
}
-// mapdelete(mapType *type, hmap *map[any]any, key any)
#pragma textflag NOSPLIT
-void
-runtime·mapdelete(MapType *t, Hmap *h, ...)
-{
- byte *ak;
-
+func reflect·mapassign(t *MapType, h *Hmap, key *byte, val *byte) {
if(h == nil)
- return;
+ runtime·panicstring("assignment to entry in nil map");
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapassign);
+ runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), reflect·mapassign);
+ }
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
- ak = (byte*)(&h + 1);
- runtime·mapassign(t, h, ak, nil);
+ hash_insert(t, h, key, val);
if(debug) {
- runtime·prints("mapdelete: map=");
+ runtime·prints("mapassign: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- t->key->alg->print(t->key->size, ak);
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("; val=");
+ t->elem->alg->print(t->elem->size, val);
runtime·prints("\n");
}
}
-// For reflect:
-// func mapassign(t type h map, key, val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
- byte *ak, *av;
-
+#pragma textflag NOSPLIT
+func reflect·mapdelete(t *MapType, h *Hmap, key *byte) {
if(h == nil)
- runtime·panicstring("assignment to entry in nil map");
- if(raceenabled)
- runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
- if(t->key->size <= sizeof(key))
- ak = (byte*)&key;
- else
- ak = (byte*)key;
- if(t->elem->size <= sizeof(val))
- av = (byte*)&val;
- else
- av = (byte*)val;
- if(!pres)
- av = nil;
- runtime·mapassign(t, h, ak, av);
+ return; // see bug 8051
+ if(raceenabled) {
+ runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapdelete);
+ runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapdelete);
+ }
+ hash_remove(t, h, key);
+
+ if(debug) {
+ runtime·prints("mapdelete: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, key);
+ runtime·prints("\n");
+ }
}
-// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
-void
-runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
+#pragma textflag NOSPLIT
+func mapiterinit(t *MapType, h *Hmap, it *Hiter) {
+ // Clear pointer fields so garbage collector does not complain.
+ it->key = nil;
+ it->value = nil;
+ it->t = nil;
+ it->h = nil;
+ it->buckets = nil;
+ it->bptr = nil;
+
if(h == nil || h->count == 0) {
it->key = nil;
return;
@@ -1219,20 +1035,13 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
}
}
-// For reflect:
-// func mapiterinit(h map) (it iter)
-void
-reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
+func reflect·mapiterinit(t *MapType, h *Hmap) (it *Hiter) {
it = runtime·mal(sizeof *it);
- FLUSH(&it);
runtime·mapiterinit(t, h, it);
}
-// mapiternext(hiter *any);
-void
-runtime·mapiternext(struct hash_iter *it)
-{
+#pragma textflag NOSPLIT
+func mapiternext(it *Hiter) {
if(raceenabled)
runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
@@ -1246,85 +1055,16 @@ runtime·mapiternext(struct hash_iter *it)
}
}
-// For reflect:
-// func mapiternext(it iter)
-void
-reflect·mapiternext(struct hash_iter *it)
-{
+func reflect·mapiternext(it *Hiter) {
runtime·mapiternext(it);
}
-// mapiter1(hiter *any) (key any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter1(struct hash_iter *it, ...)
-{
- byte *ak, *res;
- Type *key;
-
- ak = (byte*)(&it + 1);
-
- res = it->key;
- if(res == nil)
- runtime·throw("runtime.mapiter1: key:val nil pointer");
-
- key = it->t->key;
- key->alg->copy(key->size, ak, res);
-
- if(debug) {
- runtime·prints("mapiter1: iter=");
- runtime·printpointer(it);
- runtime·prints("; map=");
- runtime·printpointer(it->h);
- runtime·prints("\n");
- }
-}
-
-bool
-runtime·mapiterkey(struct hash_iter *it, void *ak)
-{
- byte *res;
- Type *key;
-
- res = it->key;
- if(res == nil)
- return false;
- key = it->t->key;
- key->alg->copy(key->size, ak, res);
- return true;
-}
-
-// For reflect:
-// func mapiterkey(h map) (key iword, ok bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
-{
- byte *res;
- Type *tkey;
-
- key = 0;
- ok = false;
- res = it->key;
- if(res != nil) {
- tkey = it->t->key;
- if(tkey->size <= sizeof(key))
- tkey->alg->copy(tkey->size, (byte*)&key, res);
- else
- key = (uintptr)res;
- ok = true;
- }
- FLUSH(&key);
- FLUSH(&ok);
+func reflect·mapiterkey(it *Hiter) (key *byte) {
+ key = it->key;
}
-// For reflect:
-// func maplen(h map) (len int)
-// Like len(m) in the actual language, we treat the nil map as length 0.
-void
-reflect·maplen(Hmap *h, intgo len)
-{
+#pragma textflag NOSPLIT
+func reflect·maplen(h *Hmap) (len int) {
if(h == nil)
len = 0;
else {
@@ -1332,35 +1072,6 @@ reflect·maplen(Hmap *h, intgo len)
if(raceenabled)
runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
}
- FLUSH(&len);
-}
-
-// mapiter2(hiter *any) (key any, val any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter2(struct hash_iter *it, ...)
-{
- byte *ak, *av, *res;
- MapType *t;
-
- t = it->t;
- ak = (byte*)(&it + 1);
- av = ak + ROUND(t->key->size, t->elem->align);
-
- res = it->key;
- if(res == nil)
- runtime·throw("runtime.mapiter2: key:val nil pointer");
-
- t->key->alg->copy(t->key->size, ak, res);
- t->elem->alg->copy(t->elem->size, av, it->value);
-
- if(debug) {
- runtime·prints("mapiter2: iter=");
- runtime·printpointer(it);
- runtime·prints("; map=");
- runtime·printpointer(it->h);
- runtime·prints("\n");
- }
}
// exported value for testing
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
new file mode 100644
index 000000000..522d1ad01
--- /dev/null
+++ b/src/pkg/runtime/hashmap.h
@@ -0,0 +1,147 @@
+// 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.
+
+// This file contains the implementation of Go's map type.
+//
+// The map is just a hash table. The data is arranged
+// into an array of buckets. Each bucket contains up to
+// 8 key/value pairs. The low-order bits of the hash are
+// used to select a bucket. Each bucket contains a few
+// high-order bits of each hash to distinguish the entries
+// within a single bucket.
+//
+// If more than 8 keys hash to a bucket, we chain on
+// extra buckets.
+//
+// When the hashtable grows, we allocate a new array
+// of buckets twice as big. Buckets are incrementally
+// copied from the old bucket array to the new bucket array.
+//
+// Map iterators walk through the array of buckets and
+// return the keys in walk order (bucket #, then overflow
+// chain order, then bucket index). To maintain iteration
+// semantics, we never move keys within their bucket (if
+// we did, keys might be returned 0 or 2 times). When
+// growing the table, iterators remain iterating through the
+// old table and must check the new table if the bucket
+// they are iterating through has been moved ("evacuated")
+// to the new table.
+
+// Maximum number of key/value pairs a bucket can hold.
+#define BUCKETSIZE 8
+
+// Maximum average load of a bucket that triggers growth.
+#define LOAD 6.5
+
+// Picking LOAD: too large and we have lots of overflow
+// buckets, too small and we waste a lot of space. I wrote
+// a simple program to check some stats for different loads:
+// (64-bit, 8 byte keys and values)
+// LOAD %overflow bytes/entry hitprobe missprobe
+// 4.00 2.13 20.77 3.00 4.00
+// 4.50 4.05 17.30 3.25 4.50
+// 5.00 6.85 14.77 3.50 5.00
+// 5.50 10.55 12.94 3.75 5.50
+// 6.00 15.27 11.67 4.00 6.00
+// 6.50 20.90 10.79 4.25 6.50
+// 7.00 27.14 10.15 4.50 7.00
+// 7.50 34.03 9.73 4.75 7.50
+// 8.00 41.10 9.40 5.00 8.00
+//
+// %overflow = percentage of buckets which have an overflow bucket
+// bytes/entry = overhead bytes used per key/value pair
+// hitprobe = # of entries to check when looking up a present key
+// missprobe = # of entries to check when looking up an absent key
+//
+// Keep in mind this data is for maximally loaded tables, i.e. just
+// before the table grows. Typical tables will be somewhat less loaded.
+
+// Maximum key or value size to keep inline (instead of mallocing per element).
+// Must fit in a uint8.
+// Fast versions cannot handle big values - the cutoff size for
+// fast versions in ../../cmd/gc/walk.c must be at most this value.
+#define MAXKEYSIZE 128
+#define MAXVALUESIZE 128
+
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ // Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
+ // ../reflect/type.go. Don't change this structure without also changing that code!
+ uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (or special mark below)
+ Bucket *overflow; // overflow bucket, if any
+ uint64 data[1]; // BUCKETSIZE keys followed by BUCKETSIZE values
+};
+// NOTE: packing all the keys together and then all the values together makes the
+// code a bit more complicated than alternating key/value/key/value/... but it allows
+// us to eliminate padding which would be needed for, e.g., map[int64]int8.
+
+// tophash values. We reserve a few possibilities for special marks.
+// Each bucket (including its overflow buckets, if any) will have either all or none of its
+// entries in the Evacuated* states (except during the evacuate() method, which only happens
+// during map writes and thus no one else can observe the map during that time).
+enum
+{
+ Empty = 0, // cell is empty
+ EvacuatedEmpty = 1, // cell is empty, bucket is evacuated.
+ EvacuatedX = 2, // key/value is valid. Entry has been evacuated to first half of larger table.
+ EvacuatedY = 3, // same as above, but evacuated to second half of larger table.
+ MinTopHash = 4, // minimum tophash for a normal filled cell.
+};
+#define evacuated(b) ((b)->tophash[0] > Empty && (b)->tophash[0] < MinTopHash)
+
+struct Hmap
+{
+ // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
+ // ../reflect/type.go. Don't change this structure without also changing that code!
+ uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
+ uint32 flags;
+ uint32 hash0; // hash seed
+ uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
+ uint8 keysize; // key size in bytes
+ uint8 valuesize; // value size in bytes
+ uint16 bucketsize; // bucket size in bytes
+
+ byte *buckets; // array of 2^B Buckets. may be nil if count==0.
+ byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
+ uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
+};
+
+// possible flags
+enum
+{
+ IndirectKey = 1, // storing pointers to keys
+ IndirectValue = 2, // storing pointers to values
+ Iterator = 4, // there may be an iterator using buckets
+ OldIterator = 8, // there may be an iterator using oldbuckets
+};
+
+// Macros for dereferencing indirect keys
+#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
+#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
+
+// If you modify Hiter, also change cmd/gc/reflect.c to indicate
+// the layout of this structure.
+struct Hiter
+{
+ uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
+ uint8* value; // Must be in second position (see cmd/gc/range.c).
+
+ MapType *t;
+ Hmap *h;
+ byte *buckets; // bucket ptr at hash_iter initialization time
+ struct Bucket *bptr; // current bucket
+
+ uint8 offset; // intra-bucket offset to start from during iteration (should be big enough to hold BUCKETSIZE-1)
+ bool done;
+
+ // state of table at time iterator is initialized
+ uint8 B;
+
+ // iter state
+ uintptr bucket;
+ uintptr i;
+ intptr check_bucket;
+};
+
diff --git a/src/pkg/runtime/hashmap_fast.c b/src/pkg/runtime/hashmap_fast.c
index 796582e2d..83bf6feb5 100644
--- a/src/pkg/runtime/hashmap_fast.c
+++ b/src/pkg/runtime/hashmap_fast.c
@@ -5,24 +5,23 @@
// Fast hashmap lookup specialized to a specific key type.
// Included by hashmap.c once for each specialized type.
-// Note that this code differs from hash_lookup in that
-// it returns a pointer to the result, not the result itself.
-// The returned pointer is only valid until the next GC
-// point, so the caller must dereference it before then.
-
// +build ignore
+// Because this file is #included, it cannot be processed by goc2c,
+// so we have to handle the Go resuts ourselves.
+
#pragma textflag NOSPLIT
void
-HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
+HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
{
uintptr bucket, i;
Bucket *b;
KEYTYPE *k;
- byte *v;
+ byte *v, **valueptr;
uint8 top;
int8 keymaybe;
+ valueptr = (byte**)&base;
if(debug) {
runtime·prints("runtime.mapaccess1_fastXXX: map=");
runtime·printpointer(h);
@@ -31,8 +30,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
runtime·prints("\n");
}
if(h == nil || h->count == 0) {
- value = empty_value;
- FLUSH(&value);
+ *valueptr = t->elem->zero;
return;
}
if(raceenabled)
@@ -45,26 +43,24 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
b = (Bucket*)h->buckets;
if(FASTKEY(key)) {
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
}
} else {
keymaybe = -1;
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
if(MAYBE_EQ(key, *k)) {
@@ -82,8 +78,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
if(keymaybe >= 0) {
k = (KEYTYPE*)b->data + keymaybe;
if(SLOW_EQ(key, *k)) {
- value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
- FLUSH(&value);
+ *valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
return;
}
}
@@ -93,8 +88,8 @@ dohash:
bucket = h->hash0;
HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
top = bucket >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
bucket &= (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -112,29 +107,30 @@ dohash:
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- FLUSH(&value);
+ *valueptr = v;
return;
}
}
b = b->overflow;
} while(b != nil);
}
- value = empty_value;
- FLUSH(&value);
+ *valueptr = t->elem->zero;
}
#pragma textflag NOSPLIT
void
-HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
+HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
{
uintptr bucket, i;
Bucket *b;
KEYTYPE *k;
- byte *v;
+ byte *v, **valueptr;
uint8 top;
int8 keymaybe;
+ bool *okptr;
+ valueptr = (byte**)&base;
+ okptr = (bool*)(valueptr+1);
if(debug) {
runtime·prints("runtime.mapaccess2_fastXXX: map=");
runtime·printpointer(h);
@@ -143,10 +139,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
runtime·prints("\n");
}
if(h == nil || h->count == 0) {
- value = empty_value;
- res = false;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = t->elem->zero;
+ *okptr = false;
return;
}
if(raceenabled)
@@ -159,30 +153,26 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
b = (Bucket*)h->buckets;
if(FASTKEY(key)) {
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
}
} else {
keymaybe = -1;
for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
- if(b->tophash[i] == 0)
+ if(b->tophash[i] == Empty)
continue;
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
if(MAYBE_EQ(key, *k)) {
@@ -200,10 +190,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
if(keymaybe >= 0) {
k = (KEYTYPE*)b->data + keymaybe;
if(SLOW_EQ(key, *k)) {
- value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
+ *okptr = true;
return;
}
}
@@ -213,8 +201,8 @@ dohash:
bucket = h->hash0;
HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
top = bucket >> (sizeof(uintptr)*8 - 8);
- if(top == 0)
- top = 1;
+ if(top < MinTopHash)
+ top += MinTopHash;
bucket &= (((uintptr)1 << h->B) - 1);
if(h->oldbuckets != nil) {
i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -232,18 +220,14 @@ dohash:
if(QUICK_NE(key, *k))
continue;
if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
- value = v;
- res = true;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = v;
+ *okptr = true;
return;
}
}
b = b->overflow;
} while(b != nil);
}
- value = empty_value;
- res = false;
- FLUSH(&value);
- FLUSH(&res);
+ *valueptr = t->elem->zero;
+ *okptr = false;
}
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
new file mode 100644
index 000000000..744c59f9b
--- /dev/null
+++ b/src/pkg/runtime/heapdump.c
@@ -0,0 +1,981 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Implementation of runtime/debug.WriteHeapDump. Writes all
+// objects in the heap plus additional info (roots, threads,
+// finalizers, etc.) to a file.
+
+// The format of the dumped file is described at
+// http://code.google.com/p/go-wiki/wiki/heapdump13
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "mgc0.h"
+#include "type.h"
+#include "typekind.h"
+#include "funcdata.h"
+#include "zaexperiment.h"
+#include "../../cmd/ld/textflag.h"
+
+extern byte data[];
+extern byte edata[];
+extern byte bss[];
+extern byte ebss[];
+extern byte gcdata[];
+extern byte gcbss[];
+
+enum {
+ FieldKindEol = 0,
+ FieldKindPtr = 1,
+ FieldKindString = 2,
+ FieldKindSlice = 3,
+ FieldKindIface = 4,
+ FieldKindEface = 5,
+
+ TagEOF = 0,
+ TagObject = 1,
+ TagOtherRoot = 2,
+ TagType = 3,
+ TagGoRoutine = 4,
+ TagStackFrame = 5,
+ TagParams = 6,
+ TagFinalizer = 7,
+ TagItab = 8,
+ TagOSThread = 9,
+ TagMemStats = 10,
+ TagQueuedFinalizer = 11,
+ TagData = 12,
+ TagBss = 13,
+ TagDefer = 14,
+ TagPanic = 15,
+ TagMemProf = 16,
+ TagAllocSample = 17,
+
+ TypeInfo_Conservative = 127,
+};
+
+static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
+static void dumpfields(uintptr *prog);
+static void dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind);
+static void dumpbvtypes(BitVector *bv, byte *base);
+
+// fd to write the dump to.
+static uintptr dumpfd;
+
+// buffer of pending write data
+enum {
+ BufSize = 4096,
+};
+#pragma dataflag NOPTR
+static byte buf[BufSize];
+static uintptr nbuf;
+
+static void
+write(byte *data, uintptr len)
+{
+ if(len + nbuf <= BufSize) {
+ runtime·memmove(buf + nbuf, data, len);
+ nbuf += len;
+ return;
+ }
+ runtime·write(dumpfd, buf, nbuf);
+ if(len >= BufSize) {
+ runtime·write(dumpfd, data, len);
+ nbuf = 0;
+ } else {
+ runtime·memmove(buf, data, len);
+ nbuf = len;
+ }
+}
+
+static void
+flush(void)
+{
+ runtime·write(dumpfd, buf, nbuf);
+ nbuf = 0;
+}
+
+// Cache of types that have been serialized already.
+// We use a type's hash field to pick a bucket.
+// Inside a bucket, we keep a list of types that
+// have been serialized so far, most recently used first.
+// Note: when a bucket overflows we may end up
+// serializing a type more than once. That's ok.
+enum {
+ TypeCacheBuckets = 256, // must be a power of 2
+ TypeCacheAssoc = 4,
+};
+typedef struct TypeCacheBucket TypeCacheBucket;
+struct TypeCacheBucket {
+ Type *t[TypeCacheAssoc];
+};
+static TypeCacheBucket typecache[TypeCacheBuckets];
+
+// dump a uint64 in a varint format parseable by encoding/binary
+static void
+dumpint(uint64 v)
+{
+ byte buf[10];
+ int32 n;
+ n = 0;
+ while(v >= 0x80) {
+ buf[n++] = v | 0x80;
+ v >>= 7;
+ }
+ buf[n++] = v;
+ write(buf, n);
+}
+
+static void
+dumpbool(bool b)
+{
+ dumpint(b ? 1 : 0);
+}
+
+// dump varint uint64 length followed by memory contents
+static void
+dumpmemrange(byte *data, uintptr len)
+{
+ dumpint(len);
+ write(data, len);
+}
+
+static void
+dumpstr(String s)
+{
+ dumpmemrange(s.str, s.len);
+}
+
+static void
+dumpcstr(int8 *c)
+{
+ dumpmemrange((byte*)c, runtime·findnull((byte*)c));
+}
+
+// dump information for a type
+static void
+dumptype(Type *t)
+{
+ TypeCacheBucket *b;
+ int32 i, j;
+
+ if(t == nil) {
+ return;
+ }
+
+ // If we've definitely serialized the type before,
+ // no need to do it again.
+ b = &typecache[t->hash & (TypeCacheBuckets-1)];
+ if(t == b->t[0]) return;
+ for(i = 1; i < TypeCacheAssoc; i++) {
+ if(t == b->t[i]) {
+ // Move-to-front
+ for(j = i; j > 0; j--) {
+ b->t[j] = b->t[j-1];
+ }
+ b->t[0] = t;
+ return;
+ }
+ }
+ // Might not have been dumped yet. Dump it and
+ // remember we did so.
+ for(j = TypeCacheAssoc-1; j > 0; j--) {
+ b->t[j] = b->t[j-1];
+ }
+ b->t[0] = t;
+
+ // dump the type
+ dumpint(TagType);
+ dumpint((uintptr)t);
+ dumpint(t->size);
+ if(t->x == nil || t->x->pkgPath == nil || t->x->name == nil) {
+ dumpstr(*t->string);
+ } else {
+ dumpint(t->x->pkgPath->len + 1 + t->x->name->len);
+ write(t->x->pkgPath->str, t->x->pkgPath->len);
+ write((byte*)".", 1);
+ write(t->x->name->str, t->x->name->len);
+ }
+ dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+ dumpfields((uintptr*)t->gc + 1);
+}
+
+// returns true if object is scannable
+static bool
+scannable(byte *obj)
+{
+ uintptr *b, off, shift;
+
+ off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ return ((*b >> shift) & bitScan) != 0;
+}
+
+// dump an object
+static void
+dumpobj(byte *obj, uintptr size, Type *type, uintptr kind)
+{
+ if(type != nil) {
+ dumptype(type);
+ dumpefacetypes(obj, size, type, kind);
+ }
+
+ dumpint(TagObject);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)type);
+ dumpint(kind);
+ dumpmemrange(obj, size);
+}
+
+static void
+dumpotherroot(int8 *description, byte *to)
+{
+ dumpint(TagOtherRoot);
+ dumpcstr(description);
+ dumpint((uintptr)to);
+}
+
+static void
+dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot)
+{
+ dumpint(TagFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)fint);
+ dumpint((uintptr)ot);
+}
+
+typedef struct ChildInfo ChildInfo;
+struct ChildInfo {
+ // Information passed up from the callee frame about
+ // the layout of the outargs region.
+ uintptr argoff; // where the arguments start in the frame
+ uintptr arglen; // size of args region
+ BitVector args; // if args.n >= 0, pointer map of args region
+
+ byte *sp; // callee sp
+ uintptr depth; // depth in call stack (0 == most recent)
+};
+
+// dump kinds & offsets of interesting fields in bv
+static void
+dumpbv(BitVector *bv, uintptr offset)
+{
+ uintptr i;
+
+ for(i = 0; i < bv->n; i += BitsPerPointer) {
+ switch(bv->data[i/32] >> i%32 & 3) {
+ case BitsDead:
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ dumpint(FieldKindPtr);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ break;
+ case BitsMultiWord:
+ switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+ case BitsString:
+ dumpint(FieldKindString);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ case BitsSlice:
+ dumpint(FieldKindSlice);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += 2 * BitsPerPointer;
+ break;
+ case BitsIface:
+ dumpint(FieldKindIface);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ case BitsEface:
+ dumpint(FieldKindEface);
+ dumpint(offset + i / BitsPerPointer * PtrSize);
+ i += BitsPerPointer;
+ break;
+ }
+ }
+ }
+}
+
+static bool
+dumpframe(Stkframe *s, void *arg)
+{
+ Func *f;
+ ChildInfo *child;
+ uintptr pc, off, size;
+ int32 pcdata;
+ StackMap *stackmap;
+ int8 *name;
+ BitVector bv;
+
+ child = (ChildInfo*)arg;
+ f = s->fn;
+
+ // Figure out what we can about our stack map
+ pc = s->pc;
+ if(pc != f->entry)
+ pc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc);
+ if(pcdata == -1) {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0;
+ }
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+
+ // Dump any types we will need to resolve Efaces.
+ if(child->args.n >= 0)
+ dumpbvtypes(&child->args, (byte*)s->sp + child->argoff);
+ if(stackmap != nil && stackmap->n > 0) {
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ dumpbvtypes(&bv, s->varp - bv.n / BitsPerPointer * PtrSize);
+ } else {
+ bv.n = -1;
+ }
+
+ // Dump main body of stack frame.
+ dumpint(TagStackFrame);
+ dumpint(s->sp); // lowest address in frame
+ dumpint(child->depth); // # of frames deep on the stack
+ dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack
+ dumpmemrange((byte*)s->sp, s->fp - s->sp); // frame contents
+ dumpint(f->entry);
+ dumpint(s->pc);
+ dumpint(s->continpc);
+ name = runtime·funcname(f);
+ if(name == nil)
+ name = "unknown function";
+ dumpcstr(name);
+
+ // Dump fields in the outargs section
+ if(child->args.n >= 0) {
+ dumpbv(&child->args, child->argoff);
+ } else {
+ // conservative - everything might be a pointer
+ for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ }
+
+ // Dump fields in the local vars section
+ if(stackmap == nil) {
+ // No locals information, dump everything.
+ for(off = child->arglen; off < s->varp - (byte*)s->sp; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ } else if(stackmap->n < 0) {
+ // Locals size information, dump just the locals.
+ size = -stackmap->n;
+ for(off = s->varp - size - (byte*)s->sp; off < s->varp - (byte*)s->sp; off += PtrSize) {
+ dumpint(FieldKindPtr);
+ dumpint(off);
+ }
+ } else if(stackmap->n > 0) {
+ // Locals bitmap information, scan just the pointers in
+ // locals.
+ dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - (byte*)s->sp);
+ }
+ dumpint(FieldKindEol);
+
+ // Record arg info for parent.
+ child->argoff = s->argp - (byte*)s->fp;
+ child->arglen = s->arglen;
+ child->sp = (byte*)s->sp;
+ child->depth++;
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap != nil)
+ child->args = runtime·stackmapdata(stackmap, pcdata);
+ else
+ child->args.n = -1;
+ return true;
+}
+
+static void
+dumpgoroutine(G *gp)
+{
+ uintptr sp, pc, lr;
+ ChildInfo child;
+ Defer *d;
+ Panic *p;
+
+ if(gp->syscallstack != (uintptr)nil) {
+ sp = gp->syscallsp;
+ pc = gp->syscallpc;
+ lr = 0;
+ } else {
+ sp = gp->sched.sp;
+ pc = gp->sched.pc;
+ lr = gp->sched.lr;
+ }
+
+ dumpint(TagGoRoutine);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)sp);
+ dumpint(gp->goid);
+ dumpint(gp->gopc);
+ dumpint(gp->status);
+ dumpbool(gp->issystem);
+ dumpbool(gp->isbackground);
+ dumpint(gp->waitsince);
+ dumpcstr(gp->waitreason);
+ dumpint((uintptr)gp->sched.ctxt);
+ dumpint((uintptr)gp->m);
+ dumpint((uintptr)gp->defer);
+ dumpint((uintptr)gp->panic);
+
+ // dump stack
+ child.args.n = -1;
+ child.arglen = 0;
+ child.sp = nil;
+ child.depth = 0;
+ if(!ScanStackByFrames)
+ runtime·throw("need frame info to dump stacks");
+ runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false);
+
+ // dump defer & panic records
+ for(d = gp->defer; d != nil; d = d->link) {
+ dumpint(TagDefer);
+ dumpint((uintptr)d);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)d->argp);
+ dumpint((uintptr)d->pc);
+ dumpint((uintptr)d->fn);
+ dumpint((uintptr)d->fn->fn);
+ dumpint((uintptr)d->link);
+ }
+ for (p = gp->panic; p != nil; p = p->link) {
+ dumpint(TagPanic);
+ dumpint((uintptr)p);
+ dumpint((uintptr)gp);
+ dumpint((uintptr)p->arg.type);
+ dumpint((uintptr)p->arg.data);
+ dumpint((uintptr)p->defer);
+ dumpint((uintptr)p->link);
+ }
+}
+
+static void
+dumpgs(void)
+{
+ G *gp;
+ uint32 i;
+
+ // goroutines & stacks
+ for(i = 0; i < runtime·allglen; i++) {
+ gp = runtime·allg[i];
+ switch(gp->status){
+ default:
+ runtime·printf("unexpected G.status %d\n", gp->status);
+ runtime·throw("mark - bad status");
+ case Gdead:
+ break;
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ dumpgoroutine(gp);
+ break;
+ }
+ }
+}
+
+static void
+finq_callback(FuncVal *fn, byte *obj, uintptr nret, Type *fint, PtrType *ot)
+{
+ dumpint(TagQueuedFinalizer);
+ dumpint((uintptr)obj);
+ dumpint((uintptr)fn);
+ dumpint((uintptr)fn->fn);
+ dumpint((uintptr)fint);
+ dumpint((uintptr)ot);
+ USED(&nret);
+}
+
+
+static void
+dumproots(void)
+{
+ MSpan *s, **allspans;
+ uint32 spanidx;
+ Special *sp;
+ SpecialFinalizer *spf;
+ byte *p;
+
+ // data segment
+ dumpint(TagData);
+ dumpint((uintptr)data);
+ dumpmemrange(data, edata - data);
+ dumpfields((uintptr*)gcdata + 1);
+
+ // bss segment
+ dumpint(TagBss);
+ dumpint((uintptr)bss);
+ dumpmemrange(bss, ebss - bss);
+ dumpfields((uintptr*)gcbss + 1);
+
+ // MSpan.types
+ allspans = runtime·mheap.allspans;
+ for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+ s = allspans[spanidx];
+ if(s->state == MSpanInUse) {
+ // The garbage collector ignores type pointers stored in MSpan.types:
+ // - Compiler-generated types are stored outside of heap.
+ // - The reflect package has runtime-generated types cached in its data structures.
+ // The garbage collector relies on finding the references via that cache.
+ switch(s->types.compression) {
+ case MTypes_Empty:
+ case MTypes_Single:
+ break;
+ case MTypes_Words:
+ case MTypes_Bytes:
+ dumpotherroot("runtime type info", (byte*)s->types.data);
+ break;
+ }
+
+ // Finalizers
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialFinalizer)
+ continue;
+ spf = (SpecialFinalizer*)sp;
+ p = (byte*)((s->start << PageShift) + spf->offset);
+ dumpfinalizer(p, spf->fn, spf->fint, spf->ot);
+ }
+ }
+ }
+
+ // Finalizer queue
+ runtime·iterate_finq(finq_callback);
+}
+
+// Bit vector of free marks.
+// Needs to be as big as the largest number of objects per span.
+static byte free[PageSize/8];
+
+static void
+dumpobjs(void)
+{
+ uintptr i, j, size, n, off, shift, *bitp, bits, ti, kind;
+ MSpan *s;
+ MLink *l;
+ byte *p;
+ Type *t;
+
+ for(i = 0; i < runtime·mheap.nspan; i++) {
+ s = runtime·mheap.allspans[i];
+ if(s->state != MSpanInUse)
+ continue;
+ p = (byte*)(s->start << PageShift);
+ size = s->elemsize;
+ n = (s->npages << PageShift) / size;
+ if(n > PageSize/8)
+ runtime·throw("free array doesn't have enough entries");
+ for(l = s->freelist; l != nil; l = l->next) {
+ free[((byte*)l - p) / size] = true;
+ }
+ for(j = 0; j < n; j++, p += size) {
+ if(free[j]) {
+ free[j] = false;
+ continue;
+ }
+ off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;
+ bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ bits = *bitp >> shift;
+
+ // Skip FlagNoGC allocations (stacks)
+ if((bits & bitAllocated) == 0)
+ continue;
+
+ // extract type and kind
+ ti = runtime·gettype(p);
+ t = (Type*)(ti & ~(uintptr)(PtrSize-1));
+ kind = ti & (PtrSize-1);
+
+ // dump it
+ if(kind == TypeInfo_Chan)
+ t = ((ChanType*)t)->elem; // use element type for chan encoding
+ if(t == nil && scannable(p))
+ kind = TypeInfo_Conservative; // special kind for conservatively scanned objects
+ dumpobj(p, size, t, kind);
+ }
+ }
+}
+
+static void
+dumpparams(void)
+{
+ byte *x;
+
+ dumpint(TagParams);
+ x = (byte*)1;
+ if(*(byte*)&x == 1)
+ dumpbool(false); // little-endian ptrs
+ else
+ dumpbool(true); // big-endian ptrs
+ dumpint(PtrSize);
+ dumpint(runtime·Hchansize);
+ dumpint((uintptr)runtime·mheap.arena_start);
+ dumpint((uintptr)runtime·mheap.arena_used);
+ dumpint(thechar);
+ dumpcstr(GOEXPERIMENT);
+ dumpint(runtime·ncpu);
+}
+
+static void
+itab_callback(Itab *tab)
+{
+ Type *t;
+
+ dumpint(TagItab);
+ dumpint((uintptr)tab);
+ t = tab->type;
+ dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+}
+
+static void
+dumpitabs(void)
+{
+ runtime·iterate_itabs(itab_callback);
+}
+
+static void
+dumpms(void)
+{
+ M *mp;
+
+ for(mp = runtime·allm; mp != nil; mp = mp->alllink) {
+ dumpint(TagOSThread);
+ dumpint((uintptr)mp);
+ dumpint(mp->id);
+ dumpint(mp->procid);
+ }
+}
+
+static void
+dumpmemstats(void)
+{
+ int32 i;
+
+ dumpint(TagMemStats);
+ dumpint(mstats.alloc);
+ dumpint(mstats.total_alloc);
+ dumpint(mstats.sys);
+ dumpint(mstats.nlookup);
+ dumpint(mstats.nmalloc);
+ dumpint(mstats.nfree);
+ dumpint(mstats.heap_alloc);
+ dumpint(mstats.heap_sys);
+ dumpint(mstats.heap_idle);
+ dumpint(mstats.heap_inuse);
+ dumpint(mstats.heap_released);
+ dumpint(mstats.heap_objects);
+ dumpint(mstats.stacks_inuse);
+ dumpint(mstats.stacks_sys);
+ dumpint(mstats.mspan_inuse);
+ dumpint(mstats.mspan_sys);
+ dumpint(mstats.mcache_inuse);
+ dumpint(mstats.mcache_sys);
+ dumpint(mstats.buckhash_sys);
+ dumpint(mstats.gc_sys);
+ dumpint(mstats.other_sys);
+ dumpint(mstats.next_gc);
+ dumpint(mstats.last_gc);
+ dumpint(mstats.pause_total_ns);
+ for(i = 0; i < 256; i++)
+ dumpint(mstats.pause_ns[i]);
+ dumpint(mstats.numgc);
+}
+
+static void
+dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
+{
+ uintptr i, pc;
+ Func *f;
+ byte buf[20];
+ String file;
+ int32 line;
+
+ dumpint(TagMemProf);
+ dumpint((uintptr)b);
+ dumpint(size);
+ dumpint(nstk);
+ for(i = 0; i < nstk; i++) {
+ pc = stk[i];
+ f = runtime·findfunc(pc);
+ if(f == nil) {
+ runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
+ dumpcstr((int8*)buf);
+ dumpcstr("?");
+ dumpint(0);
+ } else {
+ dumpcstr(runtime·funcname(f));
+ // TODO: Why do we need to back up to a call instruction here?
+ // Maybe profiler should do this.
+ if(i > 0 && pc > f->entry) {
+ if(thechar == '6' || thechar == '8')
+ pc--;
+ else
+ pc -= 4; // arm, etc
+ }
+ line = runtime·funcline(f, pc, &file);
+ dumpstr(file);
+ dumpint(line);
+ }
+ }
+ dumpint(allocs);
+ dumpint(frees);
+}
+
+static void
+dumpmemprof(void)
+{
+ MSpan *s, **allspans;
+ uint32 spanidx;
+ Special *sp;
+ SpecialProfile *spp;
+ byte *p;
+
+ runtime·iterate_memprof(dumpmemprof_callback);
+
+ allspans = runtime·mheap.allspans;
+ for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+ s = allspans[spanidx];
+ if(s->state != MSpanInUse)
+ continue;
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialProfile)
+ continue;
+ spp = (SpecialProfile*)sp;
+ p = (byte*)((s->start << PageShift) + spp->offset);
+ dumpint(TagAllocSample);
+ dumpint((uintptr)p);
+ dumpint((uintptr)spp->b);
+ }
+ }
+}
+
+static void
+mdump(G *gp)
+{
+ byte *hdr;
+ uintptr i;
+ MSpan *s;
+
+ // make sure we're done sweeping
+ for(i = 0; i < runtime·mheap.nspan; i++) {
+ s = runtime·mheap.allspans[i];
+ if(s->state == MSpanInUse)
+ runtime·MSpan_EnsureSwept(s);
+ }
+
+ runtime·memclr((byte*)&typecache[0], sizeof(typecache));
+ hdr = (byte*)"go1.3 heap dump\n";
+ write(hdr, runtime·findnull(hdr));
+ dumpparams();
+ dumpitabs();
+ dumpobjs();
+ dumpgs();
+ dumpms();
+ dumproots();
+ dumpmemstats();
+ dumpmemprof();
+ dumpint(TagEOF);
+ flush();
+
+ gp->param = nil;
+ gp->status = Grunning;
+ runtime·gogo(&gp->sched);
+}
+
+void
+runtime∕debug·WriteHeapDump(uintptr fd)
+{
+ // Stop the world.
+ runtime·semacquire(&runtime·worldsema, false);
+ m->gcing = 1;
+ m->locks++;
+ runtime·stoptheworld();
+
+ // Update stats so we can dump them.
+ // As a side effect, flushes all the MCaches so the MSpan.freelist
+ // lists contain all the free objects.
+ runtime·updatememstats(nil);
+
+ // Set dump file.
+ dumpfd = fd;
+
+ // Call dump routine on M stack.
+ g->status = Gwaiting;
+ g->waitreason = "dumping heap";
+ runtime·mcall(mdump);
+
+ // Reset dump file.
+ dumpfd = 0;
+
+ // Start up the world again.
+ m->gcing = 0;
+ runtime·semrelease(&runtime·worldsema);
+ runtime·starttheworld();
+ m->locks--;
+}
+
+// Runs the specified gc program. Calls the callback for every
+// pointer-like field specified by the program and passes to the
+// callback the kind and offset of that field within the object.
+// offset is the offset in the object of the start of the program.
+// Returns a pointer to the opcode that ended the gc program (either
+// GC_END or GC_ARRAY_NEXT).
+static uintptr*
+playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg)
+{
+ uintptr len, elemsize, i, *end;
+
+ for(;;) {
+ switch(prog[0]) {
+ case GC_END:
+ return prog;
+ case GC_PTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_APTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_ARRAY_START:
+ len = prog[2];
+ elemsize = prog[3];
+ end = nil;
+ for(i = 0; i < len; i++) {
+ end = playgcprog(offset + prog[1] + i * elemsize, prog + 4, callback, arg);
+ if(end[0] != GC_ARRAY_NEXT)
+ runtime·throw("GC_ARRAY_START did not have matching GC_ARRAY_NEXT");
+ }
+ prog = end + 1;
+ break;
+ case GC_ARRAY_NEXT:
+ return prog;
+ case GC_CALL:
+ playgcprog(offset + prog[1], (uintptr*)((byte*)prog + *(int32*)&prog[2]), callback, arg);
+ prog += 3;
+ break;
+ case GC_CHAN_PTR:
+ callback(arg, FieldKindPtr, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_STRING:
+ callback(arg, FieldKindString, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_EFACE:
+ callback(arg, FieldKindEface, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_IFACE:
+ callback(arg, FieldKindIface, offset + prog[1]);
+ prog += 2;
+ break;
+ case GC_SLICE:
+ callback(arg, FieldKindSlice, offset + prog[1]);
+ prog += 3;
+ break;
+ case GC_REGION:
+ playgcprog(offset + prog[1], (uintptr*)prog[3] + 1, callback, arg);
+ prog += 4;
+ break;
+ default:
+ runtime·printf("%D\n", (uint64)prog[0]);
+ runtime·throw("bad gc op");
+ }
+ }
+}
+
+static void
+dump_callback(void *p, uintptr kind, uintptr offset)
+{
+ USED(&p);
+ dumpint(kind);
+ dumpint(offset);
+}
+
+// dumpint() the kind & offset of each field in an object.
+static void
+dumpfields(uintptr *prog)
+{
+ playgcprog(0, prog, dump_callback, nil);
+ dumpint(FieldKindEol);
+}
+
+static void
+dumpeface_callback(void *p, uintptr kind, uintptr offset)
+{
+ Eface *e;
+
+ if(kind != FieldKindEface)
+ return;
+ e = (Eface*)((byte*)p + offset);
+ dumptype(e->type);
+}
+
+// The heap dump reader needs to be able to disambiguate
+// Eface entries. So it needs to know every type that might
+// appear in such an entry. The following two routines accomplish
+// that.
+
+// Dump all the types that appear in the type field of
+// any Eface contained in obj.
+static void
+dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind)
+{
+ uintptr i;
+
+ switch(kind) {
+ case TypeInfo_SingleObject:
+ playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ case TypeInfo_Array:
+ for(i = 0; i <= size - type->size; i += type->size)
+ playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ case TypeInfo_Chan:
+ if(type->size == 0) // channels may have zero-sized objects in them
+ break;
+ for(i = runtime·Hchansize; i <= size - type->size; i += type->size)
+ playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+ break;
+ }
+}
+
+// Dump all the types that appear in the type field of
+// any Eface described by this bit vector.
+static void
+dumpbvtypes(BitVector *bv, byte *base)
+{
+ uintptr i;
+
+ for(i = 0; i < bv->n; i += BitsPerPointer) {
+ if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
+ continue;
+ switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+ case BitsString:
+ case BitsIface:
+ i += BitsPerPointer;
+ break;
+ case BitsSlice:
+ i += 2 * BitsPerPointer;
+ break;
+ case BitsEface:
+ dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
+ i += BitsPerPointer;
+ break;
+ }
+ }
+}
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.goc
index ecbdcc707..c0a17e303 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.goc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "type.h"
@@ -9,15 +10,11 @@
#include "malloc.h"
#include "../../cmd/ld/textflag.h"
-void
-runtime·printiface(Iface i)
-{
+func printiface(i Iface) {
runtime·printf("(%p,%p)", i.tab, i.data);
}
-void
-runtime·printeface(Eface e)
-{
+func printeface(e Eface) {
runtime·printf("(%p,%p)", e.type, e.data);
}
@@ -137,6 +134,20 @@ out:
return m;
}
+// call the callback for every itab that is currently allocated.
+void
+runtime·iterate_itabs(void (*callback)(Itab*))
+{
+ int32 i;
+ Itab *tab;
+
+ for(i = 0; i < nelem(hash); i++) {
+ for(tab = hash[i]; tab != nil; tab = tab->link) {
+ callback(tab);
+ }
+ }
+}
+
static void
copyin(Type *t, void *src, void **dst)
{
@@ -150,7 +161,7 @@ copyin(Type *t, void *src, void **dst)
if(size <= sizeof(*dst))
alg->copy(size, dst, src);
else {
- p = runtime·mal(size);
+ p = runtime·cnew(t);
alg->copy(size, p, src);
*dst = p;
}
@@ -172,66 +183,45 @@ copyout(Type *t, void **src, void *dst)
}
#pragma textflag NOSPLIT
-void
-runtime·typ2Itab(Type *t, InterfaceType *inter, Itab **cache, Itab *ret)
-{
- Itab *tab;
-
+func typ2Itab(t *Type, inter *InterfaceType, cache **Itab) (tab *Itab) {
tab = itab(inter, t, 0);
runtime·atomicstorep(cache, tab);
- ret = tab;
- FLUSH(&ret);
}
-// func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
#pragma textflag NOSPLIT
-void
-runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, ...)
-{
- byte *elem;
- Iface *ret;
+func convT2I(t *Type, inter *InterfaceType, cache **Itab, elem *byte) (ret Iface) {
Itab *tab;
- int32 wid;
- elem = (byte*)(&cache+1);
- wid = t->size;
- ret = (Iface*)(elem + ROUND(wid, Structrnd));
tab = runtime·atomicloadp(cache);
if(!tab) {
tab = itab(inter, t, 0);
runtime·atomicstorep(cache, tab);
}
- ret->tab = tab;
- copyin(t, elem, &ret->data);
+ ret.tab = tab;
+ copyin(t, elem, &ret.data);
}
-// func convT2E(typ *byte, elem any) (ret any)
#pragma textflag NOSPLIT
-void
-runtime·convT2E(Type *t, ...)
-{
- byte *elem;
- Eface *ret;
- int32 wid;
-
- elem = (byte*)(&t+1);
- wid = t->size;
- ret = (Eface*)(elem + ROUND(wid, Structrnd));
- ret->type = t;
- copyin(t, elem, &ret->data);
+func convT2E(t *Type, elem *byte) (ret Eface) {
+ ret.type = t;
+ copyin(t, elem, &ret.data);
}
static void assertI2Tret(Type *t, Iface i, byte *ret);
-// func ifaceI2T(typ *byte, iface any) (ret any)
+/*
+ * NOTE: Cannot use 'func' here, because we have to declare
+ * a return value, the only types we have are at least 1 byte large,
+ * goc2c will zero the return value, and the actual return value
+ * might have size 0 bytes, in which case the zeroing of the
+ * 1 or more bytes would be wrong.
+ * Using C lets us control (avoid) the initial zeroing.
+ */
#pragma textflag NOSPLIT
void
-runtime·assertI2T(Type *t, Iface i, ...)
+runtime·assertI2T(Type *t, Iface i, GoOutput retbase)
{
- byte *ret;
-
- ret = (byte*)(&i+1);
- assertI2Tret(t, i, ret);
+ assertI2Tret(t, i, (byte*)&retbase);
}
static void
@@ -256,47 +246,38 @@ assertI2Tret(Type *t, Iface i, byte *ret)
copyout(t, &i.data, ret);
}
-// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag NOSPLIT
-void
-runtime·assertI2T2(Type *t, Iface i, ...)
-{
- byte *ret;
+func assertI2T2(t *Type, i Iface) (ret byte, ...) {
bool *ok;
int32 wid;
- ret = (byte*)(&i+1);
wid = t->size;
- ok = (bool*)(ret + wid);
+ ok = (bool*)(&ret + wid);
if(i.tab == nil || i.tab->type != t) {
*ok = false;
- runtime·memclr(ret, wid);
+ runtime·memclr(&ret, wid);
return;
}
*ok = true;
- copyout(t, &i.data, ret);
+ copyout(t, &i.data, &ret);
}
-void
-runtime·assertI2TOK(Type *t, Iface i, bool ok)
-{
+func assertI2TOK(t *Type, i Iface) (ok bool) {
ok = i.tab!=nil && i.tab->type==t;
- FLUSH(&ok);
}
static void assertE2Tret(Type *t, Eface e, byte *ret);
-// func ifaceE2T(typ *byte, iface any) (ret any)
+/*
+ * NOTE: Cannot use 'func' here. See assertI2T above.
+ */
#pragma textflag NOSPLIT
void
-runtime·assertE2T(Type *t, Eface e, ...)
+runtime·assertE2T(Type *t, Eface e, GoOutput retbase)
{
- byte *ret;
-
- ret = (byte*)(&e+1);
- assertE2Tret(t, e, ret);
+ assertE2Tret(t, e, (byte*)&retbase);
}
static void
@@ -319,40 +300,29 @@ assertE2Tret(Type *t, Eface e, byte *ret)
copyout(t, &e.data, ret);
}
-// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag NOSPLIT
-void
-runtime·assertE2T2(Type *t, Eface e, ...)
-{
- byte *ret;
+func assertE2T2(t *Type, e Eface) (ret byte, ...) {
bool *ok;
int32 wid;
- ret = (byte*)(&e+1);
wid = t->size;
- ok = (bool*)(ret + wid);
+ ok = (bool*)(&ret + wid);
if(t != e.type) {
*ok = false;
- runtime·memclr(ret, wid);
+ runtime·memclr(&ret, wid);
return;
}
*ok = true;
- copyout(t, &e.data, ret);
+ copyout(t, &e.data, &ret);
}
-void
-runtime·assertE2TOK(Type *t, Eface e, bool ok)
-{
+func assertE2TOK(t *Type, e Eface) (ok bool) {
ok = t==e.type;
- FLUSH(&ok);
}
-// func convI2E(elem any) (ret any)
-void
-runtime·convI2E(Iface i, Eface ret)
-{
+func convI2E(i Iface) (ret Eface) {
Itab *tab;
ret.data = i.data;
@@ -360,13 +330,9 @@ runtime·convI2E(Iface i, Eface ret)
ret.type = nil;
else
ret.type = tab->type;
- FLUSH(&ret);
}
-// func ifaceI2E(typ *byte, iface any) (ret any)
-void
-runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
-{
+func assertI2E(inter *InterfaceType, i Iface) (ret Eface) {
Itab *tab;
Eface err;
@@ -380,13 +346,9 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
}
ret.data = i.data;
ret.type = tab->type;
- FLUSH(&ret);
}
-// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
-{
+func assertI2E2(inter *InterfaceType, i Iface) (ret Eface, ok bool) {
Itab *tab;
USED(inter);
@@ -399,14 +361,9 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
ok = 1;
}
ret.data = i.data;
- FLUSH(&ret);
- FLUSH(&ok);
}
-// func convI2I(typ *byte, elem any) (ret any)
-void
-runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
-{
+func convI2I(inter *InterfaceType, i Iface) (ret Iface) {
Itab *tab;
ret.data = i.data;
@@ -416,7 +373,6 @@ runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
ret.tab = tab;
else
ret.tab = itab(inter, tab->type, 0);
- FLUSH(&ret);
}
void
@@ -437,17 +393,11 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
ret->tab = itab(inter, tab->type, 0);
}
-// func ifaceI2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
-{
+func assertI2I(inter *InterfaceType, i Iface) (ret Iface) {
runtime·ifaceI2I(inter, i, &ret);
}
-// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
-{
+func assertI2I2(inter *InterfaceType, i Iface) (ret Iface, ok bool) {
Itab *tab;
tab = i.tab;
@@ -460,8 +410,6 @@ runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
ret.tab = 0;
ok = 0;
}
- FLUSH(&ret);
- FLUSH(&ok);
}
void
@@ -492,25 +440,15 @@ runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
return true;
}
-// For reflect
-// func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
-void
-reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
-{
+func reflect·ifaceE2I(inter *InterfaceType, e Eface, dst *Iface) {
runtime·ifaceE2I(inter, e, dst);
}
-// func ifaceE2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
-{
+func assertE2I(inter *InterfaceType, e Eface) (ret Iface) {
runtime·ifaceE2I(inter, e, &ret);
}
-// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
-{
+func assertE2I2(inter *InterfaceType, e Eface) (ret Iface, ok bool) {
if(e.type == nil) {
ok = 0;
ret.data = nil;
@@ -522,14 +460,9 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
ok = 1;
ret.data = e.data;
}
- FLUSH(&ret);
- FLUSH(&ok);
}
-// func ifaceE2E(typ *byte, iface any) (ret any)
-void
-runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
-{
+func assertE2E(inter *InterfaceType, e Eface) (ret Eface) {
Type *t;
Eface err;
@@ -542,18 +475,12 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
runtime·panic(err);
}
ret = e;
- FLUSH(&ret);
}
-// func ifaceE2E2(iface any) (ret any, ok bool)
-void
-runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
-{
+func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) {
USED(inter);
ret = e;
ok = e.type != nil;
- FLUSH(&ret);
- FLUSH(&ok);
}
static uintptr
@@ -641,81 +568,53 @@ runtime·efaceeq_c(Eface e1, Eface e2)
return ifaceeq1(e1.data, e2.data, e1.type);
}
-// ifaceeq(i1 any, i2 any) (ret bool);
-void
-runtime·ifaceeq(Iface i1, Iface i2, bool ret)
-{
+func ifaceeq(i1 Iface, i2 Iface) (ret bool) {
ret = runtime·ifaceeq_c(i1, i2);
- FLUSH(&ret);
}
-// efaceeq(i1 any, i2 any) (ret bool)
-void
-runtime·efaceeq(Eface e1, Eface e2, bool ret)
-{
+func efaceeq(e1 Eface, e2 Eface) (ret bool) {
ret = runtime·efaceeq_c(e1, e2);
- FLUSH(&ret);
}
-// ifacethash(i1 any) (ret uint32);
-void
-runtime·ifacethash(Iface i1, uint32 ret)
-{
+func ifacethash(i1 Iface) (ret uint32) {
Itab *tab;
ret = 0;
tab = i1.tab;
if(tab != nil)
ret = tab->type->hash;
- FLUSH(&ret);
}
-// efacethash(e1 any) (ret uint32)
-void
-runtime·efacethash(Eface e1, uint32 ret)
-{
+func efacethash(e1 Eface) (ret uint32) {
Type *t;
ret = 0;
t = e1.type;
if(t != nil)
ret = t->hash;
- FLUSH(&ret);
}
-void
-reflect·unsafe_Typeof(Eface e, Eface ret)
-{
+func reflect·unsafe_Typeof(e Eface) (ret Eface) {
if(e.type == nil) {
ret.type = nil;
ret.data = nil;
} else {
ret = *(Eface*)(e.type);
}
- FLUSH(&ret);
}
-void
-reflect·unsafe_New(Type *t, void *ret)
-{
+func reflect·unsafe_New(t *Type) (ret *byte) {
ret = runtime·cnew(t);
- FLUSH(&ret);
}
-void
-reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
-{
+func reflect·unsafe_NewArray(t *Type, n int) (ret *byte) {
ret = runtime·cnewarray(t, n);
- FLUSH(&ret);
}
-void
-reflect·typelinks(Slice ret)
-{
+func reflect·typelinks() (ret Slice) {
extern Type *typelink[], *etypelink[];
static int32 first = 1;
ret.array = (byte*)typelink;
ret.len = etypelink - typelink;
ret.cap = ret.len;
- FLUSH(&ret);
}
diff --git a/src/pkg/runtime/lfstack.c b/src/pkg/runtime/lfstack.goc
index 140384d3d..f7b8effa0 100644
--- a/src/pkg/runtime/lfstack.c
+++ b/src/pkg/runtime/lfstack.goc
@@ -4,6 +4,7 @@
// Lock-free stack.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
@@ -17,6 +18,20 @@
#define PTR_MASK ((1ull<<PTR_BITS)-1)
#define CNT_MASK (0ull-1)
+#ifdef _64BIT
+#ifdef GOOS_solaris
+// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
+// Use low-order three bits as ABA counter.
+// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
+#undef PTR_BITS
+#undef CNT_MASK
+#undef PTR_MASK
+#define PTR_BITS 0
+#define CNT_MASK 7
+#define PTR_MASK ((0ull-1)<<3)
+#endif
+#endif
+
void
runtime·lfstackpush(uint64 *head, LFNode *node)
{
@@ -57,9 +72,10 @@ runtime·lfstackpop(uint64 *head)
}
}
-void
-runtime·lfstackpop2(uint64 *head, LFNode *node)
-{
+func lfstackpush_go(head *uint64, node *LFNode) {
+ runtime·lfstackpush(head, node);
+}
+
+func lfstackpop_go(head *uint64) (node *LFNode) {
node = runtime·lfstackpop(head);
- FLUSH(&node);
}
diff --git a/src/pkg/runtime/lfstack_test.go b/src/pkg/runtime/lfstack_test.go
index 505aae605..e51877704 100644
--- a/src/pkg/runtime/lfstack_test.go
+++ b/src/pkg/runtime/lfstack_test.go
@@ -71,6 +71,8 @@ func TestLFStack(t *testing.T) {
}
}
+var stress []*MyNode
+
func TestLFStackStress(t *testing.T) {
const K = 100
P := 4 * GOMAXPROCS(-1)
@@ -80,14 +82,15 @@ func TestLFStackStress(t *testing.T) {
}
// Create 2 stacks.
stacks := [2]*uint64{new(uint64), new(uint64)}
- // Need to keep additional referenfces to nodes, the stack is not all that type-safe.
- var nodes []*MyNode
+ // Need to keep additional references to nodes,
+ // the lock-free stack is not type-safe.
+ stress = nil
// Push K elements randomly onto the stacks.
sum := 0
for i := 0; i < K; i++ {
sum += i
node := &MyNode{data: i}
- nodes = append(nodes, node)
+ stress = append(stress, node)
LFStackPush(stacks[i%2], fromMyNode(node))
}
c := make(chan bool, P)
@@ -127,4 +130,7 @@ func TestLFStackStress(t *testing.T) {
if sum2 != sum {
t.Fatalf("Wrong sum %d/%d", sum2, sum)
}
+
+ // Let nodes be collected now.
+ stress = nil
}
diff --git a/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c
index e6e9be923..c16ac905d 100644
--- a/src/pkg/runtime/lock_futex.c
+++ b/src/pkg/runtime/lock_futex.c
@@ -130,8 +130,11 @@ runtime·notesleep(Note *n)
{
if(g != m->g0)
runtime·throw("notesleep not on g0");
- while(runtime·atomicload((uint32*)&n->key) == 0)
+ while(runtime·atomicload((uint32*)&n->key) == 0) {
+ m->blocked = true;
runtime·futexsleep((uint32*)&n->key, 0, -1);
+ m->blocked = false;
+ }
}
#pragma textflag NOSPLIT
@@ -143,8 +146,11 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
// does not count against our nosplit stack sequence.
if(ns < 0) {
- while(runtime·atomicload((uint32*)&n->key) == 0)
+ while(runtime·atomicload((uint32*)&n->key) == 0) {
+ m->blocked = true;
runtime·futexsleep((uint32*)&n->key, 0, -1);
+ m->blocked = false;
+ }
return true;
}
@@ -153,7 +159,9 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
deadline = runtime·nanotime() + ns;
for(;;) {
+ m->blocked = true;
runtime·futexsleep((uint32*)&n->key, 0, ns);
+ m->blocked = false;
if(runtime·atomicload((uint32*)&n->key) != 0)
break;
now = runtime·nanotime();
diff --git a/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c
index 3d58cc87f..ff8fdfd42 100644
--- a/src/pkg/runtime/lock_sema.c
+++ b/src/pkg/runtime/lock_sema.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin netbsd openbsd plan9 windows
+// +build darwin nacl netbsd openbsd plan9 solaris windows
#include "runtime.h"
#include "stack.h"
@@ -161,7 +161,9 @@ runtime·notesleep(Note *n)
return;
}
// Queued. Sleep.
+ m->blocked = true;
runtime·semasleep(-1);
+ m->blocked = false;
}
#pragma textflag NOSPLIT
@@ -181,18 +183,23 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
if(ns < 0) {
// Queued. Sleep.
+ m->blocked = true;
runtime·semasleep(-1);
+ m->blocked = false;
return true;
}
deadline = runtime·nanotime() + ns;
for(;;) {
// Registered. Sleep.
+ m->blocked = true;
if(runtime·semasleep(ns) >= 0) {
+ m->blocked = false;
// Acquired semaphore, semawakeup unregistered us.
// Done.
return true;
}
+ m->blocked = false;
// Interrupted or timed out. Still registered. Semaphore not acquired.
ns = deadline - runtime·nanotime();
@@ -214,8 +221,10 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
} else if(mp == (M*)LOCKED) {
// Wakeup happened so semaphore is available.
// Grab it to avoid getting out of sync.
+ m->blocked = true;
if(runtime·semasleep(-1) < 0)
runtime·throw("runtime: unable to acquire - semaphore out of sync");
+ m->blocked = false;
return true;
} else
runtime·throw("runtime: unexpected waitm - semaphore out of sync");
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index c3ede4abd..7b7e350d8 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -19,6 +19,8 @@ package runtime
// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
#pragma dataflag NOPTR
MHeap runtime·mheap;
+#pragma dataflag NOPTR
+MStats mstats;
int32 runtime·checking;
@@ -26,6 +28,10 @@ extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go
extern volatile intgo runtime·MemProfileRate;
+static MSpan* largealloc(uint32, uintptr*);
+static void profilealloc(void *v, uintptr size);
+static void settype(MSpan *s, void *v, uintptr typ);
+
// Allocate an object of at least size bytes.
// Small objects are allocated from the per-thread cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
@@ -34,12 +40,12 @@ void*
runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
{
int32 sizeclass;
+ uintptr tinysize, size1;
intgo rate;
MCache *c;
- MCacheList *l;
- uintptr npages;
MSpan *s;
- MLink *v;
+ MLink *v, *next;
+ byte *tiny;
if(size == 0) {
// All 0-length allocations use this pointer.
@@ -49,8 +55,8 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
}
if(m->mallocing)
runtime·throw("malloc/free - deadlock");
- // Disable preemption during settype_flush.
- // We can not use m->mallocing for this, because settype_flush calls mallocgc.
+ // Disable preemption during settype.
+ // We can not use m->mallocing for this, because settype calls mallocgc.
m->locks++;
m->mallocing = 1;
@@ -58,7 +64,82 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
size += sizeof(uintptr);
c = m->mcache;
- if(size <= MaxSmallSize) {
+ if(!runtime·debug.efence && size <= MaxSmallSize) {
+ if((flag&(FlagNoScan|FlagNoGC)) == FlagNoScan && size < TinySize) {
+ // Tiny allocator.
+ //
+ // Tiny allocator combines several tiny allocation requests
+ // into a single memory block. The resulting memory block
+ // is freed when all subobjects are unreachable. The subobjects
+ // must be FlagNoScan (don't have pointers), this ensures that
+ // the amount of potentially wasted memory is bounded.
+ //
+ // Size of the memory block used for combining (TinySize) is tunable.
+ // Current setting is 16 bytes, which relates to 2x worst case memory
+ // wastage (when all but one subobjects are unreachable).
+ // 8 bytes would result in no wastage at all, but provides less
+ // opportunities for combining.
+ // 32 bytes provides more opportunities for combining,
+ // but can lead to 4x worst case wastage.
+ // The best case winning is 8x regardless of block size.
+ //
+ // Objects obtained from tiny allocator must not be freed explicitly.
+ // So when an object will be freed explicitly, we ensure that
+ // its size >= TinySize.
+ //
+ // SetFinalizer has a special case for objects potentially coming
+ // from tiny allocator, it such case it allows to set finalizers
+ // for an inner byte of a memory block.
+ //
+ // The main targets of tiny allocator are small strings and
+ // standalone escaping variables. On a json benchmark
+ // the allocator reduces number of allocations by ~12% and
+ // reduces heap size by ~20%.
+
+ tinysize = c->tinysize;
+ if(size <= tinysize) {
+ tiny = c->tiny;
+ // Align tiny pointer for required (conservative) alignment.
+ if((size&7) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 8);
+ else if((size&3) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 4);
+ else if((size&1) == 0)
+ tiny = (byte*)ROUND((uintptr)tiny, 2);
+ size1 = size + (tiny - c->tiny);
+ if(size1 <= tinysize) {
+ // The object fits into existing tiny block.
+ v = (MLink*)tiny;
+ c->tiny += size1;
+ c->tinysize -= size1;
+ m->mallocing = 0;
+ m->locks--;
+ if(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
+ g->stackguard0 = StackPreempt;
+ return v;
+ }
+ }
+ // Allocate a new TinySize block.
+ s = c->alloc[TinySizeClass];
+ if(s->freelist == nil)
+ s = runtime·MCache_Refill(c, TinySizeClass);
+ v = s->freelist;
+ next = v->next;
+ s->freelist = next;
+ s->ref++;
+ if(next != nil) // prefetching nil leads to a DTLB miss
+ PREFETCH(next);
+ ((uint64*)v)[0] = 0;
+ ((uint64*)v)[1] = 0;
+ // See if we need to replace the existing tiny block with the new one
+ // based on amount of remaining free space.
+ if(TinySize-size > tinysize) {
+ c->tiny = (byte*)v + size;
+ c->tinysize = TinySize - size;
+ }
+ size = TinySize;
+ goto done;
+ }
// Allocate from mcache free lists.
// Inlined version of SizeToClass().
if(size <= 1024-8)
@@ -66,87 +147,117 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
else
sizeclass = runtime·size_to_class128[(size-1024+127) >> 7];
size = runtime·class_to_size[sizeclass];
- l = &c->list[sizeclass];
- if(l->list == nil)
- runtime·MCache_Refill(c, sizeclass);
- v = l->list;
- l->list = v->next;
- l->nlist--;
+ s = c->alloc[sizeclass];
+ if(s->freelist == nil)
+ s = runtime·MCache_Refill(c, sizeclass);
+ v = s->freelist;
+ next = v->next;
+ s->freelist = next;
+ s->ref++;
+ if(next != nil) // prefetching nil leads to a DTLB miss
+ PREFETCH(next);
if(!(flag & FlagNoZero)) {
v->next = nil;
// block is zeroed iff second word is zero ...
- if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+ if(size > 2*sizeof(uintptr) && ((uintptr*)v)[1] != 0)
runtime·memclr((byte*)v, size);
}
+ done:
c->local_cachealloc += size;
} else {
- // TODO(rsc): Report tracebacks for very large allocations.
-
// Allocate directly from heap.
- npages = size >> PageShift;
- if((size & PageMask) != 0)
- npages++;
- s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
- if(s == nil)
- runtime·throw("out of memory");
- s->limit = (byte*)(s->start<<PageShift) + size;
- size = npages<<PageShift;
+ s = largealloc(flag, &size);
v = (void*)(s->start << PageShift);
-
- // setup for mark sweep
- runtime·markspan(v, 0, 0, true);
}
- if(!(flag & FlagNoGC))
- runtime·markallocated(v, size, (flag&FlagNoScan) != 0);
+ if(flag & FlagNoGC)
+ runtime·marknogc(v);
+ else if(!(flag & FlagNoScan))
+ runtime·markscan(v);
if(DebugTypeAtBlockEnd)
*(uintptr*)((uintptr)v+size-sizeof(uintptr)) = typ;
+ m->mallocing = 0;
// TODO: save type even if FlagNoScan? Potentially expensive but might help
// heap profiling/tracing.
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0) {
- uintptr *buf, i;
-
- buf = m->settype_buf;
- i = m->settype_bufsize;
- buf[i++] = (uintptr)v;
- buf[i++] = typ;
- m->settype_bufsize = i;
+ if(UseSpanType && !(flag & FlagNoScan) && typ != 0)
+ settype(s, v, typ);
+
+ if(raceenabled)
+ runtime·racemalloc(v, size);
+
+ if(runtime·debug.allocfreetrace)
+ runtime·tracealloc(v, size, typ);
+
+ if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
+ if(size < rate && size < c->next_sample)
+ c->next_sample -= size;
+ else
+ profilealloc(v, size);
}
- m->mallocing = 0;
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0 && m->settype_bufsize == nelem(m->settype_buf))
- runtime·settype_flush(m);
m->locks--;
if(m->locks == 0 && g->preempt) // restore the preemption request in case we've cleared it in newstack
g->stackguard0 = StackPreempt;
- if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
- if(size >= rate)
- goto profile;
- if(m->mcache->next_sample > size)
- m->mcache->next_sample -= size;
- else {
- // pick next profile time
- // If you change this, also change allocmcache.
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- m->mcache->next_sample = runtime·fastrand1() % (2*rate);
- profile:
- runtime·setblockspecial(v, true);
- runtime·MProf_Malloc(v, size);
- }
- }
-
if(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
runtime·gc(0);
- if(raceenabled)
- runtime·racemalloc(v, size);
return v;
}
+static MSpan*
+largealloc(uint32 flag, uintptr *sizep)
+{
+ uintptr npages, size;
+ MSpan *s;
+ void *v;
+
+ // Allocate directly from heap.
+ size = *sizep;
+ if(size + PageSize < size)
+ runtime·throw("out of memory");
+ npages = size >> PageShift;
+ if((size & PageMask) != 0)
+ npages++;
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
+ if(s == nil)
+ runtime·throw("out of memory");
+ s->limit = (byte*)(s->start<<PageShift) + size;
+ *sizep = npages<<PageShift;
+ v = (void*)(s->start << PageShift);
+ // setup for mark sweep
+ runtime·markspan(v, 0, 0, true);
+ return s;
+}
+
+static void
+profilealloc(void *v, uintptr size)
+{
+ uintptr rate;
+ int32 next;
+ MCache *c;
+
+ c = m->mcache;
+ rate = runtime·MemProfileRate;
+ if(size < rate) {
+ // pick next profile time
+ // If you change this, also change allocmcache.
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ next = runtime·fastrand1() % (2*rate);
+ // Subtract the "remainder" of the current allocation.
+ // Otherwise objects that are close in size to sampling rate
+ // will be under-sampled, because we consistently discard this remainder.
+ next -= (size - c->next_sample);
+ if(next < 0)
+ next = 0;
+ c->next_sample = next;
+ }
+ runtime·MProf_Malloc(v, size);
+}
+
void*
runtime·malloc(uintptr size)
{
@@ -160,7 +271,6 @@ runtime·free(void *v)
int32 sizeclass;
MSpan *s;
MCache *c;
- uint32 prof;
uintptr size;
if(v == nil)
@@ -177,39 +287,73 @@ runtime·free(void *v)
runtime·printf("free %p: not an allocated block\n", v);
runtime·throw("free runtime·mlookup");
}
- prof = runtime·blockspecial(v);
+ size = s->elemsize;
+ sizeclass = s->sizeclass;
+ // Objects that are smaller than TinySize can be allocated using tiny alloc,
+ // if then such object is combined with an object with finalizer, we will crash.
+ if(size < TinySize)
+ runtime·throw("freeing too small block");
- if(raceenabled)
- runtime·racefree(v);
+ if(runtime·debug.allocfreetrace)
+ runtime·tracefree(v, size);
+
+ // Ensure that the span is swept.
+ // If we free into an unswept span, we will corrupt GC bitmaps.
+ runtime·MSpan_EnsureSwept(s);
+
+ if(s->specials != nil)
+ runtime·freeallspecials(s, v, size);
- // Find size class for v.
- sizeclass = s->sizeclass;
c = m->mcache;
if(sizeclass == 0) {
// Large object.
- size = s->npages<<PageShift;
- *(uintptr*)(s->start<<PageShift) = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
+ s->needzero = 1;
// Must mark v freed before calling unmarkspan and MHeap_Free:
// they might coalesce v into other spans and change the bitmap further.
- runtime·markfreed(v, size);
+ runtime·markfreed(v);
runtime·unmarkspan(v, 1<<PageShift);
- runtime·MHeap_Free(&runtime·mheap, s, 1);
+ // NOTE(rsc,dvyukov): The original implementation of efence
+ // in CL 22060046 used SysFree instead of SysFault, so that
+ // the operating system would eventually give the memory
+ // back to us again, so that an efence program could run
+ // longer without running out of memory. Unfortunately,
+ // calling SysFree here without any kind of adjustment of the
+ // heap data structures means that when the memory does
+ // come back to us, we have the wrong metadata for it, either in
+ // the MSpan structures or in the garbage collection bitmap.
+ // Using SysFault here means that the program will run out of
+ // memory fairly quickly in efence mode, but at least it won't
+ // have mysterious crashes due to confused memory reuse.
+ // It should be possible to switch back to SysFree if we also
+ // implement and then call some kind of MHeap_DeleteSpan.
+ if(runtime·debug.efence)
+ runtime·SysFault((void*)(s->start<<PageShift), size);
+ else
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
c->local_nlargefree++;
c->local_largefree += size;
} else {
// Small object.
- size = runtime·class_to_size[sizeclass];
- if(size > sizeof(uintptr))
+ if(size > 2*sizeof(uintptr))
((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
+ else if(size > sizeof(uintptr))
+ ((uintptr*)v)[1] = 0;
// Must mark v freed before calling MCache_Free:
// it might coalesce v and other blocks into a bigger span
// and change the bitmap further.
- runtime·markfreed(v, size);
c->local_nsmallfree[sizeclass]++;
- runtime·MCache_Free(c, v, sizeclass, size);
+ c->local_cachealloc -= size;
+ if(c->alloc[sizeclass] == s) {
+ // We own the span, so we can just add v to the freelist
+ runtime·markfreed(v);
+ ((MLink*)v)->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
+ } else {
+ // Someone else owns this span. Add to free queue.
+ runtime·MCache_Free(c, v, sizeclass, size);
+ }
}
- if(prof)
- runtime·MProf_Free(v, size);
m->mallocing = 0;
}
@@ -261,37 +405,6 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
return 1;
}
-MCache*
-runtime·allocmcache(void)
-{
- intgo rate;
- MCache *c;
-
- runtime·lock(&runtime·mheap);
- c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
- runtime·unlock(&runtime·mheap);
- runtime·memclr((byte*)c, sizeof(*c));
-
- // Set first allocation sample size.
- rate = runtime·MemProfileRate;
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- if(rate != 0)
- c->next_sample = runtime·fastrand1() % (2*rate);
-
- return c;
-}
-
-void
-runtime·freemcache(MCache *c)
-{
- runtime·MCache_ReleaseAll(c);
- runtime·lock(&runtime·mheap);
- runtime·purgecachedstats(c);
- runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
- runtime·unlock(&runtime·mheap);
-}
-
void
runtime·purgecachedstats(MCache *c)
{
@@ -314,33 +427,42 @@ runtime·purgecachedstats(MCache *c)
}
}
-uintptr runtime·sizeof_C_MStats = sizeof(MStats);
+// Size of the trailing by_size array differs between Go and C,
+// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// sizeof_C_MStats is what C thinks about size of Go struct.
+uintptr runtime·sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
#define MaxArena32 (2U<<30)
void
runtime·mallocinit(void)
{
- byte *p;
- uintptr arena_size, bitmap_size, spans_size;
+ byte *p, *p1;
+ uintptr arena_size, bitmap_size, spans_size, p_size;
extern byte end[];
- byte *want;
uintptr limit;
uint64 i;
+ bool reserved;
p = nil;
+ p_size = 0;
arena_size = 0;
bitmap_size = 0;
spans_size = 0;
+ reserved = false;
// for 64-bit build
USED(p);
+ USED(p_size);
USED(arena_size);
USED(bitmap_size);
USED(spans_size);
runtime·InitSizes();
+ if(runtime·class_to_size[TinySizeClass] != TinySize)
+ runtime·throw("bad TinySizeClass");
+
// limit = runtime·memlimit();
// See https://code.google.com/p/go/issues/detail?id=5049
// TODO(rsc): Fix after 1.1.
@@ -380,7 +502,8 @@ runtime·mallocinit(void)
spans_size = ROUND(spans_size, PageSize);
for(i = 0; i <= 0x7f; i++) {
p = (void*)(i<<40 | 0x00c0ULL<<32);
- p = runtime·SysReserve(p, bitmap_size + spans_size + arena_size);
+ p_size = bitmap_size + spans_size + arena_size + PageSize;
+ p = runtime·SysReserve(p, p_size, &reserved);
if(p != nil)
break;
}
@@ -422,91 +545,119 @@ runtime·mallocinit(void)
// So adjust it upward a little bit ourselves: 1/4 MB to get
// away from the running binary image and then round up
// to a MB boundary.
- want = (byte*)ROUND((uintptr)end + (1<<18), 1<<20);
- p = runtime·SysReserve(want, bitmap_size + spans_size + arena_size);
+ p = (byte*)ROUND((uintptr)end + (1<<18), 1<<20);
+ p_size = bitmap_size + spans_size + arena_size + PageSize;
+ p = runtime·SysReserve(p, p_size, &reserved);
if(p == nil)
runtime·throw("runtime: cannot reserve arena virtual address space");
- if((uintptr)p & (((uintptr)1<<PageShift)-1))
- runtime·printf("runtime: SysReserve returned unaligned address %p; asked for %p", p,
- bitmap_size+spans_size+arena_size);
}
- if((uintptr)p & (((uintptr)1<<PageShift)-1))
- runtime·throw("runtime: SysReserve returned unaligned address");
- runtime·mheap.spans = (MSpan**)p;
- runtime·mheap.bitmap = p + spans_size;
- runtime·mheap.arena_start = p + spans_size + bitmap_size;
+ // PageSize can be larger than OS definition of page size,
+ // so SysReserve can give us a PageSize-unaligned pointer.
+ // To overcome this we ask for PageSize more and round up the pointer.
+ p1 = (byte*)ROUND((uintptr)p, PageSize);
+
+ runtime·mheap.spans = (MSpan**)p1;
+ runtime·mheap.bitmap = p1 + spans_size;
+ runtime·mheap.arena_start = p1 + spans_size + bitmap_size;
runtime·mheap.arena_used = runtime·mheap.arena_start;
- runtime·mheap.arena_end = runtime·mheap.arena_start + arena_size;
+ runtime·mheap.arena_end = p + p_size;
+ runtime·mheap.arena_reserved = reserved;
+
+ if(((uintptr)runtime·mheap.arena_start & (PageSize-1)) != 0)
+ runtime·throw("misrounded allocation in mallocinit");
// Initialize the rest of the allocator.
runtime·MHeap_Init(&runtime·mheap);
m->mcache = runtime·allocmcache();
// See if it works.
- runtime·free(runtime·malloc(1));
+ runtime·free(runtime·malloc(TinySize));
}
void*
runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
{
- byte *p;
+ byte *p, *p_end;
+ uintptr p_size;
+ bool reserved;
if(n > h->arena_end - h->arena_used) {
// We are in 32-bit mode, maybe we didn't use all possible address space yet.
// Reserve some more space.
byte *new_end;
- uintptr needed;
- needed = (uintptr)h->arena_used + n - (uintptr)h->arena_end;
- needed = ROUND(needed, 256<<20);
- new_end = h->arena_end + needed;
+ p_size = ROUND(n + PageSize, 256<<20);
+ new_end = h->arena_end + p_size;
if(new_end <= h->arena_start + MaxArena32) {
- p = runtime·SysReserve(h->arena_end, new_end - h->arena_end);
- if(p == h->arena_end)
+ // TODO: It would be bad if part of the arena
+ // is reserved and part is not.
+ p = runtime·SysReserve(h->arena_end, p_size, &reserved);
+ if(p == h->arena_end) {
h->arena_end = new_end;
+ h->arena_reserved = reserved;
+ }
+ else if(p+p_size <= h->arena_start + MaxArena32) {
+ // Keep everything page-aligned.
+ // Our pages are bigger than hardware pages.
+ h->arena_end = p+p_size;
+ h->arena_used = p + (-(uintptr)p&(PageSize-1));
+ h->arena_reserved = reserved;
+ } else {
+ uint64 stat;
+ stat = 0;
+ runtime·SysFree(p, p_size, &stat);
+ }
}
}
if(n <= h->arena_end - h->arena_used) {
// Keep taking from our reservation.
p = h->arena_used;
- runtime·SysMap(p, n, &mstats.heap_sys);
+ runtime·SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
h->arena_used += n;
runtime·MHeap_MapBits(h);
runtime·MHeap_MapSpans(h);
if(raceenabled)
runtime·racemapshadow(p, n);
+
+ if(((uintptr)p & (PageSize-1)) != 0)
+ runtime·throw("misrounded allocation in MHeap_SysAlloc");
return p;
}
// If using 64-bit, our reservation is all we have.
- if(sizeof(void*) == 8 && (uintptr)h->bitmap >= 0xffffffffU)
+ if(h->arena_end - h->arena_start >= MaxArena32)
return nil;
// On 32-bit, once the reservation is gone we can
// try to get memory at a location chosen by the OS
// and hope that it is in the range we allocated bitmap for.
- p = runtime·SysAlloc(n, &mstats.heap_sys);
+ p_size = ROUND(n, PageSize) + PageSize;
+ p = runtime·SysAlloc(p_size, &mstats.heap_sys);
if(p == nil)
return nil;
- if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
+ if(p < h->arena_start || p+p_size - h->arena_start >= MaxArena32) {
runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
p, h->arena_start, h->arena_start+MaxArena32);
- runtime·SysFree(p, n, &mstats.heap_sys);
+ runtime·SysFree(p, p_size, &mstats.heap_sys);
return nil;
}
-
+
+ p_end = p + p_size;
+ p += -(uintptr)p & (PageSize-1);
if(p+n > h->arena_used) {
h->arena_used = p+n;
- if(h->arena_used > h->arena_end)
- h->arena_end = h->arena_used;
+ if(p_end > h->arena_end)
+ h->arena_end = p_end;
runtime·MHeap_MapBits(h);
runtime·MHeap_MapSpans(h);
if(raceenabled)
runtime·racemapshadow(p, n);
}
+ if(((uintptr)p & (PageSize-1)) != 0)
+ runtime·throw("misrounded allocation in MHeap_SysAlloc");
return p;
}
@@ -534,7 +685,7 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat)
if(align != 0) {
if(align&(align-1))
- runtime·throw("persistentalloc: align is now a power of 2");
+ runtime·throw("persistentalloc: align is not a power of 2");
if(align > PageSize)
runtime·throw("persistentalloc: align is too large");
} else
@@ -562,95 +713,67 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat)
return p;
}
-static Lock settype_lock;
-
-void
-runtime·settype_flush(M *mp)
+static void
+settype(MSpan *s, void *v, uintptr typ)
{
- uintptr *buf, *endbuf;
uintptr size, ofs, j, t;
uintptr ntypes, nbytes2, nbytes3;
uintptr *data2;
byte *data3;
- void *v;
- uintptr typ, p;
- MSpan *s;
- buf = mp->settype_buf;
- endbuf = buf + mp->settype_bufsize;
-
- runtime·lock(&settype_lock);
- while(buf < endbuf) {
- v = (void*)*buf;
- *buf = 0;
- buf++;
- typ = *buf;
- buf++;
-
- // (Manually inlined copy of runtime·MHeap_Lookup)
- p = (uintptr)v>>PageShift;
- if(sizeof(void*) == 8)
- p -= (uintptr)runtime·mheap.arena_start >> PageShift;
- s = runtime·mheap.spans[p];
-
- if(s->sizeclass == 0) {
- s->types.compression = MTypes_Single;
- s->types.data = typ;
- continue;
+ if(s->sizeclass == 0) {
+ s->types.compression = MTypes_Single;
+ s->types.data = typ;
+ return;
+ }
+ size = s->elemsize;
+ ofs = ((uintptr)v - (s->start<<PageShift)) / size;
+
+ switch(s->types.compression) {
+ case MTypes_Empty:
+ ntypes = (s->npages << PageShift) / size;
+ nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
+ data3 = runtime·mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+ s->types.compression = MTypes_Bytes;
+ s->types.data = (uintptr)data3;
+ ((uintptr*)data3)[1] = typ;
+ data3[8*sizeof(uintptr) + ofs] = 1;
+ break;
+
+ case MTypes_Words:
+ ((uintptr*)s->types.data)[ofs] = typ;
+ break;
+
+ case MTypes_Bytes:
+ data3 = (byte*)s->types.data;
+ for(j=1; j<8; j++) {
+ if(((uintptr*)data3)[j] == typ) {
+ break;
+ }
+ if(((uintptr*)data3)[j] == 0) {
+ ((uintptr*)data3)[j] = typ;
+ break;
+ }
}
-
- size = s->elemsize;
- ofs = ((uintptr)v - (s->start<<PageShift)) / size;
-
- switch(s->types.compression) {
- case MTypes_Empty:
+ if(j < 8) {
+ data3[8*sizeof(uintptr) + ofs] = j;
+ } else {
ntypes = (s->npages << PageShift) / size;
- nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
- data3 = runtime·mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Bytes;
- s->types.data = (uintptr)data3;
- ((uintptr*)data3)[1] = typ;
- data3[8*sizeof(uintptr) + ofs] = 1;
- break;
-
- case MTypes_Words:
- ((uintptr*)s->types.data)[ofs] = typ;
- break;
-
- case MTypes_Bytes:
- data3 = (byte*)s->types.data;
- for(j=1; j<8; j++) {
- if(((uintptr*)data3)[j] == typ) {
- break;
- }
- if(((uintptr*)data3)[j] == 0) {
- ((uintptr*)data3)[j] = typ;
- break;
- }
+ nbytes2 = ntypes * sizeof(uintptr);
+ data2 = runtime·mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+ s->types.compression = MTypes_Words;
+ s->types.data = (uintptr)data2;
+
+ // Move the contents of data3 to data2. Then deallocate data3.
+ for(j=0; j<ntypes; j++) {
+ t = data3[8*sizeof(uintptr) + j];
+ t = ((uintptr*)data3)[t];
+ data2[j] = t;
}
- if(j < 8) {
- data3[8*sizeof(uintptr) + ofs] = j;
- } else {
- ntypes = (s->npages << PageShift) / size;
- nbytes2 = ntypes * sizeof(uintptr);
- data2 = runtime·mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Words;
- s->types.data = (uintptr)data2;
-
- // Move the contents of data3 to data2. Then deallocate data3.
- for(j=0; j<ntypes; j++) {
- t = data3[8*sizeof(uintptr) + j];
- t = ((uintptr*)data3)[t];
- data2[j] = t;
- }
- data2[ofs] = typ;
- }
- break;
+ data2[ofs] = typ;
}
+ break;
}
- runtime·unlock(&settype_lock);
-
- mp->settype_bufsize = 0;
}
uintptr
@@ -683,9 +806,7 @@ runtime·gettype(void *v)
runtime·throw("runtime·gettype: invalid compression kind");
}
if(0) {
- runtime·lock(&settype_lock);
runtime·printf("%p -> %d,%X\n", v, (int32)s->types.compression, (int64)t);
- runtime·unlock(&settype_lock);
}
return t;
}
@@ -701,11 +822,8 @@ runtime·mal(uintptr n)
}
#pragma textflag NOSPLIT
-void
-runtime·new(Type *typ, uint8 *ret)
-{
+func new(typ *Type) (ret *uint8) {
ret = runtime·mallocgc(typ->size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
- FLUSH(&ret);
}
static void*
@@ -732,7 +850,7 @@ runtime·cnewarray(Type *typ, intgo n)
}
func GC() {
- runtime·gc(1);
+ runtime·gc(2); // force GC and do eager sweep
}
func SetFinalizer(obj Eface, finalizer Eface) {
@@ -754,14 +872,30 @@ func SetFinalizer(obj Eface, finalizer Eface) {
runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
goto throw;
}
+ ot = (PtrType*)obj.type;
+ // As an implementation detail we do not run finalizers for zero-sized objects,
+ // because we use &runtime·zerobase for all such allocations.
+ if(ot->elem != nil && ot->elem->size == 0)
+ return;
+ // The following check is required for cases when a user passes a pointer to composite literal,
+ // but compiler makes it a pointer to global. For example:
+ // var Foo = &Object{}
+ // func main() {
+ // runtime.SetFinalizer(Foo, nil)
+ // }
+ // See issue 7656.
+ if((byte*)obj.data < runtime·mheap.arena_start || runtime·mheap.arena_used <= (byte*)obj.data)
+ return;
if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) {
- runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
- goto throw;
+ // As an implementation detail we allow to set finalizers for an inner byte
+ // of an object if it could come from tiny alloc (see mallocgc for details).
+ if(ot->elem == nil || (ot->elem->kind&KindNoPointers) == 0 || ot->elem->size >= TinySize) {
+ runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data);
+ goto throw;
+ }
}
- nret = 0;
- ot = (PtrType*)obj.type;
- fint = nil;
if(finalizer.type != nil) {
+ runtime·createfing();
if(finalizer.type->kind != KindFunc)
goto badfunc;
ft = (FuncType*)finalizer.type;
@@ -781,16 +915,20 @@ func SetFinalizer(obj Eface, finalizer Eface) {
goto badfunc;
// compute size needed for return parameters
+ nret = 0;
for(i=0; i<ft->out.len; i++) {
t = ((Type**)ft->out.array)[i];
nret = ROUND(nret, t->align) + t->size;
}
nret = ROUND(nret, sizeof(void*));
- }
-
- if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, ot)) {
- runtime·printf("runtime.SetFinalizer: finalizer already set\n");
- goto throw;
+ ot = (PtrType*)obj.type;
+ if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, ot)) {
+ runtime·printf("runtime.SetFinalizer: finalizer already set\n");
+ goto throw;
+ }
+ } else {
+ // NOTE: asking to remove a finalizer when there currently isn't one set is OK.
+ runtime·removefinalizer(obj.data);
}
return;
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 2c66c6fa7..798c130ad 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -20,7 +20,7 @@
// MHeap: the malloc heap, managed at page (4096-byte) granularity.
// MSpan: a run of pages managed by the MHeap.
// MCentral: a shared free list for a given size class.
-// MCache: a per-thread (in Go, per-M) cache for small objects.
+// MCache: a per-thread (in Go, per-P) cache for small objects.
// MStats: allocation statistics.
//
// Allocating a small object proceeds up a hierarchy of caches:
@@ -66,14 +66,14 @@
//
// The small objects on the MCache and MCentral free lists
// may or may not be zeroed. They are zeroed if and only if
-// the second word of the object is zero. The spans in the
-// page heap are always zeroed. When a span full of objects
-// is returned to the page heap, the objects that need to be
-// are zeroed first. There are two main benefits to delaying the
+// the second word of the object is zero. A span in the
+// page heap is zeroed unless s->needzero is set. When a span
+// is allocated to break into small objects, it is zeroed if needed
+// and s->needzero is set. There are two main benefits to delaying the
// zeroing this way:
//
// 1. stack frames allocated from the small object lists
-// can avoid zeroing altogether.
+// or the page heap can avoid zeroing altogether.
// 2. the cost of zeroing when reusing a small object is
// charged to the mutator, not the garbage collector.
//
@@ -90,7 +90,7 @@ typedef struct GCStats GCStats;
enum
{
- PageShift = 12,
+ PageShift = 13,
PageSize = 1<<PageShift,
PageMask = PageSize - 1,
};
@@ -103,11 +103,15 @@ enum
// size classes. NumSizeClasses is that number. It's needed here
// because there are static arrays of this length; when msize runs its
// size choosing algorithm it double-checks that NumSizeClasses agrees.
- NumSizeClasses = 61,
+ NumSizeClasses = 67,
// Tunable constants.
MaxSmallSize = 32<<10,
+ // Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
+ TinySize = 16,
+ TinySizeClass = 2,
+
FixAllocChunk = 16<<10, // Chunk size for FixAlloc
MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
HeapAllocChunk = 1<<20, // Chunk size for heap growth
@@ -154,6 +158,9 @@ struct MLink
// SysAlloc obtains a large chunk of zeroed memory from the
// operating system, typically on the order of a hundred kilobytes
// or a megabyte.
+// NOTE: SysAlloc returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
//
// SysUnused notifies the operating system that the contents
// of the memory region are no longer needed and can be reused
@@ -168,16 +175,29 @@ struct MLink
// SysReserve reserves address space without allocating memory.
// If the pointer passed to it is non-nil, the caller wants the
// reservation there, but SysReserve can still choose another
-// location if that one is unavailable.
+// location if that one is unavailable. On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it. If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
+// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
//
// SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
+//
+// SysFault marks a (already SysAlloc'd) region to fault
+// if accessed. Used only for debugging the runtime.
void* runtime·SysAlloc(uintptr nbytes, uint64 *stat);
void runtime·SysFree(void *v, uintptr nbytes, uint64 *stat);
void runtime·SysUnused(void *v, uintptr nbytes);
void runtime·SysUsed(void *v, uintptr nbytes);
-void runtime·SysMap(void *v, uintptr nbytes, uint64 *stat);
-void* runtime·SysReserve(void *v, uintptr nbytes);
+void runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
+void* runtime·SysReserve(void *v, uintptr nbytes, bool *reserved);
+void runtime·SysFault(void *v, uintptr nbytes);
// FixAlloc is a simple free-list allocator for fixed size objects.
// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
@@ -255,8 +275,9 @@ struct MStats
} by_size[NumSizeClasses];
};
-#define mstats runtime·memStats /* name shared with Go */
+#define mstats runtime·memStats
extern MStats mstats;
+void runtime·updatememstats(GCStats *stats);
// Size classes. Computed and initialized by InitSizes.
//
@@ -269,6 +290,7 @@ extern MStats mstats;
// making new objects in class i
int32 runtime·SizeToClass(int32);
+uintptr runtime·roundupsize(uintptr);
extern int32 runtime·class_to_size[NumSizeClasses];
extern int32 runtime·class_to_allocnpages[NumSizeClasses];
extern int8 runtime·size_to_class8[1024/8 + 1];
@@ -276,8 +298,6 @@ extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
extern void runtime·InitSizes(void);
-// Per-thread (in Go, per-M) cache for small objects.
-// No locking needed because it is per-thread (per-M).
typedef struct MCacheList MCacheList;
struct MCacheList
{
@@ -285,14 +305,21 @@ struct MCacheList
uint32 nlist;
};
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
struct MCache
{
// The following members are accessed on every malloc,
// so they are grouped here for better caching.
int32 next_sample; // trigger heap sample after allocating this many bytes
intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
+ // Allocator cache for tiny objects w/o pointers.
+ // See "Tiny allocator" comment in malloc.goc.
+ byte* tiny;
+ uintptr tinysize;
// The rest is not accessed on every malloc.
- MCacheList list[NumSizeClasses];
+ MSpan* alloc[NumSizeClasses]; // spans to allocate from
+ MCacheList free[NumSizeClasses];// lists of explicitly freed objects
// Local allocator stats, flushed during GC.
uintptr local_nlookup; // number of pointer lookups
uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize)
@@ -300,8 +327,8 @@ struct MCache
uintptr local_nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize)
};
-void runtime·MCache_Refill(MCache *c, int32 sizeclass);
-void runtime·MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+MSpan* runtime·MCache_Refill(MCache *c, int32 sizeclass);
+void runtime·MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size);
void runtime·MCache_ReleaseAll(MCache *c);
// MTypes describes the types of blocks allocated within a span.
@@ -341,6 +368,44 @@ struct MTypes
uintptr data;
};
+enum
+{
+ KindSpecialFinalizer = 1,
+ KindSpecialProfile = 2,
+ // Note: The finalizer special must be first because if we're freeing
+ // an object, a finalizer special will cause the freeing operation
+ // to abort, and we want to keep the other special records around
+ // if that happens.
+};
+
+typedef struct Special Special;
+struct Special
+{
+ Special* next; // linked list in span
+ uint16 offset; // span offset of object
+ byte kind; // kind of Special
+};
+
+// The described object has a finalizer set for it.
+typedef struct SpecialFinalizer SpecialFinalizer;
+struct SpecialFinalizer
+{
+ Special;
+ FuncVal* fn;
+ uintptr nret;
+ Type* fint;
+ PtrType* ot;
+};
+
+// The described object is being heap profiled.
+typedef struct Bucket Bucket; // from mprof.goc
+typedef struct SpecialProfile SpecialProfile;
+struct SpecialProfile
+{
+ Special;
+ Bucket* b;
+};
+
// An MSpan is a run of pages.
enum
{
@@ -356,17 +421,30 @@ struct MSpan
PageID start; // starting page number
uintptr npages; // number of pages in span
MLink *freelist; // list of free objects
- uint32 ref; // number of allocated objects in this span
- int32 sizeclass; // size class
+ // sweep generation:
+ // if sweepgen == h->sweepgen - 2, the span needs sweeping
+ // if sweepgen == h->sweepgen - 1, the span is currently being swept
+ // if sweepgen == h->sweepgen, the span is swept and ready to use
+ // h->sweepgen is incremented by 2 after every GC
+ uint32 sweepgen;
+ uint16 ref; // capacity - number of objects in freelist
+ uint8 sizeclass; // size class
+ bool incache; // being used by an MCache
+ uint8 state; // MSpanInUse etc
+ uint8 needzero; // needs to be zeroed before allocation
uintptr elemsize; // computed from sizeclass or from npages
- uint32 state; // MSpanInUse etc
int64 unusedsince; // First time spotted by GC in MSpanFree state
uintptr npreleased; // number of pages released to the OS
byte *limit; // end of data in span
MTypes types; // types of allocated objects in this span
+ Lock specialLock; // guards specials list
+ Special *specials; // linked list of special records sorted by offset.
+ MLink *freebuf; // objects freed explicitly, not incorporated into freelist yet
};
void runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
+void runtime·MSpan_EnsureSwept(MSpan *span);
+bool runtime·MSpan_Sweep(MSpan *span);
// Every MSpan is in one doubly-linked list,
// either one of the MHeap's free lists or one of the
@@ -374,6 +452,7 @@ void runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
void runtime·MSpanList_Init(MSpan *list);
bool runtime·MSpanList_IsEmpty(MSpan *list);
void runtime·MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime·MSpanList_InsertBack(MSpan *list, MSpan *span);
void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in
@@ -382,15 +461,16 @@ struct MCentral
{
Lock;
int32 sizeclass;
- MSpan nonempty;
- MSpan empty;
- int32 nfree;
+ MSpan nonempty; // list of spans with a free object
+ MSpan empty; // list of spans with no free objects (or cached in an MCache)
+ int32 nfree; // # of objects available in nonempty spans
};
void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
-int32 runtime·MCentral_AllocList(MCentral *c, MLink **first);
-void runtime·MCentral_FreeList(MCentral *c, MLink *first);
-void runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+MSpan* runtime·MCentral_CacheSpan(MCentral *c);
+void runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s);
+bool runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+void runtime·MCentral_FreeList(MCentral *c, MLink *start); // TODO: need this?
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
@@ -399,10 +479,15 @@ struct MHeap
{
Lock;
MSpan free[MaxMHeapList]; // free lists of given length
- MSpan large; // free lists length >= MaxMHeapList
- MSpan **allspans;
+ MSpan freelarge; // free lists length >= MaxMHeapList
+ MSpan busy[MaxMHeapList]; // busy lists of large objects of given length
+ MSpan busylarge; // busy lists of large objects length >= MaxMHeapList
+ MSpan **allspans; // all spans out there
+ MSpan **sweepspans; // copy of allspans referenced by sweeper
uint32 nspan;
uint32 nspancap;
+ uint32 sweepgen; // sweep generation, see comment in MSpan
+ uint32 sweepdone; // all spans are swept
// span lookup
MSpan** spans;
@@ -414,6 +499,7 @@ struct MHeap
byte *arena_start;
byte *arena_used;
byte *arena_end;
+ bool arena_reserved;
// central free lists for small size classes.
// the padding makes sure that the MCentrals are
@@ -426,6 +512,9 @@ struct MHeap
FixAlloc spanalloc; // allocator for Span*
FixAlloc cachealloc; // allocator for MCache*
+ FixAlloc specialfinalizeralloc; // allocator for SpecialFinalizer*
+ FixAlloc specialprofilealloc; // allocator for SpecialProfile*
+ Lock speciallock; // lock for sepcial record allocators.
// Malloc stats.
uint64 largefree; // bytes freed for large objects (>MaxSmallSize)
@@ -435,7 +524,7 @@ struct MHeap
extern MHeap runtime·mheap;
void runtime·MHeap_Init(MHeap *h);
-MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed);
+MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
MSpan* runtime·MHeap_Lookup(MHeap *h, void *v);
MSpan* runtime·MHeap_LookupMaybe(MHeap *h, void *v);
@@ -444,26 +533,28 @@ void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
void runtime·MHeap_MapBits(MHeap *h);
void runtime·MHeap_MapSpans(MHeap *h);
void runtime·MHeap_Scavenger(void);
+void runtime·MHeap_SplitSpan(MHeap *h, MSpan *s);
void* runtime·mallocgc(uintptr size, uintptr typ, uint32 flag);
void* runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat);
int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
void runtime·gc(int32 force);
-void runtime·markallocated(void *v, uintptr n, bool noptr);
+uintptr runtime·sweepone(void);
+void runtime·markscan(void *v);
+void runtime·marknogc(void *v);
void runtime·checkallocated(void *v, uintptr n);
-void runtime·markfreed(void *v, uintptr n);
+void runtime·markfreed(void *v);
void runtime·checkfreed(void *v, uintptr n);
extern int32 runtime·checking;
void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
void runtime·unmarkspan(void *v, uintptr size);
-bool runtime·blockspecial(void*);
-void runtime·setblockspecial(void*, bool);
void runtime·purgecachedstats(MCache*);
void* runtime·cnew(Type*);
void* runtime·cnewarray(Type*, intgo);
+void runtime·tracealloc(void*, uintptr, uintptr);
+void runtime·tracefree(void*, uintptr);
+void runtime·tracegc(void);
-void runtime·settype_flush(M*);
-void runtime·settype_sysfree(MSpan*);
uintptr runtime·gettype(void*);
enum
@@ -477,13 +568,25 @@ enum
};
void runtime·MProf_Malloc(void*, uintptr);
-void runtime·MProf_Free(void*, uintptr);
+void runtime·MProf_Free(Bucket*, uintptr, bool);
void runtime·MProf_GC(void);
+void runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr));
int32 runtime·gcprocs(void);
void runtime·helpgc(int32 nproc);
void runtime·gchelper(void);
+void runtime·createfing(void);
+G* runtime·wakefing(void);
+extern bool runtime·fingwait;
+extern bool runtime·fingwake;
-void runtime·walkfintab(void (*fn)(void*));
+void runtime·setprofilebucket(void *p, Bucket *b);
+
+bool runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
+void runtime·removefinalizer(void*);
+void runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot);
+
+void runtime·freeallspecials(MSpan *span, void *p, uintptr size);
+bool runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
enum
{
@@ -495,8 +598,46 @@ enum
DebugTypeAtBlockEnd = 0,
};
+// Information from the compiler about the layout of stack frames.
+typedef struct BitVector BitVector;
+struct BitVector
+{
+ int32 n; // # of bits
+ uint32 *data;
+};
+typedef struct StackMap StackMap;
+struct StackMap
+{
+ int32 n; // number of bitmaps
+ int32 nbit; // number of bits in each bitmap
+ uint32 data[];
+};
+enum {
+ // Pointer map
+ BitsPerPointer = 2,
+ BitsDead = 0,
+ BitsScalar = 1,
+ BitsPointer = 2,
+ BitsMultiWord = 3,
+ // BitsMultiWord will be set for the first word of a multi-word item.
+ // When it is set, one of the following will be set for the second word.
+ BitsString = 0,
+ BitsSlice = 1,
+ BitsIface = 2,
+ BitsEface = 3,
+};
+// Returns pointer map data for the given stackmap index
+// (the index is encoded in PCDATA_StackMapIndex).
+BitVector runtime·stackmapdata(StackMap *stackmap, int32 n);
+
// defined in mgc0.go
void runtime·gc_m_ptr(Eface*);
+void runtime·gc_g_ptr(Eface*);
void runtime·gc_itab_ptr(Eface*);
void runtime·memorydump(void);
+int32 runtime·setgcpercent(int32);
+
+// Value we use to mark dead pointers when GODEBUG=gcdead=1.
+#define PoisonGC ((uintptr)0xf969696969696969ULL)
+#define PoisonStack ((uintptr)0x6868686868686868ULL)
diff --git a/src/pkg/runtime/map_test.go b/src/pkg/runtime/map_test.go
index a221cb28c..e4e838349 100644
--- a/src/pkg/runtime/map_test.go
+++ b/src/pkg/runtime/map_test.go
@@ -409,3 +409,69 @@ func TestMapNanGrowIterator(t *testing.T) {
t.Fatalf("missing value")
}
}
+
+func TestMapIterOrder(t *testing.T) {
+ for _, n := range [...]int{3, 7, 9, 15} {
+ // Make m be {0: true, 1: true, ..., n-1: true}.
+ m := make(map[int]bool)
+ for i := 0; i < n; i++ {
+ m[i] = true
+ }
+ // Check that iterating over the map produces at least two different orderings.
+ ord := func() []int {
+ var s []int
+ for key := range m {
+ s = append(s, key)
+ }
+ return s
+ }
+ first := ord()
+ ok := false
+ for try := 0; try < 100; try++ {
+ if !reflect.DeepEqual(first, ord()) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
+ }
+ }
+}
+
+func TestMapStringBytesLookup(t *testing.T) {
+ // Use large string keys to avoid small-allocation coalescing,
+ // which can cause AllocsPerRun to report lower counts than it should.
+ m := map[string]int{
+ "1000000000000000000000000000000000000000000000000": 1,
+ "2000000000000000000000000000000000000000000000000": 2,
+ }
+ buf := []byte("1000000000000000000000000000000000000000000000000")
+ if x := m[string(buf)]; x != 1 {
+ t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
+ }
+ buf[0] = '2'
+ if x := m[string(buf)]; x != 2 {
+ t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
+ }
+
+ var x int
+ n := testing.AllocsPerRun(100, func() {
+ x += m[string(buf)]
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
+ }
+
+ x = 0
+ n = testing.AllocsPerRun(100, func() {
+ y, ok := m[string(buf)]
+ if !ok {
+ panic("!ok")
+ }
+ x += y
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
+ }
+}
diff --git a/src/pkg/runtime/mapspeed_test.go b/src/pkg/runtime/mapspeed_test.go
index d643d9898..da45ea11e 100644
--- a/src/pkg/runtime/mapspeed_test.go
+++ b/src/pkg/runtime/mapspeed_test.go
@@ -268,3 +268,33 @@ func BenchmarkSameLengthMap(b *testing.B) {
_ = m[s1]
}
}
+
+type BigKey [3]int64
+
+func BenchmarkBigKeyMap(b *testing.B) {
+ m := make(map[BigKey]bool)
+ k := BigKey{3, 4, 5}
+ m[k] = true
+ for i := 0; i < b.N; i++ {
+ _ = m[k]
+ }
+}
+
+type BigVal [3]int64
+
+func BenchmarkBigValMap(b *testing.B) {
+ m := make(map[BigKey]BigVal)
+ k := BigKey{3, 4, 5}
+ m[k] = BigVal{6, 7, 8}
+ for i := 0; i < b.N; i++ {
+ _ = m[k]
+ }
+}
+
+func BenchmarkSmallKeyMap(b *testing.B) {
+ m := make(map[int16]bool)
+ m[5] = true
+ for i := 0; i < b.N; i++ {
+ _ = m[5]
+ }
+}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 863030e74..26e3db2dc 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -10,69 +10,118 @@
#include "arch_GOARCH.h"
#include "malloc.h"
+extern volatile intgo runtime·MemProfileRate;
+
+// dummy MSpan that contains no free objects.
+static MSpan emptymspan;
+
+MCache*
+runtime·allocmcache(void)
+{
+ intgo rate;
+ MCache *c;
+ int32 i;
+
+ runtime·lock(&runtime·mheap);
+ c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
+ runtime·unlock(&runtime·mheap);
+ runtime·memclr((byte*)c, sizeof(*c));
+ for(i = 0; i < NumSizeClasses; i++)
+ c->alloc[i] = &emptymspan;
+
+ // Set first allocation sample size.
+ rate = runtime·MemProfileRate;
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ if(rate != 0)
+ c->next_sample = runtime·fastrand1() % (2*rate);
+
+ return c;
+}
+
void
+runtime·freemcache(MCache *c)
+{
+ runtime·MCache_ReleaseAll(c);
+ runtime·lock(&runtime·mheap);
+ runtime·purgecachedstats(c);
+ runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
+ runtime·unlock(&runtime·mheap);
+}
+
+// Gets a span that has a free object in it and assigns it
+// to be the cached span for the given sizeclass. Returns this span.
+MSpan*
runtime·MCache_Refill(MCache *c, int32 sizeclass)
{
MCacheList *l;
+ MSpan *s;
- // Replenish using central lists.
- l = &c->list[sizeclass];
- if(l->list)
- runtime·throw("MCache_Refill: the list is not empty");
- l->nlist = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass], &l->list);
- if(l->list == nil)
- runtime·throw("out of memory");
-}
+ m->locks++;
+ // Return the current cached span to the central lists.
+ s = c->alloc[sizeclass];
+ if(s->freelist != nil)
+ runtime·throw("refill on a nonempty span");
+ if(s != &emptymspan)
+ runtime·MCentral_UncacheSpan(&runtime·mheap.central[sizeclass], s);
-// Take n elements off l and return them to the central free list.
-static void
-ReleaseN(MCacheList *l, int32 n, int32 sizeclass)
-{
- MLink *first, **lp;
- int32 i;
+ // Push any explicitly freed objects to the central lists.
+ // Not required, but it seems like a good time to do it.
+ l = &c->free[sizeclass];
+ if(l->nlist > 0) {
+ runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
+ l->list = nil;
+ l->nlist = 0;
+ }
- // Cut off first n elements.
- first = l->list;
- lp = &l->list;
- for(i=0; i<n; i++)
- lp = &(*lp)->next;
- l->list = *lp;
- *lp = nil;
- l->nlist -= n;
-
- // Return them to central free list.
- runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], first);
+ // Get a new cached span from the central lists.
+ s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass]);
+ if(s == nil)
+ runtime·throw("out of memory");
+ if(s->freelist == nil) {
+ runtime·printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
+ runtime·throw("empty span");
+ }
+ c->alloc[sizeclass] = s;
+ m->locks--;
+ return s;
}
void
-runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+runtime·MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size)
{
MCacheList *l;
- MLink *p;
- // Put back on list.
- l = &c->list[sizeclass];
- p = v;
+ // Put on free list.
+ l = &c->free[sizeclass];
p->next = l->list;
l->list = p;
l->nlist++;
- c->local_cachealloc -= size;
- // We transfer span at a time from MCentral to MCache,
- // if we have 2 times more than that, release a half back.
- if(l->nlist >= 2*(runtime·class_to_allocnpages[sizeclass]<<PageShift)/size)
- ReleaseN(l, l->nlist/2, sizeclass);
+ // We transfer a span at a time from MCentral to MCache,
+ // so we'll do the same in the other direction.
+ if(l->nlist >= (runtime·class_to_allocnpages[sizeclass]<<PageShift)/size) {
+ runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
+ l->list = nil;
+ l->nlist = 0;
+ }
}
void
runtime·MCache_ReleaseAll(MCache *c)
{
int32 i;
+ MSpan *s;
MCacheList *l;
for(i=0; i<NumSizeClasses; i++) {
- l = &c->list[i];
- if(l->list) {
+ s = c->alloc[i];
+ if(s != &emptymspan) {
+ runtime·MCentral_UncacheSpan(&runtime·mheap.central[i], s);
+ c->alloc[i] = &emptymspan;
+ }
+ l = &c->free[i];
+ if(l->nlist > 0) {
runtime·MCentral_FreeList(&runtime·mheap.central[i], l->list);
l->list = nil;
l->nlist = 0;
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 735a7e6a9..203558fca 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -19,7 +19,8 @@
#include "malloc.h"
static bool MCentral_Grow(MCentral *c);
-static void MCentral_Free(MCentral *c, void *v);
+static void MCentral_Free(MCentral *c, MLink *v);
+static void MCentral_ReturnToHeap(MCentral *c, MSpan *s);
// Initialize a single central free list.
void
@@ -30,39 +31,115 @@ runtime·MCentral_Init(MCentral *c, int32 sizeclass)
runtime·MSpanList_Init(&c->empty);
}
-// Allocate a list of objects from the central free list.
-// Return the number of objects allocated.
-// The objects are linked together by their first words.
-// On return, *pfirst points at the first object.
-int32
-runtime·MCentral_AllocList(MCentral *c, MLink **pfirst)
+// Allocate a span to use in an MCache.
+MSpan*
+runtime·MCentral_CacheSpan(MCentral *c)
{
MSpan *s;
int32 cap, n;
+ uint32 sg;
runtime·lock(c);
- // Replenish central list if empty.
- if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
- if(!MCentral_Grow(c)) {
+ sg = runtime·mheap.sweepgen;
+retry:
+ for(s = c->nonempty.next; s != &c->nonempty; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime·unlock(c);
+ runtime·MSpan_Sweep(s);
+ runtime·lock(c);
+ // the span could have been moved to heap, retry
+ goto retry;
+ }
+ if(s->sweepgen == sg-1) {
+ // the span is being swept by background sweeper, skip
+ continue;
+ }
+ // we have a nonempty span that does not require sweeping, allocate from it
+ goto havespan;
+ }
+
+ for(s = c->empty.next; s != &c->empty; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+ // we have an empty span that requires sweeping,
+ // sweep it and see if we can free some space in it
+ runtime·MSpanList_Remove(s);
+ // swept spans are at the end of the list
+ runtime·MSpanList_InsertBack(&c->empty, s);
runtime·unlock(c);
- *pfirst = nil;
- return 0;
+ runtime·MSpan_Sweep(s);
+ runtime·lock(c);
+ // the span could be moved to nonempty or heap, retry
+ goto retry;
}
+ if(s->sweepgen == sg-1) {
+ // the span is being swept by background sweeper, skip
+ continue;
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break;
}
- s = c->nonempty.next;
+
+ // Replenish central list if empty.
+ if(!MCentral_Grow(c)) {
+ runtime·unlock(c);
+ return nil;
+ }
+ goto retry;
+
+havespan:
cap = (s->npages << PageShift) / s->elemsize;
n = cap - s->ref;
- *pfirst = s->freelist;
- s->freelist = nil;
- s->ref += n;
+ if(n == 0)
+ runtime·throw("empty span");
+ if(s->freelist == nil)
+ runtime·throw("freelist empty");
c->nfree -= n;
runtime·MSpanList_Remove(s);
- runtime·MSpanList_Insert(&c->empty, s);
+ runtime·MSpanList_InsertBack(&c->empty, s);
+ s->incache = true;
runtime·unlock(c);
- return n;
+ return s;
}
-// Free the list of objects back into the central free list.
+// Return span from an MCache.
+void
+runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s)
+{
+ MLink *v;
+ int32 cap, n;
+
+ runtime·lock(c);
+
+ s->incache = false;
+
+ // Move any explicitly freed items from the freebuf to the freelist.
+ while((v = s->freebuf) != nil) {
+ s->freebuf = v->next;
+ runtime·markfreed(v);
+ v->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
+ }
+
+ if(s->ref == 0) {
+ // Free back to heap. Unlikely, but possible.
+ MCentral_ReturnToHeap(c, s); // unlocks c
+ return;
+ }
+
+ cap = (s->npages << PageShift) / s->elemsize;
+ n = cap - s->ref;
+ if(n > 0) {
+ c->nfree += n;
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
+ }
+ runtime·unlock(c);
+}
+
+// Free the list of objects back into the central free list c.
+// Called from runtime·free.
void
runtime·MCentral_FreeList(MCentral *c, MLink *start)
{
@@ -77,51 +154,58 @@ runtime·MCentral_FreeList(MCentral *c, MLink *start)
}
// Helper: free one object back into the central free list.
+// Caller must hold lock on c on entry. Holds lock on exit.
static void
-MCentral_Free(MCentral *c, void *v)
+MCentral_Free(MCentral *c, MLink *v)
{
MSpan *s;
- MLink *p;
- int32 size;
// Find span for v.
s = runtime·MHeap_Lookup(&runtime·mheap, v);
if(s == nil || s->ref == 0)
runtime·throw("invalid free");
+ if(s->sweepgen != runtime·mheap.sweepgen)
+ runtime·throw("free into unswept span");
+
+ // If the span is currently being used unsynchronized by an MCache,
+ // we can't modify the freelist. Add to the freebuf instead. The
+ // items will get moved to the freelist when the span is returned
+ // by the MCache.
+ if(s->incache) {
+ v->next = s->freebuf;
+ s->freebuf = v;
+ return;
+ }
- // Move to nonempty if necessary.
+ // Move span to nonempty if necessary.
if(s->freelist == nil) {
runtime·MSpanList_Remove(s);
runtime·MSpanList_Insert(&c->nonempty, s);
}
- // Add v back to s's free list.
- p = v;
- p->next = s->freelist;
- s->freelist = p;
+ // Add the object to span's free list.
+ runtime·markfreed(v);
+ v->next = s->freelist;
+ s->freelist = v;
+ s->ref--;
c->nfree++;
// If s is completely freed, return it to the heap.
- if(--s->ref == 0) {
- size = runtime·class_to_size[c->sizeclass];
- runtime·MSpanList_Remove(s);
- runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
- *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
- s->freelist = nil;
- c->nfree -= (s->npages << PageShift) / size;
- runtime·unlock(c);
- runtime·MHeap_Free(&runtime·mheap, s, 0);
+ if(s->ref == 0) {
+ MCentral_ReturnToHeap(c, s); // unlocks c
runtime·lock(c);
}
}
// Free n objects from a span s back into the central free list c.
-// Called from GC.
-void
+// Called during sweep.
+// Returns true if the span was returned to heap. Sets sweepgen to
+// the latest generation.
+bool
runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end)
{
- int32 size;
-
+ if(s->incache)
+ runtime·throw("freespan into cached span");
runtime·lock(c);
// Move to nonempty if necessary.
@@ -135,20 +219,21 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *
s->freelist = start;
s->ref -= n;
c->nfree += n;
+
+ // delay updating sweepgen until here. This is the signal that
+ // the span may be used in an MCache, so it must come after the
+ // linked list operations above (actually, just after the
+ // lock of c above.)
+ runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
- // If s is completely freed, return it to the heap.
- if(s->ref == 0) {
- size = runtime·class_to_size[c->sizeclass];
- runtime·MSpanList_Remove(s);
- *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
- s->freelist = nil;
- c->nfree -= (s->npages << PageShift) / size;
- runtime·unlock(c);
- runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
- runtime·MHeap_Free(&runtime·mheap, s, 0);
- } else {
+ if(s->ref != 0) {
runtime·unlock(c);
+ return false;
}
+
+ // s is completely freed, return it to the heap.
+ MCentral_ReturnToHeap(c, s); // unlocks c
+ return true;
}
void
@@ -202,3 +287,21 @@ MCentral_Grow(MCentral *c)
runtime·MSpanList_Insert(&c->nonempty, s);
return true;
}
+
+// Return s to the heap. s must be unused (s->ref == 0). Unlocks c.
+static void
+MCentral_ReturnToHeap(MCentral *c, MSpan *s)
+{
+ int32 size;
+
+ size = runtime·class_to_size[c->sizeclass];
+ runtime·MSpanList_Remove(s);
+ s->needzero = 1;
+ s->freelist = nil;
+ if(s->ref != 0)
+ runtime·throw("ref wrong");
+ c->nfree -= (s->npages << PageShift) / size;
+ runtime·unlock(c);
+ runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ runtime·MHeap_Free(&runtime·mheap, s, 0);
+}
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index dc735e4a6..fa308b5d9 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -60,9 +60,8 @@ type MemStats struct {
var sizeof_C_MStats uintptr // filled in by malloc.goc
-var memStats MemStats
-
func init() {
+ var memStats MemStats
if sizeof_C_MStats != unsafe.Sizeof(memStats) {
println(sizeof_C_MStats, unsafe.Sizeof(memStats))
panic("MStats vs MemStatsType size mismatch")
diff --git a/src/pkg/runtime/mem_darwin.c b/src/pkg/runtime/mem_darwin.c
index a75c46d9d..878c4e1c5 100644
--- a/src/pkg/runtime/mem_darwin.c
+++ b/src/pkg/runtime/mem_darwin.c
@@ -41,11 +41,18 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -58,10 +65,12 @@ enum
};
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
+ USED(reserved);
+
runtime·xadd64(stat, n);
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
diff --git a/src/pkg/runtime/mem_dragonfly.c b/src/pkg/runtime/mem_dragonfly.c
index 025b62ea6..c270332cb 100644
--- a/src/pkg/runtime/mem_dragonfly.c
+++ b/src/pkg/runtime/mem_dragonfly.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
-
+ }
+
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
// TODO(jsing): For some reason DragonFly seems to return
// memory at a different address than we requested, even when
// there should be no reason for it to do so. This can be
diff --git a/src/pkg/runtime/mem_freebsd.c b/src/pkg/runtime/mem_freebsd.c
index 1ee2a555e..586947a2d 100644
--- a/src/pkg/runtime/mem_freebsd.c
+++ b/src/pkg/runtime/mem_freebsd.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
-
+ }
+
+ *reserved = true;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
index b0f295633..635594c36 100644
--- a/src/pkg/runtime/mem_linux.c
+++ b/src/pkg/runtime/mem_linux.c
@@ -11,6 +11,7 @@
enum
{
_PAGE_SIZE = 4096,
+ EACCES = 13,
};
static int32
@@ -19,15 +20,22 @@ addrspace_free(void *v, uintptr n)
int32 errval;
uintptr chunk;
uintptr off;
- static byte vec[4096];
+
+ // NOTE: vec must be just 1 byte long here.
+ // Mincore returns ENOMEM if any of the pages are unmapped,
+ // but we want to know that all of the pages are unmapped.
+ // To make these the same, we can only ask about one page
+ // at a time. See golang.org/issue/7476.
+ static byte vec[1];
for(off = 0; off < n; off += chunk) {
chunk = _PAGE_SIZE * sizeof vec;
if(chunk > (n - off))
chunk = n - off;
errval = runtime·mincore((int8*)v + off, chunk, vec);
- // errval is 0 if success, or -(error_code) if error.
- if (errval == 0 || errval != -ENOMEM)
+ // ENOMEM means unmapped, which is what we want.
+ // Anything else we assume means the pages are mapped.
+ if (errval != -ENOMEM)
return 0;
}
return 1;
@@ -91,8 +99,14 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
@@ -100,7 +114,7 @@ runtime·SysReserve(void *v, uintptr n)
// much address space. Instead, assume that the reservation is okay
// if we can reserve at least 64K and check the assumption in SysMap.
// Only user-mode Linux (UML) rejects these requests.
- if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if (p != v) {
if(p >= (void*)4096)
@@ -108,24 +122,26 @@ runtime·SysReserve(void *v, uintptr n)
return nil;
}
runtime·munmap(p, 64<<10);
+ *reserved = false;
return v;
}
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if((uintptr)p < 4096)
return nil;
+ *reserved = true;
return p;
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ if(!reserved) {
p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_nacl.c b/src/pkg/runtime/mem_nacl.c
new file mode 100644
index 000000000..e2bca40a4
--- /dev/null
+++ b/src/pkg/runtime/mem_nacl.c
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+ Debug = 0,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+ void *v;
+
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ if(Debug)
+ runtime·printf("SysAlloc(%p): %p\n", n, v);
+ return nil;
+ }
+ runtime·xadd64(stat, n);
+ if(Debug)
+ runtime·printf("SysAlloc(%p) = %p\n", n, v);
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ if(Debug)
+ runtime·printf("SysUnused(%p, %p)\n", v, n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+ if(Debug)
+ runtime·printf("SysFree(%p, %p)\n", v, n);
+ runtime·xadd64(stat, -(uint64)n);
+ runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(NaCl || sizeof(void*) == 8) {
+ *reserved = false;
+ return v;
+ }
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ *reserved = true;
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+ void *p;
+
+ runtime·xadd64(stat, n);
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(!reserved) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·throw("runtime: out of memory");
+ }
+ if(p != v) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ if(Debug)
+ runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·throw("runtime: out of memory");
+ }
+ if(p != v) {
+ runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+ runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
+ runtime·throw("runtime: cannot map pages in arena address space");
+ }
+ if(Debug)
+ runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+}
diff --git a/src/pkg/runtime/mem_netbsd.c b/src/pkg/runtime/mem_netbsd.c
index 91e36eb60..861ae90c7 100644
--- a/src/pkg/runtime/mem_netbsd.c
+++ b/src/pkg/runtime/mem_netbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
+ }
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
+ *reserved = true;
return p;
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_openbsd.c b/src/pkg/runtime/mem_openbsd.c
index 91e36eb60..861ae90c7 100644
--- a/src/pkg/runtime/mem_openbsd.c
+++ b/src/pkg/runtime/mem_openbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·munmap(v, n);
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
void *p;
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
- if(sizeof(void*) == 8)
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
return v;
+ }
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p < (void*)4096)
return nil;
+ *reserved = true;
return p;
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
runtime·xadd64(stat, n);
// On 64-bit, we don't actually have v reserved, so tread carefully.
- if(sizeof(void*) == 8) {
+ if(!reserved) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_plan9.c b/src/pkg/runtime/mem_plan9.c
index edf970b2f..bbf04c7ed 100644
--- a/src/pkg/runtime/mem_plan9.c
+++ b/src/pkg/runtime/mem_plan9.c
@@ -62,14 +62,21 @@ runtime·SysUsed(void *v, uintptr nbytes)
}
void
-runtime·SysMap(void *v, uintptr nbytes, uint64 *stat)
+runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
{
- USED(v, nbytes, stat);
+ USED(v, nbytes, reserved, stat);
+}
+
+void
+runtime·SysFault(void *v, uintptr nbytes)
+{
+ USED(v, nbytes);
}
void*
-runtime·SysReserve(void *v, uintptr nbytes)
+runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
{
USED(v);
+ *reserved = true;
return runtime·SysAlloc(nbytes, &mstats.heap_sys);
}
diff --git a/src/pkg/runtime/mem_solaris.c b/src/pkg/runtime/mem_solaris.c
new file mode 100644
index 000000000..034222887
--- /dev/null
+++ b/src/pkg/runtime/mem_solaris.c
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+ ENOMEM = 12,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+ void *v;
+
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ runtime·xadd64(stat, n);
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+ runtime·xadd64(stat, -(uint64)n);
+ runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // and check the assumption in SysMap.
+ if(sizeof(void*) == 8 && n > 1LL<<32) {
+ *reserved = false;
+ return v;
+ }
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ *reserved = true;
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+ void *p;
+
+ runtime·xadd64(stat, n);
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(!reserved) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/mem_windows.c b/src/pkg/runtime/mem_windows.c
index abdc72ad8..77ec6e926 100644
--- a/src/pkg/runtime/mem_windows.c
+++ b/src/pkg/runtime/mem_windows.c
@@ -15,12 +15,15 @@ enum {
MEM_RELEASE = 0x8000,
PAGE_READWRITE = 0x0004,
+ PAGE_NOACCESS = 0x0001,
};
#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+#pragma dynimport runtime·VirtualProtect VirtualProtect "kernel32.dll"
extern void *runtime·VirtualAlloc;
extern void *runtime·VirtualFree;
+extern void *runtime·VirtualProtect;
void*
runtime·SysAlloc(uintptr n, uint64 *stat)
@@ -33,10 +36,30 @@ void
runtime·SysUnused(void *v, uintptr n)
{
void *r;
+ uintptr small;
r = runtime·stdcall(runtime·VirtualFree, 3, v, n, (uintptr)MEM_DECOMMIT);
- if(r == nil)
- runtime·throw("runtime: failed to decommit pages");
+ if(r != nil)
+ return;
+
+ // Decommit failed. Usual reason is that we've merged memory from two different
+ // VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
+ // a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
+ // just not pages from multiple allocs. This is a rare case, arising only when we're
+ // trying to give memory back to the operating system, which happens on a time
+ // scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
+ // on all our VirtualAlloc calls, try freeing successively smaller pieces until
+ // we manage to free something, and then repeat. This ends up being O(n log n)
+ // in the worst case, but that's fast enough.
+ while(n > 0) {
+ small = n;
+ while(small >= 4096 && runtime·stdcall(runtime·VirtualFree, 3, v, small, (uintptr)MEM_DECOMMIT) == nil)
+ small = (small / 2) & ~(4096-1);
+ if(small < 4096)
+ runtime·throw("runtime: failed to decommit pages");
+ v = (byte*)v + small;
+ n -= small;
+ }
}
void
@@ -60,9 +83,17 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
runtime·throw("runtime: failed to release pages");
}
+void
+runtime·SysFault(void *v, uintptr n)
+{
+ // SysUnused makes the memory inaccessible and prevents its reuse
+ runtime·SysUnused(v, n);
+}
+
void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
{
+ *reserved = true;
// v is just a hint.
// First try at v.
v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
@@ -74,10 +105,12 @@ runtime·SysReserve(void *v, uintptr n)
}
void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
{
void *p;
-
+
+ USED(reserved);
+
runtime·xadd64(stat, n);
p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
if(p != v)
diff --git a/src/pkg/runtime/memclr_386.s b/src/pkg/runtime/memclr_386.s
new file mode 100644
index 000000000..4b7580cb4
--- /dev/null
+++ b/src/pkg/runtime/memclr_386.s
@@ -0,0 +1,127 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), DI
+ MOVL n+4(FP), BX
+ XORL AX, AX
+
+ // MOVOU seems always faster than REP STOSL.
+clr_tail:
+ TESTL BX, BX
+ JEQ clr_0
+ CMPL BX, $2
+ JBE clr_1or2
+ CMPL BX, $4
+ JBE clr_3or4
+ CMPL BX, $8
+ JBE clr_5through8
+ CMPL BX, $16
+ JBE clr_9through16
+ TESTL $0x4000000, runtime·cpuid_edx(SB) // check for sse2
+ JEQ nosse2
+ PXOR X0, X0
+ CMPL BX, $32
+ JBE clr_17through32
+ CMPL BX, $64
+ JBE clr_33through64
+ CMPL BX, $128
+ JBE clr_65through128
+ CMPL BX, $256
+ JBE clr_129through256
+ // TODO: use branch table and BSR to make this just a single dispatch
+
+clr_loop:
+ MOVOU X0, 0(DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, 128(DI)
+ MOVOU X0, 144(DI)
+ MOVOU X0, 160(DI)
+ MOVOU X0, 176(DI)
+ MOVOU X0, 192(DI)
+ MOVOU X0, 208(DI)
+ MOVOU X0, 224(DI)
+ MOVOU X0, 240(DI)
+ SUBL $256, BX
+ ADDL $256, DI
+ CMPL BX, $256
+ JAE clr_loop
+ JMP clr_tail
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVL AX, (DI)
+ MOVL AX, 4(DI)
+ MOVL AX, -8(DI)(BX*1)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_17through32:
+ MOVOU X0, (DI)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_33through64:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_65through128:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_129through256:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, -128(DI)(BX*1)
+ MOVOU X0, -112(DI)(BX*1)
+ MOVOU X0, -96(DI)(BX*1)
+ MOVOU X0, -80(DI)(BX*1)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+nosse2:
+ MOVL BX, CX
+ SHRL $2, CX
+ REP
+ STOSL
+ ANDL $3, BX
+ JNE clr_tail
+ RET
diff --git a/src/pkg/runtime/memclr_amd64.s b/src/pkg/runtime/memclr_amd64.s
new file mode 100644
index 000000000..6b79363b2
--- /dev/null
+++ b/src/pkg/runtime/memclr_amd64.s
@@ -0,0 +1,116 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+ MOVQ ptr+0(FP), DI
+ MOVQ n+8(FP), BX
+ XORQ AX, AX
+
+ // MOVOU seems always faster than REP STOSQ.
+clr_tail:
+ TESTQ BX, BX
+ JEQ clr_0
+ CMPQ BX, $2
+ JBE clr_1or2
+ CMPQ BX, $4
+ JBE clr_3or4
+ CMPQ BX, $8
+ JBE clr_5through8
+ CMPQ BX, $16
+ JBE clr_9through16
+ PXOR X0, X0
+ CMPQ BX, $32
+ JBE clr_17through32
+ CMPQ BX, $64
+ JBE clr_33through64
+ CMPQ BX, $128
+ JBE clr_65through128
+ CMPQ BX, $256
+ JBE clr_129through256
+ // TODO: use branch table and BSR to make this just a single dispatch
+ // TODO: for really big clears, use MOVNTDQ.
+
+clr_loop:
+ MOVOU X0, 0(DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, 128(DI)
+ MOVOU X0, 144(DI)
+ MOVOU X0, 160(DI)
+ MOVOU X0, 176(DI)
+ MOVOU X0, 192(DI)
+ MOVOU X0, 208(DI)
+ MOVOU X0, 224(DI)
+ MOVOU X0, 240(DI)
+ SUBQ $256, BX
+ ADDQ $256, DI
+ CMPQ BX, $256
+ JAE clr_loop
+ JMP clr_tail
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVQ AX, (DI)
+ MOVQ AX, -8(DI)(BX*1)
+ RET
+clr_17through32:
+ MOVOU X0, (DI)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_33through64:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_65through128:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
+clr_129through256:
+ MOVOU X0, (DI)
+ MOVOU X0, 16(DI)
+ MOVOU X0, 32(DI)
+ MOVOU X0, 48(DI)
+ MOVOU X0, 64(DI)
+ MOVOU X0, 80(DI)
+ MOVOU X0, 96(DI)
+ MOVOU X0, 112(DI)
+ MOVOU X0, -128(DI)(BX*1)
+ MOVOU X0, -112(DI)(BX*1)
+ MOVOU X0, -96(DI)(BX*1)
+ MOVOU X0, -80(DI)(BX*1)
+ MOVOU X0, -64(DI)(BX*1)
+ MOVOU X0, -48(DI)(BX*1)
+ MOVOU X0, -32(DI)(BX*1)
+ MOVOU X0, -16(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memclr_arm.s b/src/pkg/runtime/memclr_arm.s
index d5ff75d7a..b19ea72a3 100644
--- a/src/pkg/runtime/memclr_arm.s
+++ b/src/pkg/runtime/memclr_arm.s
@@ -40,12 +40,6 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
CMP $4, R(N) /* need at least 4 bytes to copy */
BLT _1tail
- AND $0xFF, R(0) /* it's a byte */
- SLL $8, R(0), R(TMP) /* replicate to a word */
- ORR R(TMP), R(0)
- SLL $16, R(0), R(TMP)
- ORR R(TMP), R(0)
-
_4align: /* align on 4 */
AND.S $3, R(TO), R(TMP)
BEQ _4aligned
diff --git a/src/pkg/runtime/memclr_plan9_386.s b/src/pkg/runtime/memclr_plan9_386.s
new file mode 100644
index 000000000..9b496785a
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_386.s
@@ -0,0 +1,50 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+ MOVL ptr+0(FP), DI
+ MOVL n+4(FP), BX
+ XORL AX, AX
+
+clr_tail:
+ TESTL BX, BX
+ JEQ clr_0
+ CMPL BX, $2
+ JBE clr_1or2
+ CMPL BX, $4
+ JBE clr_3or4
+ CMPL BX, $8
+ JBE clr_5through8
+ CMPL BX, $16
+ JBE clr_9through16
+ MOVL BX, CX
+ SHRL $2, CX
+ REP
+ STOSL
+ ANDL $3, BX
+ JNE clr_tail
+ RET
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVL AX, (DI)
+ MOVL AX, 4(DI)
+ MOVL AX, -8(DI)(BX*1)
+ MOVL AX, -4(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memclr_plan9_amd64.s b/src/pkg/runtime/memclr_plan9_amd64.s
new file mode 100644
index 000000000..6b33054f5
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_amd64.s
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+ MOVQ ptr+0(FP), DI
+ MOVQ n+8(FP), BX
+ XORQ AX, AX
+
+clr_tail:
+ TESTQ BX, BX
+ JEQ clr_0
+ CMPQ BX, $2
+ JBE clr_1or2
+ CMPQ BX, $4
+ JBE clr_3or4
+ CMPQ BX, $8
+ JBE clr_5through8
+ CMPQ BX, $16
+ JBE clr_9through16
+ MOVQ BX, CX
+ SHRQ $2, CX
+ REP
+ STOSQ
+ ANDQ $3, BX
+ JNE clr_tail
+ RET
+
+clr_1or2:
+ MOVB AX, (DI)
+ MOVB AX, -1(DI)(BX*1)
+clr_0:
+ RET
+clr_3or4:
+ MOVW AX, (DI)
+ MOVW AX, -2(DI)(BX*1)
+ RET
+clr_5through8:
+ MOVL AX, (DI)
+ MOVL AX, -4(DI)(BX*1)
+ RET
+clr_9through16:
+ MOVQ AX, (DI)
+ MOVQ AX, -8(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_386.s b/src/pkg/runtime/memmove_386.s
index 13d575973..3aed8ad07 100644
--- a/src/pkg/runtime/memmove_386.s
+++ b/src/pkg/runtime/memmove_386.s
@@ -23,6 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// +build !plan9
+
#include "../../cmd/ld/textflag.h"
TEXT runtime·memmove(SB), NOSPLIT, $0-12
diff --git a/src/pkg/runtime/memmove_amd64.s b/src/pkg/runtime/memmove_amd64.s
index f1641cdb2..5895846db 100644
--- a/src/pkg/runtime/memmove_amd64.s
+++ b/src/pkg/runtime/memmove_amd64.s
@@ -23,6 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// +build !plan9
+
#include "../../cmd/ld/textflag.h"
// void runtime·memmove(void*, void*, uintptr)
diff --git a/src/pkg/runtime/memmove_nacl_amd64p32.s b/src/pkg/runtime/memmove_nacl_amd64p32.s
new file mode 100644
index 000000000..1b5733112
--- /dev/null
+++ b/src/pkg/runtime/memmove_nacl_amd64p32.s
@@ -0,0 +1,46 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT runtime·memmove(SB), NOSPLIT, $0-12
+ MOVL to+0(FP), DI
+ MOVL fr+4(FP), SI
+ MOVL n+8(FP), BX
+
+ CMPL SI, DI
+ JLS back
+
+forward:
+ MOVL BX, CX
+ SHRL $3, CX
+ ANDL $7, BX
+ REP; MOVSQ
+ MOVL BX, CX
+ REP; MOVSB
+ RET
+
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+
+ ADDL BX, DI
+ ADDL BX, SI
+ STD
+
+ MOVL BX, CX
+ SHRL $3, CX
+ ANDL $7, BX
+ SUBL $8, DI
+ SUBL $8, SI
+ REP; MOVSQ
+ ADDL $7, DI
+ ADDL $7, SI
+ MOVL BX, CX
+ REP; MOVSB
+ CLD
+
+ RET
diff --git a/src/pkg/runtime/memmove_plan9_386.s b/src/pkg/runtime/memmove_plan9_386.s
new file mode 100644
index 000000000..187616cd0
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_386.s
@@ -0,0 +1,127 @@
+// Inferno's libkern/memmove-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.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 runtime·memmove(SB), NOSPLIT, $0-12
+ MOVL to+0(FP), DI
+ MOVL fr+4(FP), SI
+ MOVL n+8(FP), BX
+
+ // REP instructions have a high startup cost, so we handle small sizes
+ // with some straightline code. The REP MOVSL instruction is really fast
+ // for large sizes. The cutover is approximately 1K.
+tail:
+ TESTL BX, BX
+ JEQ move_0
+ CMPL BX, $2
+ JBE move_1or2
+ CMPL BX, $4
+ JBE move_3or4
+ CMPL BX, $8
+ JBE move_5through8
+ CMPL BX, $16
+ JBE move_9through16
+
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ REP; MOVSL
+ JMP tail
+/*
+ * check overlap
+ */
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+
+ ADDL BX, DI
+ ADDL BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+
+ SUBL $4, DI
+ SUBL $4, SI
+ REP; MOVSL
+
+ CLD
+ ADDL $4, DI
+ ADDL $4, SI
+ SUBL BX, DI
+ SUBL BX, SI
+ JMP tail
+
+move_1or2:
+ MOVB (SI), AX
+ MOVB -1(SI)(BX*1), CX
+ MOVB AX, (DI)
+ MOVB CX, -1(DI)(BX*1)
+move_0:
+ RET
+move_3or4:
+ MOVW (SI), AX
+ MOVW -2(SI)(BX*1), CX
+ MOVW AX, (DI)
+ MOVW CX, -2(DI)(BX*1)
+ RET
+move_5through8:
+ MOVL (SI), AX
+ MOVL -4(SI)(BX*1), CX
+ MOVL AX, (DI)
+ MOVL CX, -4(DI)(BX*1)
+ RET
+move_9through16:
+ MOVL (SI), AX
+ MOVL 4(SI), CX
+ MOVL -8(SI)(BX*1), DX
+ MOVL -4(SI)(BX*1), BP
+ MOVL AX, (DI)
+ MOVL CX, 4(DI)
+ MOVL DX, -8(DI)(BX*1)
+ MOVL BP, -4(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_plan9_amd64.s b/src/pkg/runtime/memmove_plan9_amd64.s
new file mode 100644
index 000000000..60108273c
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_amd64.s
@@ -0,0 +1,126 @@
+// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.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"
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB), NOSPLIT, $0-24
+
+ MOVQ to+0(FP), DI
+ MOVQ fr+8(FP), SI
+ MOVQ n+16(FP), BX
+
+ // REP instructions have a high startup cost, so we handle small sizes
+ // with some straightline code. The REP MOVSQ instruction is really fast
+ // for large sizes. The cutover is approximately 1K.
+tail:
+ TESTQ BX, BX
+ JEQ move_0
+ CMPQ BX, $2
+ JBE move_1or2
+ CMPQ BX, $4
+ JBE move_3or4
+ CMPQ BX, $8
+ JBE move_5through8
+ CMPQ BX, $16
+ JBE move_9through16
+
+/*
+ * check and set for backwards
+ */
+ CMPQ SI, DI
+ JLS back
+
+/*
+ * forward copy loop
+ */
+forward:
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ REP; MOVSQ
+ JMP tail
+
+back:
+/*
+ * check overlap
+ */
+ MOVQ SI, CX
+ ADDQ BX, CX
+ CMPQ CX, DI
+ JLS forward
+
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+ ADDQ BX, DI
+ ADDQ BX, SI
+ STD
+
+/*
+ * copy
+ */
+ MOVQ BX, CX
+ SHRQ $3, CX
+ ANDQ $7, BX
+
+ SUBQ $8, DI
+ SUBQ $8, SI
+ REP; MOVSQ
+
+ CLD
+ ADDQ $8, DI
+ ADDQ $8, SI
+ SUBQ BX, DI
+ SUBQ BX, SI
+ JMP tail
+
+move_1or2:
+ MOVB (SI), AX
+ MOVB -1(SI)(BX*1), CX
+ MOVB AX, (DI)
+ MOVB CX, -1(DI)(BX*1)
+move_0:
+ RET
+move_3or4:
+ MOVW (SI), AX
+ MOVW -2(SI)(BX*1), CX
+ MOVW AX, (DI)
+ MOVW CX, -2(DI)(BX*1)
+ RET
+move_5through8:
+ MOVL (SI), AX
+ MOVL -4(SI)(BX*1), CX
+ MOVL AX, (DI)
+ MOVL CX, -4(DI)(BX*1)
+ RET
+move_9through16:
+ MOVQ (SI), AX
+ MOVQ -8(SI)(BX*1), CX
+ MOVQ AX, (DI)
+ MOVQ CX, -8(DI)(BX*1)
+ RET
diff --git a/src/pkg/runtime/memmove_test.go b/src/pkg/runtime/memmove_test.go
index 9525f0682..540f0feb5 100644
--- a/src/pkg/runtime/memmove_test.go
+++ b/src/pkg/runtime/memmove_test.go
@@ -5,6 +5,7 @@
package runtime_test
import (
+ . "runtime"
"testing"
)
@@ -80,7 +81,7 @@ func TestMemmoveAlias(t *testing.T) {
}
}
-func bmMemmove(n int, b *testing.B) {
+func bmMemmove(b *testing.B, n int) {
x := make([]byte, n)
y := make([]byte, n)
b.SetBytes(int64(n))
@@ -89,28 +90,154 @@ func bmMemmove(n int, b *testing.B) {
}
}
-func BenchmarkMemmove0(b *testing.B) { bmMemmove(0, b) }
-func BenchmarkMemmove1(b *testing.B) { bmMemmove(1, b) }
-func BenchmarkMemmove2(b *testing.B) { bmMemmove(2, b) }
-func BenchmarkMemmove3(b *testing.B) { bmMemmove(3, b) }
-func BenchmarkMemmove4(b *testing.B) { bmMemmove(4, b) }
-func BenchmarkMemmove5(b *testing.B) { bmMemmove(5, b) }
-func BenchmarkMemmove6(b *testing.B) { bmMemmove(6, b) }
-func BenchmarkMemmove7(b *testing.B) { bmMemmove(7, b) }
-func BenchmarkMemmove8(b *testing.B) { bmMemmove(8, b) }
-func BenchmarkMemmove9(b *testing.B) { bmMemmove(9, b) }
-func BenchmarkMemmove10(b *testing.B) { bmMemmove(10, b) }
-func BenchmarkMemmove11(b *testing.B) { bmMemmove(11, b) }
-func BenchmarkMemmove12(b *testing.B) { bmMemmove(12, b) }
-func BenchmarkMemmove13(b *testing.B) { bmMemmove(13, b) }
-func BenchmarkMemmove14(b *testing.B) { bmMemmove(14, b) }
-func BenchmarkMemmove15(b *testing.B) { bmMemmove(15, b) }
-func BenchmarkMemmove16(b *testing.B) { bmMemmove(16, b) }
-func BenchmarkMemmove32(b *testing.B) { bmMemmove(32, b) }
-func BenchmarkMemmove64(b *testing.B) { bmMemmove(64, b) }
-func BenchmarkMemmove128(b *testing.B) { bmMemmove(128, b) }
-func BenchmarkMemmove256(b *testing.B) { bmMemmove(256, b) }
-func BenchmarkMemmove512(b *testing.B) { bmMemmove(512, b) }
-func BenchmarkMemmove1024(b *testing.B) { bmMemmove(1024, b) }
-func BenchmarkMemmove2048(b *testing.B) { bmMemmove(2048, b) }
-func BenchmarkMemmove4096(b *testing.B) { bmMemmove(4096, b) }
+func BenchmarkMemmove0(b *testing.B) { bmMemmove(b, 0) }
+func BenchmarkMemmove1(b *testing.B) { bmMemmove(b, 1) }
+func BenchmarkMemmove2(b *testing.B) { bmMemmove(b, 2) }
+func BenchmarkMemmove3(b *testing.B) { bmMemmove(b, 3) }
+func BenchmarkMemmove4(b *testing.B) { bmMemmove(b, 4) }
+func BenchmarkMemmove5(b *testing.B) { bmMemmove(b, 5) }
+func BenchmarkMemmove6(b *testing.B) { bmMemmove(b, 6) }
+func BenchmarkMemmove7(b *testing.B) { bmMemmove(b, 7) }
+func BenchmarkMemmove8(b *testing.B) { bmMemmove(b, 8) }
+func BenchmarkMemmove9(b *testing.B) { bmMemmove(b, 9) }
+func BenchmarkMemmove10(b *testing.B) { bmMemmove(b, 10) }
+func BenchmarkMemmove11(b *testing.B) { bmMemmove(b, 11) }
+func BenchmarkMemmove12(b *testing.B) { bmMemmove(b, 12) }
+func BenchmarkMemmove13(b *testing.B) { bmMemmove(b, 13) }
+func BenchmarkMemmove14(b *testing.B) { bmMemmove(b, 14) }
+func BenchmarkMemmove15(b *testing.B) { bmMemmove(b, 15) }
+func BenchmarkMemmove16(b *testing.B) { bmMemmove(b, 16) }
+func BenchmarkMemmove32(b *testing.B) { bmMemmove(b, 32) }
+func BenchmarkMemmove64(b *testing.B) { bmMemmove(b, 64) }
+func BenchmarkMemmove128(b *testing.B) { bmMemmove(b, 128) }
+func BenchmarkMemmove256(b *testing.B) { bmMemmove(b, 256) }
+func BenchmarkMemmove512(b *testing.B) { bmMemmove(b, 512) }
+func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
+func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
+func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }
+
+func TestMemclr(t *testing.T) {
+ size := 512
+ if testing.Short() {
+ size = 128 + 16
+ }
+ mem := make([]byte, size)
+ for i := 0; i < size; i++ {
+ mem[i] = 0xee
+ }
+ for n := 0; n < size; n++ {
+ for x := 0; x <= size-n; x++ { // offset in mem
+ MemclrBytes(mem[x : x+n])
+ for i := 0; i < x; i++ {
+ if mem[i] != 0xee {
+ t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i])
+ }
+ }
+ for i := x; i < x+n; i++ {
+ if mem[i] != 0 {
+ t.Fatalf("failed clear mem[%d] = %d", i, mem[i])
+ }
+ mem[i] = 0xee
+ }
+ for i := x + n; i < size; i++ {
+ if mem[i] != 0xee {
+ t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i])
+ }
+ }
+ }
+ }
+}
+
+func bmMemclr(b *testing.B, n int) {
+ x := make([]byte, n)
+ b.SetBytes(int64(n))
+ for i := 0; i < b.N; i++ {
+ MemclrBytes(x)
+ }
+}
+func BenchmarkMemclr5(b *testing.B) { bmMemclr(b, 5) }
+func BenchmarkMemclr16(b *testing.B) { bmMemclr(b, 16) }
+func BenchmarkMemclr64(b *testing.B) { bmMemclr(b, 64) }
+func BenchmarkMemclr256(b *testing.B) { bmMemclr(b, 256) }
+func BenchmarkMemclr4096(b *testing.B) { bmMemclr(b, 4096) }
+func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }
+
+func BenchmarkClearFat32(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [32]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [64]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat128(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [128]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat256(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [256]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat512(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [512]byte
+ _ = x
+ }
+}
+func BenchmarkClearFat1024(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x [1024]byte
+ _ = x
+ }
+}
+
+func BenchmarkCopyFat32(b *testing.B) {
+ var x [32 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
+func BenchmarkCopyFat64(b *testing.B) {
+ var x [64 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
+func BenchmarkCopyFat128(b *testing.B) {
+ var x [128 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
+func BenchmarkCopyFat256(b *testing.B) {
+ var x [256 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
+func BenchmarkCopyFat512(b *testing.B) {
+ var x [512 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
+func BenchmarkCopyFat1024(b *testing.B) {
+ var x [1024 / 4]uint32
+ for i := 0; i < b.N; i++ {
+ y := x
+ _ = y
+ }
+}
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
deleted file mode 100644
index 3e524d3e0..000000000
--- a/src/pkg/runtime/mfinal.c
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-
-enum { debug = 0 };
-
-typedef struct Fin Fin;
-struct Fin
-{
- FuncVal *fn;
- uintptr nret;
- Type *fint;
- PtrType *ot;
-};
-
-// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
-// Table size is power of 3 so that hash can be key % max.
-// Key[i] == (void*)-1 denotes free but formerly occupied entry
-// (doesn't stop the linear scan).
-// Key and val are separate tables because the garbage collector
-// must be instructed to ignore the pointers in key but follow the
-// pointers in val.
-typedef struct Fintab Fintab;
-struct Fintab
-{
- Lock;
- void **key;
- Fin *val;
- int32 nkey; // number of non-nil entries in key
- int32 ndead; // number of dead (-1) entries in key
- int32 max; // size of key, val allocations
-};
-
-#define TABSZ 17
-#define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ])
-
-static struct {
- Fintab;
- uint8 pad[CacheLineSize - sizeof(Fintab)];
-} fintab[TABSZ];
-
-static void
-addfintab(Fintab *t, void *k, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
-{
- int32 i, j;
-
- i = (uintptr)k % (uintptr)t->max;
- for(j=0; j<t->max; j++) {
- if(t->key[i] == nil) {
- t->nkey++;
- goto ret;
- }
- if(t->key[i] == (void*)-1) {
- t->ndead--;
- goto ret;
- }
- if(++i == t->max)
- i = 0;
- }
-
- // cannot happen - table is known to be non-full
- runtime·throw("finalizer table inconsistent");
-
-ret:
- t->key[i] = k;
- t->val[i].fn = fn;
- t->val[i].nret = nret;
- t->val[i].fint = fint;
- t->val[i].ot = ot;
-}
-
-static bool
-lookfintab(Fintab *t, void *k, bool del, Fin *f)
-{
- int32 i, j;
-
- if(t->max == 0)
- return false;
- i = (uintptr)k % (uintptr)t->max;
- for(j=0; j<t->max; j++) {
- if(t->key[i] == nil)
- return false;
- if(t->key[i] == k) {
- if(f)
- *f = t->val[i];
- if(del) {
- t->key[i] = (void*)-1;
- t->val[i].fn = nil;
- t->val[i].nret = 0;
- t->val[i].ot = nil;
- t->ndead++;
- }
- return true;
- }
- if(++i == t->max)
- i = 0;
- }
-
- // cannot happen - table is known to be non-full
- runtime·throw("finalizer table inconsistent");
- return false;
-}
-
-static void
-resizefintab(Fintab *tab)
-{
- Fintab newtab;
- void *k;
- int32 i;
-
- runtime·memclr((byte*)&newtab, sizeof newtab);
- newtab.max = tab->max;
- if(newtab.max == 0)
- newtab.max = 3*3*3;
- else if(tab->ndead < tab->nkey/2) {
- // grow table if not many dead values.
- // otherwise just rehash into table of same size.
- newtab.max *= 3;
- }
-
- newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], 0, FlagNoInvokeGC|FlagNoScan);
- newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, FlagNoInvokeGC);
-
- for(i=0; i<tab->max; i++) {
- k = tab->key[i];
- if(k != nil && k != (void*)-1)
- addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret, tab->val[i].fint, tab->val[i].ot);
- }
-
- runtime·free(tab->key);
- runtime·free(tab->val);
-
- tab->key = newtab.key;
- tab->val = newtab.val;
- tab->nkey = newtab.nkey;
- tab->ndead = newtab.ndead;
- tab->max = newtab.max;
-}
-
-bool
-runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
-{
- Fintab *tab;
- byte *base;
-
- if(debug) {
- if(!runtime·mlookup(p, &base, nil, nil) || p != base)
- runtime·throw("addfinalizer on invalid pointer");
- }
-
- tab = TAB(p);
- runtime·lock(tab);
- if(f == nil) {
- lookfintab(tab, p, true, nil);
- runtime·unlock(tab);
- return true;
- }
-
- if(lookfintab(tab, p, false, nil)) {
- runtime·unlock(tab);
- return false;
- }
-
- if(tab->nkey >= tab->max/2+tab->max/4) {
- // keep table at most 3/4 full:
- // allocate new table and rehash.
- resizefintab(tab);
- }
-
- addfintab(tab, p, f, nret, fint, ot);
- runtime·setblockspecial(p, true);
- runtime·unlock(tab);
- return true;
-}
-
-// get finalizer; if del, delete finalizer.
-// caller is responsible for updating RefHasFinalizer (special) bit.
-bool
-runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type **fint, PtrType **ot)
-{
- Fintab *tab;
- bool res;
- Fin f;
-
- tab = TAB(p);
- runtime·lock(tab);
- res = lookfintab(tab, p, del, &f);
- runtime·unlock(tab);
- if(res==false)
- return false;
- *fn = f.fn;
- *nret = f.nret;
- *fint = f.fint;
- *ot = f.ot;
- return true;
-}
-
-void
-runtime·walkfintab(void (*fn)(void*))
-{
- void **key;
- void **ekey;
- int32 i;
-
- for(i=0; i<TABSZ; i++) {
- runtime·lock(&fintab[i]);
- key = fintab[i].key;
- ekey = key + fintab[i].max;
- for(; key < ekey; key++)
- if(*key != nil && *key != ((void*)-1))
- fn(*key);
- runtime·unlock(&fintab[i]);
- }
-}
diff --git a/src/pkg/runtime/mfinal_test.go b/src/pkg/runtime/mfinal_test.go
index 6efef9bb0..6b53888ab 100644
--- a/src/pkg/runtime/mfinal_test.go
+++ b/src/pkg/runtime/mfinal_test.go
@@ -6,10 +6,9 @@ package runtime_test
import (
"runtime"
- "sync"
- "sync/atomic"
"testing"
"time"
+ "unsafe"
)
type Tintptr *int // assignable to *int
@@ -46,13 +45,15 @@ func TestFinalizerType(t *testing.T) {
}
for _, tt := range finalizerTests {
+ done := make(chan bool, 1)
go func() {
v := new(int)
*v = 97531
runtime.SetFinalizer(tt.convert(v), tt.finalizer)
v = nil
+ done <- true
}()
- time.Sleep(1 * time.Second)
+ <-done
runtime.GC()
select {
case <-ch:
@@ -73,6 +74,7 @@ func TestFinalizerInterfaceBig(t *testing.T) {
t.Skipf("Skipping on non-amd64 machine")
}
ch := make(chan bool)
+ done := make(chan bool, 1)
go func() {
v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
old := *v
@@ -87,8 +89,9 @@ func TestFinalizerInterfaceBig(t *testing.T) {
close(ch)
})
v = nil
+ done <- true
}()
- time.Sleep(1 * time.Second)
+ <-done
runtime.GC()
select {
case <-ch:
@@ -100,51 +103,137 @@ func TestFinalizerInterfaceBig(t *testing.T) {
func fin(v *int) {
}
+// Verify we don't crash at least. golang.org/issue/6857
+func TestFinalizerZeroSizedStruct(t *testing.T) {
+ type Z struct{}
+ z := new(Z)
+ runtime.SetFinalizer(z, func(*Z) {})
+}
+
func BenchmarkFinalizer(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- var wg sync.WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go func() {
- var data [CallsPerSched]*int
- for i := 0; i < CallsPerSched; i++ {
- data[i] = new(int)
+ const Batch = 1000
+ b.RunParallel(func(pb *testing.PB) {
+ var data [Batch]*int
+ for i := 0; i < Batch; i++ {
+ data[i] = new(int)
+ }
+ for pb.Next() {
+ for i := 0; i < Batch; i++ {
+ runtime.SetFinalizer(data[i], fin)
}
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for i := 0; i < CallsPerSched; i++ {
- runtime.SetFinalizer(data[i], fin)
- }
- for i := 0; i < CallsPerSched; i++ {
- runtime.SetFinalizer(data[i], nil)
- }
+ for i := 0; i < Batch; i++ {
+ runtime.SetFinalizer(data[i], nil)
}
- wg.Done()
- }()
- }
- wg.Wait()
+ }
+ })
}
func BenchmarkFinalizerRun(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- var wg sync.WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for i := 0; i < CallsPerSched; i++ {
- v := new(int)
- runtime.SetFinalizer(v, fin)
- }
- runtime.GC()
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ v := new(int)
+ runtime.SetFinalizer(v, fin)
+ }
+ })
+}
+
+// One chunk must be exactly one sizeclass in size.
+// It should be a sizeclass not used much by others, so we
+// have a greater chance of finding adjacent ones.
+// size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
+const objsize = 320
+
+type objtype [objsize]byte
+
+func adjChunks() (*objtype, *objtype) {
+ var s []*objtype
+
+ for {
+ c := new(objtype)
+ for _, d := range s {
+ if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
+ return c, d
}
- wg.Done()
- }()
+ if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
+ return d, c
+ }
+ }
+ s = append(s, c)
+ }
+}
+
+// Make sure an empty slice on the stack doesn't pin the next object in memory.
+func TestEmptySlice(t *testing.T) {
+ if true { // disable until bug 7564 is fixed.
+ return
+ }
+ x, y := adjChunks()
+
+ // the pointer inside xs points to y.
+ xs := x[objsize:] // change objsize to objsize-1 and the test passes
+
+ fin := make(chan bool, 1)
+ runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+ runtime.GC()
+ select {
+ case <-fin:
+ case <-time.After(4 * time.Second):
+ t.Errorf("finalizer of next object in memory didn't run")
+ }
+ xsglobal = xs // keep empty slice alive until here
+}
+
+var xsglobal []byte
+
+func adjStringChunk() (string, *objtype) {
+ b := make([]byte, objsize)
+ for {
+ s := string(b)
+ t := new(objtype)
+ p := *(*uintptr)(unsafe.Pointer(&s))
+ q := uintptr(unsafe.Pointer(t))
+ if p+objsize == q {
+ return s, t
+ }
+ }
+}
+
+// Make sure an empty string on the stack doesn't pin the next object in memory.
+func TestEmptyString(t *testing.T) {
+ x, y := adjStringChunk()
+
+ ss := x[objsize:] // change objsize to objsize-1 and the test passes
+ fin := make(chan bool, 1)
+ // set finalizer on string contents of y
+ runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+ runtime.GC()
+ select {
+ case <-fin:
+ case <-time.After(4 * time.Second):
+ t.Errorf("finalizer of next string in memory didn't run")
}
- wg.Wait()
+ ssglobal = ss // keep 0-length string live until here
+}
+
+var ssglobal string
+
+// Test for issue 7656.
+func TestFinalizerOnGlobal(t *testing.T) {
+ runtime.SetFinalizer(Foo1, func(p *Object1) {})
+ runtime.SetFinalizer(Foo2, func(p *Object2) {})
+ runtime.SetFinalizer(Foo1, nil)
+ runtime.SetFinalizer(Foo2, nil)
}
+
+type Object1 struct {
+ Something []byte
+}
+
+type Object2 struct {
+ Something byte
+}
+
+var (
+ Foo2 = &Object2{}
+ Foo1 = &Object1{}
+)
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 761f128a8..392da535b 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2,13 +2,60 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Garbage collector.
+// Garbage collector (GC).
+//
+// GC is:
+// - mark&sweep
+// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
+// - parallel (up to MaxGcproc threads)
+// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
+// - non-moving/non-compacting
+// - full (non-partial)
+//
+// GC rate.
+// Next GC is after we've allocated an extra amount of memory proportional to
+// the amount already in use. The proportion is controlled by GOGC environment variable
+// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
+// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
+// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
+// (and also the amount of extra memory used).
+//
+// Concurrent sweep.
+// The sweep phase proceeds concurrently with normal program execution.
+// The heap is swept span-by-span both lazily (when a goroutine needs another span)
+// and concurrently in a background goroutine (this helps programs that are not CPU bound).
+// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
+// and so next_gc calculation is tricky and happens as follows.
+// At the end of the stop-the-world phase next_gc is conservatively set based on total
+// heap size; all spans are marked as "needs sweeping".
+// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
+// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
+// closer to the target value. However, this is not enough to avoid over-allocating memory.
+// Consider that a goroutine wants to allocate a new span for a large object and
+// there are no free swept spans, but there are small-object unswept spans.
+// If the goroutine naively allocates a new span, it can surpass the yet-unknown
+// target next_gc value. In order to prevent such cases (1) when a goroutine needs
+// to allocate a new small-object span, it sweeps small-object spans for the same
+// object size until it frees at least one object; (2) when a goroutine needs to
+// allocate large-object span from heap, it sweeps spans until it frees at least
+// that many pages into heap. Together these two measures ensure that we don't surpass
+// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
+// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
+// but there can still be other one-page unswept spans which could be combined into a two-page span.
+// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
+// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
+// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
+// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
+// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
+// The finalizer goroutine is kicked off only when all spans are swept.
+// When the next GC starts, it sweeps all not-yet-swept spans (if any).
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
#include "mgc0.h"
+#include "chan.h"
#include "race.h"
#include "type.h"
#include "typekind.h"
@@ -17,14 +64,11 @@
enum {
Debug = 0,
- DebugMark = 0, // run second pass to check mark
CollectStats = 0,
- ScanStackByFrames = 0,
- IgnorePreciseGC = 0,
+ ConcurrentSweep = 1,
- // Four bits per word (see #defines below).
- wordsPerBitmapWord = sizeof(void*)*8/4,
- bitShift = sizeof(void*)*8/4,
+ WorkbufSize = 16*1024,
+ FinBlockSize = 4*1024,
handoffThreshold = 4,
IntermediateBufferCapacity = 64,
@@ -34,46 +78,50 @@ enum {
LOOP = 2,
PC_BITS = PRECISE | LOOP,
- // Pointer map
- BitsPerPointer = 2,
- BitsNoPointer = 0,
- BitsPointer = 1,
- BitsIface = 2,
- BitsEface = 3,
+ RootData = 0,
+ RootBss = 1,
+ RootFinalizers = 2,
+ RootSpanTypes = 3,
+ RootFlushCaches = 4,
+ RootCount = 5,
};
-// Bits in per-word bitmap.
-// #defines because enum might not be able to hold the values.
-//
-// Each word in the bitmap describes wordsPerBitmapWord words
-// of heap memory. There are 4 bitmap bits dedicated to each heap word,
-// so on a 64-bit system there is one bitmap word per 16 heap words.
-// The bits in the word are packed together by type first, then by
-// heap location, so each 64-bit bitmap word consists of, from top to bottom,
-// the 16 bitSpecial bits for the corresponding heap words, then the 16 bitMarked bits,
-// then the 16 bitNoScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
-// This layout makes it easier to iterate over the bits of a given type.
-//
-// The bitmap starts at mheap.arena_start and extends *backward* from
-// there. On a 64-bit system the off'th word in the arena is tracked by
-// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
-// the only difference is that the divisor is 8.)
-//
-// To pull out the bits corresponding to a given pointer p, we use:
-//
-// off = p - (uintptr*)mheap.arena_start; // word offset
-// b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
-// shift = off % wordsPerBitmapWord
-// bits = *b >> shift;
-// /* then test bits & bitAllocated, bits & bitMarked, etc. */
-//
-#define bitAllocated ((uintptr)1<<(bitShift*0))
-#define bitNoScan ((uintptr)1<<(bitShift*1)) /* when bitAllocated is set */
-#define bitMarked ((uintptr)1<<(bitShift*2)) /* when bitAllocated is set */
-#define bitSpecial ((uintptr)1<<(bitShift*3)) /* when bitAllocated is set - has finalizer or being profiled */
-#define bitBlockBoundary ((uintptr)1<<(bitShift*1)) /* when bitAllocated is NOT set */
+#define GcpercentUnknown (-2)
+
+// Initialized from $GOGC. GOGC=off means no gc.
+static int32 gcpercent = GcpercentUnknown;
+
+static FuncVal* poolcleanup;
+
+void
+sync·runtime_registerPoolCleanup(FuncVal *f)
+{
+ poolcleanup = f;
+}
+
+static void
+clearpools(void)
+{
+ P *p, **pp;
+ MCache *c;
+ int32 i;
+
+ // clear sync.Pool's
+ if(poolcleanup != nil)
+ reflect·call(poolcleanup, nil, 0, 0);
-#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+ for(pp=runtime·allp; p=*pp; pp++) {
+ // clear tinyalloc pool
+ c = p->mcache;
+ if(c != nil) {
+ c->tiny = nil;
+ c->tinysize = 0;
+ }
+ // clear defer pools
+ for(i=0; i<nelem(p->deferpool); i++)
+ p->deferpool[i] = nil;
+ }
+}
// Holding worldsema grants an M the right to try to stop the world.
// The procedure is:
@@ -98,11 +146,10 @@ struct Obj
uintptr ti; // type info
};
-// The size of Workbuf is N*PageSize.
typedef struct Workbuf Workbuf;
struct Workbuf
{
-#define SIZE (2*PageSize-sizeof(LFNode)-sizeof(uintptr))
+#define SIZE (WorkbufSize-sizeof(LFNode)-sizeof(uintptr))
LFNode node; // must be first
uintptr nobj;
Obj obj[SIZE/sizeof(Obj) - 1];
@@ -138,39 +185,44 @@ extern byte ebss[];
extern byte gcdata[];
extern byte gcbss[];
-static G *fing;
-static FinBlock *finq; // list of finalizers that are to be executed
-static FinBlock *finc; // cache of free blocks
-static FinBlock *allfin; // list of all blocks
-static Lock finlock;
-static int32 fingwait;
+static Lock finlock; // protects the following variables
+static FinBlock *finq; // list of finalizers that are to be executed
+static FinBlock *finc; // cache of free blocks
+static FinBlock *allfin; // list of all blocks
+bool runtime·fingwait;
+bool runtime·fingwake;
+
+static Lock gclock;
+static G* fing;
-static void runfinq(void);
+static void runfinq(void);
+static void bgsweep(void);
static Workbuf* getempty(Workbuf*);
static Workbuf* getfull(Workbuf*);
static void putempty(Workbuf*);
static Workbuf* handoff(Workbuf*);
static void gchelperstart(void);
+static void flushallmcaches(void);
+static bool scanframe(Stkframe *frame, void *wbufp);
+static void addstackroots(G *gp, Workbuf **wbufp);
+
+static FuncVal runfinqv = {runfinq};
+static FuncVal bgsweepv = {bgsweep};
static struct {
uint64 full; // lock-free list of full blocks
uint64 empty; // lock-free list of empty blocks
byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
uint32 nproc;
+ int64 tstart;
volatile uint32 nwait;
volatile uint32 ndone;
- volatile uint32 debugmarkdone;
Note alldone;
ParFor *markfor;
- ParFor *sweepfor;
Lock;
byte *chunk;
uintptr nchunk;
-
- Obj *roots;
- uint32 nroot;
- uint32 rootcap;
} work;
enum {
@@ -207,6 +259,8 @@ static struct {
uint64 foundword;
uint64 foundspan;
} markonly;
+ uint32 nbgsweep;
+ uint32 npausesweep;
} gcstats;
// markonly marks an object. It returns true if the object
@@ -260,8 +314,7 @@ markonly(void *obj)
// (Manually inlined copy of MHeap_LookupMaybe.)
k = (uintptr)obj>>PageShift;
x = k;
- if(sizeof(void*) == 8)
- x -= (uintptr)runtime·mheap.arena_start>>PageShift;
+ x -= (uintptr)runtime·mheap.arena_start>>PageShift;
s = runtime·mheap.spans[x];
if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
return false;
@@ -317,6 +370,24 @@ struct PtrTarget
uintptr ti;
};
+typedef struct Scanbuf Scanbuf;
+struct Scanbuf
+{
+ struct {
+ PtrTarget *begin;
+ PtrTarget *end;
+ PtrTarget *pos;
+ } ptr;
+ struct {
+ Obj *begin;
+ Obj *end;
+ Obj *pos;
+ } obj;
+ Workbuf *wbuf;
+ Obj *wp;
+ uintptr nobj;
+};
+
typedef struct BufferList BufferList;
struct BufferList
{
@@ -350,7 +421,7 @@ static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf
// (find block start, mark and enqueue)
static void
-flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushptrbuf(Scanbuf *sbuf)
{
byte *p, *arena_start, *obj;
uintptr size, *bitp, bits, shift, j, x, xbits, off, nobj, ti, n;
@@ -358,17 +429,19 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
PageID k;
Obj *wp;
Workbuf *wbuf;
+ PtrTarget *ptrbuf;
PtrTarget *ptrbuf_end;
arena_start = runtime·mheap.arena_start;
- wp = *_wp;
- wbuf = *_wbuf;
- nobj = *_nobj;
+ wp = sbuf->wp;
+ wbuf = sbuf->wbuf;
+ nobj = sbuf->nobj;
- ptrbuf_end = *ptrbufpos;
- n = ptrbuf_end - ptrbuf;
- *ptrbufpos = ptrbuf;
+ ptrbuf = sbuf->ptr.begin;
+ ptrbuf_end = sbuf->ptr.pos;
+ n = ptrbuf_end - sbuf->ptr.begin;
+ sbuf->ptr.pos = sbuf->ptr.begin;
if(CollectStats) {
runtime·xadd64(&gcstats.ptr.sum, n);
@@ -387,152 +460,146 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
runtime·throw("ptrbuf has to be smaller than WorkBuf");
}
- // TODO(atom): This block is a branch of an if-then-else statement.
- // The single-threaded branch may be added in a next CL.
- {
- // Multi-threaded version.
+ while(ptrbuf < ptrbuf_end) {
+ obj = ptrbuf->p;
+ ti = ptrbuf->ti;
+ ptrbuf++;
+
+ // obj belongs to interval [mheap.arena_start, mheap.arena_used).
+ if(Debug > 1) {
+ if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used)
+ runtime·throw("object is outside of mheap");
+ }
- while(ptrbuf < ptrbuf_end) {
- obj = ptrbuf->p;
- ti = ptrbuf->ti;
- ptrbuf++;
+ // obj may be a pointer to a live object.
+ // Try to find the beginning of the object.
- // obj belongs to interval [mheap.arena_start, mheap.arena_used).
- if(Debug > 1) {
- if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used)
- runtime·throw("object is outside of mheap");
- }
+ // Round down to word boundary.
+ if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
+ obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+ ti = 0;
+ }
- // obj may be a pointer to a live object.
- // Try to find the beginning of the object.
+ // Find bits for this word.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
- // Round down to word boundary.
- if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
- ti = 0;
- }
+ // Pointing at the beginning of a block?
+ if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+ if(CollectStats)
+ runtime·xadd64(&gcstats.flushptrbuf.foundbit, 1);
+ goto found;
+ }
- // Find bits for this word.
- off = (uintptr*)obj - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
+ ti = 0;
- // Pointing at the beginning of a block?
- if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+ // Pointing just past the beginning?
+ // Scan backward a little to find a block boundary.
+ for(j=shift; j-->0; ) {
+ if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
+ obj = (byte*)obj - (shift-j)*PtrSize;
+ shift = j;
+ bits = xbits>>shift;
if(CollectStats)
- runtime·xadd64(&gcstats.flushptrbuf.foundbit, 1);
+ runtime·xadd64(&gcstats.flushptrbuf.foundword, 1);
goto found;
}
+ }
- ti = 0;
-
- // Pointing just past the beginning?
- // Scan backward a little to find a block boundary.
- for(j=shift; j-->0; ) {
- if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
- obj = (byte*)obj - (shift-j)*PtrSize;
- shift = j;
- bits = xbits>>shift;
- if(CollectStats)
- runtime·xadd64(&gcstats.flushptrbuf.foundword, 1);
- goto found;
- }
- }
-
- // Otherwise consult span table to find beginning.
- // (Manually inlined copy of MHeap_LookupMaybe.)
- k = (uintptr)obj>>PageShift;
- x = k;
- if(sizeof(void*) == 8)
- x -= (uintptr)arena_start>>PageShift;
- s = runtime·mheap.spans[x];
- if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
- continue;
- p = (byte*)((uintptr)s->start<<PageShift);
- if(s->sizeclass == 0) {
- obj = p;
- } else {
- size = s->elemsize;
- int32 i = ((byte*)obj - p)/size;
- obj = p+i*size;
- }
+ // Otherwise consult span table to find beginning.
+ // (Manually inlined copy of MHeap_LookupMaybe.)
+ k = (uintptr)obj>>PageShift;
+ x = k;
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime·mheap.spans[x];
+ if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
+ continue;
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ obj = p;
+ } else {
+ size = s->elemsize;
+ int32 i = ((byte*)obj - p)/size;
+ obj = p+i*size;
+ }
- // Now that we know the object header, reload bits.
- off = (uintptr*)obj - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
- if(CollectStats)
- runtime·xadd64(&gcstats.flushptrbuf.foundspan, 1);
+ // Now that we know the object header, reload bits.
+ off = (uintptr*)obj - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+ if(CollectStats)
+ runtime·xadd64(&gcstats.flushptrbuf.foundspan, 1);
- found:
- // Now we have bits, bitp, and shift correct for
- // obj pointing at the base of the object.
- // Only care about allocated and not marked.
- if((bits & (bitAllocated|bitMarked)) != bitAllocated)
- continue;
- if(work.nproc == 1)
- *bitp |= bitMarked<<shift;
- else {
- for(;;) {
- x = *bitp;
- if(x & (bitMarked<<shift))
- goto continue_obj;
- if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
- break;
- }
+ found:
+ // Now we have bits, bitp, and shift correct for
+ // obj pointing at the base of the object.
+ // Only care about allocated and not marked.
+ if((bits & (bitAllocated|bitMarked)) != bitAllocated)
+ continue;
+ if(work.nproc == 1)
+ *bitp |= bitMarked<<shift;
+ else {
+ for(;;) {
+ x = *bitp;
+ if(x & (bitMarked<<shift))
+ goto continue_obj;
+ if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+ break;
}
+ }
- // If object has no pointers, don't need to scan further.
- if((bits & bitNoScan) != 0)
- continue;
+ // If object has no pointers, don't need to scan further.
+ if((bits & bitScan) == 0)
+ continue;
- // Ask span about size class.
- // (Manually inlined copy of MHeap_Lookup.)
- x = (uintptr)obj >> PageShift;
- if(sizeof(void*) == 8)
- x -= (uintptr)arena_start>>PageShift;
- s = runtime·mheap.spans[x];
+ // Ask span about size class.
+ // (Manually inlined copy of MHeap_Lookup.)
+ x = (uintptr)obj >> PageShift;
+ x -= (uintptr)arena_start>>PageShift;
+ s = runtime·mheap.spans[x];
- PREFETCH(obj);
+ PREFETCH(obj);
- *wp = (Obj){obj, s->elemsize, ti};
- wp++;
- nobj++;
- continue_obj:;
- }
+ *wp = (Obj){obj, s->elemsize, ti};
+ wp++;
+ nobj++;
+ continue_obj:;
+ }
- // If another proc wants a pointer, give it some.
- if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
- wbuf->nobj = nobj;
- wbuf = handoff(wbuf);
- nobj = wbuf->nobj;
- wp = wbuf->obj + nobj;
- }
+ // If another proc wants a pointer, give it some.
+ if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
+ wbuf->nobj = nobj;
+ wbuf = handoff(wbuf);
+ nobj = wbuf->nobj;
+ wp = wbuf->obj + nobj;
}
- *_wp = wp;
- *_wbuf = wbuf;
- *_nobj = nobj;
+ sbuf->wp = wp;
+ sbuf->wbuf = wbuf;
+ sbuf->nobj = nobj;
}
static void
-flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushobjbuf(Scanbuf *sbuf)
{
uintptr nobj, off;
Obj *wp, obj;
Workbuf *wbuf;
+ Obj *objbuf;
Obj *objbuf_end;
- wp = *_wp;
- wbuf = *_wbuf;
- nobj = *_nobj;
+ wp = sbuf->wp;
+ wbuf = sbuf->wbuf;
+ nobj = sbuf->nobj;
- objbuf_end = *objbufpos;
- *objbufpos = objbuf;
+ objbuf = sbuf->obj.begin;
+ objbuf_end = sbuf->obj.pos;
+ sbuf->obj.pos = sbuf->obj.begin;
while(objbuf < objbuf_end) {
obj = *objbuf++;
@@ -570,9 +637,9 @@ flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_
wp = wbuf->obj + nobj;
}
- *_wp = wp;
- *_wbuf = wbuf;
- *_nobj = nobj;
+ sbuf->wp = wp;
+ sbuf->wbuf = wbuf;
+ sbuf->nobj = nobj;
}
// Program that scans the whole block and treats every block element as a potential pointer
@@ -607,8 +674,7 @@ checkptr(void *obj, uintptr objti)
if(t == nil)
return;
x = (uintptr)obj >> PageShift;
- if(sizeof(void*) == 8)
- x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
+ x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
s = runtime·mheap.spans[x];
objstart = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass != 0) {
@@ -636,8 +702,8 @@ checkptr(void *obj, uintptr objti)
// A simple best-effort check until first GC_END.
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
if(pc1[j] != pc2[j]) {
- runtime·printf("invalid gc type info for '%s' at %p, type info %p, block info %p\n",
- t->string ? (int8*)t->string->str : (int8*)"?", j, pc1[j], pc2[j]);
+ runtime·printf("invalid gc type info for '%s', type info %p [%d]=%p, block info %p [%d]=%p\n",
+ t->string ? (int8*)t->string->str : (int8*)"?", pc1, (int32)j, pc1[j], pc2, (int32)j, pc2[j]);
runtime·throw("invalid gc type info");
}
}
@@ -650,30 +716,27 @@ checkptr(void *obj, uintptr objti)
// a work list in the Workbuf* structures and loops in the main function
// body. Keeping an explicit work list is easier on the stack allocator and
// more efficient.
-//
-// wbuf: current work buffer
-// wp: storage for next queued pointer (write pointer)
-// nobj: number of queued objects
static void
-scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
+scanblock(Workbuf *wbuf, bool keepworking)
{
byte *b, *arena_start, *arena_used;
- uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
+ uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
uintptr *pc, precise_type, nominal_size;
uintptr *chan_ret, chancap;
void *obj;
- Type *t;
+ Type *t, *et;
Slice *sliceptr;
+ String *stringptr;
Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
BufferList *scanbuffers;
- PtrTarget *ptrbuf, *ptrbuf_end, *ptrbufpos;
- Obj *objbuf, *objbuf_end, *objbufpos;
+ Scanbuf sbuf;
Eface *eface;
Iface *iface;
Hchan *chan;
ChanType *chantype;
+ Obj *wp;
- if(sizeof(Workbuf) % PageSize != 0)
+ if(sizeof(Workbuf) % WorkbufSize != 0)
runtime·throw("scanblock: size of Workbuf is suboptimal");
// Memory arena parameters.
@@ -681,21 +744,30 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
arena_used = runtime·mheap.arena_used;
stack_ptr = stack+nelem(stack)-1;
-
+
precise_type = false;
nominal_size = 0;
- // Allocate ptrbuf
- {
- scanbuffers = &bufferList[m->helpgc];
- ptrbuf = &scanbuffers->ptrtarget[0];
- ptrbuf_end = &scanbuffers->ptrtarget[0] + nelem(scanbuffers->ptrtarget);
- objbuf = &scanbuffers->obj[0];
- objbuf_end = &scanbuffers->obj[0] + nelem(scanbuffers->obj);
+ if(wbuf) {
+ nobj = wbuf->nobj;
+ wp = &wbuf->obj[nobj];
+ } else {
+ nobj = 0;
+ wp = nil;
}
- ptrbufpos = ptrbuf;
- objbufpos = objbuf;
+ // Initialize sbuf
+ scanbuffers = &bufferList[m->helpgc];
+
+ sbuf.ptr.begin = sbuf.ptr.pos = &scanbuffers->ptrtarget[0];
+ sbuf.ptr.end = sbuf.ptr.begin + nelem(scanbuffers->ptrtarget);
+
+ sbuf.obj.begin = sbuf.obj.pos = &scanbuffers->obj[0];
+ sbuf.obj.end = sbuf.obj.begin + nelem(scanbuffers->obj);
+
+ sbuf.wbuf = wbuf;
+ sbuf.wp = wp;
+ sbuf.nobj = nobj;
// (Silence the compiler)
chan = nil;
@@ -707,17 +779,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
for(;;) {
// Each iteration scans the block b of length n, queueing pointers in
// the work buffer.
- if(Debug > 1) {
- runtime·printf("scanblock %p %D\n", b, (int64)n);
- }
if(CollectStats) {
runtime·xadd64(&gcstats.nbytes, n);
- runtime·xadd64(&gcstats.obj.sum, nobj);
+ runtime·xadd64(&gcstats.obj.sum, sbuf.nobj);
runtime·xadd64(&gcstats.obj.cnt, 1);
}
if(ti != 0) {
+ if(Debug > 1) {
+ runtime·printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
+ }
pc = (uintptr*)(ti & ~(uintptr)PC_BITS);
precise_type = (ti & PRECISE);
stack_top.elemsize = pc[0];
@@ -773,14 +845,22 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc = chanProg;
break;
default:
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D type %p %S\n", b, (int64)n, type, *t->string);
runtime·throw("scanblock: invalid type");
return;
}
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D type %p %S pc=%p\n", b, (int64)n, type, *t->string, pc);
} else {
pc = defaultProg;
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D unknown type\n", b, (int64)n);
}
} else {
pc = defaultProg;
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D no span types\n", b, (int64)n);
}
if(IgnorePreciseGC)
@@ -788,7 +868,6 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc++;
stack_top.b = (uintptr)b;
-
end_b = (uintptr)b + n - PtrSize;
for(;;) {
@@ -801,6 +880,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_PTR:
obj = *(void**)(stack_top.b + pc[1]);
objti = pc[2];
+ if(Debug > 2)
+ runtime·printf("gc_ptr @%p: %p ti=%p\n", stack_top.b+pc[1], obj, objti);
pc += 3;
if(Debug)
checkptr(obj, objti);
@@ -808,6 +889,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_SLICE:
sliceptr = (Slice*)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime·printf("gc_slice @%p: %p/%D/%D\n", sliceptr, sliceptr->array, (int64)sliceptr->len, (int64)sliceptr->cap);
if(sliceptr->cap != 0) {
obj = sliceptr->array;
// Can't use slice element type for scanning,
@@ -821,27 +904,34 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_APTR:
obj = *(void**)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime·printf("gc_aptr @%p: %p\n", stack_top.b+pc[1], obj);
pc += 2;
break;
case GC_STRING:
- obj = *(void**)(stack_top.b + pc[1]);
- markonly(obj);
+ stringptr = (String*)(stack_top.b + pc[1]);
+ if(Debug > 2)
+ runtime·printf("gc_string @%p: %p/%D\n", stack_top.b+pc[1], stringptr->str, (int64)stringptr->len);
+ if(stringptr->len != 0)
+ markonly(stringptr->str);
pc += 2;
continue;
case GC_EFACE:
eface = (Eface*)(stack_top.b + pc[1]);
pc += 2;
+ if(Debug > 2)
+ runtime·printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->type, eface->data);
if(eface->type == nil)
continue;
// eface->type
t = eface->type;
if((void*)t >= arena_start && (void*)t < arena_used) {
- *ptrbufpos++ = (PtrTarget){t, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){t, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// eface->data
@@ -851,8 +941,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
obj = eface->data;
- if((t->kind & ~KindNoPointers) == KindPtr)
- objti = (uintptr)((PtrType*)t)->elem->gc;
+ if((t->kind & ~KindNoPointers) == KindPtr) {
+ // Only use type information if it is a pointer-containing type.
+ // This matches the GC programs written by cmd/gc/reflect.c's
+ // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+ et = ((PtrType*)t)->elem;
+ if(!(et->kind & KindNoPointers))
+ objti = (uintptr)((PtrType*)t)->elem->gc;
+ }
} else {
obj = eface->data;
objti = (uintptr)t->gc;
@@ -863,14 +959,16 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_IFACE:
iface = (Iface*)(stack_top.b + pc[1]);
pc += 2;
+ if(Debug > 2)
+ runtime·printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], iface->tab, nil, iface->data);
if(iface->tab == nil)
continue;
// iface->tab
if((void*)iface->tab >= arena_start && (void*)iface->tab < arena_used) {
- *ptrbufpos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
// iface->data
@@ -881,8 +979,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
obj = iface->data;
- if((t->kind & ~KindNoPointers) == KindPtr)
- objti = (uintptr)((PtrType*)t)->elem->gc;
+ if((t->kind & ~KindNoPointers) == KindPtr) {
+ // Only use type information if it is a pointer-containing type.
+ // This matches the GC programs written by cmd/gc/reflect.c's
+ // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+ et = ((PtrType*)t)->elem;
+ if(!(et->kind & KindNoPointers))
+ objti = (uintptr)((PtrType*)t)->elem->gc;
+ }
} else {
obj = iface->data;
objti = (uintptr)t->gc;
@@ -893,11 +997,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_DEFAULT_PTR:
while(stack_top.b <= end_b) {
obj = *(byte**)stack_top.b;
+ if(Debug > 2)
+ runtime·printf("gc_default_ptr @%p: %p\n", stack_top.b, obj);
stack_top.b += PtrSize;
if(obj >= arena_start && obj < arena_used) {
- *ptrbufpos++ = (PtrTarget){obj, 0};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){obj, 0};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
}
goto next_block;
@@ -926,7 +1032,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
if(*(byte**)i != nil) {
// Found a value that may be a pointer.
// Do a rescan of the entire block.
- enqueue((Obj){b, n, 0}, &wbuf, &wp, &nobj);
+ enqueue((Obj){b, n, 0}, &sbuf.wbuf, &sbuf.wp, &sbuf.nobj);
if(CollectStats) {
runtime·xadd64(&gcstats.rescan, 1);
runtime·xadd64(&gcstats.rescanbytes, n);
@@ -972,13 +1078,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
objti = pc[3];
pc += 4;
- *objbufpos++ = (Obj){obj, size, objti};
- if(objbufpos == objbuf_end)
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ if(Debug > 2)
+ runtime·printf("gc_region @%p: %D %p\n", stack_top.b+pc[1], (int64)size, objti);
+ *sbuf.obj.pos++ = (Obj){obj, size, objti};
+ if(sbuf.obj.pos == sbuf.obj.end)
+ flushobjbuf(&sbuf);
continue;
case GC_CHAN_PTR:
chan = *(Hchan**)(stack_top.b + pc[1]);
+ if(Debug > 2 && chan != nil)
+ runtime·printf("gc_chan_ptr @%p: %p/%D/%D %p\n", stack_top.b+pc[1], chan, (int64)chan->qcount, (int64)chan->dataqsiz, pc[2]);
if(chan == nil) {
pc += 3;
continue;
@@ -1007,10 +1117,10 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
- *objbufpos++ = (Obj){(byte*)chan+runtime·Hchansize, chancap*chantype->elem->size,
+ *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime·Hchansize, chancap*chantype->elem->size,
(uintptr)chantype->elem->gc | PRECISE | LOOP};
- if(objbufpos == objbuf_end)
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ if(sbuf.obj.pos == sbuf.obj.end)
+ flushobjbuf(&sbuf);
}
}
if(chan_ret == nil)
@@ -1019,14 +1129,15 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
continue;
default:
+ runtime·printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
runtime·throw("scanblock: invalid GC instruction");
return;
}
if(obj >= arena_start && obj < arena_used) {
- *ptrbufpos++ = (PtrTarget){obj, objti};
- if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ *sbuf.ptr.pos++ = (PtrTarget){obj, objti};
+ if(sbuf.ptr.pos == sbuf.ptr.end)
+ flushptrbuf(&sbuf);
}
}
@@ -1034,109 +1145,31 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// Done scanning [b, b+n). Prepare for the next iteration of
// the loop by setting b, n, ti to the parameters for the next block.
- if(nobj == 0) {
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
- flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+ if(sbuf.nobj == 0) {
+ flushptrbuf(&sbuf);
+ flushobjbuf(&sbuf);
- if(nobj == 0) {
+ if(sbuf.nobj == 0) {
if(!keepworking) {
- if(wbuf)
- putempty(wbuf);
- goto endscan;
+ if(sbuf.wbuf)
+ putempty(sbuf.wbuf);
+ return;
}
// Emptied our buffer: refill.
- wbuf = getfull(wbuf);
- if(wbuf == nil)
- goto endscan;
- nobj = wbuf->nobj;
- wp = wbuf->obj + wbuf->nobj;
+ sbuf.wbuf = getfull(sbuf.wbuf);
+ if(sbuf.wbuf == nil)
+ return;
+ sbuf.nobj = sbuf.wbuf->nobj;
+ sbuf.wp = sbuf.wbuf->obj + sbuf.wbuf->nobj;
}
}
// Fetch b from the work buffer.
- --wp;
- b = wp->p;
- n = wp->n;
- ti = wp->ti;
- nobj--;
- }
-
-endscan:;
-}
-
-// debug_scanblock is the debug copy of scanblock.
-// it is simpler, slower, single-threaded, recursive,
-// and uses bitSpecial as the mark bit.
-static void
-debug_scanblock(byte *b, uintptr n)
-{
- byte *obj, *p;
- void **vp;
- uintptr size, *bitp, bits, shift, i, xbits, off;
- MSpan *s;
-
- if(!DebugMark)
- runtime·throw("debug_scanblock without DebugMark");
-
- if((intptr)n < 0) {
- runtime·printf("debug_scanblock %p %D\n", b, (int64)n);
- runtime·throw("debug_scanblock");
- }
-
- // Align b to a word boundary.
- off = (uintptr)b & (PtrSize-1);
- if(off != 0) {
- b += PtrSize - off;
- n -= PtrSize - off;
- }
-
- vp = (void**)b;
- n /= PtrSize;
- for(i=0; i<n; i++) {
- obj = (byte*)vp[i];
-
- // Words outside the arena cannot be pointers.
- if((byte*)obj < runtime·mheap.arena_start || (byte*)obj >= runtime·mheap.arena_used)
- continue;
-
- // Round down to word boundary.
- obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
-
- // Consult span table to find beginning.
- s = runtime·MHeap_LookupMaybe(&runtime·mheap, obj);
- if(s == nil)
- continue;
-
- p = (byte*)((uintptr)s->start<<PageShift);
- size = s->elemsize;
- if(s->sizeclass == 0) {
- obj = p;
- } else {
- int32 i = ((byte*)obj - p)/size;
- obj = p+i*size;
- }
-
- // Now that we know the object header, reload bits.
- off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start;
- bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
-
- // Now we have bits, bitp, and shift correct for
- // obj pointing at the base of the object.
- // If not allocated or already marked, done.
- if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0) // NOTE: bitSpecial not bitMarked
- continue;
- *bitp |= bitSpecial<<shift;
- if(!(bits & bitMarked))
- runtime·printf("found unmarked block %p in %p\n", obj, vp+i);
-
- // If object has no pointers, don't need to scan further.
- if((bits & bitNoScan) != 0)
- continue;
-
- debug_scanblock(obj, size);
+ --sbuf.wp;
+ b = sbuf.wp->p;
+ n = sbuf.wp->n;
+ ti = sbuf.wp->ti;
+ sbuf.nobj--;
}
}
@@ -1196,18 +1229,102 @@ enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj)
}
static void
+enqueue1(Workbuf **wbufp, Obj obj)
+{
+ Workbuf *wbuf;
+
+ wbuf = *wbufp;
+ if(wbuf->nobj >= nelem(wbuf->obj))
+ *wbufp = wbuf = getempty(wbuf);
+ wbuf->obj[wbuf->nobj++] = obj;
+}
+
+static void
markroot(ParFor *desc, uint32 i)
{
- Obj *wp;
Workbuf *wbuf;
- uintptr nobj;
+ FinBlock *fb;
+ MHeap *h;
+ MSpan **allspans, *s;
+ uint32 spanidx, sg;
+ G *gp;
+ void *p;
USED(&desc);
- wp = nil;
- wbuf = nil;
- nobj = 0;
- enqueue(work.roots[i], &wbuf, &wp, &nobj);
- scanblock(wbuf, wp, nobj, false);
+ wbuf = getempty(nil);
+ // Note: if you add a case here, please also update heapdump.c:dumproots.
+ switch(i) {
+ case RootData:
+ enqueue1(&wbuf, (Obj){data, edata - data, (uintptr)gcdata});
+ break;
+
+ case RootBss:
+ enqueue1(&wbuf, (Obj){bss, ebss - bss, (uintptr)gcbss});
+ break;
+
+ case RootFinalizers:
+ for(fb=allfin; fb; fb=fb->alllink)
+ enqueue1(&wbuf, (Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
+ break;
+
+ case RootSpanTypes:
+ // mark span types and MSpan.specials (to walk spans only once)
+ h = &runtime·mheap;
+ sg = h->sweepgen;
+ allspans = h->allspans;
+ for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+ Special *sp;
+ SpecialFinalizer *spf;
+
+ s = allspans[spanidx];
+ if(s->sweepgen != sg) {
+ runtime·printf("sweep %d %d\n", s->sweepgen, sg);
+ runtime·throw("gc: unswept span");
+ }
+ if(s->state != MSpanInUse)
+ continue;
+ // The garbage collector ignores type pointers stored in MSpan.types:
+ // - Compiler-generated types are stored outside of heap.
+ // - The reflect package has runtime-generated types cached in its data structures.
+ // The garbage collector relies on finding the references via that cache.
+ if(s->types.compression == MTypes_Words || s->types.compression == MTypes_Bytes)
+ markonly((byte*)s->types.data);
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialFinalizer)
+ continue;
+ // don't mark finalized object, but scan it so we
+ // retain everything it points to.
+ spf = (SpecialFinalizer*)sp;
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p = (void*)((s->start << PageShift) + spf->offset/s->elemsize*s->elemsize);
+ enqueue1(&wbuf, (Obj){p, s->elemsize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->fint, PtrSize, 0});
+ enqueue1(&wbuf, (Obj){(void*)&spf->ot, PtrSize, 0});
+ }
+ }
+ break;
+
+ case RootFlushCaches:
+ flushallmcaches();
+ break;
+
+ default:
+ // the rest is scanning goroutine stacks
+ if(i - RootCount >= runtime·allglen)
+ runtime·throw("markroot: bad index");
+ gp = runtime·allg[i - RootCount];
+ // remember when we've first observed the G blocked
+ // needed only to output in traceback
+ if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0)
+ gp->waitsince = work.tstart;
+ addstackroots(gp, &wbuf);
+ break;
+
+ }
+
+ if(wbuf)
+ scanblock(wbuf, false);
}
// Get an empty work buffer off the work.empty list,
@@ -1304,43 +1421,20 @@ handoff(Workbuf *b)
return b1;
}
-static void
-addroot(Obj obj)
-{
- uint32 cap;
- Obj *new;
-
- if(work.nroot >= work.rootcap) {
- cap = PageSize/sizeof(Obj);
- if(cap < 2*work.rootcap)
- cap = 2*work.rootcap;
- new = (Obj*)runtime·SysAlloc(cap*sizeof(Obj), &mstats.gc_sys);
- if(new == nil)
- runtime·throw("runtime: cannot allocate memory");
- if(work.roots != nil) {
- runtime·memmove(new, work.roots, work.rootcap*sizeof(Obj));
- runtime·SysFree(work.roots, work.rootcap*sizeof(Obj), &mstats.gc_sys);
- }
- work.roots = new;
- work.rootcap = cap;
- }
- work.roots[work.nroot] = obj;
- work.nroot++;
-}
-
extern byte pclntab[]; // base for f->ptrsoff
-typedef struct BitVector BitVector;
-struct BitVector
+BitVector
+runtime·stackmapdata(StackMap *stackmap, int32 n)
{
- int32 n;
- uint32 data[];
-};
+ if(n < 0 || n >= stackmap->n)
+ runtime·throw("stackmapdata: index out of range");
+ return (BitVector){stackmap->nbit, stackmap->data + n*((stackmap->nbit+31)/32)};
+}
// Scans an interface data value when the interface type indicates
// that it is a pointer.
static void
-scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
+scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue, void *wbufp)
{
Itab *tab;
Type *type;
@@ -1356,16 +1450,17 @@ scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
return;
}
}
- addroot((Obj){scanp+PtrSize, PtrSize, 0});
+ enqueue1(wbufp, (Obj){scanp+PtrSize, PtrSize, 0});
}
// Starting from scanp, scans words corresponding to set bits.
static void
-scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
+scanbitvector(Func *f, bool precise, byte *scanp, BitVector *bv, bool afterprologue, void *wbufp)
{
uintptr word, bits;
uint32 *wordp;
int32 i, remptrs;
+ byte *p;
wordp = bv->data;
for(remptrs = bv->n; remptrs > 0; remptrs -= 32) {
@@ -1377,11 +1472,88 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
i /= BitsPerPointer;
for(; i > 0; i--) {
bits = word & 3;
- if(bits != BitsNoPointer && *(void**)scanp != nil)
- if(bits == BitsPointer)
- addroot((Obj){scanp, PtrSize, 0});
- else
- scaninterfacedata(bits, scanp, afterprologue);
+ switch(bits) {
+ case BitsDead:
+ if(runtime·debug.gcdead)
+ *(uintptr*)scanp = PoisonGC;
+ break;
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ p = *(byte**)scanp;
+ if(p != nil) {
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: ptr %p\n", runtime·funcname(f), scanp, p);
+ if(precise && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+ // Looks like a junk value in a pointer slot.
+ // Liveness analysis wrong?
+ m->traceback = 2;
+ runtime·printf("bad pointer in frame %s at %p: %p\n", runtime·funcname(f), scanp, p);
+ runtime·throw("bad pointer in scanbitvector");
+ }
+ enqueue1(wbufp, (Obj){scanp, PtrSize, 0});
+ }
+ break;
+ case BitsMultiWord:
+ p = scanp;
+ word >>= BitsPerPointer;
+ scanp += PtrSize;
+ i--;
+ if(i == 0) {
+ // Get next chunk of bits
+ remptrs -= 32;
+ word = *wordp++;
+ if(remptrs < 32)
+ i = remptrs;
+ else
+ i = 32;
+ i /= BitsPerPointer;
+ }
+ switch(word & 3) {
+ case BitsString:
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: string %p/%D\n", runtime·funcname(f), p, ((String*)p)->str, (int64)((String*)p)->len);
+ if(((String*)p)->len != 0)
+ markonly(((String*)p)->str);
+ break;
+ case BitsSlice:
+ word >>= BitsPerPointer;
+ scanp += PtrSize;
+ i--;
+ if(i == 0) {
+ // Get next chunk of bits
+ remptrs -= 32;
+ word = *wordp++;
+ if(remptrs < 32)
+ i = remptrs;
+ else
+ i = 32;
+ i /= BitsPerPointer;
+ }
+ if(Debug > 2)
+ runtime·printf("frame %s @%p: slice %p/%D/%D\n", runtime·funcname(f), p, ((Slice*)p)->array, (int64)((Slice*)p)->len, (int64)((Slice*)p)->cap);
+ if(((Slice*)p)->cap < ((Slice*)p)->len) {
+ m->traceback = 2;
+ runtime·printf("bad slice in frame %s at %p: %p/%p/%p\n", runtime·funcname(f), p, ((byte**)p)[0], ((byte**)p)[1], ((byte**)p)[2]);
+ runtime·throw("slice capacity smaller than length");
+ }
+ if(((Slice*)p)->cap != 0)
+ enqueue1(wbufp, (Obj){p, PtrSize, 0});
+ break;
+ case BitsIface:
+ case BitsEface:
+ if(*(byte**)p != nil) {
+ if(Debug > 2) {
+ if((word&3) == BitsEface)
+ runtime·printf("frame %s @%p: eface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+ else
+ runtime·printf("frame %s @%p: iface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+ }
+ scaninterfacedata(word & 3, p, afterprologue, wbufp);
+ }
+ break;
+ }
+ }
word >>= BitsPerPointer;
scanp += PtrSize;
}
@@ -1389,64 +1561,111 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
}
// Scan a stack frame: local variables and function arguments/results.
-static void
-addframeroots(Stkframe *frame, void*)
+static bool
+scanframe(Stkframe *frame, void *wbufp)
{
Func *f;
- BitVector *args, *locals;
+ StackMap *stackmap;
+ BitVector bv;
uintptr size;
+ uintptr targetpc;
+ int32 pcdata;
bool afterprologue;
+ bool precise;
f = frame->fn;
+ targetpc = frame->continpc;
+ if(targetpc == 0) {
+ // Frame is dead.
+ return true;
+ }
+ if(targetpc != f->entry)
+ targetpc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+ if(pcdata == -1) {
+ // We do not have a valid pcdata value but there might be a
+ // stackmap for this function. It is likely that we are looking
+ // at the function prologue, assume so and hope for the best.
+ pcdata = 0;
+ }
// Scan local variables if stack frame has been allocated.
// Use pointer information if known.
afterprologue = (frame->varp > (byte*)frame->sp);
+ precise = false;
if(afterprologue) {
- locals = runtime·funcdata(f, FUNCDATA_GCLocals);
- if(locals == nil) {
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil) {
// No locals information, scan everything.
size = frame->varp - (byte*)frame->sp;
- addroot((Obj){frame->varp - size, size, 0});
- } else if(locals->n < 0) {
- // Locals size information, scan just the
+ if(Debug > 2)
+ runtime·printf("frame %s unsized locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+ enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+ } else if(stackmap->n < 0) {
+ // Locals size information, scan just the locals.
+ size = -stackmap->n;
+ if(Debug > 2)
+ runtime·printf("frame %s conservative locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+ enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+ } else if(stackmap->n > 0) {
+ // Locals bitmap information, scan just the pointers in
// locals.
- size = -locals->n;
- addroot((Obj){frame->varp - size, size, 0});
- } else if(locals->n > 0) {
- // Locals bitmap information, scan just the
- // pointers in locals.
- size = (locals->n*PtrSize) / BitsPerPointer;
- scanbitvector(frame->varp - size, locals, afterprologue);
+ if(pcdata < 0 || pcdata >= stackmap->n) {
+ // don't know where we are
+ runtime·printf("pcdata is %d and %d stack map entries for %s (targetpc=%p)\n",
+ pcdata, stackmap->n, runtime·funcname(f), targetpc);
+ runtime·throw("scanframe: bad symbol table");
+ }
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ size = (bv.n * PtrSize) / BitsPerPointer;
+ precise = true;
+ scanbitvector(f, true, frame->varp - size, &bv, afterprologue, wbufp);
}
}
// Scan arguments.
// Use pointer information if known.
- args = runtime·funcdata(f, FUNCDATA_GCArgs);
- if(args != nil && args->n > 0)
- scanbitvector(frame->argp, args, false);
- else
- addroot((Obj){frame->argp, frame->arglen, 0});
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap != nil) {
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ scanbitvector(f, precise, frame->argp, &bv, true, wbufp);
+ } else {
+ if(Debug > 2)
+ runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+ enqueue1(wbufp, (Obj){frame->argp, frame->arglen, 0});
+ }
+ return true;
}
static void
-addstackroots(G *gp)
+addstackroots(G *gp, Workbuf **wbufp)
{
M *mp;
int32 n;
Stktop *stk;
- uintptr sp, guard, pc, lr;
+ uintptr sp, guard;
void *base;
uintptr size;
- stk = (Stktop*)gp->stackbase;
- guard = gp->stackguard;
+ switch(gp->status){
+ default:
+ runtime·printf("unexpected G.status %d (goroutine %p %D)\n", gp->status, gp, gp->goid);
+ runtime·throw("mark - bad status");
+ case Gdead:
+ return;
+ case Grunning:
+ runtime·throw("mark - world not stopped");
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ break;
+ }
if(gp == g)
runtime·throw("can't scan our own stack");
if((mp = gp->m) != nil && mp->helpgc)
runtime·throw("can't scan gchelper stack");
+
if(gp->syscallstack != (uintptr)nil) {
// Scanning another goroutine that is about to enter or might
// have just exited a system call. It may be executing code such
@@ -1454,35 +1673,33 @@ addstackroots(G *gp)
// Use the stack segment and stack pointer at the time of
// the system call instead, since that won't change underfoot.
sp = gp->syscallsp;
- pc = gp->syscallpc;
- lr = 0;
stk = (Stktop*)gp->syscallstack;
guard = gp->syscallguard;
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
sp = gp->sched.sp;
- pc = gp->sched.pc;
- lr = gp->sched.lr;
-
+ stk = (Stktop*)gp->stackbase;
+ guard = gp->stackguard;
// For function about to start, context argument is a root too.
if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base, &size, nil))
- addroot((Obj){base, size, 0});
+ enqueue1(wbufp, (Obj){base, size, 0});
}
if(ScanStackByFrames) {
+ USED(sp);
USED(stk);
USED(guard);
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil, false);
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, scanframe, wbufp, false);
} else {
- USED(lr);
- USED(pc);
n = 0;
while(stk) {
if(sp < guard-StackGuard || (uintptr)stk < sp) {
runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
runtime·throw("scanstack");
}
- addroot((Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
+ if(Debug > 2)
+ runtime·printf("conservative stack %p+%p\n", (byte*)sp, (uintptr)stk-sp);
+ enqueue1(wbufp, (Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
sp = stk->gobuf.sp;
guard = stk->stackguard;
stk = (Stktop*)stk->stackbase;
@@ -1491,101 +1708,17 @@ addstackroots(G *gp)
}
}
-static void
-addfinroots(void *v)
-{
- uintptr size;
- void *base;
-
- size = 0;
- if(!runtime·mlookup(v, &base, &size, nil) || !runtime·blockspecial(base))
- runtime·throw("mark - finalizer inconsistency");
-
- // do not mark the finalizer block itself. just mark the things it points at.
- addroot((Obj){base, size, 0});
-}
-
-static void
-addroots(void)
-{
- G *gp;
- FinBlock *fb;
- MSpan *s, **allspans;
- uint32 spanidx;
-
- work.nroot = 0;
-
- // data & bss
- // TODO(atom): load balancing
- addroot((Obj){data, edata - data, (uintptr)gcdata});
- addroot((Obj){bss, ebss - bss, (uintptr)gcbss});
-
- // MSpan.types
- allspans = runtime·mheap.allspans;
- for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
- s = allspans[spanidx];
- if(s->state == MSpanInUse) {
- // The garbage collector ignores type pointers stored in MSpan.types:
- // - Compiler-generated types are stored outside of heap.
- // - The reflect package has runtime-generated types cached in its data structures.
- // The garbage collector relies on finding the references via that cache.
- switch(s->types.compression) {
- case MTypes_Empty:
- case MTypes_Single:
- break;
- case MTypes_Words:
- case MTypes_Bytes:
- markonly((byte*)s->types.data);
- break;
- }
- }
- }
-
- // stacks
- for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
- switch(gp->status){
- default:
- runtime·printf("unexpected G.status %d\n", gp->status);
- runtime·throw("mark - bad status");
- case Gdead:
- break;
- case Grunning:
- runtime·throw("mark - world not stopped");
- case Grunnable:
- case Gsyscall:
- case Gwaiting:
- addstackroots(gp);
- break;
- }
- }
-
- runtime·walkfintab(addfinroots);
-
- for(fb=allfin; fb; fb=fb->alllink)
- addroot((Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
-}
-
-static bool
-handlespecial(byte *p, uintptr size)
+void
+runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
{
- FuncVal *fn;
- uintptr nret;
- PtrType *ot;
- Type *fint;
FinBlock *block;
Finalizer *f;
- if(!runtime·getfinalizer(p, true, &fn, &nret, &fint, &ot)) {
- runtime·setblockspecial(p, false);
- runtime·MProf_Free(p, size);
- return false;
- }
-
runtime·lock(&finlock);
if(finq == nil || finq->cnt == finq->cap) {
if(finc == nil) {
- finc = runtime·persistentalloc(PageSize, 0, &mstats.gc_sys);
- finc->cap = (PageSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
+ finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
+ finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
finc->alllink = allfin;
allfin = finc;
}
@@ -1601,33 +1734,79 @@ handlespecial(byte *p, uintptr size)
f->fint = fint;
f->ot = ot;
f->arg = p;
+ runtime·fingwake = true;
runtime·unlock(&finlock);
- return true;
+}
+
+void
+runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
+{
+ FinBlock *fb;
+ Finalizer *f;
+ uintptr i;
+
+ for(fb = allfin; fb; fb = fb->alllink) {
+ for(i = 0; i < fb->cnt; i++) {
+ f = &fb->fin[i];
+ callback(f->fn, f->arg, f->nret, f->fint, f->ot);
+ }
+ }
+}
+
+void
+runtime·MSpan_EnsureSwept(MSpan *s)
+{
+ uint32 sg;
+
+ // Caller must disable preemption.
+ // Otherwise when this function returns the span can become unswept again
+ // (if GC is triggered on another goroutine).
+ if(m->locks == 0 && m->mallocing == 0 && g != m->g0)
+ runtime·throw("MSpan_EnsureSwept: m is not locked");
+
+ sg = runtime·mheap.sweepgen;
+ if(runtime·atomicload(&s->sweepgen) == sg)
+ return;
+ if(runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime·MSpan_Sweep(s);
+ return;
+ }
+ // unfortunate condition, and we don't have efficient means to wait
+ while(runtime·atomicload(&s->sweepgen) != sg)
+ runtime·osyield();
}
// Sweep frees or collects finalizers for blocks not marked in the mark phase.
// It clears the mark bits in preparation for the next GC round.
-static void
-sweepspan(ParFor *desc, uint32 idx)
+// Returns true if the span was returned to heap.
+bool
+runtime·MSpan_Sweep(MSpan *s)
{
- int32 cl, n, npages;
- uintptr size;
+ int32 cl, n, npages, nfree;
+ uintptr size, off, *bitp, shift, bits;
+ uint32 sweepgen;
byte *p;
MCache *c;
byte *arena_start;
MLink head, *end;
- int32 nfree;
byte *type_data;
byte compression;
uintptr type_data_inc;
- MSpan *s;
-
- USED(&desc);
- s = runtime·mheap.allspans[idx];
- if(s->state != MSpanInUse)
- return;
+ MLink *x;
+ Special *special, **specialp, *y;
+ bool res, sweepgenset;
+
+ // It's critical that we enter this function with preemption disabled,
+ // GC must not start while we are in the middle of this function.
+ if(m->locks == 0 && m->mallocing == 0 && g != m->g0)
+ runtime·throw("MSpan_Sweep: m is not locked");
+ sweepgen = runtime·mheap.sweepgen;
+ if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+ runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+ s->state, s->sweepgen, sweepgen);
+ runtime·throw("MSpan_Sweep: bad span state");
+ }
arena_start = runtime·mheap.arena_start;
- p = (byte*)(s->start << PageShift);
cl = s->sizeclass;
size = s->elemsize;
if(cl == 0) {
@@ -1637,10 +1816,52 @@ sweepspan(ParFor *desc, uint32 idx)
npages = runtime·class_to_allocnpages[cl];
n = (npages << PageShift) / size;
}
+ res = false;
nfree = 0;
end = &head;
c = m->mcache;
-
+ sweepgenset = false;
+
+ // mark any free objects in this span so we don't collect them
+ for(x = s->freelist; x != nil; x = x->next) {
+ // This is markonly(x) but faster because we don't need
+ // atomic access and we're guaranteed to be pointing at
+ // the head of a valid object.
+ off = (uintptr*)x - (uintptr*)runtime·mheap.arena_start;
+ bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ *bitp |= bitMarked<<shift;
+ }
+
+ // Unlink & free special records for any objects we're about to free.
+ specialp = &s->specials;
+ special = *specialp;
+ while(special != nil) {
+ // A finalizer can be set for an inner byte of an object, find object beginning.
+ p = (byte*)(s->start << PageShift) + special->offset/size*size;
+ off = (uintptr*)p - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ bits = *bitp>>shift;
+ if((bits & (bitAllocated|bitMarked)) == bitAllocated) {
+ // Find the exact byte for which the special was setup
+ // (as opposed to object beginning).
+ p = (byte*)(s->start << PageShift) + special->offset;
+ // about to free object: splice out special record
+ y = special;
+ special = special->next;
+ *specialp = special;
+ if(!runtime·freespecial(y, p, size, false)) {
+ // stop freeing of object if it has a finalizer
+ *bitp |= bitMarked << shift;
+ }
+ } else {
+ // object is still live: keep special record
+ specialp = &special->next;
+ special = *specialp;
+ }
+ }
+
type_data = (byte*)s->types.data;
type_data_inc = sizeof(uintptr);
compression = s->types.compression;
@@ -1654,9 +1875,8 @@ sweepspan(ParFor *desc, uint32 idx)
// Sweep through n objects of given size starting at p.
// This thread owns the span now, so it can manipulate
// the block bitmap without atomic operations.
+ p = (byte*)(s->start << PageShift);
for(; n > 0; n--, p += size, type_data+=type_data_inc) {
- uintptr off, *bitp, shift, bits;
-
off = (uintptr*)p - (uintptr*)arena_start;
bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
@@ -1666,33 +1886,32 @@ sweepspan(ParFor *desc, uint32 idx)
continue;
if((bits & bitMarked) != 0) {
- if(DebugMark) {
- if(!(bits & bitSpecial))
- runtime·printf("found spurious mark on %p\n", p);
- *bitp &= ~(bitSpecial<<shift);
- }
*bitp &= ~(bitMarked<<shift);
continue;
}
- // Special means it has a finalizer or is being profiled.
- // In DebugMark mode, the bit has been coopted so
- // we have to assume all blocks are special.
- if(DebugMark || (bits & bitSpecial) != 0) {
- if(handlespecial(p, size))
- continue;
- }
+ if(runtime·debug.allocfreetrace)
+ runtime·tracefree(p, size);
- // Mark freed; restore block boundary bit.
- *bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ // Clear mark and scan bits.
+ *bitp &= ~((bitScan|bitMarked)<<shift);
if(cl == 0) {
// Free large span.
runtime·unmarkspan(p, 1<<PageShift);
- *(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll; // needs zeroing
- runtime·MHeap_Free(&runtime·mheap, s, 1);
+ s->needzero = 1;
+ // important to set sweepgen before returning it to heap
+ runtime·atomicstore(&s->sweepgen, sweepgen);
+ sweepgenset = true;
+ // See note about SysFault vs SysFree in malloc.goc.
+ if(runtime·debug.efence)
+ runtime·SysFault(p, size);
+ else
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
c->local_nlargefree++;
c->local_largefree += size;
+ runtime·xadd64(&mstats.next_gc, -(uint64)(size * (gcpercent + 100)/100));
+ res = true;
} else {
// Free small object.
switch(compression) {
@@ -1703,19 +1922,113 @@ sweepspan(ParFor *desc, uint32 idx)
*(byte*)type_data = 0;
break;
}
- if(size > sizeof(uintptr))
+ if(size > 2*sizeof(uintptr))
((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll; // mark as "needs to be zeroed"
-
+ else if(size > sizeof(uintptr))
+ ((uintptr*)p)[1] = 0;
+
end->next = (MLink*)p;
end = (MLink*)p;
nfree++;
}
}
- if(nfree) {
+ // We need to set s->sweepgen = h->sweepgen only when all blocks are swept,
+ // because of the potential for a concurrent free/SetFinalizer.
+ // But we need to set it before we make the span available for allocation
+ // (return it to heap or mcentral), because allocation code assumes that a
+ // span is already swept if available for allocation.
+
+ if(!sweepgenset && nfree == 0) {
+ // The span must be in our exclusive ownership until we update sweepgen,
+ // check for potential races.
+ if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+ runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+ s->state, s->sweepgen, sweepgen);
+ runtime·throw("MSpan_Sweep: bad span state after sweep");
+ }
+ runtime·atomicstore(&s->sweepgen, sweepgen);
+ }
+ if(nfree > 0) {
c->local_nsmallfree[cl] += nfree;
c->local_cachealloc -= nfree * size;
- runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree, head.next, end);
+ runtime·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
+ res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree, head.next, end);
+ //MCentral_FreeSpan updates sweepgen
+ }
+ return res;
+}
+
+// State of background sweep.
+// Pretected by gclock.
+static struct
+{
+ G* g;
+ bool parked;
+
+ MSpan** spans;
+ uint32 nspan;
+ uint32 spanidx;
+} sweep;
+
+// background sweeping goroutine
+static void
+bgsweep(void)
+{
+ g->issystem = 1;
+ for(;;) {
+ while(runtime·sweepone() != -1) {
+ gcstats.nbgsweep++;
+ runtime·gosched();
+ }
+ runtime·lock(&gclock);
+ if(!runtime·mheap.sweepdone) {
+ // It's possible if GC has happened between sweepone has
+ // returned -1 and gclock lock.
+ runtime·unlock(&gclock);
+ continue;
+ }
+ sweep.parked = true;
+ g->isbackground = true;
+ runtime·parkunlock(&gclock, "GC sweep wait");
+ g->isbackground = false;
+ }
+}
+
+// sweeps one span
+// returns number of pages returned to heap, or -1 if there is nothing to sweep
+uintptr
+runtime·sweepone(void)
+{
+ MSpan *s;
+ uint32 idx, sg;
+ uintptr npages;
+
+ // increment locks to ensure that the goroutine is not preempted
+ // in the middle of sweep thus leaving the span in an inconsistent state for next GC
+ m->locks++;
+ sg = runtime·mheap.sweepgen;
+ for(;;) {
+ idx = runtime·xadd(&sweep.spanidx, 1) - 1;
+ if(idx >= sweep.nspan) {
+ runtime·mheap.sweepdone = true;
+ m->locks--;
+ return -1;
+ }
+ s = sweep.spans[idx];
+ if(s->state != MSpanInUse) {
+ s->sweepgen = sg;
+ continue;
+ }
+ if(s->sweepgen != sg-2 || !runtime·cas(&s->sweepgen, sg-2, sg-1))
+ continue;
+ if(s->incache)
+ runtime·throw("sweep of incache span");
+ npages = s->npages;
+ if(!runtime·MSpan_Sweep(s))
+ npages = 0;
+ m->locks--;
+ return npages;
}
}
@@ -1727,7 +2040,7 @@ dumpspan(uint32 idx)
byte *p;
byte *arena_start;
MSpan *s;
- bool allocated, special;
+ bool allocated;
s = runtime·mheap.allspans[idx];
if(s->state != MSpanInUse)
@@ -1754,7 +2067,6 @@ dumpspan(uint32 idx)
bits = *bitp>>shift;
allocated = ((bits & bitAllocated) != 0);
- special = ((bits & bitSpecial) != 0);
for(i=0; i<size; i+=sizeof(void*)) {
if(column == 0) {
@@ -1762,7 +2074,6 @@ dumpspan(uint32 idx)
}
if(i == 0) {
runtime·printf(allocated ? "(" : "[");
- runtime·printf(special ? "@" : "");
runtime·printf("%p: ", p+i);
} else {
runtime·printf(" ");
@@ -1798,42 +2109,24 @@ runtime·memorydump(void)
void
runtime·gchelper(void)
{
- int32 nproc;
+ uint32 nproc;
+ m->traceback = 2;
gchelperstart();
// parallel mark for over gc roots
runtime·parfordo(work.markfor);
// help other threads scan secondary blocks
- scanblock(nil, nil, 0, true);
-
- if(DebugMark) {
- // wait while the main thread executes mark(debug_scanblock)
- while(runtime·atomicload(&work.debugmarkdone) == 0)
- runtime·usleep(10);
- }
+ scanblock(nil, true);
- runtime·parfordo(work.sweepfor);
bufferList[m->helpgc].busy = 0;
nproc = work.nproc; // work.nproc can change right after we increment work.ndone
if(runtime·xadd(&work.ndone, +1) == nproc-1)
runtime·notewakeup(&work.alldone);
+ m->traceback = 0;
}
-#define GcpercentUnknown (-2)
-
-// Initialized from $GOGC. GOGC=off means no gc.
-//
-// Next gc is after we've allocated an extra amount of
-// memory proportional to the amount already in use.
-// If gcpercent=100 and we're using 4M, we'll gc again
-// when we get to 8M. This keeps the gc cost in linear
-// proportion to the allocation cost. Adjusting gcpercent
-// just changes the linear constant (and also the amount of
-// extra memory used).
-static int32 gcpercent = GcpercentUnknown;
-
static void
cachestats(void)
{
@@ -1849,12 +2142,25 @@ cachestats(void)
}
static void
-updatememstats(GCStats *stats)
+flushallmcaches(void)
+{
+ P *p, **pp;
+ MCache *c;
+
+ // Flush MCache's to MCentral.
+ for(pp=runtime·allp; p=*pp; pp++) {
+ c = p->mcache;
+ if(c==nil)
+ continue;
+ runtime·MCache_ReleaseAll(c);
+ }
+}
+
+void
+runtime·updatememstats(GCStats *stats)
{
M *mp;
MSpan *s;
- MCache *c;
- P *p, **pp;
int32 i;
uint64 stacks_inuse, smallfree;
uint64 *src, *dst;
@@ -1895,12 +2201,7 @@ updatememstats(GCStats *stats)
}
// Flush MCache's to MCentral.
- for(pp=runtime·allp; p=*pp; pp++) {
- c = p->mcache;
- if(c==nil)
- continue;
- runtime·MCache_ReleaseAll(c);
- }
+ flushallmcaches();
// Aggregate local stats.
cachestats();
@@ -1942,6 +2243,7 @@ updatememstats(GCStats *stats)
struct gc_args
{
int64 start_time; // start time of GC in ns (just before stoptheworld)
+ bool eagersweep;
};
static void gc(struct gc_args *args);
@@ -1960,8 +2262,8 @@ readgogc(void)
return runtime·atoi(p);
}
-static FuncVal runfinqv = {runfinq};
-
+// force = 1 - do GC regardless of current heap usage
+// force = 2 - go GC and eager sweep
void
runtime·gc(int32 force)
{
@@ -1997,7 +2299,7 @@ runtime·gc(int32 force)
return;
runtime·semacquire(&runtime·worldsema, false);
- if(!force && mstats.heap_alloc < mstats.next_gc) {
+ if(force==0 && mstats.heap_alloc < mstats.next_gc) {
// typically threads which lost the race to grab
// worldsema exit here when gc is done.
runtime·semrelease(&runtime·worldsema);
@@ -2006,22 +2308,25 @@ runtime·gc(int32 force)
// Ok, we're doing it! Stop everybody else
a.start_time = runtime·nanotime();
+ a.eagersweep = force >= 2;
m->gcing = 1;
runtime·stoptheworld();
+ clearpools();
+
// Run gc on the g0 stack. We do this so that the g stack
// we're currently running on will no longer change. Cuts
// the root set down a bit (g0 stacks are not scanned, and
// we don't need to scan gc's internal state). Also an
// enabler for copyable stacks.
for(i = 0; i < (runtime·debug.gctrace > 1 ? 2 : 1); i++) {
+ if(i > 0)
+ a.start_time = runtime·nanotime();
// switch to g0, call gc(&a), then switch back
g->param = &a;
g->status = Gwaiting;
g->waitreason = "garbage collection";
runtime·mcall(mgc);
- // record a new start time in case we're going around again
- a.start_time = runtime·nanotime();
}
// all done
@@ -2032,19 +2337,10 @@ runtime·gc(int32 force)
m->locks--;
// now that gc is done, kick off finalizer thread if needed
- if(finq != nil) {
- runtime·lock(&finlock);
- // kick off or wake up goroutine to run queued finalizers
- if(fing == nil)
- fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
- else if(fingwait) {
- fingwait = 0;
- runtime·ready(fing);
- }
- runtime·unlock(&finlock);
+ if(!ConcurrentSweep) {
+ // give the queued finalizers, if any, a chance to run
+ runtime·gosched();
}
- // give the queued finalizers, if any, a chance to run
- runtime·gosched();
}
static void
@@ -2060,33 +2356,24 @@ static void
gc(struct gc_args *args)
{
int64 t0, t1, t2, t3, t4;
- uint64 heap0, heap1, obj0, obj1, ninstr;
+ uint64 heap0, heap1, obj, ninstr;
GCStats stats;
- M *mp;
uint32 i;
Eface eface;
+ if(runtime·debug.allocfreetrace)
+ runtime·tracegc();
+
+ m->traceback = 2;
t0 = args->start_time;
+ work.tstart = args->start_time;
if(CollectStats)
runtime·memclr((byte*)&gcstats, sizeof(gcstats));
- for(mp=runtime·allm; mp; mp=mp->alllink)
- runtime·settype_flush(mp);
-
- heap0 = 0;
- obj0 = 0;
- if(runtime·debug.gctrace) {
- updatememstats(nil);
- heap0 = mstats.heap_alloc;
- obj0 = mstats.nmalloc - mstats.nfree;
- }
-
m->locks++; // disable gc during mallocs in parforalloc
if(work.markfor == nil)
work.markfor = runtime·parforalloc(MaxGcproc);
- if(work.sweepfor == nil)
- work.sweepfor = runtime·parforalloc(MaxGcproc);
m->locks--;
if(itabtype == nil) {
@@ -2095,43 +2382,49 @@ gc(struct gc_args *args)
itabtype = ((PtrType*)eface.type)->elem;
}
+ t1 = 0;
+ if(runtime·debug.gctrace)
+ t1 = runtime·nanotime();
+
+ // Sweep what is not sweeped by bgsweep.
+ while(runtime·sweepone() != -1)
+ gcstats.npausesweep++;
+
work.nwait = 0;
work.ndone = 0;
- work.debugmarkdone = 0;
work.nproc = runtime·gcprocs();
- addroots();
- runtime·parforsetup(work.markfor, work.nproc, work.nroot, nil, false, markroot);
- runtime·parforsetup(work.sweepfor, work.nproc, runtime·mheap.nspan, nil, true, sweepspan);
+ runtime·parforsetup(work.markfor, work.nproc, RootCount + runtime·allglen, nil, false, markroot);
if(work.nproc > 1) {
runtime·noteclear(&work.alldone);
runtime·helpgc(work.nproc);
}
- t1 = runtime·nanotime();
+ t2 = 0;
+ if(runtime·debug.gctrace)
+ t2 = runtime·nanotime();
gchelperstart();
runtime·parfordo(work.markfor);
- scanblock(nil, nil, 0, true);
+ scanblock(nil, true);
- if(DebugMark) {
- for(i=0; i<work.nroot; i++)
- debug_scanblock(work.roots[i].p, work.roots[i].n);
- runtime·atomicstore(&work.debugmarkdone, 1);
- }
- t2 = runtime·nanotime();
+ t3 = 0;
+ if(runtime·debug.gctrace)
+ t3 = runtime·nanotime();
- runtime·parfordo(work.sweepfor);
bufferList[m->helpgc].busy = 0;
- t3 = runtime·nanotime();
-
if(work.nproc > 1)
runtime·notesleep(&work.alldone);
cachestats();
+ // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
+ // estimate what was live heap size after previous GC (for tracing only)
+ heap0 = mstats.next_gc*100/(gcpercent+100);
+ // conservatively set next_gc to high value assuming that everything is live
+ // concurrent/lazy sweep will reduce this number while discovering new garbage
mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
t4 = runtime·nanotime();
- mstats.last_gc = t4;
+ mstats.last_gc = runtime·unixnanotime(); // must be Unix time to make sense to user
mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
mstats.pause_total_ns += t4 - t0;
mstats.numgc++;
@@ -2139,22 +2432,29 @@ gc(struct gc_args *args)
runtime·printf("pause %D\n", t4-t0);
if(runtime·debug.gctrace) {
- updatememstats(&stats);
heap1 = mstats.heap_alloc;
- obj1 = mstats.nmalloc - mstats.nfree;
+ runtime·updatememstats(&stats);
+ if(heap1 != mstats.heap_alloc) {
+ runtime·printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
+ runtime·throw("mstats skew");
+ }
+ obj = mstats.nmalloc - mstats.nfree;
- stats.nprocyield += work.sweepfor->nprocyield;
- stats.nosyield += work.sweepfor->nosyield;
- stats.nsleep += work.sweepfor->nsleep;
+ stats.nprocyield += work.markfor->nprocyield;
+ stats.nosyield += work.markfor->nosyield;
+ stats.nsleep += work.markfor->nsleep;
- runtime·printf("gc%d(%d): %D+%D+%D ms, %D -> %D MB %D -> %D (%D-%D) objects,"
+ runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
+ " %d/%d/%d sweeps,"
" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
- mstats.numgc, work.nproc, (t2-t1)/1000000, (t3-t2)/1000000, (t1-t0+t4-t3)/1000000,
- heap0>>20, heap1>>20, obj0, obj1,
+ mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
+ heap0>>20, heap1>>20, obj,
mstats.nmalloc, mstats.nfree,
+ sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep,
stats.nhandoff, stats.nhandoffcnt,
- work.sweepfor->nsteal, work.sweepfor->nstealcnt,
+ work.markfor->nsteal, work.markfor->nstealcnt,
stats.nprocyield, stats.nosyield, stats.nsleep);
+ gcstats.nbgsweep = gcstats.npausesweep = 0;
if(CollectStats) {
runtime·printf("scan: %D bytes, %D objects, %D untyped, %D types from MSpan\n",
gcstats.nbytes, gcstats.obj.cnt, gcstats.obj.notype, gcstats.obj.typelookup);
@@ -2181,9 +2481,49 @@ gc(struct gc_args *args)
}
}
+ // We cache current runtime·mheap.allspans array in sweep.spans,
+ // because the former can be resized and freed.
+ // Otherwise we would need to take heap lock every time
+ // we want to convert span index to span pointer.
+
+ // Free the old cached array if necessary.
+ if(sweep.spans && sweep.spans != runtime·mheap.allspans)
+ runtime·SysFree(sweep.spans, sweep.nspan*sizeof(sweep.spans[0]), &mstats.other_sys);
+ // Cache the current array.
+ runtime·mheap.sweepspans = runtime·mheap.allspans;
+ runtime·mheap.sweepgen += 2;
+ runtime·mheap.sweepdone = false;
+ sweep.spans = runtime·mheap.allspans;
+ sweep.nspan = runtime·mheap.nspan;
+ sweep.spanidx = 0;
+
+ // Temporary disable concurrent sweep, because we see failures on builders.
+ if(ConcurrentSweep && !args->eagersweep) {
+ runtime·lock(&gclock);
+ if(sweep.g == nil)
+ sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, runtime·gc);
+ else if(sweep.parked) {
+ sweep.parked = false;
+ runtime·ready(sweep.g);
+ }
+ runtime·unlock(&gclock);
+ } else {
+ // Sweep all spans eagerly.
+ while(runtime·sweepone() != -1)
+ gcstats.npausesweep++;
+ }
+
+ // Shrink a stack if not much of it is being used.
+ // TODO: do in a parfor
+ for(i = 0; i < runtime·allglen; i++)
+ runtime·shrinkstack(runtime·allg[i]);
+
runtime·MProf_GC();
+ m->traceback = 0;
}
+extern uintptr runtime·sizeof_C_MStats;
+
void
runtime·ReadMemStats(MStats *stats)
{
@@ -2194,8 +2534,10 @@ runtime·ReadMemStats(MStats *stats)
runtime·semacquire(&runtime·worldsema, false);
m->gcing = 1;
runtime·stoptheworld();
- updatememstats(nil);
- *stats = mstats;
+ runtime·updatememstats(nil);
+ // Size of the trailing by_size array differs between Go and C,
+ // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+ runtime·memcopy(runtime·sizeof_C_MStats, stats, &mstats);
m->gcing = 0;
m->locks++;
runtime·semrelease(&runtime·worldsema);
@@ -2234,9 +2576,10 @@ runtime∕debug·readGCStats(Slice *pauses)
pauses->len = n+3;
}
-void
-runtime∕debug·setGCPercent(intgo in, intgo out)
-{
+int32
+runtime·setgcpercent(int32 in) {
+ int32 out;
+
runtime·lock(&runtime·mheap);
if(gcpercent == GcpercentUnknown)
gcpercent = readgogc();
@@ -2245,7 +2588,7 @@ runtime∕debug·setGCPercent(intgo in, intgo out)
in = -1;
gcpercent = in;
runtime·unlock(&runtime·mheap);
- FLUSH(&out);
+ return out;
}
static void
@@ -2268,15 +2611,38 @@ runfinq(void)
uint32 framesz, framecap, i;
Eface *ef, ef1;
+ // This function blocks for long periods of time, and because it is written in C
+ // we have no liveness information. Zero everything so that uninitialized pointers
+ // do not cause memory leaks.
+ f = nil;
+ fb = nil;
+ next = nil;
frame = nil;
framecap = 0;
+ framesz = 0;
+ i = 0;
+ ef = nil;
+ ef1.type = nil;
+ ef1.data = nil;
+
+ // force flush to memory
+ USED(&f);
+ USED(&fb);
+ USED(&next);
+ USED(&framesz);
+ USED(&i);
+ USED(&ef);
+ USED(&ef1);
+
for(;;) {
runtime·lock(&finlock);
fb = finq;
finq = nil;
if(fb == nil) {
- fingwait = 1;
- runtime·park(runtime·unlock, &finlock, "finalizer wait");
+ runtime·fingwait = true;
+ g->isbackground = true;
+ runtime·parkunlock(&finlock, "finalizer wait");
+ g->isbackground = false;
continue;
}
runtime·unlock(&finlock);
@@ -2290,7 +2656,7 @@ runfinq(void)
if(framecap < framesz) {
runtime·free(frame);
// The frame does not contain pointers interesting for GC,
- // all not yet finalized objects are stored in finc.
+ // all not yet finalized objects are stored in finq.
// If we do not mark it as FlagNoScan,
// the last finalized object is not collected.
frame = runtime·mallocgc(framesz, 0, FlagNoScan|FlagNoInvokeGC);
@@ -2313,80 +2679,99 @@ runfinq(void)
if(!runtime·ifaceE2I2((InterfaceType*)f->fint, ef1, (Iface*)frame))
runtime·throw("invalid type conversion in runfinq");
}
- reflect·call(f->fn, frame, framesz);
+ reflect·call(f->fn, frame, framesz, framesz);
f->fn = nil;
f->arg = nil;
f->ot = nil;
}
fb->cnt = 0;
+ runtime·lock(&finlock);
fb->next = finc;
finc = fb;
+ runtime·unlock(&finlock);
}
+
+ // Zero everything that's dead, to avoid memory leaks.
+ // See comment at top of function.
+ f = nil;
+ fb = nil;
+ next = nil;
+ i = 0;
+ ef = nil;
+ ef1.type = nil;
+ ef1.data = nil;
runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
}
}
-// mark the block at v of size n as allocated.
-// If noscan is true, mark it as not needing scanning.
void
-runtime·markallocated(void *v, uintptr n, bool noscan)
+runtime·createfing(void)
{
- uintptr *b, obits, bits, off, shift;
+ if(fing != nil)
+ return;
+ // Here we use gclock instead of finlock,
+ // because newproc1 can allocate, which can cause on-demand span sweep,
+ // which can queue finalizers, which would deadlock.
+ runtime·lock(&gclock);
+ if(fing == nil)
+ fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
+ runtime·unlock(&gclock);
+}
- if(0)
- runtime·printf("markallocated %p+%p\n", v, n);
+G*
+runtime·wakefing(void)
+{
+ G *res;
- if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
- runtime·throw("markallocated: bad pointer");
+ res = nil;
+ runtime·lock(&finlock);
+ if(runtime·fingwait && runtime·fingwake) {
+ runtime·fingwait = false;
+ runtime·fingwake = false;
+ res = fing;
+ }
+ runtime·unlock(&finlock);
+ return res;
+}
+
+void
+runtime·marknogc(void *v)
+{
+ uintptr *b, off, shift;
off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
+ *b = (*b & ~(bitAllocated<<shift)) | bitBlockBoundary<<shift;
+}
- for(;;) {
- obits = *b;
- bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
- if(noscan)
- bits |= bitNoScan<<shift;
- if(runtime·gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime·casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
+void
+runtime·markscan(void *v)
+{
+ uintptr *b, off, shift;
+
+ off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
+ b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ *b |= bitScan<<shift;
}
-// mark the block at v of size n as freed.
+// mark the block at v as freed.
void
-runtime·markfreed(void *v, uintptr n)
+runtime·markfreed(void *v)
{
- uintptr *b, obits, bits, off, shift;
+ uintptr *b, off, shift;
if(0)
- runtime·printf("markfreed %p+%p\n", v, n);
+ runtime·printf("markfreed %p\n", v);
- if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+ if((byte*)v > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
runtime·throw("markfreed: bad pointer");
off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
-
- for(;;) {
- obits = *b;
- bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
- if(runtime·gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime·casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
+ *b = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
}
// check that the block at v of size n is marked freed.
@@ -2418,15 +2803,28 @@ runtime·checkfreed(void *v, uintptr n)
void
runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
{
- uintptr *b, off, shift;
+ uintptr *b, *b0, off, shift, i, x;
byte *p;
if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
runtime·throw("markspan: bad pointer");
+ if(runtime·checking) {
+ // bits should be all zero at the start
+ off = (byte*)v + size - runtime·mheap.arena_start;
+ b = (uintptr*)(runtime·mheap.arena_start - off/wordsPerBitmapWord);
+ for(i = 0; i < size/PtrSize/wordsPerBitmapWord; i++) {
+ if(b[i] != 0)
+ runtime·throw("markspan: span bits not zero");
+ }
+ }
+
p = v;
if(leftover) // mark a boundary just past end of last block too
n++;
+
+ b0 = nil;
+ x = 0;
for(; n-- > 0; p += size) {
// Okay to use non-atomic ops here, because we control
// the entire span, and each bitmap word has bits for only
@@ -2435,8 +2833,15 @@ runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start; // word offset
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
- *b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ if(b0 != b) {
+ if(b0 != nil)
+ *b0 = x;
+ b0 = b;
+ x = 0;
+ }
+ x |= bitAllocated<<shift;
}
+ *b0 = x;
}
// unmark the span of memory at v of length n bytes.
@@ -2465,50 +2870,6 @@ runtime·unmarkspan(void *v, uintptr n)
*b-- = 0;
}
-bool
-runtime·blockspecial(void *v)
-{
- uintptr *b, off, shift;
-
- if(DebugMark)
- return true;
-
- off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
- b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
-
- return (*b & (bitSpecial<<shift)) != 0;
-}
-
-void
-runtime·setblockspecial(void *v, bool s)
-{
- uintptr *b, off, shift, bits, obits;
-
- if(DebugMark)
- return;
-
- off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
- b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
-
- for(;;) {
- obits = *b;
- if(s)
- bits = obits | (bitSpecial<<shift);
- else
- bits = obits & ~(bitSpecial<<shift);
- if(runtime·gomaxprocs == 1) {
- *b = bits;
- break;
- } else {
- // more than one goroutine is potentially running: use atomic op
- if(runtime·casp((void**)b, (void*)obits, (void*)bits))
- break;
- }
- }
-}
-
void
runtime·MHeap_MapBits(MHeap *h)
{
@@ -2522,9 +2883,10 @@ runtime·MHeap_MapBits(MHeap *h)
n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
n = ROUND(n, bitmapChunk);
+ n = ROUND(n, PhysPageSize);
if(h->bitmap_mapped >= n)
return;
- runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys);
+ runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
h->bitmap_mapped = n;
}
diff --git a/src/pkg/runtime/mgc0.go b/src/pkg/runtime/mgc0.go
index b15054662..624485d18 100644
--- a/src/pkg/runtime/mgc0.go
+++ b/src/pkg/runtime/mgc0.go
@@ -9,7 +9,19 @@ func gc_m_ptr(ret *interface{}) {
*ret = (*m)(nil)
}
+// Called from C. Returns the Go type *g.
+func gc_g_ptr(ret *interface{}) {
+ *ret = (*g)(nil)
+}
+
// Called from C. Returns the Go type *itab.
func gc_itab_ptr(ret *interface{}) {
*ret = (*itab)(nil)
}
+
+func timenow() (sec int64, nsec int32)
+
+func gc_unixnanotime(now *int64) {
+ sec, nsec := timenow()
+ *now = sec*1e9 + int64(nsec)
+}
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
index f8abe6c9c..16000d1ae 100644
--- a/src/pkg/runtime/mgc0.h
+++ b/src/pkg/runtime/mgc0.h
@@ -44,3 +44,44 @@ enum {
// - at most GC_STACK_CAPACITY allocations because of GC_ARRAY_START
GC_STACK_CAPACITY = 8,
};
+
+enum {
+ ScanStackByFrames = 1,
+ IgnorePreciseGC = 0,
+
+ // Four bits per word (see #defines below).
+ wordsPerBitmapWord = sizeof(void*)*8/4,
+ bitShift = sizeof(void*)*8/4,
+};
+
+// Bits in per-word bitmap.
+// #defines because enum might not be able to hold the values.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory. There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+// The bits in the word are packed together by type first, then by
+// heap location, so each 64-bit bitmap word consists of, from top to bottom,
+// the 16 bitMarked bits for the corresponding heap words,
+// then the 16 bitScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
+// This layout makes it easier to iterate over the bits of a given type.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there. On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start. (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+//
+// To pull out the bits corresponding to a given pointer p, we use:
+//
+// off = p - (uintptr*)mheap.arena_start; // word offset
+// b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
+// shift = off % wordsPerBitmapWord
+// bits = *b >> shift;
+// /* then test bits & bitAllocated, bits & bitMarked, etc. */
+//
+#define bitAllocated ((uintptr)1<<(bitShift*0)) /* block start; eligible for garbage collection */
+#define bitScan ((uintptr)1<<(bitShift*1)) /* when bitAllocated is set */
+#define bitMarked ((uintptr)1<<(bitShift*2)) /* when bitAllocated is set */
+#define bitBlockBoundary ((uintptr)1<<(bitShift*1)) /* when bitAllocated is NOT set - mark for FlagNoGC objects */
+
+#define bitMask (bitAllocated | bitScan | bitMarked)
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index fc80c2600..7e83eb283 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -41,7 +41,10 @@ RecordSpan(void *vh, byte *p)
runtime·throw("runtime: cannot allocate memory");
if(h->allspans) {
runtime·memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
- runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
+ // Don't free the old array if it's referenced by sweep.
+ // See the comment in mgc0.c.
+ if(h->allspans != runtime·mheap.sweepspans)
+ runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
}
h->allspans = all;
h->nspancap = cap;
@@ -57,10 +60,15 @@ runtime·MHeap_Init(MHeap *h)
runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
+ runtime·FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
+ runtime·FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
// h->mapcache needs no init
- for(i=0; i<nelem(h->free); i++)
+ for(i=0; i<nelem(h->free); i++) {
runtime·MSpanList_Init(&h->free[i]);
- runtime·MSpanList_Init(&h->large);
+ runtime·MSpanList_Init(&h->busy[i]);
+ }
+ runtime·MSpanList_Init(&h->freelarge);
+ runtime·MSpanList_Init(&h->busylarge);
for(i=0; i<nelem(h->central); i++)
runtime·MCentral_Init(&h->central[i], i);
}
@@ -72,20 +80,95 @@ runtime·MHeap_MapSpans(MHeap *h)
// Map spans array, PageSize at a time.
n = (uintptr)h->arena_used;
- if(sizeof(void*) == 8)
- n -= (uintptr)h->arena_start;
+ n -= (uintptr)h->arena_start;
n = n / PageSize * sizeof(h->spans[0]);
- n = ROUND(n, PageSize);
+ n = ROUND(n, PhysPageSize);
if(h->spans_mapped >= n)
return;
- runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
+ runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
h->spans_mapped = n;
}
+// Sweeps spans in list until reclaims at least npages into heap.
+// Returns the actual number of pages reclaimed.
+static uintptr
+MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
+{
+ MSpan *s;
+ uintptr n;
+ uint32 sg;
+
+ n = 0;
+ sg = runtime·mheap.sweepgen;
+retry:
+ for(s = list->next; s != list; s = s->next) {
+ if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+ runtime·MSpanList_Remove(s);
+ // swept spans are at the end of the list
+ runtime·MSpanList_InsertBack(list, s);
+ runtime·unlock(h);
+ n += runtime·MSpan_Sweep(s);
+ runtime·lock(h);
+ if(n >= npages)
+ return n;
+ // the span could have been moved elsewhere
+ goto retry;
+ }
+ if(s->sweepgen == sg-1) {
+ // the span is being sweept by background sweeper, skip
+ continue;
+ }
+ // already swept empty span,
+ // all subsequent ones must also be either swept or in process of sweeping
+ break;
+ }
+ return n;
+}
+
+// Sweeps and reclaims at least npage pages into heap.
+// Called before allocating npage pages.
+static void
+MHeap_Reclaim(MHeap *h, uintptr npage)
+{
+ uintptr reclaimed, n;
+
+ // First try to sweep busy spans with large objects of size >= npage,
+ // this has good chances of reclaiming the necessary space.
+ for(n=npage; n < nelem(h->busy); n++) {
+ if(MHeap_ReclaimList(h, &h->busy[n], npage))
+ return; // Bingo!
+ }
+
+ // Then -- even larger objects.
+ if(MHeap_ReclaimList(h, &h->busylarge, npage))
+ return; // Bingo!
+
+ // Now try smaller objects.
+ // One such object is not enough, so we need to reclaim several of them.
+ reclaimed = 0;
+ for(n=0; n < npage && n < nelem(h->busy); n++) {
+ reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
+ if(reclaimed >= npage)
+ return;
+ }
+
+ // Now sweep everything that is not yet swept.
+ runtime·unlock(h);
+ for(;;) {
+ n = runtime·sweepone();
+ if(n == -1) // all spans are swept
+ break;
+ reclaimed += n;
+ if(reclaimed >= npage)
+ break;
+ }
+ runtime·lock(h);
+}
+
// Allocate a new span of npage pages from the heap
// and record its size class in the HeapMap and HeapMapCache.
MSpan*
-runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed)
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
{
MSpan *s;
@@ -95,14 +178,22 @@ runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
mstats.heap_inuse += npage<<PageShift;
- if(acct) {
+ if(large) {
mstats.heap_objects++;
mstats.heap_alloc += npage<<PageShift;
+ // Swept spans are at the end of lists.
+ if(s->npages < nelem(h->free))
+ runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
+ else
+ runtime·MSpanList_InsertBack(&h->busylarge, s);
}
}
runtime·unlock(h);
- if(s != nil && *(uintptr*)(s->start<<PageShift) != 0 && zeroed)
- runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ if(s != nil) {
+ if(needzero && s->needzero)
+ runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+ s->needzero = 0;
+ }
return s;
}
@@ -113,6 +204,11 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
MSpan *s, *t;
PageID p;
+ // To prevent excessive heap growth, before allocating n pages
+ // we need to sweep and reclaim at least n pages.
+ if(!h->sweepdone)
+ MHeap_Reclaim(h, npage);
+
// Try in fixed-size lists up to max.
for(n=npage; n < nelem(h->free); n++) {
if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
@@ -136,29 +232,12 @@ HaveSpan:
if(s->npages < npage)
runtime·throw("MHeap_AllocLocked - bad npages");
runtime·MSpanList_Remove(s);
+ runtime·atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse;
mstats.heap_idle -= s->npages<<PageShift;
mstats.heap_released -= s->npreleased<<PageShift;
- if(s->npreleased > 0) {
- // We have called runtime·SysUnused with these pages, and on
- // Unix systems it called madvise. At this point at least
- // some BSD-based kernels will return these pages either as
- // zeros or with the old data. For our caller, the first word
- // in the page indicates whether the span contains zeros or
- // not (this word was set when the span was freed by
- // MCentral_Free or runtime·MCentral_FreeSpan). If the first
- // page in the span is returned as zeros, and some subsequent
- // page is returned with the old data, then we will be
- // returning a span that is assumed to be all zeros, but the
- // actual data will not be all zeros. Avoid that problem by
- // explicitly marking the span as not being zeroed, just in
- // case. The beadbead constant we use here means nothing, it
- // is just a unique constant not seen elsewhere in the
- // runtime, as a clue in case it turns up unexpectedly in
- // memory or in a stack trace.
+ if(s->npreleased > 0)
runtime·SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
- *(uintptr*)(s->start<<PageShift) = (uintptr)0xbeadbeadbeadbeadULL;
- }
s->npreleased = 0;
if(s->npages > npage) {
@@ -167,13 +246,13 @@ HaveSpan:
runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
s->npages = npage;
p = t->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ p -= ((uintptr)h->arena_start>>PageShift);
if(p > 0)
h->spans[p-1] = s;
h->spans[p] = t;
h->spans[p+t->npages-1] = t;
- *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShift); // copy "needs zeroing" mark
+ t->needzero = s->needzero;
+ runtime·atomicstore(&t->sweepgen, h->sweepgen);
t->state = MSpanInUse;
MHeap_FreeLocked(h, t);
t->unusedsince = s->unusedsince; // preserve age
@@ -186,8 +265,7 @@ HaveSpan:
s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
s->types.compression = MTypes_Empty;
p = s->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ p -= ((uintptr)h->arena_start>>PageShift);
for(n=0; n<npage; n++)
h->spans[p+n] = s;
return s;
@@ -197,7 +275,7 @@ HaveSpan:
static MSpan*
MHeap_AllocLarge(MHeap *h, uintptr npage)
{
- return BestFit(&h->large, npage, nil);
+ return BestFit(&h->freelarge, npage, nil);
}
// Search list for smallest span with >= npage pages.
@@ -255,10 +333,10 @@ MHeap_Grow(MHeap *h, uintptr npage)
s = runtime·FixAlloc_Alloc(&h->spanalloc);
runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
p = s->start;
- if(sizeof(void*) == 8)
- p -= ((uintptr)h->arena_start>>PageShift);
+ p -= ((uintptr)h->arena_start>>PageShift);
h->spans[p] = s;
h->spans[p + s->npages - 1] = s;
+ runtime·atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse;
MHeap_FreeLocked(h, s);
return true;
@@ -273,8 +351,7 @@ runtime·MHeap_Lookup(MHeap *h, void *v)
uintptr p;
p = (uintptr)v;
- if(sizeof(void*) == 8)
- p -= (uintptr)h->arena_start;
+ p -= (uintptr)h->arena_start;
return h->spans[p >> PageShift];
}
@@ -295,8 +372,7 @@ runtime·MHeap_LookupMaybe(MHeap *h, void *v)
return nil;
p = (uintptr)v>>PageShift;
q = p;
- if(sizeof(void*) == 8)
- q -= (uintptr)h->arena_start >> PageShift;
+ q -= (uintptr)h->arena_start >> PageShift;
s = h->spans[q];
if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
return nil;
@@ -322,20 +398,19 @@ runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
static void
MHeap_FreeLocked(MHeap *h, MSpan *s)
{
- uintptr *sp, *tp;
MSpan *t;
PageID p;
s->types.compression = MTypes_Empty;
- if(s->state != MSpanInUse || s->ref != 0) {
- runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ if(s->state != MSpanInUse || s->ref != 0 || s->sweepgen != h->sweepgen) {
+ runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d sweepgen %d/%d\n",
+ s, s->start<<PageShift, s->state, s->ref, s->sweepgen, h->sweepgen);
runtime·throw("MHeap_FreeLocked - invalid free");
}
mstats.heap_idle += s->npages<<PageShift;
s->state = MSpanFree;
runtime·MSpanList_Remove(s);
- sp = (uintptr*)(s->start<<PageShift);
// Stamp newly unused spans. The scavenger will use that
// info to potentially give back some pages to the OS.
s->unusedsince = runtime·nanotime();
@@ -343,16 +418,12 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
// Coalesce with earlier, later spans.
p = s->start;
- if(sizeof(void*) == 8)
- p -= (uintptr)h->arena_start >> PageShift;
+ p -= (uintptr)h->arena_start >> PageShift;
if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse) {
- if(t->npreleased == 0) { // cant't touch this otherwise
- tp = (uintptr*)(t->start<<PageShift);
- *tp |= *sp; // propagate "needs zeroing" mark
- }
s->start = t->start;
s->npages += t->npages;
s->npreleased = t->npreleased; // absorb released pages
+ s->needzero |= t->needzero;
p -= t->npages;
h->spans[p] = s;
runtime·MSpanList_Remove(t);
@@ -360,12 +431,9 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
runtime·FixAlloc_Free(&h->spanalloc, t);
}
if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse) {
- if(t->npreleased == 0) { // cant't touch this otherwise
- tp = (uintptr*)(t->start<<PageShift);
- *sp |= *tp; // propagate "needs zeroing" mark
- }
s->npages += t->npages;
s->npreleased += t->npreleased;
+ s->needzero |= t->needzero;
h->spans[p + s->npages - 1] = s;
runtime·MSpanList_Remove(t);
t->state = MSpanDead;
@@ -376,7 +444,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
if(s->npages < nelem(h->free))
runtime·MSpanList_Insert(&h->free[s->npages], s);
else
- runtime·MSpanList_Insert(&h->large, s);
+ runtime·MSpanList_Insert(&h->freelarge, s);
}
static void
@@ -419,7 +487,7 @@ scavenge(int32 k, uint64 now, uint64 limit)
sumreleased = 0;
for(i=0; i < nelem(h->free); i++)
sumreleased += scavengelist(&h->free[i], now, limit);
- sumreleased += scavengelist(&h->large, now, limit);
+ sumreleased += scavengelist(&h->freelarge, now, limit);
if(runtime·debug.gctrace > 0) {
if(sumreleased > 0)
@@ -440,6 +508,7 @@ runtime·MHeap_Scavenger(void)
{
MHeap *h;
uint64 tick, now, forcegc, limit;
+ int64 unixnow;
int32 k;
Note note, *notep;
@@ -463,8 +532,8 @@ runtime·MHeap_Scavenger(void)
runtime·notetsleepg(&note, tick);
runtime·lock(h);
- now = runtime·nanotime();
- if(now - mstats.last_gc > forcegc) {
+ unixnow = runtime·unixnanotime();
+ if(unixnow - mstats.last_gc > forcegc) {
runtime·unlock(h);
// The scavenger can not block other goroutines,
// otherwise deadlock detector can fire spuriously.
@@ -476,8 +545,8 @@ runtime·MHeap_Scavenger(void)
if(runtime·debug.gctrace > 0)
runtime·printf("scvg%d: GC forced\n", k);
runtime·lock(h);
- now = runtime·nanotime();
}
+ now = runtime·nanotime();
scavenge(k, now, limit);
runtime·unlock(h);
}
@@ -486,7 +555,7 @@ runtime·MHeap_Scavenger(void)
void
runtime∕debug·freeOSMemory(void)
{
- runtime·gc(1);
+ runtime·gc(2); // force GC and do eager sweep
runtime·lock(&runtime·mheap);
scavenge(-1, ~(uintptr)0, 0);
runtime·unlock(&runtime·mheap);
@@ -503,11 +572,16 @@ runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
span->freelist = nil;
span->ref = 0;
span->sizeclass = 0;
+ span->incache = false;
span->elemsize = 0;
- span->state = 0;
+ span->state = MSpanDead;
span->unusedsince = 0;
span->npreleased = 0;
span->types.compression = MTypes_Empty;
+ span->specialLock.key = 0;
+ span->specials = nil;
+ span->needzero = 0;
+ span->freebuf = nil;
}
// Initialize an empty doubly-linked list.
@@ -549,4 +623,310 @@ runtime·MSpanList_Insert(MSpan *list, MSpan *span)
span->prev->next = span;
}
+void
+runtime·MSpanList_InsertBack(MSpan *list, MSpan *span)
+{
+ if(span->next != nil || span->prev != nil) {
+ runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
+ runtime·throw("MSpanList_Insert");
+ }
+ span->next = list;
+ span->prev = list->prev;
+ span->next->prev = span;
+ span->prev->next = span;
+}
+// Adds the special record s to the list of special records for
+// the object p. All fields of s should be filled in except for
+// offset & next, which this routine will fill in.
+// Returns true if the special was successfully added, false otherwise.
+// (The add will fail only if a record with the same p and s->kind
+// already exists.)
+static bool
+addspecial(void *p, Special *s)
+{
+ MSpan *span;
+ Special **t, *x;
+ uintptr offset;
+ byte kind;
+
+ span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
+ if(span == nil)
+ runtime·throw("addspecial on invalid pointer");
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ m->locks++;
+ runtime·MSpan_EnsureSwept(span);
+
+ offset = (uintptr)p - (span->start << PageShift);
+ kind = s->kind;
+
+ runtime·lock(&span->specialLock);
+
+ // Find splice point, check for existing record.
+ t = &span->specials;
+ while((x = *t) != nil) {
+ if(offset == x->offset && kind == x->kind) {
+ runtime·unlock(&span->specialLock);
+ m->locks--;
+ return false; // already exists
+ }
+ if(offset < x->offset || (offset == x->offset && kind < x->kind))
+ break;
+ t = &x->next;
+ }
+ // Splice in record, fill in offset.
+ s->offset = offset;
+ s->next = x;
+ *t = s;
+ runtime·unlock(&span->specialLock);
+ m->locks--;
+ return true;
+}
+
+// Removes the Special record of the given kind for the object p.
+// Returns the record if the record existed, nil otherwise.
+// The caller must FixAlloc_Free the result.
+static Special*
+removespecial(void *p, byte kind)
+{
+ MSpan *span;
+ Special *s, **t;
+ uintptr offset;
+
+ span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
+ if(span == nil)
+ runtime·throw("removespecial on invalid pointer");
+
+ // Ensure that the span is swept.
+ // GC accesses specials list w/o locks. And it's just much safer.
+ m->locks++;
+ runtime·MSpan_EnsureSwept(span);
+
+ offset = (uintptr)p - (span->start << PageShift);
+
+ runtime·lock(&span->specialLock);
+ t = &span->specials;
+ while((s = *t) != nil) {
+ // This function is used for finalizers only, so we don't check for
+ // "interior" specials (p must be exactly equal to s->offset).
+ if(offset == s->offset && kind == s->kind) {
+ *t = s->next;
+ runtime·unlock(&span->specialLock);
+ m->locks--;
+ return s;
+ }
+ t = &s->next;
+ }
+ runtime·unlock(&span->specialLock);
+ m->locks--;
+ return nil;
+}
+
+// Adds a finalizer to the object p. Returns true if it succeeded.
+bool
+runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
+{
+ SpecialFinalizer *s;
+
+ runtime·lock(&runtime·mheap.speciallock);
+ s = runtime·FixAlloc_Alloc(&runtime·mheap.specialfinalizeralloc);
+ runtime·unlock(&runtime·mheap.speciallock);
+ s->kind = KindSpecialFinalizer;
+ s->fn = f;
+ s->nret = nret;
+ s->fint = fint;
+ s->ot = ot;
+ if(addspecial(p, s))
+ return true;
+
+ // There was an old finalizer
+ runtime·lock(&runtime·mheap.speciallock);
+ runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
+ runtime·unlock(&runtime·mheap.speciallock);
+ return false;
+}
+
+// Removes the finalizer (if any) from the object p.
+void
+runtime·removefinalizer(void *p)
+{
+ SpecialFinalizer *s;
+
+ s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
+ if(s == nil)
+ return; // there wasn't a finalizer to remove
+ runtime·lock(&runtime·mheap.speciallock);
+ runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
+ runtime·unlock(&runtime·mheap.speciallock);
+}
+
+// Set the heap profile bucket associated with addr to b.
+void
+runtime·setprofilebucket(void *p, Bucket *b)
+{
+ SpecialProfile *s;
+
+ runtime·lock(&runtime·mheap.speciallock);
+ s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc);
+ runtime·unlock(&runtime·mheap.speciallock);
+ s->kind = KindSpecialProfile;
+ s->b = b;
+ if(!addspecial(p, s))
+ runtime·throw("setprofilebucket: profile already set");
+}
+
+// Do whatever cleanup needs to be done to deallocate s. It has
+// already been unlinked from the MSpan specials list.
+// Returns true if we should keep working on deallocating p.
+bool
+runtime·freespecial(Special *s, void *p, uintptr size, bool freed)
+{
+ SpecialFinalizer *sf;
+ SpecialProfile *sp;
+
+ switch(s->kind) {
+ case KindSpecialFinalizer:
+ sf = (SpecialFinalizer*)s;
+ runtime·queuefinalizer(p, sf->fn, sf->nret, sf->fint, sf->ot);
+ runtime·lock(&runtime·mheap.speciallock);
+ runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, sf);
+ runtime·unlock(&runtime·mheap.speciallock);
+ return false; // don't free p until finalizer is done
+ case KindSpecialProfile:
+ sp = (SpecialProfile*)s;
+ runtime·MProf_Free(sp->b, size, freed);
+ runtime·lock(&runtime·mheap.speciallock);
+ runtime·FixAlloc_Free(&runtime·mheap.specialprofilealloc, sp);
+ runtime·unlock(&runtime·mheap.speciallock);
+ return true;
+ default:
+ runtime·throw("bad special kind");
+ return true;
+ }
+}
+
+// Free all special records for p.
+void
+runtime·freeallspecials(MSpan *span, void *p, uintptr size)
+{
+ Special *s, **t, *list;
+ uintptr offset;
+
+ if(span->sweepgen != runtime·mheap.sweepgen)
+ runtime·throw("runtime: freeallspecials: unswept span");
+ // first, collect all specials into the list; then, free them
+ // this is required to not cause deadlock between span->specialLock and proflock
+ list = nil;
+ offset = (uintptr)p - (span->start << PageShift);
+ runtime·lock(&span->specialLock);
+ t = &span->specials;
+ while((s = *t) != nil) {
+ if(offset + size <= s->offset)
+ break;
+ if(offset <= s->offset) {
+ *t = s->next;
+ s->next = list;
+ list = s;
+ } else
+ t = &s->next;
+ }
+ runtime·unlock(&span->specialLock);
+
+ while(list != nil) {
+ s = list;
+ list = s->next;
+ if(!runtime·freespecial(s, p, size, true))
+ runtime·throw("can't explicitly free an object with a finalizer");
+ }
+}
+
+// Split an allocated span into two equal parts.
+void
+runtime·MHeap_SplitSpan(MHeap *h, MSpan *s)
+{
+ MSpan *t;
+ MCentral *c;
+ uintptr i;
+ uintptr npages;
+ PageID p;
+
+ if(s->state != MSpanInUse)
+ runtime·throw("MHeap_SplitSpan on a free span");
+ if(s->sizeclass != 0 && s->ref != 1)
+ runtime·throw("MHeap_SplitSpan doesn't have an allocated object");
+ npages = s->npages;
+
+ // remove the span from whatever list it is in now
+ if(s->sizeclass > 0) {
+ // must be in h->central[x].empty
+ c = &h->central[s->sizeclass];
+ runtime·lock(c);
+ runtime·MSpanList_Remove(s);
+ runtime·unlock(c);
+ runtime·lock(h);
+ } else {
+ // must be in h->busy/busylarge
+ runtime·lock(h);
+ runtime·MSpanList_Remove(s);
+ }
+ // heap is locked now
+
+ if(npages == 1) {
+ // convert span of 1 PageSize object to a span of 2 PageSize/2 objects.
+ s->ref = 2;
+ s->sizeclass = runtime·SizeToClass(PageSize/2);
+ s->elemsize = PageSize/2;
+ } else {
+ // convert span of n>1 pages into two spans of n/2 pages each.
+ if((s->npages & 1) != 0)
+ runtime·throw("MHeap_SplitSpan on an odd size span");
+
+ // compute position in h->spans
+ p = s->start;
+ p -= (uintptr)h->arena_start >> PageShift;
+
+ // Allocate a new span for the first half.
+ t = runtime·FixAlloc_Alloc(&h->spanalloc);
+ runtime·MSpan_Init(t, s->start, npages/2);
+ t->limit = (byte*)((t->start + npages/2) << PageShift);
+ t->state = MSpanInUse;
+ t->elemsize = npages << (PageShift - 1);
+ t->sweepgen = s->sweepgen;
+ if(t->elemsize <= MaxSmallSize) {
+ t->sizeclass = runtime·SizeToClass(t->elemsize);
+ t->ref = 1;
+ }
+
+ // the old span holds the second half.
+ s->start += npages/2;
+ s->npages = npages/2;
+ s->elemsize = npages << (PageShift - 1);
+ if(s->elemsize <= MaxSmallSize) {
+ s->sizeclass = runtime·SizeToClass(s->elemsize);
+ s->ref = 1;
+ }
+
+ // update span lookup table
+ for(i = p; i < p + npages/2; i++)
+ h->spans[i] = t;
+ }
+
+ // place the span into a new list
+ if(s->sizeclass > 0) {
+ runtime·unlock(h);
+ c = &h->central[s->sizeclass];
+ runtime·lock(c);
+ // swept spans are at the end of the list
+ runtime·MSpanList_InsertBack(&c->empty, s);
+ runtime·unlock(c);
+ } else {
+ // Swept spans are at the end of lists.
+ if(s->npages < nelem(h->free))
+ runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
+ else
+ runtime·MSpanList_InsertBack(&h->busylarge, s);
+ runtime·unlock(h);
+ }
+}
diff --git a/src/pkg/runtime/mknacl.sh b/src/pkg/runtime/mknacl.sh
new file mode 100644
index 000000000..47fb7bd88
--- /dev/null
+++ b/src/pkg/runtime/mknacl.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# 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.
+
+cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
+ awk '
+ BEGIN {
+ printf("// generated by mknacl.sh - do not edit\n")
+ }
+ NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
+ name=$2
+ sub(/^NACL_sys_/, "SYS_", name)
+ printf("#define %s %s\n", name, $3)
+ }' >syscall_nacl.h
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 4ae74f0c2..9c23a16f8 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -22,7 +22,6 @@ enum { MProf, BProf }; // profile types
// Per-call-stack profiling information.
// Lookup by hashing call stack into a linked-list hash table.
-typedef struct Bucket Bucket;
struct Bucket
{
Bucket *next; // next in hash list
@@ -34,14 +33,33 @@ struct Bucket
{
struct // typ == MProf
{
+ // The following complex 3-stage scheme of stats accumulation
+ // is required to obtain a consistent picture of mallocs and frees
+ // for some point in time.
+ // The problem is that mallocs come in real time, while frees
+ // come only after a GC during concurrent sweeping. So if we would
+ // naively count them, we would get a skew toward mallocs.
+ //
+ // Mallocs are accounted in recent stats.
+ // Explicit frees are accounted in recent stats.
+ // GC frees are accounted in prev stats.
+ // After GC prev stats are added to final stats and
+ // recent stats are moved into prev stats.
uintptr allocs;
uintptr frees;
uintptr alloc_bytes;
uintptr free_bytes;
- uintptr recent_allocs; // since last gc
+
+ uintptr prev_allocs; // since last but one till last gc
+ uintptr prev_frees;
+ uintptr prev_alloc_bytes;
+ uintptr prev_free_bytes;
+
+ uintptr recent_allocs; // since last gc till now
uintptr recent_frees;
uintptr recent_alloc_bytes;
uintptr recent_free_bytes;
+
};
struct // typ == BProf
{
@@ -49,7 +67,8 @@ struct Bucket
int64 cycles;
};
};
- uintptr hash;
+ uintptr hash; // hash of size + stk
+ uintptr size;
uintptr nstk;
uintptr stk[1];
};
@@ -63,7 +82,7 @@ static uintptr bucketmem;
// Return the bucket for stk[0:nstk], allocating new bucket if needed.
static Bucket*
-stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, uintptr size, uintptr *stk, int32 nstk, bool alloc)
{
int32 i;
uintptr h;
@@ -82,12 +101,17 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
h += h<<10;
h ^= h>>6;
}
+ // hash in size
+ h += size;
+ h += h<<10;
+ h ^= h>>6;
+ // finalize
h += h<<3;
h ^= h>>11;
i = h%BuckHashSize;
for(b = buckhash[i]; b; b=b->next)
- if(b->typ == typ && b->hash == h && b->nstk == nstk &&
+ if(b->typ == typ && b->hash == h && b->size == size && b->nstk == nstk &&
runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
@@ -99,6 +123,7 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
b->typ = typ;
b->hash = h;
+ b->size = size;
b->nstk = nstk;
b->next = buckhash[i];
buckhash[i] = b;
@@ -118,10 +143,16 @@ MProf_GC(void)
Bucket *b;
for(b=mbuckets; b; b=b->allnext) {
- b->allocs += b->recent_allocs;
- b->frees += b->recent_frees;
- b->alloc_bytes += b->recent_alloc_bytes;
- b->free_bytes += b->recent_free_bytes;
+ b->allocs += b->prev_allocs;
+ b->frees += b->prev_frees;
+ b->alloc_bytes += b->prev_alloc_bytes;
+ b->free_bytes += b->prev_free_bytes;
+
+ b->prev_allocs = b->recent_allocs;
+ b->prev_frees = b->recent_frees;
+ b->prev_alloc_bytes = b->recent_alloc_bytes;
+ b->prev_free_bytes = b->recent_free_bytes;
+
b->recent_allocs = 0;
b->recent_frees = 0;
b->recent_alloc_bytes = 0;
@@ -138,143 +169,39 @@ runtime·MProf_GC(void)
runtime·unlock(&proflock);
}
-// Map from pointer to Bucket* that allocated it.
-// Three levels:
-// Linked-list hash table for top N-AddrHashShift bits.
-// Array index for next AddrDenseBits bits.
-// Linked list for next AddrHashShift-AddrDenseBits bits.
-// This is more efficient than using a general map,
-// because of the typical clustering of the pointer keys.
-
-typedef struct AddrHash AddrHash;
-typedef struct AddrEntry AddrEntry;
-
-enum {
- AddrHashBits = 12, // good for 4GB of used address space
- AddrHashShift = 20, // each AddrHash knows about 1MB of address space
- AddrDenseBits = 8, // good for a profiling rate of 4096 bytes
-};
-
-struct AddrHash
-{
- AddrHash *next; // next in top-level hash table linked list
- uintptr addr; // addr>>20
- AddrEntry *dense[1<<AddrDenseBits];
-};
-
-struct AddrEntry
-{
- AddrEntry *next; // next in bottom-level linked list
- uint32 addr;
- Bucket *b;
-};
-
-static AddrHash **addrhash; // points to (AddrHash*)[1<<AddrHashBits]
-static AddrEntry *addrfree;
-static uintptr addrmem;
-
-// Multiplicative hash function:
-// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
-// This is a good multiplier as suggested in CLR, Knuth. The hash
-// value is taken to be the top AddrHashBits bits of the bottom 32 bits
-// of the multiplied value.
-enum {
- HashMultiplier = 2654435769U
-};
-
-// Set the bucket associated with addr to b.
-static void
-setaddrbucket(uintptr addr, Bucket *b)
-{
- int32 i;
- uint32 h;
- AddrHash *ah;
- AddrEntry *e;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
-
- ah = runtime·persistentalloc(sizeof *ah, 0, &mstats.buckhash_sys);
- addrmem += sizeof *ah;
- ah->next = addrhash[h];
- ah->addr = addr>>AddrHashShift;
- addrhash[h] = ah;
-
-found:
- if((e = addrfree) == nil) {
- e = runtime·persistentalloc(64*sizeof *e, 0, &mstats.buckhash_sys);
- addrmem += 64*sizeof *e;
- for(i=0; i+1<64; i++)
- e[i].next = &e[i+1];
- e[63].next = nil;
- }
- addrfree = e->next;
- e->addr = (uint32)~(addr & ((1<<AddrHashShift)-1));
- e->b = b;
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- e->next = ah->dense[h];
- ah->dense[h] = e;
-}
-
-// Get the bucket associated with addr and clear the association.
-static Bucket*
-getaddrbucket(uintptr addr)
-{
- uint32 h;
- AddrHash *ah;
- AddrEntry *e, **l;
- Bucket *b;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
- return nil;
-
-found:
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
- if(e->addr == (uint32)~(addr & ((1<<AddrHashShift)-1))) {
- *l = e->next;
- b = e->b;
- e->next = addrfree;
- addrfree = e;
- return b;
- }
- }
- return nil;
-}
-
// Called by malloc to record a profiled block.
void
runtime·MProf_Malloc(void *p, uintptr size)
{
- int32 nstk;
uintptr stk[32];
Bucket *b;
+ int32 nstk;
- nstk = runtime·callers(1, stk, 32);
+ nstk = runtime·callers(1, stk, nelem(stk));
runtime·lock(&proflock);
- b = stkbucket(MProf, stk, nstk, true);
+ b = stkbucket(MProf, size, stk, nstk, true);
b->recent_allocs++;
b->recent_alloc_bytes += size;
- setaddrbucket((uintptr)p, b);
runtime·unlock(&proflock);
+
+ // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
+ // This reduces potential contention and chances of deadlocks.
+ // Since the object must be alive during call to MProf_Malloc,
+ // it's fine to do this non-atomically.
+ runtime·setprofilebucket(p, b);
}
// Called when freeing a profiled block.
void
-runtime·MProf_Free(void *p, uintptr size)
+runtime·MProf_Free(Bucket *b, uintptr size, bool freed)
{
- Bucket *b;
-
runtime·lock(&proflock);
- b = getaddrbucket((uintptr)p);
- if(b != nil) {
+ if(freed) {
b->recent_frees++;
b->recent_free_bytes += size;
+ } else {
+ b->prev_frees++;
+ b->prev_free_bytes += size;
}
runtime·unlock(&proflock);
}
@@ -311,9 +238,9 @@ runtime·blockevent(int64 cycles, int32 skip)
if(rate <= 0 || (rate > cycles && runtime·fastrand1()%rate > cycles))
return;
- nstk = runtime·callers(skip, stk, 32);
+ nstk = runtime·callers(skip, stk, nelem(stk));
runtime·lock(&proflock);
- b = stkbucket(BProf, stk, nstk, true);
+ b = stkbucket(BProf, 0, stk, nstk, true);
b->count++;
b->cycles += cycles;
runtime·unlock(&proflock);
@@ -365,6 +292,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
// garbage collection is disabled from the beginning of execution,
// accumulate stats as if a GC just happened, and recount buckets.
MProf_GC();
+ MProf_GC();
n = 0;
for(b=mbuckets; b; b=b->allnext)
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
@@ -381,6 +309,18 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
runtime·unlock(&proflock);
}
+void
+runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr))
+{
+ Bucket *b;
+
+ runtime·lock(&proflock);
+ for(b=mbuckets; b; b=b->allnext) {
+ callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
+ }
+ runtime·unlock(&proflock);
+}
+
// Must match BlockProfileRecord in debug.go.
typedef struct BRecord BRecord;
struct BRecord {
@@ -483,7 +423,7 @@ saveg(uintptr pc, uintptr sp, G *gp, TRecord *r)
}
func GoroutineProfile(b Slice) (n int, ok bool) {
- uintptr pc, sp;
+ uintptr pc, sp, i;
TRecord *r;
G *gp;
@@ -502,7 +442,8 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
ok = true;
r = (TRecord*)b.array;
saveg(pc, sp, g, r++);
- for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
+ for(i = 0; i < runtime·allglen; i++) {
+ gp = runtime·allg[i];
if(gp == g || gp->status == Gdead)
continue;
saveg(~(uintptr)0, ~(uintptr)0, gp, r++);
@@ -515,8 +456,72 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
}
}
+// Tracing of alloc/free/gc.
+
+static Lock tracelock;
+
+static int8*
+typeinfoname(int32 typeinfo)
+{
+ if(typeinfo == TypeInfo_SingleObject)
+ return "single object";
+ else if(typeinfo == TypeInfo_Array)
+ return "array";
+ else if(typeinfo == TypeInfo_Chan)
+ return "channel";
+ runtime·throw("typinfoname: unknown type info");
+ return nil;
+}
+
+void
+runtime·tracealloc(void *p, uintptr size, uintptr typ)
+{
+ int8 *name;
+ Type *type;
+
+ runtime·lock(&tracelock);
+ m->traceback = 2;
+ type = (Type*)(typ & ~3);
+ name = typeinfoname(typ & 3);
+ if(type == nil)
+ runtime·printf("tracealloc(%p, %p, %s)\n", p, size, name);
+ else
+ runtime·printf("tracealloc(%p, %p, %s of %S)\n", p, size, name, *type->string);
+ if(m->curg == nil || g == m->curg) {
+ runtime·goroutineheader(g);
+ runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+ } else {
+ runtime·goroutineheader(m->curg);
+ runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, m->curg);
+ }
+ runtime·printf("\n");
+ m->traceback = 0;
+ runtime·unlock(&tracelock);
+}
+
+void
+runtime·tracefree(void *p, uintptr size)
+{
+ runtime·lock(&tracelock);
+ m->traceback = 2;
+ runtime·printf("tracefree(%p, %p)\n", p, size);
+ runtime·goroutineheader(g);
+ runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+ runtime·printf("\n");
+ m->traceback = 0;
+ runtime·unlock(&tracelock);
+}
+
void
-runtime·mprofinit(void)
+runtime·tracegc(void)
{
- addrhash = runtime·persistentalloc((1<<AddrHashBits)*sizeof *addrhash, 0, &mstats.buckhash_sys);
+ runtime·lock(&tracelock);
+ m->traceback = 2;
+ runtime·printf("tracegc()\n");
+ // running on m->g0 stack; show all non-g0 goroutines
+ runtime·tracebackothers(g);
+ runtime·printf("end tracegc\n");
+ runtime·printf("\n");
+ m->traceback = 0;
+ runtime·unlock(&tracelock);
}
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index 50b372b61..2fbd5e104 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -28,8 +28,11 @@
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
+#include "../../cmd/ld/textflag.h"
+#pragma dataflag NOPTR
int32 runtime·class_to_size[NumSizeClasses];
+#pragma dataflag NOPTR
int32 runtime·class_to_allocnpages[NumSizeClasses];
// The SizeToClass lookup is implemented using two arrays,
@@ -41,11 +44,15 @@ int32 runtime·class_to_allocnpages[NumSizeClasses];
// size divided by 128 (rounded up). The arrays are filled in
// by InitSizes.
+#pragma dataflag NOPTR
int8 runtime·size_to_class8[1024/8 + 1];
+#pragma dataflag NOPTR
int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-static int32
-SizeToClass(int32 size)
+void runtime·testdefersizes(void);
+
+int32
+runtime·SizeToClass(int32 size)
{
if(size > MaxSmallSize)
runtime·throw("SizeToClass - invalid size");
@@ -90,9 +97,9 @@ runtime·InitSizes(void)
// objects into the page, we might as well
// use just this size instead of having two
// different sizes.
- if(sizeclass > 1
- && npages == runtime·class_to_allocnpages[sizeclass-1]
- && allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
+ if(sizeclass > 1 &&
+ npages == runtime·class_to_allocnpages[sizeclass-1] &&
+ allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
runtime·class_to_size[sizeclass-1] = size;
continue;
}
@@ -119,7 +126,7 @@ runtime·InitSizes(void)
// Double-check SizeToClass.
if(0) {
for(n=0; n < MaxSmallSize; n++) {
- sizeclass = SizeToClass(n);
+ sizeclass = runtime·SizeToClass(n);
if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
runtime·printf("incorrect SizeToClass");
@@ -133,6 +140,8 @@ runtime·InitSizes(void)
}
}
+ runtime·testdefersizes();
+
// Copy out for statistics table.
for(i=0; i<nelem(runtime·class_to_size); i++)
mstats.by_size[i].size = runtime·class_to_size[i];
@@ -158,3 +167,18 @@ dump:
}
runtime·throw("InitSizes failed");
}
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+uintptr
+runtime·roundupsize(uintptr size)
+{
+ if(size < MaxSmallSize) {
+ if(size <= 1024-8)
+ return runtime·class_to_size[runtime·size_to_class8[(size+7)>>3]];
+ else
+ return runtime·class_to_size[runtime·size_to_class128[(size-1024+127) >> 7]];
+ }
+ if(size + PageSize < size)
+ return size;
+ return ROUND(size, PageSize);
+}
diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
index d27bef167..7b3d16d02 100644
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
@@ -19,21 +19,46 @@ package net
// An implementation must call the following function to denote that the pd is ready.
// void runtime·netpollready(G **gpp, PollDesc *pd, int32 mode);
+// PollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
+// goroutines respectively. The semaphore can be in the following states:
+// READY - io readiness notification is pending;
+// a goroutine consumes the notification by changing the state to nil.
+// WAIT - a goroutine prepares to park on the semaphore, but not yet parked;
+// the goroutine commits to park by changing the state to G pointer,
+// or, alternatively, concurrent io notification changes the state to READY,
+// or, alternatively, concurrent timeout/close changes the state to nil.
+// G pointer - the goroutine is blocked on the semaphore;
+// io notification or timeout/close changes the state to READY or nil respectively
+// and unparks the goroutine.
+// nil - nothing of the above.
#define READY ((G*)1)
+#define WAIT ((G*)2)
+
+enum
+{
+ PollBlockSize = 4*1024,
+};
struct PollDesc
{
PollDesc* link; // in pollcache, protected by pollcache.Lock
+
+ // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
+ // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
+ // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO rediness notification)
+ // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
+ // in a lock-free way by all operations.
Lock; // protectes the following fields
uintptr fd;
bool closing;
uintptr seq; // protects from stale timers and ready notifications
- G* rg; // G waiting for read or READY (binary semaphore)
+ G* rg; // READY, WAIT, G waiting for read or nil
Timer rt; // read deadline timer (set if rt.fv != nil)
int64 rd; // read deadline
- G* wg; // the same for writes
- Timer wt;
- int64 wd;
+ G* wg; // READY, WAIT, G waiting for write or nil
+ Timer wt; // write deadline timer
+ int64 wd; // write deadline
+ void* user; // user settable cookie
};
static struct
@@ -47,7 +72,7 @@ static struct
// seq is incremented when deadlines are changed or descriptor is reused.
} pollcache;
-static bool netpollblock(PollDesc*, int32);
+static bool netpollblock(PollDesc*, int32, bool);
static G* netpollunblock(PollDesc*, int32, bool);
static void deadline(int64, Eface);
static void readDeadline(int64, Eface);
@@ -59,6 +84,11 @@ static FuncVal deadlineFn = {(void(*)(void))deadline};
static FuncVal readDeadlineFn = {(void(*)(void))readDeadline};
static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline};
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+ ns = runtime·nanotime();
+}
+
func runtime_pollServerInit() {
runtime·netpollinit();
}
@@ -97,7 +127,6 @@ func runtime_pollClose(pd *PollDesc) {
}
func runtime_pollReset(pd *PollDesc, mode int) (err int) {
- runtime·lock(pd);
err = checkerr(pd, mode);
if(err)
goto ret;
@@ -106,14 +135,15 @@ func runtime_pollReset(pd *PollDesc, mode int) (err int) {
else if(mode == 'w')
pd->wg = nil;
ret:
- runtime·unlock(pd);
}
func runtime_pollWait(pd *PollDesc, mode int) (err int) {
- runtime·lock(pd);
err = checkerr(pd, mode);
if(err == 0) {
- while(!netpollblock(pd, mode)) {
+ // As for now only Solaris uses level-triggered IO.
+ if(Solaris)
+ runtime·netpollarm(pd, mode);
+ while(!netpollblock(pd, mode, false)) {
err = checkerr(pd, mode);
if(err != 0)
break;
@@ -122,15 +152,13 @@ func runtime_pollWait(pd *PollDesc, mode int) (err int) {
// Pretend it has not happened and retry.
}
}
- runtime·unlock(pd);
}
func runtime_pollWaitCanceled(pd *PollDesc, mode int) {
- runtime·lock(pd);
- // wait for ioready, ignore closing or timeouts.
- while(!netpollblock(pd, mode))
+ // This function is used only on windows after a failed attempt to cancel
+ // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
+ while(!netpollblock(pd, mode, true))
;
- runtime·unlock(pd);
}
func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
@@ -185,7 +213,7 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
}
// If we set the new deadline in the past, unblock currently pending IO if any.
rg = nil;
- wg = nil;
+ runtime·atomicstorep(&wg, nil); // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
if(pd->rd < 0)
rg = netpollunblock(pd, 'r', false);
if(pd->wd < 0)
@@ -205,6 +233,7 @@ func runtime_pollUnblock(pd *PollDesc) {
runtime·throw("runtime_pollUnblock: already closing");
pd->closing = true;
pd->seq++;
+ runtime·atomicstorep(&rg, nil); // full memory barrier between store to closing and read of rg/wg in netpollunblock
rg = netpollunblock(pd, 'r', false);
wg = netpollunblock(pd, 'w', false);
if(pd->rt.fv) {
@@ -228,6 +257,30 @@ runtime·netpollfd(PollDesc *pd)
return pd->fd;
}
+void**
+runtime·netpolluser(PollDesc *pd)
+{
+ return &pd->user;
+}
+
+bool
+runtime·netpollclosing(PollDesc *pd)
+{
+ return pd->closing;
+}
+
+void
+runtime·netpolllock(PollDesc *pd)
+{
+ runtime·lock(pd);
+}
+
+void
+runtime·netpollunlock(PollDesc *pd)
+{
+ runtime·unlock(pd);
+}
+
// make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
void
runtime·netpollready(G **gpp, PollDesc *pd, int32 mode)
@@ -235,12 +288,10 @@ runtime·netpollready(G **gpp, PollDesc *pd, int32 mode)
G *rg, *wg;
rg = wg = nil;
- runtime·lock(pd);
if(mode == 'r' || mode == 'r'+'w')
rg = netpollunblock(pd, 'r', true);
if(mode == 'w' || mode == 'r'+'w')
wg = netpollunblock(pd, 'w', true);
- runtime·unlock(pd);
if(rg) {
rg->schedlink = *gpp;
*gpp = rg;
@@ -261,51 +312,75 @@ checkerr(PollDesc *pd, int32 mode)
return 0;
}
+static bool
+blockcommit(G *gp, G **gpp)
+{
+ return runtime·casp(gpp, WAIT, gp);
+}
+
// returns true if IO is ready, or false if timedout or closed
+// waitio - wait only for completed IO, ignore errors
static bool
-netpollblock(PollDesc *pd, int32 mode)
+netpollblock(PollDesc *pd, int32 mode, bool waitio)
{
- G **gpp;
+ G **gpp, *old;
gpp = &pd->rg;
if(mode == 'w')
gpp = &pd->wg;
- if(*gpp == READY) {
- *gpp = nil;
- return true;
+
+ // set the gpp semaphore to WAIT
+ for(;;) {
+ old = *gpp;
+ if(old == READY) {
+ *gpp = nil;
+ return true;
+ }
+ if(old != nil)
+ runtime·throw("netpollblock: double wait");
+ if(runtime·casp(gpp, nil, WAIT))
+ break;
}
- if(*gpp != nil)
- runtime·throw("netpollblock: double wait");
- *gpp = g;
- runtime·park(runtime·unlock, &pd->Lock, "IO wait");
- runtime·lock(pd);
- if(g->param)
- return true;
- return false;
+
+ // need to recheck error states after setting gpp to WAIT
+ // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
+ // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
+ if(waitio || checkerr(pd, mode) == 0)
+ runtime·park((bool(*)(G*, void*))blockcommit, gpp, "IO wait");
+ // be careful to not lose concurrent READY notification
+ old = runtime·xchgp(gpp, nil);
+ if(old > WAIT)
+ runtime·throw("netpollblock: corrupted state");
+ return old == READY;
}
static G*
netpollunblock(PollDesc *pd, int32 mode, bool ioready)
{
- G **gpp, *old;
+ G **gpp, *old, *new;
gpp = &pd->rg;
if(mode == 'w')
gpp = &pd->wg;
- if(*gpp == READY)
- return nil;
- if(*gpp == nil) {
- // Only set READY for ioready. runtime_pollWait
- // will check for timeout/cancel before waiting.
+
+ for(;;) {
+ old = *gpp;
+ if(old == READY)
+ return nil;
+ if(old == nil && !ioready) {
+ // Only set READY for ioready. runtime_pollWait
+ // will check for timeout/cancel before waiting.
+ return nil;
+ }
+ new = nil;
if(ioready)
- *gpp = READY;
- return nil;
+ new = READY;
+ if(runtime·casp(gpp, old, new))
+ break;
}
- old = *gpp;
- // pass unblock reason onto blocked g
- old->param = (void*)ioready;
- *gpp = nil;
- return old;
+ if(old > WAIT)
+ return old; // must be G*
+ return nil;
}
static void
@@ -331,14 +406,14 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write)
if(pd->rd <= 0 || pd->rt.fv == nil)
runtime·throw("deadlineimpl: inconsistent read deadline");
pd->rd = -1;
- pd->rt.fv = nil;
+ runtime·atomicstorep(&pd->rt.fv, nil); // full memory barrier between store to rd and load of rg in netpollunblock
rg = netpollunblock(pd, 'r', false);
}
if(write) {
if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
runtime·throw("deadlineimpl: inconsistent write deadline");
pd->wd = -1;
- pd->wt.fv = nil;
+ runtime·atomicstorep(&pd->wt.fv, nil); // full memory barrier between store to wd and load of wg in netpollunblock
wg = netpollunblock(pd, 'w', false);
}
runtime·unlock(pd);
@@ -374,7 +449,7 @@ allocPollDesc(void)
runtime·lock(&pollcache);
if(pollcache.first == nil) {
- n = PageSize/sizeof(*pd);
+ n = PollBlockSize/sizeof(*pd);
if(n == 0)
n = 1;
// Must be in non-GC memory because can be referenced
diff --git a/src/pkg/runtime/netpoll_epoll.c b/src/pkg/runtime/netpoll_epoll.c
index 885ac5e4d..9ea5e1a59 100644
--- a/src/pkg/runtime/netpoll_epoll.c
+++ b/src/pkg/runtime/netpoll_epoll.c
@@ -52,6 +52,13 @@ runtime·netpollclose(uintptr fd)
return -res;
}
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd, mode);
+ runtime·throw("unused");
+}
+
// polls for ready network connections
// returns list of goroutines that become runnable
G*
diff --git a/src/pkg/runtime/netpoll_kqueue.c b/src/pkg/runtime/netpoll_kqueue.c
index afc8d6859..171346cce 100644
--- a/src/pkg/runtime/netpoll_kqueue.c
+++ b/src/pkg/runtime/netpoll_kqueue.c
@@ -59,6 +59,13 @@ runtime·netpollclose(uintptr fd)
return 0;
}
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd, mode);
+ runtime·throw("unused");
+}
+
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
G*
diff --git a/src/pkg/runtime/netpoll_nacl.c b/src/pkg/runtime/netpoll_nacl.c
new file mode 100644
index 000000000..b75753a23
--- /dev/null
+++ b/src/pkg/runtime/netpoll_nacl.c
@@ -0,0 +1,37 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+void
+runtime·netpollinit(void)
+{
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+ USED(fd);
+ USED(pd);
+ return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+ USED(fd);
+ return 0;
+}
+
+G*
+runtime·netpoll(bool block)
+{
+ USED(block);
+ return nil;
+}
diff --git a/src/pkg/runtime/netpoll_solaris.c b/src/pkg/runtime/netpoll_solaris.c
new file mode 100644
index 000000000..a2631a8ab
--- /dev/null
+++ b/src/pkg/runtime/netpoll_solaris.c
@@ -0,0 +1,268 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Solaris runtime-integrated network poller.
+//
+// Solaris uses event ports for scalable network I/O. Event
+// ports are level-triggered, unlike epoll and kqueue which
+// can be configured in both level-triggered and edge-triggered
+// mode. Level triggering means we have to keep track of a few things
+// ourselves. After we receive an event for a file descriptor,
+// it's our responsibility to ask again to be notified for future
+// events for that descriptor. When doing this we must keep track of
+// what kind of events the goroutines are currently interested in,
+// for example a fd may be open both for reading and writing.
+//
+// A description of the high level operation of this code
+// follows. Networking code will get a file descriptor by some means
+// and will register it with the netpolling mechanism by a code path
+// that eventually calls runtime·netpollopen. runtime·netpollopen
+// calls port_associate with an empty event set. That means that we
+// will not receive any events at this point. The association needs
+// to be done at this early point because we need to process the I/O
+// readiness notification at some point in the future. If I/O becomes
+// ready when nobody is listening, when we finally care about it,
+// nobody will tell us anymore.
+//
+// Beside calling runtime·netpollopen, the networking code paths
+// will call runtime·netpollarm each time goroutines are interested
+// in doing network I/O. Because now we know what kind of I/O we
+// are interested in (reading/writting), we can call port_associate
+// passing the correct type of event set (POLLIN/POLLOUT). As we made
+// sure to have already associated the file descriptor with the port,
+// when we now call port_associate, we will unblock the main poller
+// loop (in runtime·netpoll) right away if the socket is actually
+// ready for I/O.
+//
+// The main poller loop runs in its own thread waiting for events
+// using port_getn. When an event happens, it will tell the scheduler
+// about it using runtime·netpollready. Besides doing this, it must
+// also re-associate the events that were not part of this current
+// notification with the file descriptor. Failing to do this would
+// mean each notification will prevent concurrent code using the
+// same file descriptor in parallel.
+//
+// The logic dealing with re-associations is encapsulated in
+// runtime·netpollupdate. This function takes care to associate the
+// descriptor only with the subset of events that were previously
+// part of the association, except the one that just happened. We
+// can't re-associate with that right away, because event ports
+// are level triggered so it would cause a busy loop. Instead, that
+// association is effected only by the runtime·netpollarm code path,
+// when Go code actually asks for I/O.
+//
+// The open and arming mechanisms are serialized using the lock
+// inside PollDesc. This is required because the netpoll loop runs
+// asynchonously in respect to other Go code and by the time we get
+// to call port_associate to update the association in the loop, the
+// file descriptor might have been closed and reopened already. The
+// lock allows runtime·netpollupdate to be called synchronously from
+// the loop thread while preventing other threads operating to the
+// same PollDesc, so once we unblock in the main loop, until we loop
+// again we know for sure we are always talking about the same file
+// descriptor and can safely access the data we want (the event set).
+
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·port_create port_create "libc.so"
+#pragma dynimport libc·port_associate port_associate "libc.so"
+#pragma dynimport libc·port_dissociate port_dissociate "libc.so"
+#pragma dynimport libc·port_getn port_getn "libc.so"
+extern uintptr libc·fcntl;
+extern uintptr libc·port_create;
+extern uintptr libc·port_associate;
+extern uintptr libc·port_dissociate;
+extern uintptr libc·port_getn;
+
+#define errno (*m->perrno)
+
+int32
+runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
+{
+ return runtime·sysvicall6(libc·fcntl, 3,
+ (uintptr)fd, (uintptr)cmd, (uintptr)arg);
+}
+
+int32
+runtime·port_create(void)
+{
+ return runtime·sysvicall6(libc·port_create, 0);
+}
+
+int32
+runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
+{
+ return runtime·sysvicall6(libc·port_associate,
+ 5, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
+}
+
+int32
+runtime·port_dissociate(int32 port, int32 source, uintptr object)
+{
+ return runtime·sysvicall6(libc·port_dissociate,
+ 3, (uintptr)port, (uintptr)source, object);
+}
+
+int32
+runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
+{
+ return runtime·sysvicall6(libc·port_getn, 5, (uintptr)port,
+ (uintptr)evs, (uintptr)max, (uintptr)nget, (uintptr)timeout);
+}
+
+static int32 portfd = -1;
+
+void
+runtime·netpollinit(void)
+{
+ if((portfd = runtime·port_create()) >= 0) {
+ runtime·fcntl(portfd, F_SETFD, FD_CLOEXEC);
+ return;
+ }
+
+ runtime·printf("netpollinit: failed to create port (%d)\n", errno);
+ runtime·throw("netpollinit: failed to create port");
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+ int32 r;
+
+ runtime·netpolllock(pd);
+ // We don't register for any specific type of events yet, that's
+ // netpollarm's job. We merely ensure we call port_associate before
+ // asynchonous connect/accept completes, so when we actually want
+ // to do any I/O, the call to port_associate (from netpollarm,
+ // with the interested event set) will unblock port_getn right away
+ // because of the I/O readiness notification.
+ *runtime·netpolluser(pd) = 0;
+ r = runtime·port_associate(portfd, PORT_SOURCE_FD, fd, 0, (uintptr)pd);
+ runtime·netpollunlock(pd);
+ return r;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+ return runtime·port_dissociate(portfd, PORT_SOURCE_FD, fd);
+}
+
+// Updates the association with a new set of interested events. After
+// this call, port_getn will return one and only one event for that
+// particular descriptor, so this function needs to be called again.
+void
+runtime·netpollupdate(PollDesc* pd, uint32 set, uint32 clear)
+{
+ uint32 *ep, old, events;
+ uintptr fd = runtime·netpollfd(pd);
+ ep = (uint32*)runtime·netpolluser(pd);
+
+ if(runtime·netpollclosing(pd))
+ return;
+
+ old = *ep;
+ events = (old & ~clear) | set;
+ if(old == events)
+ return;
+
+ if(events && runtime·port_associate(portfd, PORT_SOURCE_FD, fd, events, (uintptr)pd) != 0) {
+ runtime·printf("netpollupdate: failed to associate (%d)\n", errno);
+ runtime·throw("netpollupdate: failed to associate");
+ }
+ *ep = events;
+}
+
+// subscribe the fd to the port such that port_getn will return one event.
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ runtime·netpolllock(pd);
+ switch(mode) {
+ case 'r':
+ runtime·netpollupdate(pd, POLLIN, 0);
+ break;
+ case 'w':
+ runtime·netpollupdate(pd, POLLOUT, 0);
+ break;
+ default:
+ runtime·throw("netpollarm: bad mode");
+ }
+ runtime·netpollunlock(pd);
+}
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+G*
+runtime·netpoll(bool block)
+{
+ static int32 lasterr;
+ PortEvent events[128], *ev;
+ PollDesc *pd;
+ int32 i, mode, clear;
+ uint32 n;
+ Timespec *wait = nil, zero;
+ G *gp;
+
+ if(portfd == -1)
+ return (nil);
+
+ if(!block) {
+ zero.tv_sec = 0;
+ zero.tv_nsec = 0;
+ wait = &zero;
+ }
+
+retry:
+ n = 1;
+ if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) {
+ if(errno != EINTR && errno != lasterr) {
+ lasterr = errno;
+ runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno);
+ }
+ goto retry;
+ }
+
+ gp = nil;
+ for(i = 0; i < n; i++) {
+ ev = &events[i];
+
+ if(ev->portev_events == 0)
+ continue;
+ pd = (PollDesc *)ev->portev_user;
+
+ mode = 0;
+ clear = 0;
+ if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) {
+ mode += 'r';
+ clear |= POLLIN;
+ }
+ if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) {
+ mode += 'w';
+ clear |= POLLOUT;
+ }
+ // To effect edge-triggered events, we need to be sure to
+ // update our association with whatever events were not
+ // set with the event. For example if we are registered
+ // for POLLIN|POLLOUT, and we get POLLIN, besides waking
+ // the goroutine interested in POLLIN we have to not forget
+ // about the one interested in POLLOUT.
+ if(clear != 0) {
+ runtime·netpolllock(pd);
+ runtime·netpollupdate(pd, 0, clear);
+ runtime·netpollunlock(pd);
+ }
+
+ if(mode)
+ runtime·netpollready(&gp, pd, mode);
+ }
+
+ if(block && gp == nil)
+ goto retry;
+ return gp;
+}
diff --git a/src/pkg/runtime/netpoll_windows.c b/src/pkg/runtime/netpoll_windows.c
index b510a41e2..f3cd15c7a 100644
--- a/src/pkg/runtime/netpoll_windows.c
+++ b/src/pkg/runtime/netpoll_windows.c
@@ -72,6 +72,13 @@ runtime·netpollclose(uintptr fd)
return 0;
}
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+ USED(pd, mode);
+ runtime·throw("unused");
+}
+
// Polls for completed network IO.
// Returns list of goroutines that become runnable.
G*
@@ -94,13 +101,17 @@ retry:
n = nelem(entries) / runtime·gomaxprocs;
if(n < 8)
n = 8;
+ if(block)
+ m->blocked = true;
if(runtime·stdcall(runtime·GetQueuedCompletionStatusEx, 6, iocphandle, entries, (uintptr)n, &n, (uintptr)wait, (uintptr)0) == 0) {
+ m->blocked = false;
errno = runtime·getlasterror();
if(!block && errno == WAIT_TIMEOUT)
return nil;
runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
}
+ m->blocked = false;
for(i = 0; i < n; i++) {
op = entries[i].op;
errno = 0;
@@ -113,7 +124,10 @@ retry:
op = nil;
errno = 0;
qty = 0;
+ if(block)
+ m->blocked = true;
if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &op, (uintptr)wait) == 0) {
+ m->blocked = false;
errno = runtime·getlasterror();
if(!block && errno == WAIT_TIMEOUT)
return nil;
@@ -123,6 +137,7 @@ retry:
}
// dequeued failed IO packet, so report that
}
+ m->blocked = false;
handlecompletion(&gp, op, errno, qty);
}
if(block && gp == nil)
diff --git a/src/pkg/runtime/norace_test.go b/src/pkg/runtime/norace_test.go
index a3d5b0086..3b171877a 100644
--- a/src/pkg/runtime/norace_test.go
+++ b/src/pkg/runtime/norace_test.go
@@ -9,7 +9,6 @@ package runtime_test
import (
"runtime"
- "sync/atomic"
"testing"
)
@@ -31,28 +30,17 @@ func BenchmarkSyscallExcessWork(b *testing.B) {
}
func benchmarkSyscall(b *testing.B, work, excess int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1) * excess
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- foo := 42
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- runtime.Entersyscall()
- for i := 0; i < work; i++ {
- foo *= 2
- foo /= 2
- }
- runtime.Exitsyscall()
- }
+ b.SetParallelism(excess)
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 42
+ for pb.Next() {
+ runtime.Entersyscall()
+ for i := 0; i < work; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ runtime.Exitsyscall()
+ }
+ _ = foo
+ })
}
diff --git a/src/pkg/runtime/os_darwin.c b/src/pkg/runtime/os_darwin.c
index 9eb1b4626..33a2df958 100644
--- a/src/pkg/runtime/os_darwin.c
+++ b/src/pkg/runtime/os_darwin.c
@@ -59,6 +59,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -434,9 +435,12 @@ runtime·mach_semrelease(uint32 sem)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -444,7 +448,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -517,3 +521,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_darwin.h b/src/pkg/runtime/os_darwin.h
index b4f49e023..91a405f21 100644
--- a/src/pkg/runtime/os_darwin.h
+++ b/src/pkg/runtime/os_darwin.h
@@ -23,6 +23,7 @@ int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
typedef uint32 Sigset;
void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
struct Sigaction;
void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
@@ -39,4 +40,3 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 3
-
diff --git a/src/pkg/runtime/os_dragonfly.c b/src/pkg/runtime/os_dragonfly.c
index cf427b78c..e7fd2cc06 100644
--- a/src/pkg/runtime/os_dragonfly.c
+++ b/src/pkg/runtime/os_dragonfly.c
@@ -122,6 +122,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -169,9 +170,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -179,7 +183,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -280,3 +284,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_dragonfly.h b/src/pkg/runtime/os_dragonfly.h
index ebbd0eb15..fddeede85 100644
--- a/src/pkg/runtime/os_dragonfly.h
+++ b/src/pkg/runtime/os_dragonfly.h
@@ -12,6 +12,7 @@ void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigprocmask(Sigset *, Sigset *);
+void runtime·unblocksignals(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
diff --git a/src/pkg/runtime/os_freebsd.c b/src/pkg/runtime/os_freebsd.c
index 042097bdd..02b13472c 100644
--- a/src/pkg/runtime/os_freebsd.c
+++ b/src/pkg/runtime/os_freebsd.c
@@ -50,7 +50,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
Timespec ts;
if(ns < 0) {
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
if(ret >= 0 || ret == -EINTR)
return;
goto fail;
@@ -58,7 +58,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
ts.tv_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, &ts);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, &ts);
if(ret >= 0 || ret == -EINTR)
return;
@@ -78,7 +78,7 @@ runtime·futexwakeup(uint32 *addr, uint32 cnt)
{
int32 ret;
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
if(ret >= 0)
return;
@@ -130,6 +130,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -177,9 +178,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -187,7 +191,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -288,3 +292,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h
index c1853e65d..4b2c25330 100644
--- a/src/pkg/runtime/os_freebsd.h
+++ b/src/pkg/runtime/os_freebsd.h
@@ -12,6 +12,7 @@ void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigprocmask(Sigset *, Sigset *);
+void runtime·unblocksignals(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c
index cb45fe8ce..8a945242b 100644
--- a/src/pkg/runtime/os_linux.c
+++ b/src/pkg/runtime/os_linux.c
@@ -218,9 +218,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -228,7 +231,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -331,3 +334,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
+}
diff --git a/src/pkg/runtime/os_linux.h b/src/pkg/runtime/os_linux.h
index b2d3f6f2a..d4b1902c3 100644
--- a/src/pkg/runtime/os_linux.h
+++ b/src/pkg/runtime/os_linux.h
@@ -28,6 +28,7 @@ struct Sigset
uint32 mask[2];
};
void runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
+void runtime·unblocksignals(void);
#define SIG_SETMASK 2
#define RLIMIT_AS 9
diff --git a/src/pkg/runtime/os_linux_arm.c b/src/pkg/runtime/os_linux_arm.c
index 570b3f0be..aad08b989 100644
--- a/src/pkg/runtime/os_linux_arm.c
+++ b/src/pkg/runtime/os_linux_arm.c
@@ -16,7 +16,7 @@
static uint32 runtime·randomNumber;
uint8 runtime·armArch = 6; // we default to ARMv6
uint32 runtime·hwcap; // set by setup_auxv
-uint8 runtime·goarm; // set by 5l
+extern uint8 runtime·goarm; // set by 5l
void
runtime·checkgoarm(void)
diff --git a/src/pkg/runtime/os_nacl.c b/src/pkg/runtime/os_nacl.c
new file mode 100644
index 000000000..3196e2ce3
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.c
@@ -0,0 +1,278 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "stack.h"
+
+int8 *goos = "nacl";
+extern SigTab runtime·sigtab[];
+
+void runtime·sigtramp(void);
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+ mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+ int32 ret;
+
+ // Initialize signal handling
+ ret = runtime·nacl_exception_stack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+ if(ret < 0)
+ runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
+
+ ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
+ if(ret < 0)
+ runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
+int8 runtime·sigtrampp[] = "runtime: sigtramp";
+
+extern byte runtime·tls0[];
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = 1;
+ m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+ *(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ *rnd = nil;
+ *rnd_len = 0;
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+ Timespec ts;
+
+ ts.tv_sec = us/1000000;
+ ts.tv_nsec = (us%1000000)*1000;
+ runtime·nacl_nanosleep(&ts, nil);
+}
+
+void runtime·mstart_nacl(void);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ int32 ret;
+ void **tls;
+
+ tls = (void**)mp->tls;
+ tls[0] = mp->g0;
+ tls[1] = mp;
+ ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
+ if(ret < 0) {
+ runtime·printf("nacl_thread_create: error %d\n", -ret);
+ runtime·throw("newosproc");
+ }
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ int32 mu, cond;
+
+ mu = runtime·nacl_mutex_create(0);
+ if(mu < 0) {
+ runtime·printf("nacl_mutex_create: error %d\n", -mu);
+ runtime·throw("semacreate");
+ }
+ cond = runtime·nacl_cond_create(0);
+ if(cond < 0) {
+ runtime·printf("nacl_cond_create: error %d\n", -cond);
+ runtime·throw("semacreate");
+ }
+ m->waitsemalock = mu;
+ return cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+ int32 ret;
+
+ ret = runtime·nacl_mutex_lock(m->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ if(m->waitsemacount > 0) {
+ m->waitsemacount = 0;
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return 0;
+ }
+
+ while(m->waitsemacount == 0) {
+ if(ns < 0) {
+ ret = runtime·nacl_cond_wait(m->waitsema, m->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_cond_wait: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ } else {
+ Timespec ts;
+
+ ns += runtime·nanotime();
+ ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
+ ret = runtime·nacl_cond_timed_wait_abs(m->waitsema, m->waitsemalock, &ts);
+ if(ret == -ETIMEDOUT) {
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return -1;
+ }
+ if(ret < 0) {
+ //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+ runtime·throw("semasleep");
+ }
+ }
+ }
+
+ m->waitsemacount = 0;
+ runtime·nacl_mutex_unlock(m->waitsemalock);
+ return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ int32 ret;
+
+ ret = runtime·nacl_mutex_lock(mp->waitsemalock);
+ if(ret < 0) {
+ //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+ runtime·throw("semawakeup");
+ }
+ if(mp->waitsemacount != 0) {
+ //runtime·printf("semawakeup: double wakeup\n");
+ runtime·throw("semawakeup");
+ }
+ mp->waitsemacount = 1;
+ runtime·nacl_cond_signal(mp->waitsema);
+ runtime·nacl_mutex_unlock(mp->waitsemalock);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ runtime·printf("memlimit\n");
+ return 0;
+}
+
+#pragma dataflag NOPTR
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag NOSPLIT
+void
+runtime·badsignal2(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+ runtime·exit(2);
+}
+
+void runtime·madvise(byte*, uintptr, int32) { }
+void runtime·munmap(byte*, uintptr) {}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ USED(hz);
+}
+
+void
+runtime·sigdisable(uint32)
+{
+}
+
+void
+runtime·sigenable(uint32)
+{
+}
+
+void
+runtime·closeonexec(int32)
+{
+}
+
+void
+runtime·sigpanic(void)
+{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ // Native Client only invokes the exception handler for memory faults.
+ g->sig = SIGSEGV;
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+}
+
+uint32 runtime·writelock; // test-and-set spin lock for runtime.write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*runtime·nacl_irt_query)(void);
+
+int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
+
+int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
+
+int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
+*/ \ No newline at end of file
diff --git a/src/pkg/runtime/os_nacl.h b/src/pkg/runtime/os_nacl.h
new file mode 100644
index 000000000..7c9d9c242
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.h
@@ -0,0 +1,162 @@
+enum {
+ NSIG = 32,
+ SI_USER = 1,
+
+ // native_client/src/trusted/service_runtime/include/sys/errno.h
+ // The errors are mainly copied from Linux.
+ EPERM = 1, /* Operation not permitted */
+ ENOENT = 2, /* No such file or directory */
+ ESRCH = 3, /* No such process */
+ EINTR = 4, /* Interrupted system call */
+ EIO = 5, /* I/O error */
+ ENXIO = 6, /* No such device or address */
+ E2BIG = 7, /* Argument list too long */
+ ENOEXEC = 8, /* Exec format error */
+ EBADF = 9, /* Bad file number */
+ ECHILD = 10, /* No child processes */
+ EAGAIN = 11, /* Try again */
+ ENOMEM = 12, /* Out of memory */
+ EACCES = 13, /* Permission denied */
+ EFAULT = 14, /* Bad address */
+ EBUSY = 16, /* Device or resource busy */
+ EEXIST = 17, /* File exists */
+ EXDEV = 18, /* Cross-device link */
+ ENODEV = 19, /* No such device */
+ ENOTDIR = 20, /* Not a directory */
+ EISDIR = 21, /* Is a directory */
+ EINVAL = 22, /* Invalid argument */
+ ENFILE = 23, /* File table overflow */
+ EMFILE = 24, /* Too many open files */
+ ENOTTY = 25, /* Not a typewriter */
+ EFBIG = 27, /* File too large */
+ ENOSPC = 28, /* No space left on device */
+ ESPIPE = 29, /* Illegal seek */
+ EROFS = 30, /* Read-only file system */
+ EMLINK = 31, /* Too many links */
+ EPIPE = 32, /* Broken pipe */
+ ENAMETOOLONG = 36, /* File name too long */
+ ENOSYS = 38, /* Function not implemented */
+ EDQUOT = 122, /* Quota exceeded */
+ EDOM = 33, /* Math arg out of domain of func */
+ ERANGE = 34, /* Math result not representable */
+ EDEADLK = 35, /* Deadlock condition */
+ ENOLCK = 37, /* No record locks available */
+ ENOTEMPTY = 39, /* Directory not empty */
+ ELOOP = 40, /* Too many symbolic links */
+ ENOMSG = 42, /* No message of desired type */
+ EIDRM = 43, /* Identifier removed */
+ ECHRNG = 44, /* Channel number out of range */
+ EL2NSYNC = 45, /* Level 2 not synchronized */
+ EL3HLT = 46, /* Level 3 halted */
+ EL3RST = 47, /* Level 3 reset */
+ ELNRNG = 48, /* Link number out of range */
+ EUNATCH = 49, /* Protocol driver not attached */
+ ENOCSI = 50, /* No CSI structure available */
+ EL2HLT = 51, /* Level 2 halted */
+ EBADE = 52, /* Invalid exchange */
+ EBADR = 53, /* Invalid request descriptor */
+ EXFULL = 54, /* Exchange full */
+ ENOANO = 55, /* No anode */
+ EBADRQC = 56, /* Invalid request code */
+ EBADSLT = 57, /* Invalid slot */
+ EDEADLOCK = EDEADLK, /* File locking deadlock error */
+ EBFONT = 59, /* Bad font file fmt */
+ ENOSTR = 60, /* Device not a stream */
+ ENODATA = 61, /* No data (for no delay io) */
+ ETIME = 62, /* Timer expired */
+ ENOSR = 63, /* Out of streams resources */
+ ENONET = 64, /* Machine is not on the network */
+ ENOPKG = 65, /* Package not installed */
+ EREMOTE = 66, /* The object is remote */
+ ENOLINK = 67, /* The link has been severed */
+ EADV = 68, /* Advertise error */
+ ESRMNT = 69, /* Srmount error */
+ ECOMM = 70, /* Communication error on send */
+ EPROTO = 71, /* Protocol error */
+ EMULTIHOP = 72, /* Multihop attempted */
+ EDOTDOT = 73, /* Cross mount point (not really error) */
+ EBADMSG = 74, /* Trying to read unreadable message */
+ EOVERFLOW = 75, /* Value too large for defined data type */
+ ENOTUNIQ = 76, /* Given log. name not unique */
+ EBADFD = 77, /* f.d. invalid for this operation */
+ EREMCHG = 78, /* Remote address changed */
+ ELIBACC = 79, /* Can't access a needed shared lib */
+ ELIBBAD = 80, /* Accessing a corrupted shared lib */
+ ELIBSCN = 81, /* .lib section in a.out corrupted */
+ ELIBMAX = 82, /* Attempting to link in too many libs */
+ ELIBEXEC = 83, /* Attempting to exec a shared library */
+ EILSEQ = 84,
+ EUSERS = 87,
+ ENOTSOCK = 88, /* Socket operation on non-socket */
+ EDESTADDRREQ = 89, /* Destination address required */
+ EMSGSIZE = 90, /* Message too long */
+ EPROTOTYPE = 91, /* Protocol wrong type for socket */
+ ENOPROTOOPT = 92, /* Protocol not available */
+ EPROTONOSUPPORT = 93, /* Unknown protocol */
+ ESOCKTNOSUPPORT = 94, /* Socket type not supported */
+ EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
+ EPFNOSUPPORT = 96, /* Protocol family not supported */
+ EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
+ EADDRINUSE = 98, /* Address already in use */
+ EADDRNOTAVAIL = 99, /* Address not available */
+ ENETDOWN = 100, /* Network interface is not configured */
+ ENETUNREACH = 101, /* Network is unreachable */
+ ENETRESET = 102,
+ ECONNABORTED = 103, /* Connection aborted */
+ ECONNRESET = 104, /* Connection reset by peer */
+ ENOBUFS = 105, /* No buffer space available */
+ EISCONN = 106, /* Socket is already connected */
+ ENOTCONN = 107, /* Socket is not connected */
+ ESHUTDOWN = 108, /* Can't send after socket shutdown */
+ ETOOMANYREFS = 109,
+ ETIMEDOUT = 110, /* Connection timed out */
+ ECONNREFUSED = 111, /* Connection refused */
+ EHOSTDOWN = 112, /* Host is down */
+ EHOSTUNREACH = 113, /* Host is unreachable */
+ EALREADY = 114, /* Socket already connected */
+ EINPROGRESS = 115, /* Connection already in progress */
+ ESTALE = 116,
+ ENOTSUP = EOPNOTSUPP, /* Not supported */
+ ENOMEDIUM = 123, /* No medium (in tape drive) */
+ ECANCELED = 125, /* Operation canceled. */
+ ELBIN = 2048, /* Inode is remote (not really error) */
+ EFTYPE = 2049, /* Inappropriate file type or format */
+ ENMFILE = 2050, /* No more files */
+ EPROCLIM = 2051,
+ ENOSHARE = 2052, /* No such host or network path */
+ ECASECLASH = 2053, /* Filename exists with different case */
+ EWOULDBLOCK = EAGAIN, /* Operation would block */
+
+ // native_client/src/trusted/service_runtime/include/bits/mman.h.
+ // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+ // Those MAP_*values are different from these.
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_SHARED = 0x1,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ MAP_ANON = 0x20,
+};
+typedef byte* kevent_udata;
+
+int32 runtime·nacl_exception_stack(byte*, int32);
+int32 runtime·nacl_exception_handler(void*, void*);
+int32 runtime·nacl_sem_create(int32);
+int32 runtime·nacl_sem_wait(int32);
+int32 runtime·nacl_sem_post(int32);
+int32 runtime·nacl_mutex_create(int32);
+int32 runtime·nacl_mutex_lock(int32);
+int32 runtime·nacl_mutex_trylock(int32);
+int32 runtime·nacl_mutex_unlock(int32);
+int32 runtime·nacl_cond_create(int32);
+int32 runtime·nacl_cond_wait(int32, int32);
+int32 runtime·nacl_cond_signal(int32);
+int32 runtime·nacl_cond_broadcast(int32);
+int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
+int32 runtime·nacl_thread_create(void*, void*, void*, void*);
+int32 runtime·nacl_nanosleep(Timespec*, Timespec*);
+
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/os_netbsd.c b/src/pkg/runtime/os_netbsd.c
index a49dca295..93229bffe 100644
--- a/src/pkg/runtime/os_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -188,6 +188,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -237,9 +238,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -247,7 +251,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -326,3 +330,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
index 55743c8d5..16e9833af 100644
--- a/src/pkg/runtime/os_netbsd.h
+++ b/src/pkg/runtime/os_netbsd.h
@@ -18,6 +18,7 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
extern void runtime·lwp_tramp(void);
diff --git a/src/pkg/runtime/os_openbsd.c b/src/pkg/runtime/os_openbsd.c
index 18377a047..08a290a05 100644
--- a/src/pkg/runtime/os_openbsd.c
+++ b/src/pkg/runtime/os_openbsd.c
@@ -82,7 +82,7 @@ runtime·semasleep(int64 ns)
// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
ts.tv_nsec = 0;
ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
- runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil);
+ runtime·thrsleep(&m->waitsemacount, CLOCK_MONOTONIC, &ts, &m->waitsemalock, nil);
}
// reacquire lock
while(runtime·xchg(&m->waitsemalock, 1))
@@ -167,6 +167,7 @@ runtime·osinit(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
+ #pragma dataflag NOPTR
static byte urandom_data[HashRandomBytes];
int32 fd;
fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -214,9 +215,12 @@ runtime·unminit(void)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -224,7 +228,7 @@ runtime·sigpanic(void)
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -300,3 +304,9 @@ runtime·signalstack(byte *p, int32 n)
st.ss_flags = SS_DISABLE;
runtime·sigaltstack(&st, nil);
}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, sigset_none);
+}
diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h
index 4746b314f..bbfde39e2 100644
--- a/src/pkg/runtime/os_openbsd.h
+++ b/src/pkg/runtime/os_openbsd.h
@@ -18,6 +18,7 @@ void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
Sigset runtime·sigprocmask(int32, Sigset);
+void runtime·unblocksignals(void);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
#define NSIG 33
diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c
index 07db2c305..14d4fae48 100644
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -102,8 +102,18 @@ runtime·crash(void)
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
- *rnd = nil;
- *rnd_len = 0;
+ static byte random_data[HashRandomBytes];
+ int32 fd;
+
+ fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
}
void
@@ -183,13 +193,15 @@ runtime·itoa(int32 n, byte *p, uint32 len)
void
runtime·goexitsall(int8 *status)
{
+ int8 buf[ERRMAX];
M *mp;
int32 pid;
+ runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status);
pid = getpid();
for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
if(mp->procid != pid)
- runtime·postnote(mp->procid, status);
+ runtime·postnote(mp->procid, buf);
}
int32
@@ -271,6 +283,8 @@ runtime·semasleep(int64 ns)
if(ns >= 0) {
ms = runtime·timediv(ns, 1000000, nil);
+ if(ms == 0)
+ ms = 1;
ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms);
if(ret == 1)
return 0; // success
@@ -295,15 +309,82 @@ os·sigpipe(void)
runtime·throw("too many writes on closed pipe");
}
+static int64
+atolwhex(byte *p)
+{
+ int64 n;
+ int32 f;
+
+ n = 0;
+ f = 0;
+ while(*p == ' ' || *p == '\t')
+ p++;
+ if(*p == '-' || *p == '+') {
+ if(*p++ == '-')
+ f = 1;
+ while(*p == ' ' || *p == '\t')
+ p++;
+ }
+ if(p[0] == '0' && p[1]) {
+ if(p[1] == 'x' || p[1] == 'X') {
+ p += 2;
+ for(;;) {
+ if('0' <= *p && *p <= '9')
+ n = n*16 + *p++ - '0';
+ else if('a' <= *p && *p <= 'f')
+ n = n*16 + *p++ - 'a' + 10;
+ else if('A' <= *p && *p <= 'F')
+ n = n*16 + *p++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while('0' <= *p && *p <= '7')
+ n = n*8 + *p++ - '0';
+ } else
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
void
runtime·sigpanic(void)
{
- if(g->sigpc == 0)
- runtime·panicstring("call of nil func value");
- runtime·panicstring(m->notesig);
-
- if(g->sig == 1 || g->sig == 2)
+ byte *p;
+
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ switch(g->sig) {
+ case SIGRFAULT:
+ case SIGWFAULT:
+ p = runtime·strstr((byte*)m->notesig, (byte*)"addr=")+5;
+ g->sigcode1 = atolwhex(p);
+ if(g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
+ break;
+ case SIGTRAP:
+ if(g->paniconfault)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·throw(m->notesig);
+ break;
+ case SIGINTDIV:
+ runtime·panicstring("integer divide by zero");
+ break;
+ case SIGFLOAT:
+ runtime·panicstring("floating point error");
+ break;
+ default:
+ runtime·panicstring(m->notesig);
+ break;
+ }
}
int32
@@ -313,9 +394,9 @@ runtime·read(int32 fd, void *buf, int32 nbytes)
}
int32
-runtime·write(int32 fd, void *buf, int32 nbytes)
+runtime·write(uintptr fd, void *buf, int32 nbytes)
{
- return runtime·pwrite(fd, buf, nbytes, -1LL);
+ return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
}
uintptr
diff --git a/src/pkg/runtime/os_plan9.h b/src/pkg/runtime/os_plan9.h
index f0474cda5..00ea8366d 100644
--- a/src/pkg/runtime/os_plan9.h
+++ b/src/pkg/runtime/os_plan9.h
@@ -78,5 +78,12 @@ struct Tos {
/* top of stack is here */
};
-#define NSIG 5 /* number of signals in runtime·SigTab array */
+#define NSIG 14 /* number of signals in runtime·SigTab array */
#define ERRMAX 128 /* max length of note string */
+
+/* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
+#define SIGRFAULT 2
+#define SIGWFAULT 3
+#define SIGINTDIV 4
+#define SIGFLOAT 5
+#define SIGTRAP 6
diff --git a/src/pkg/runtime/os_plan9_386.c b/src/pkg/runtime/os_plan9_386.c
index 0844d726b..80d711f33 100644
--- a/src/pkg/runtime/os_plan9_386.c
+++ b/src/pkg/runtime/os_plan9_386.c
@@ -10,71 +10,80 @@
void
runtime·dumpregs(Ureg *u)
{
- runtime·printf("ax %X\n", u->ax);
- runtime·printf("bx %X\n", u->bx);
- runtime·printf("cx %X\n", u->cx);
- runtime·printf("dx %X\n", u->dx);
- runtime·printf("di %X\n", u->di);
- runtime·printf("si %X\n", u->si);
- runtime·printf("bp %X\n", u->bp);
- runtime·printf("sp %X\n", u->sp);
- runtime·printf("pc %X\n", u->pc);
- runtime·printf("flags %X\n", u->flags);
- runtime·printf("cs %X\n", u->cs);
- runtime·printf("fs %X\n", u->fs);
- runtime·printf("gs %X\n", u->gs);
+ runtime·printf("ax %x\n", u->ax);
+ runtime·printf("bx %x\n", u->bx);
+ runtime·printf("cx %x\n", u->cx);
+ runtime·printf("dx %x\n", u->dx);
+ runtime·printf("di %x\n", u->di);
+ runtime·printf("si %x\n", u->si);
+ runtime·printf("bp %x\n", u->bp);
+ runtime·printf("sp %x\n", u->sp);
+ runtime·printf("pc %x\n", u->pc);
+ runtime·printf("flags %x\n", u->flags);
+ runtime·printf("cs %x\n", u->cs);
+ runtime·printf("fs %x\n", u->fs);
+ runtime·printf("gs %x\n", u->gs);
}
int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
{
+ uintptr *sp;
+ SigTab *t;
bool crash;
Ureg *ureg;
- uintptr *sp;
- SigTab *sig, *nsig;
- intgo len, i;
+ intgo len, n;
+ int32 sig, flags;
- if(!s)
- return NCONT;
-
- len = runtime·findnull((byte*)s);
- if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
- return NDFLT;
-
- nsig = nil;
- sig = runtime·sigtab;
- for(i=0; i < NSIG; i++) {
- if(runtime·strstr((byte*)s, (byte*)sig->name)) {
- nsig = sig;
+ ureg = (Ureg*)v;
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in runtime·sigtramp.
+ if(ureg == nil || note == nil) {
+ runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+ goto Throw;
+ }
+
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ len = runtime·findnull((byte*)note);
+ if(len > ERRMAX-1) {
+ runtime·printf("sighandler: note is longer than ERRMAX\n");
+ goto Throw;
+ }
+
+ // See if the note matches one of the patterns in runtime·sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = SigNotify;
+ for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+ t = &runtime·sigtab[sig];
+ n = runtime·findnull((byte*)t->name);
+ if(len < n)
+ continue;
+ if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+ flags = t->flags;
break;
}
- sig++;
}
- if(nsig == nil)
- return NDFLT;
-
- ureg = v;
- if(nsig->flags & SigPanic) {
- if(gp == nil || m->notesig == 0)
- goto Throw;
+ if(flags & SigGoExit)
+ runtime·exits(note+9); // Strip "go: exit " prefix.
- // Save error string from sigtramp's stack,
- // into gsignal->sigcode0, so we can reliably
- // access it from the panic routines.
- if(len > ERRMAX)
- len = ERRMAX;
- runtime·memmove((void*)m->notesig, (void*)s, len);
+ if(flags & SigPanic) {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ runtime·memmove(m->notesig, note, len+1);
- gp->sig = i;
+ gp->sig = sig;
gp->sigpc = ureg->pc;
- // Only push runtime·sigpanic if ureg->pc != 0.
- // If ureg->pc == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
+ // Only push runtime·sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to runtime·sigpanic instead. (Otherwise the trace will end at
+ // runtime·sigpanic and we won't get to see who faulted).
if(ureg->pc != 0) {
sp = (uintptr*)ureg->sp;
*--sp = ureg->pc;
@@ -84,34 +93,42 @@ runtime·sighandler(void *v, int8 *s, G *gp)
return NCONT;
}
- if(!(nsig->flags & SigThrow))
- return NDFLT;
+ if(flags & SigNotify) {
+ // TODO(ality): See if os/signal wants it.
+ //if(runtime·sigsend(...))
+ // return NCONT;
+ }
+ if(flags & SigKill)
+ goto Exit;
+ if(!(flags & SigThrow))
+ return NCONT;
Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
- runtime·printf("%s\n", s);
- runtime·printf("PC=%X\n", ureg->pc);
+ runtime·printf("%s\n", note);
+ runtime·printf("PC=%x\n", ureg->pc);
runtime·printf("\n");
if(runtime·gotraceback(&crash)) {
+ runtime·goroutineheader(gp);
runtime·traceback(ureg->pc, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
+ runtime·printf("\n");
runtime·dumpregs(ureg);
}
if(crash)
runtime·crash();
- runtime·goexitsall("");
- runtime·exits(s);
-
- return 0;
+Exit:
+ runtime·goexitsall(note);
+ runtime·exits(note);
+ return NDFLT; // not reached
}
-
void
runtime·sigenable(uint32 sig)
{
diff --git a/src/pkg/runtime/os_plan9_amd64.c b/src/pkg/runtime/os_plan9_amd64.c
index 58822ff84..a4e5ba819 100644
--- a/src/pkg/runtime/os_plan9_amd64.c
+++ b/src/pkg/runtime/os_plan9_amd64.c
@@ -34,55 +34,64 @@ runtime·dumpregs(Ureg *u)
}
int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
{
+ uintptr *sp;
+ SigTab *t;
bool crash;
Ureg *ureg;
- uintptr *sp;
- SigTab *sig, *nsig;
- intgo i, len;
+ intgo len, n;
+ int32 sig, flags;
- if(!s)
- return NCONT;
-
- len = runtime·findnull((byte*)s);
- if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
- return NDFLT;
-
- nsig = nil;
- sig = runtime·sigtab;
- for(i=0; i < NSIG; i++) {
- if(runtime·strstr((byte*)s, (byte*)sig->name)) {
- nsig = sig;
+ ureg = (Ureg*)v;
+
+ // The kernel will never pass us a nil note or ureg so we probably
+ // made a mistake somewhere in runtime·sigtramp.
+ if(ureg == nil || note == nil) {
+ runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+ goto Throw;
+ }
+
+ // Check that the note is no more than ERRMAX bytes (including
+ // the trailing NUL). We should never receive a longer note.
+ len = runtime·findnull((byte*)note);
+ if(len > ERRMAX-1) {
+ runtime·printf("sighandler: note is longer than ERRMAX\n");
+ goto Throw;
+ }
+
+ // See if the note matches one of the patterns in runtime·sigtab.
+ // Notes that do not match any pattern can be handled at a higher
+ // level by the program but will otherwise be ignored.
+ flags = SigNotify;
+ for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+ t = &runtime·sigtab[sig];
+ n = runtime·findnull((byte*)t->name);
+ if(len < n)
+ continue;
+ if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+ flags = t->flags;
break;
}
- sig++;
}
- if(nsig == nil)
- return NDFLT;
-
- ureg = v;
- if(nsig->flags & SigPanic) {
- if(gp == nil || m->notesig == 0)
- goto Throw;
+ if(flags & SigGoExit)
+ runtime·exits(note+9); // Strip "go: exit " prefix.
- // Save error string from sigtramp's stack,
- // into gsignal->sigcode0, so we can reliably
- // access it from the panic routines.
- if(len > ERRMAX)
- len = ERRMAX;
- runtime·memmove((void*)m->notesig, (void*)s, len);
+ if(flags & SigPanic) {
+ // Copy the error string from sigtramp's stack into m->notesig so
+ // we can reliably access it from the panic routines.
+ runtime·memmove(m->notesig, note, len+1);
- gp->sig = i;
+ gp->sig = sig;
gp->sigpc = ureg->ip;
- // Only push runtime·sigpanic if ureg->ip != 0.
- // If ureg->ip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
+ // Only push runtime·sigpanic if PC != 0.
+ //
+ // If PC == 0, probably panicked because of a call to a nil func.
+ // Not pushing that onto SP will make the trace look like a call
+ // to runtime·sigpanic instead. (Otherwise the trace will end at
+ // runtime·sigpanic and we won't get to see who faulted).
if(ureg->ip != 0) {
sp = (uintptr*)ureg->sp;
*--sp = ureg->ip;
@@ -92,31 +101,40 @@ runtime·sighandler(void *v, int8 *s, G *gp)
return NCONT;
}
- if(!(nsig->flags & SigThrow))
- return NDFLT;
+ if(flags & SigNotify) {
+ // TODO(ality): See if os/signal wants it.
+ //if(runtime·sigsend(...))
+ // return NCONT;
+ }
+ if(flags & SigKill)
+ goto Exit;
+ if(!(flags & SigThrow))
+ return NCONT;
Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
- runtime·printf("%s\n", s);
+ runtime·printf("%s\n", note);
runtime·printf("PC=%X\n", ureg->ip);
runtime·printf("\n");
if(runtime·gotraceback(&crash)) {
+ runtime·goroutineheader(gp);
runtime·traceback(ureg->ip, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
+ runtime·printf("\n");
runtime·dumpregs(ureg);
}
if(crash)
runtime·crash();
- runtime·goexitsall("");
- runtime·exits(s);
-
- return 0;
+Exit:
+ runtime·goexitsall(note);
+ runtime·exits(note);
+ return NDFLT; // not reached
}
void
diff --git a/src/pkg/runtime/os_solaris.c b/src/pkg/runtime/os_solaris.c
new file mode 100644
index 000000000..c6bbea311
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.c
@@ -0,0 +1,583 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+#include "stack.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynexport end _end
+#pragma dynexport etext _etext
+#pragma dynexport edata _edata
+
+#pragma dynimport libc·___errno ___errno "libc.so"
+#pragma dynimport libc·clock_gettime clock_gettime "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·exit exit "libc.so"
+#pragma dynimport libc·fstat fstat "libc.so"
+#pragma dynimport libc·getcontext getcontext "libc.so"
+#pragma dynimport libc·getrlimit getrlimit "libc.so"
+#pragma dynimport libc·malloc malloc "libc.so"
+#pragma dynimport libc·mmap mmap "libc.so"
+#pragma dynimport libc·munmap munmap "libc.so"
+#pragma dynimport libc·open open "libc.so"
+#pragma dynimport libc·pthread_attr_destroy pthread_attr_destroy "libc.so"
+#pragma dynimport libc·pthread_attr_getstack pthread_attr_getstack "libc.so"
+#pragma dynimport libc·pthread_attr_init pthread_attr_init "libc.so"
+#pragma dynimport libc·pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
+#pragma dynimport libc·pthread_attr_setstack pthread_attr_setstack "libc.so"
+#pragma dynimport libc·pthread_create pthread_create "libc.so"
+#pragma dynimport libc·raise raise "libc.so"
+#pragma dynimport libc·read read "libc.so"
+#pragma dynimport libc·select select "libc.so"
+#pragma dynimport libc·sched_yield sched_yield "libc.so"
+#pragma dynimport libc·sem_init sem_init "libc.so"
+#pragma dynimport libc·sem_post sem_post "libc.so"
+#pragma dynimport libc·sem_reltimedwait_np sem_reltimedwait_np "libc.so"
+#pragma dynimport libc·sem_wait sem_wait "libc.so"
+#pragma dynimport libc·setitimer setitimer "libc.so"
+#pragma dynimport libc·sigaction sigaction "libc.so"
+#pragma dynimport libc·sigaltstack sigaltstack "libc.so"
+#pragma dynimport libc·sigprocmask sigprocmask "libc.so"
+#pragma dynimport libc·sysconf sysconf "libc.so"
+#pragma dynimport libc·usleep usleep "libc.so"
+#pragma dynimport libc·write write "libc.so"
+
+extern uintptr libc·___errno;
+extern uintptr libc·clock_gettime;
+extern uintptr libc·close;
+extern uintptr libc·exit;
+extern uintptr libc·fstat;
+extern uintptr libc·getcontext;
+extern uintptr libc·getrlimit;
+extern uintptr libc·malloc;
+extern uintptr libc·mmap;
+extern uintptr libc·munmap;
+extern uintptr libc·open;
+extern uintptr libc·pthread_attr_destroy;
+extern uintptr libc·pthread_attr_getstack;
+extern uintptr libc·pthread_attr_init;
+extern uintptr libc·pthread_attr_setdetachstate;
+extern uintptr libc·pthread_attr_setstack;
+extern uintptr libc·pthread_create;
+extern uintptr libc·raise;
+extern uintptr libc·read;
+extern uintptr libc·sched_yield;
+extern uintptr libc·select;
+extern uintptr libc·sem_init;
+extern uintptr libc·sem_post;
+extern uintptr libc·sem_reltimedwait_np;
+extern uintptr libc·sem_wait;
+extern uintptr libc·setitimer;
+extern uintptr libc·sigaction;
+extern uintptr libc·sigaltstack;
+extern uintptr libc·sigprocmask;
+extern uintptr libc·sysconf;
+extern uintptr libc·usleep;
+extern uintptr libc·write;
+
+void runtime·getcontext(Ucontext *context);
+int32 runtime·pthread_attr_destroy(PthreadAttr* attr);
+int32 runtime·pthread_attr_init(PthreadAttr* attr);
+int32 runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size);
+int32 runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state);
+int32 runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size);
+int32 runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg);
+uint32 runtime·tstart_sysvicall(M *newm);
+int32 runtime·sem_init(SemT* sem, int32 pshared, uint32 value);
+int32 runtime·sem_post(SemT* sem);
+int32 runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout);
+int32 runtime·sem_wait(SemT* sem);
+int64 runtime·sysconf(int32 name);
+
+extern SigTab runtime·sigtab[];
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+// Calling sysvcall on os stack.
+#pragma textflag NOSPLIT
+uintptr
+runtime·sysvicall6(uintptr fn, int32 count, ...)
+{
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->libcall.fn = (void*)fn;
+ m->libcall.n = (uintptr)count;
+ for(;count; count--)
+ m->scratch.v[count - 1] = *((uintptr*)&count + count);
+ m->libcall.args = (uintptr*)&m->scratch.v[0];
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ return m->libcall.r1;
+}
+
+static int32
+getncpu(void)
+{
+ int32 n;
+
+ n = (int32)runtime·sysconf(_SC_NPROCESSORS_ONLN);
+ if(n < 1)
+ return 1;
+ return n;
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getncpu();
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ PthreadAttr attr;
+ Sigset oset;
+ Pthread tid;
+ int32 ret;
+
+ USED(stk);
+ if(runtime·pthread_attr_init(&attr) != 0)
+ runtime·throw("pthread_attr_init");
+ if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0)
+ runtime·throw("pthread_attr_setstack");
+ if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stackbase, &mp->g0->stacksize) != 0)
+ runtime·throw("pthread_attr_getstack");
+ if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+ runtime·throw("pthread_attr_setdetachstate");
+
+ // Disable signals during create, so that the new thread starts
+ // with signals disabled. It will enable them in minit.
+ runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
+ ret = runtime·pthread_create(&tid, &attr, (void (*)(void))runtime·tstart_sysvicall, mp);
+ runtime·sigprocmask(SIG_SETMASK, &oset, nil);
+ if(ret != 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), ret);
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ #pragma dataflag NOPTR
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+ mp->gsignal = runtime·malg(32*1024);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+ runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno);
+ // Initialize signal handling
+ runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+ runtime·signalstack(nil, 0);
+}
+
+void
+runtime·sigpanic(void)
+{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ Rlimit rl;
+ extern byte text[], end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = end - text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+extern void runtime·sigtramp(void);
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask.__sigbits[0] = ~(uint32)0;
+ sa.sa_mask.__sigbits[1] = ~(uint32)0;
+ sa.sa_mask.__sigbits[2] = ~(uint32)0;
+ sa.sa_mask.__sigbits[3] = ~(uint32)0;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ *((void**)&sa._funcptr[0]) = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ if(*((void**)&sa._funcptr[0]) == runtime·sigtramp)
+ return runtime·sighandler;
+ return *((void**)&sa._funcptr[0]);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·unblocksignals(void)
+{
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+ SemT* sem;
+
+ // Call libc's malloc rather than runtime·malloc. This will
+ // allocate space on the C heap. We can't call runtime·malloc
+ // here because it could cause a deadlock.
+ m->libcall.fn = (void*)libc·malloc;
+ m->libcall.n = 1;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = (uintptr)sizeof(*sem);
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ sem = (void*)m->libcall.r1;
+ if(runtime·sem_init(sem, 0, 0) != 0)
+ runtime·throw("sem_init");
+ return (uintptr)sem;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+ if(ns >= 0) {
+ m->ts.tv_sec = ns / 1000000000LL;
+ m->ts.tv_nsec = ns % 1000000000LL;
+
+ m->libcall.fn = (void*)libc·sem_reltimedwait_np;
+ m->libcall.n = 2;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = m->waitsema;
+ m->scratch.v[1] = (uintptr)&m->ts;
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ if(*m->perrno != 0) {
+ if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR)
+ return -1;
+ runtime·throw("sem_reltimedwait_np");
+ }
+ return 0;
+ }
+ for(;;) {
+ m->libcall.fn = (void*)libc·sem_wait;
+ m->libcall.n = 1;
+ runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+ m->scratch.v[0] = m->waitsema;
+ m->libcall.args = (uintptr*)&m->scratch;
+ runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+ if(m->libcall.r1 == 0)
+ break;
+ if(*m->perrno == EINTR)
+ continue;
+ runtime·throw("sem_wait");
+ }
+ return 0;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+ SemT* sem = (SemT*)mp->waitsema;
+ if(runtime·sem_post(sem) != 0)
+ runtime·throw("sem_post");
+}
+
+int32
+runtime·close(int32 fd)
+{
+ return runtime·sysvicall6(libc·close, 1, (uintptr)fd);
+}
+
+void
+runtime·exit(int32 r)
+{
+ runtime·sysvicall6(libc·exit, 1, (uintptr)r);
+}
+
+/* int32 */ void
+runtime·getcontext(Ucontext* context)
+{
+ runtime·sysvicall6(libc·getcontext, 1, (uintptr)context);
+}
+
+int32
+runtime·getrlimit(int32 res, Rlimit* rlp)
+{
+ return runtime·sysvicall6(libc·getrlimit, 2, (uintptr)res, (uintptr)rlp);
+}
+
+uint8*
+runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
+{
+ return (uint8*)runtime·sysvicall6(libc·mmap, 6, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
+}
+
+void
+runtime·munmap(byte* addr, uintptr len)
+{
+ runtime·sysvicall6(libc·munmap, 2, (uintptr)addr, (uintptr)len);
+}
+
+extern int64 runtime·nanotime1(void);
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+ return runtime·sysvicall6((uintptr)runtime·nanotime1, 0);
+}
+
+void
+time·now(int64 sec, int32 usec)
+{
+ int64 ns;
+
+ ns = runtime·nanotime();
+ sec = ns / 1000000000LL;
+ usec = ns - sec * 1000000000LL;
+ FLUSH(&sec);
+ FLUSH(&usec);
+}
+
+int32
+runtime·open(int8* path, int32 oflag, int32 mode)
+{
+ return runtime·sysvicall6(libc·open, 3, (uintptr)path, (uintptr)oflag, (uintptr)mode);
+}
+
+int32
+runtime·pthread_attr_destroy(PthreadAttr* attr)
+{
+ return runtime·sysvicall6(libc·pthread_attr_destroy, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
+{
+ return runtime·sysvicall6(libc·pthread_attr_getstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_attr_init(PthreadAttr* attr)
+{
+ return runtime·sysvicall6(libc·pthread_attr_init, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
+{
+ return runtime·sysvicall6(libc·pthread_attr_setdetachstate, 2, (uintptr)attr, (uintptr)state);
+}
+
+int32
+runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
+{
+ return runtime·sysvicall6(libc·pthread_attr_setstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
+{
+ return runtime·sysvicall6(libc·pthread_create, 4, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
+}
+
+/* int32 */ void
+runtime·raise(int32 sig)
+{
+ runtime·sysvicall6(libc·raise, 1, (uintptr)sig);
+}
+
+int32
+runtime·read(int32 fd, void* buf, int32 nbyte)
+{
+ return runtime·sysvicall6(libc·read, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
+{
+ return runtime·sysvicall6(libc·sem_init, 3, (uintptr)sem, (uintptr)pshared, (uintptr)value);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_post(SemT* sem)
+{
+ return runtime·sysvicall6(libc·sem_post, 1, (uintptr)sem);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
+{
+ return runtime·sysvicall6(libc·sem_reltimedwait_np, 2, (uintptr)sem, (uintptr)timeout);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_wait(SemT* sem)
+{
+ return runtime·sysvicall6(libc·sem_wait, 1, (uintptr)sem);
+}
+
+/* int32 */ void
+runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
+{
+ runtime·sysvicall6(libc·setitimer, 3, (uintptr)which, (uintptr)value, (uintptr)ovalue);
+}
+
+/* int32 */ void
+runtime·sigaction(int32 sig, struct Sigaction* act, struct Sigaction* oact)
+{
+ runtime·sysvicall6(libc·sigaction, 3, (uintptr)sig, (uintptr)act, (uintptr)oact);
+}
+
+/* int32 */ void
+runtime·sigaltstack(Sigaltstack* ss, Sigaltstack* oss)
+{
+ runtime·sysvicall6(libc·sigaltstack, 2, (uintptr)ss, (uintptr)oss);
+}
+
+/* int32 */ void
+runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
+{
+ runtime·sysvicall6(libc·sigprocmask, 3, (uintptr)how, (uintptr)set, (uintptr)oset);
+}
+
+int64
+runtime·sysconf(int32 name)
+{
+ return runtime·sysvicall6(libc·sysconf, 1, (uintptr)name);
+}
+
+void
+runtime·usleep(uint32 us)
+{
+ runtime·sysvicall6(libc·usleep, 1, (uintptr)us);
+}
+
+int32
+runtime·write(uintptr fd, void* buf, int32 nbyte)
+{
+ return runtime·sysvicall6(libc·write, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+void
+runtime·osyield(void)
+{
+ runtime·sysvicall6(libc·sched_yield, 0);
+}
diff --git a/src/pkg/runtime/os_solaris.h b/src/pkg/runtime/os_solaris.h
new file mode 100644
index 000000000..f3fae5da2
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SS_DISABLE 2
+
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+typedef uintptr kevent_udata;
+
+struct sigaction;
+
+void runtime·sigpanic(void);
+
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+void runtime·sigaction(int32, struct Sigaction*, struct Sigaction*);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigprocmask(int32, Sigset*, Sigset*);
+void runtime·unblocksignals(void);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+#define NSIG 73 /* number of signals in runtime·SigTab array */
+#define SI_USER 0
+
+void runtime·raisesigpipe(void);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void runtime·sigpanic(void);
+
+#define _UC_SIGMASK 0x01
+#define _UC_CPU 0x04
+
+#define RLIMIT_AS 10
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+ int64 rlim_cur;
+ int64 rlim_max;
+};
+int32 runtime·getrlimit(int32, Rlimit*);
+
+// Call a library function with SysV conventions,
+// and switch to os stack during the call.
+#pragma varargck countpos runtime·sysvicall6 2
+#pragma varargck type runtime·sysvicall6 uintptr
+#pragma varargck type runtime·sysvicall6 int32
+void runtime·asmsysvicall6(void *c);
+uintptr runtime·sysvicall6(uintptr fn, int32 count, ...);
+
+void runtime·miniterrno(void *fn);
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c
index c3e296aa6..0dd44ed1b 100644
--- a/src/pkg/runtime/os_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -8,6 +8,7 @@
#include "os_GOOS.h"
#include "../../cmd/ld/textflag.h"
+#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
@@ -26,20 +27,20 @@
#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll"
+#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
-#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-
-extern void *runtime·NtWaitForSingleObject;
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
+extern void *runtime·AddVectoredExceptionHandler;
extern void *runtime·CloseHandle;
extern void *runtime·CreateEvent;
extern void *runtime·CreateThread;
@@ -58,19 +59,25 @@ extern void *runtime·GetSystemTimeAsFileTime;
extern void *runtime·GetThreadContext;
extern void *runtime·LoadLibrary;
extern void *runtime·LoadLibraryA;
+extern void *runtime·NtWaitForSingleObject;
extern void *runtime·ResumeThread;
extern void *runtime·SetConsoleCtrlHandler;
extern void *runtime·SetEvent;
+extern void *runtime·SetProcessPriorityBoost;
extern void *runtime·SetThreadPriority;
extern void *runtime·SetWaitableTimer;
extern void *runtime·Sleep;
extern void *runtime·SuspendThread;
-extern void *runtime·timeBeginPeriod;
extern void *runtime·WaitForSingleObject;
extern void *runtime·WriteFile;
+extern void *runtime·timeBeginPeriod;
void *runtime·GetQueuedCompletionStatusEx;
+extern uintptr runtime·externalthreadhandlerp;
+void runtime·externalthreadhandler(void);
+void runtime·sigtramp(void);
+
static int32
getproccount(void)
{
@@ -84,25 +91,22 @@ void
runtime·osinit(void)
{
void *kernel32;
- void *SetProcessPriorityBoost;
- // -1 = current process, -2 = current thread
- runtime·stdcall(runtime·DuplicateHandle, 7,
- (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
- (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+ runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
+
+ runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
runtime·ncpu = getproccount();
+
+ // Windows dynamic priority boosting assumes that a process has different types
+ // of dedicated threads -- GUI, IO, computational, etc. Go processes use
+ // equivalent threads that all do a mix of GUI, IO, computations, etc.
+ // In such context dynamic priority boosting does nothing but harm, so we turn it off.
+ runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll");
if(kernel32 != nil) {
- // Windows dynamic priority boosting assumes that a process has different types
- // of dedicated threads -- GUI, IO, computational, etc. Go processes use
- // equivalent threads that all do a mix of GUI, IO, computations, etc.
- // In such context dynamic priority boosting does nothing but harm, so we turn it off.
- SetProcessPriorityBoost = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "SetProcessPriorityBoost");
- if(SetProcessPriorityBoost != nil) // supported since Windows XP
- runtime·stdcall(SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx");
}
}
@@ -162,7 +166,7 @@ runtime·exit(int32 code)
}
int32
-runtime·write(int32 fd, void *buf, int32 n)
+runtime·write(uintptr fd, void *buf, int32 n)
{
void *handle;
uint32 written;
@@ -176,7 +180,9 @@ runtime·write(int32 fd, void *buf, int32 n)
handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
break;
default:
- return -1;
+ // assume fd is real windows handle.
+ handle = (void*)fd;
+ break;
}
runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
return written;
@@ -229,7 +235,6 @@ runtime·newosproc(M *mp, void *stk)
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc");
}
- runtime·atomicstorep(&mp->thread, thandle);
}
// Called to initialize a new m (including the bootstrap m).
@@ -245,14 +250,19 @@ runtime·mpreinit(M *mp)
void
runtime·minit(void)
{
- runtime·install_exception_handler();
+ void *thandle;
+
+ // -1 = current process, -2 = current thread
+ runtime·stdcall(runtime·DuplicateHandle, 7,
+ (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle,
+ (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+ runtime·atomicstorep(&m->thread, thandle);
}
// Called from dropm to undo the effect of an minit.
void
runtime·unminit(void)
{
- runtime·remove_exception_handler();
}
#pragma textflag NOSPLIT
@@ -285,11 +295,20 @@ time·now(int64 sec, int32 usec)
void *
runtime·stdcall(void *fn, int32 count, ...)
{
- m->wincall.fn = fn;
- m->wincall.n = count;
- m->wincall.args = (uintptr*)&count + 1;
- runtime·asmcgocall(runtime·asmstdcall, &m->wincall);
- return (void*)m->wincall.r1;
+ m->libcall.fn = fn;
+ m->libcall.n = count;
+ m->libcall.args = (uintptr*)&count + 1;
+ if(m->profilehz != 0) {
+ // leave pc/sp for cpu profiler
+ m->libcallg = g;
+ m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ m->libcallsp = (uintptr)runtime·getcallersp(&fn);
+ }
+ runtime·asmcgocall(runtime·asmstdcall, &m->libcall);
+ m->libcallsp = 0;
+ return (void*)m->libcall.r1;
}
extern void runtime·usleep1(uint32);
@@ -329,9 +348,12 @@ runtime·issigpanic(uint32 code)
void
runtime·sigpanic(void)
{
+ if(!runtime·canpanic(g))
+ runtime·throw("unexpected signal during runtime execution");
+
switch(g->sig) {
case EXCEPTION_ACCESS_VIOLATION:
- if(g->sigcode1 < 0x1000) {
+ if(g->sigcode1 < 0x1000 || g->paniconfault) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -352,8 +374,6 @@ runtime·sigpanic(void)
runtime·throw("fault");
}
-extern void *runtime·sigtramp;
-
void
runtime·initsig(void)
{
@@ -383,7 +403,7 @@ runtime·ctrlhandler1(uint32 type)
return 0;
}
-extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·dosigprof(Context *r, G *gp, M *mp);
extern void runtime·profileloop(void);
static void *profiletimer;
@@ -402,13 +422,11 @@ profilem(M *mp)
tls = runtime·tls0;
gp = *(G**)tls;
- if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
- // align Context to 16 bytes
- r = (Context*)((uintptr)(&rbuf[15]) & ~15);
- r->ContextFlags = CONTEXT_CONTROL;
- runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
- runtime·dosigprof(r, gp);
- }
+ // align Context to 16 bytes
+ r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+ r->ContextFlags = CONTEXT_CONTROL;
+ runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+ runtime·dosigprof(r, gp, mp);
}
void
@@ -425,10 +443,13 @@ runtime·profileloop1(void)
allm = runtime·atomicloadp(&runtime·allm);
for(mp = allm; mp != nil; mp = mp->alllink) {
thread = runtime·atomicloadp(&mp->thread);
- if(thread == nil)
+ // Do not profile threads blocked on Notes,
+ // this includes idle worker threads,
+ // idle timer thread, idle heap scavenger, etc.
+ if(thread == nil || mp->profilehz == 0 || mp->blocked)
continue;
runtime·stdcall(runtime·SuspendThread, 1, thread);
- if(mp->profilehz != 0)
+ if(mp->profilehz != 0 && !mp->blocked)
profilem(mp);
runtime·stdcall(runtime·ResumeThread, 1, thread);
}
diff --git a/src/pkg/runtime/os_windows_386.c b/src/pkg/runtime/os_windows_386.c
index c377e5b6c..c36a00114 100644
--- a/src/pkg/runtime/os_windows_386.c
+++ b/src/pkg/runtime/os_windows_386.c
@@ -24,16 +24,47 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %x\n", r->SegGs);
}
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
uintptr *sp;
+ extern byte text[], etext[];
+
+ if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+ // This exception is intended to be caught by debuggers.
+ // There is a not-very-informational message like
+ // "Invalid parameter passed to C runtime function"
+ // sitting at info->ExceptionInformation[0] (a wchar_t*),
+ // with length info->ExceptionInformation[1].
+ // The default behavior is to ignore this exception,
+ // but somehow returning 0 here (meaning keep going)
+ // makes the program crash instead. Maybe Windows has no
+ // other handler registered? In any event, ignore it.
+ return -1;
+ }
+
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if(r->Eip < (uint32)text || (uint32)etext < r->Eip)
+ return 0;
switch(info->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
- r->Eip--; // because 8l generates 2 bytes for INT3
- return 1;
+ // It is unclear whether this is needed, unclear whether it
+ // would work, and unclear how to test it. Leave out for now.
+ // This only handles breakpoint instructions written in the
+ // assembly sources, not breakpoints set by a debugger, and
+ // there are very few of the former.
+ //
+ // r->Eip--; // because 8l generates 2 bytes for INT3
+ // return 0;
+ break;
}
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -58,15 +89,15 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
r->Esp = (uintptr)sp;
}
r->Eip = (uintptr)runtime·sigpanic;
- return 0;
+ return -1;
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
- runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
- info->ExceptionInformation[0], info->ExceptionInformation[1]);
+ runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1], r->Eip);
runtime·printf("PC=%x\n", r->Eip);
if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -84,9 +115,8 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
if(crash)
runtime·crash();
-
runtime·exit(2);
- return 0;
+ return -1; // not reached
}
void
@@ -102,7 +132,7 @@ runtime·sigdisable(uint32 sig)
}
void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
{
- runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
+ runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
}
diff --git a/src/pkg/runtime/os_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c
index 97c48feb0..7fb973cde 100644
--- a/src/pkg/runtime/os_windows_amd64.c
+++ b/src/pkg/runtime/os_windows_amd64.c
@@ -32,15 +32,44 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %X\n", (uint64)r->SegGs);
}
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
uintptr *sp;
+ extern byte text[], etext[];
+
+ if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+ // This exception is intended to be caught by debuggers.
+ // There is a not-very-informational message like
+ // "Invalid parameter passed to C runtime function"
+ // sitting at info->ExceptionInformation[0] (a wchar_t*),
+ // with length info->ExceptionInformation[1].
+ // The default behavior is to ignore this exception,
+ // but somehow returning 0 here (meaning keep going)
+ // makes the program crash instead. Maybe Windows has no
+ // other handler registered? In any event, ignore it.
+ return -1;
+ }
+
+ // Only handle exception if executing instructions in Go binary
+ // (not Windows library code).
+ if(r->Rip < (uint64)text || (uint64)etext < r->Rip)
+ return 0;
switch(info->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
- return 1;
+ // It is unclear whether this is needed, unclear whether it
+ // would work, and unclear how to test it. Leave out for now.
+ // This only handles breakpoint instructions written in the
+ // assembly sources, not breakpoints set by a debugger, and
+ // there are very few of the former.
+ break;
}
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -65,15 +94,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
r->Rsp = (uintptr)sp;
}
r->Rip = (uintptr)runtime·sigpanic;
- return 0;
+ return -1;
}
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
- runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
- info->ExceptionInformation[0], info->ExceptionInformation[1]);
+ runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
+
runtime·printf("PC=%X\n", r->Rip);
if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -92,7 +122,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
runtime·crash();
runtime·exit(2);
- return 0;
+ return -1; // not reached
}
void
@@ -108,7 +138,7 @@ runtime·sigdisable(uint32 sig)
}
void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
{
- runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
+ runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
}
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c
index 8227a444d..f577b37b5 100644
--- a/src/pkg/runtime/panic.c
+++ b/src/pkg/runtime/panic.c
@@ -13,108 +13,63 @@
uint32 runtime·panicking;
static Lock paniclk;
-enum
-{
- DeferChunkSize = 2048
-};
+// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
+// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
+// This maps exactly to malloc size classes.
+
+// defer size class for arg size sz
+#define DEFERCLASS(sz) (((sz)+7)>>4)
+// total size of memory block for defer with arg size sz
+#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
-// Allocate a Defer, usually as part of the larger frame of deferred functions.
-// Each defer must be released with both popdefer and freedefer.
+// Allocate a Defer, usually using per-P pool.
+// Each defer must be released with freedefer.
static Defer*
newdefer(int32 siz)
{
- int32 total;
- DeferChunk *c;
+ int32 total, sc;
Defer *d;
-
- c = g->dchunk;
- total = sizeof(*d) + ROUND(siz, sizeof(uintptr)) - sizeof(d->args);
- if(c == nil || total > DeferChunkSize - c->off) {
- if(total > DeferChunkSize / 2) {
- // Not worth putting in any chunk.
- // Allocate a separate block.
- d = runtime·malloc(total);
- d->siz = siz;
- d->special = 1;
- d->free = 1;
- d->link = g->defer;
- g->defer = d;
- return d;
- }
-
- // Cannot fit in current chunk.
- // Switch to next chunk, allocating if necessary.
- c = g->dchunknext;
- if(c == nil)
- c = runtime·malloc(DeferChunkSize);
- c->prev = g->dchunk;
- c->off = sizeof(*c);
- g->dchunk = c;
- g->dchunknext = nil;
+ P *p;
+
+ d = nil;
+ sc = DEFERCLASS(siz);
+ if(sc < nelem(p->deferpool)) {
+ p = m->p;
+ d = p->deferpool[sc];
+ if(d)
+ p->deferpool[sc] = d->link;
+ }
+ if(d == nil) {
+ // deferpool is empty or just a big defer
+ total = TOTALSIZE(siz);
+ d = runtime·malloc(total);
}
-
- d = (Defer*)((byte*)c + c->off);
- c->off += total;
d->siz = siz;
d->special = 0;
- d->free = 0;
d->link = g->defer;
g->defer = d;
- return d;
-}
-
-// Pop the current defer from the defer stack.
-// Its contents are still valid until the goroutine begins executing again.
-// In particular it is safe to call reflect.call(d->fn, d->argp, d->siz) after
-// popdefer returns.
-static void
-popdefer(void)
-{
- Defer *d;
- DeferChunk *c;
- int32 total;
-
- d = g->defer;
- if(d == nil)
- runtime·throw("runtime: popdefer nil");
- g->defer = d->link;
- if(d->special) {
- // Nothing else to do.
- return;
- }
- total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
- c = g->dchunk;
- if(c == nil || (byte*)d+total != (byte*)c+c->off)
- runtime·throw("runtime: popdefer phase error");
- c->off -= total;
- if(c->off == sizeof(*c)) {
- // Chunk now empty, so pop from stack.
- // Save in dchunknext both to help with pingponging between frames
- // and to make sure d is still valid on return.
- if(g->dchunknext != nil)
- runtime·free(g->dchunknext);
- g->dchunknext = c;
- g->dchunk = c->prev;
- }
+ return d;
}
// Free the given defer.
-// For defers in the per-goroutine chunk this just clears the saved arguments.
-// For large defers allocated on the heap, this frees them.
// The defer cannot be used after this call.
static void
freedefer(Defer *d)
{
- int32 total;
+ int32 sc;
+ P *p;
- if(d->special) {
- if(d->free)
- runtime·free(d);
- } else {
- // Wipe out any possible pointers in argp/pc/fn/args.
- total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
- runtime·memclr((byte*)d, total);
- }
+ if(d->special)
+ return;
+ sc = DEFERCLASS(d->siz);
+ if(sc < nelem(p->deferpool)) {
+ p = m->p;
+ d->link = p->deferpool[sc];
+ p->deferpool[sc] = d;
+ // No need to wipe out pointers in argp/pc/fn/args,
+ // because we empty the pool before GC.
+ } else
+ runtime·free(d);
}
// Create a new deferred function fn with siz bytes of arguments.
@@ -157,14 +112,12 @@ runtime·deferproc(int32 siz, FuncVal *fn, ...)
// is called again and again until there are no more deferred functions.
// Cannot split the stack because we reuse the caller's frame to
// call the deferred function.
-//
-// The ... in the prototype keeps the compiler from declaring
-// an argument frame size. deferreturn is a very special function,
-// and if the runtime ever asks for its frame size, that means
-// the traceback routines are probably broken.
+
+// The single argument isn't actually used - it just has its address
+// taken so it can be matched against pending defers.
#pragma textflag NOSPLIT
void
-runtime·deferreturn(uintptr arg0, ...)
+runtime·deferreturn(uintptr arg0)
{
Defer *d;
byte *argp;
@@ -184,7 +137,7 @@ runtime·deferreturn(uintptr arg0, ...)
m->locks++;
runtime·memmove(argp, d->args, d->siz);
fn = d->fn;
- popdefer();
+ g->defer = d->link;
freedefer(d);
m->locks--;
if(m->locks == 0 && g->preempt)
@@ -192,6 +145,37 @@ runtime·deferreturn(uintptr arg0, ...)
runtime·jmpdefer(fn, argp);
}
+// Ensure that defer arg sizes that map to the same defer size class
+// also map to the same malloc size class.
+void
+runtime·testdefersizes(void)
+{
+ P *p;
+ int32 i, siz, defersc, mallocsc;
+ int32 map[nelem(p->deferpool)];
+
+ for(i=0; i<nelem(p->deferpool); i++)
+ map[i] = -1;
+ for(i=0;; i++) {
+ defersc = DEFERCLASS(i);
+ if(defersc >= nelem(p->deferpool))
+ break;
+ siz = TOTALSIZE(i);
+ mallocsc = runtime·SizeToClass(siz);
+ siz = runtime·class_to_size[mallocsc];
+ // runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
+ if(map[defersc] < 0) {
+ map[defersc] = mallocsc;
+ continue;
+ }
+ if(map[defersc] != mallocsc) {
+ runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
+ i, siz, map[defersc], mallocsc);
+ runtime·throw("bad defer size class");
+ }
+ }
+}
+
// Run all deferred functions for the current goroutine.
static void
rundefer(void)
@@ -199,8 +183,8 @@ rundefer(void)
Defer *d;
while((d = g->defer) != nil) {
- popdefer();
- reflect·call(d->fn, (byte*)d->args, d->siz);
+ g->defer = d->link;
+ reflect·call(d->fn, (byte*)d->args, d->siz, d->siz);
freedefer(d);
}
}
@@ -221,37 +205,65 @@ printpanics(Panic *p)
}
static void recovery(G*);
+static void abortpanic(Panic*);
+static FuncVal abortpanicV = { (void(*)(void))abortpanic };
// The implementation of the predeclared function panic.
void
runtime·panic(Eface e)
{
- Defer *d;
- Panic *p;
+ Defer *d, dabort;
+ Panic p;
void *pc, *argp;
-
- p = runtime·mal(sizeof *p);
- p->arg = e;
- p->link = g->panic;
- p->stackbase = g->stackbase;
- g->panic = p;
+
+ runtime·memclr((byte*)&p, sizeof p);
+ p.arg = e;
+ p.link = g->panic;
+ p.stackbase = g->stackbase;
+ g->panic = &p;
+
+ dabort.fn = &abortpanicV;
+ dabort.siz = sizeof(&p);
+ dabort.args[0] = &p;
+ dabort.argp = NoArgs;
+ dabort.special = true;
for(;;) {
d = g->defer;
if(d == nil)
break;
// take defer off list in case of recursive panic
- popdefer();
- g->ispanic = true; // rock for newstack, where reflect.newstackcall ends up
+ g->defer = d->link;
+ g->ispanic = true; // rock for runtime·newstack, where runtime·newstackcall ends up
argp = d->argp;
pc = d->pc;
+
+ // The deferred function may cause another panic,
+ // so newstackcall may not return. Set up a defer
+ // to mark this panic aborted if that happens.
+ dabort.link = g->defer;
+ g->defer = &dabort;
+ p.defer = d;
+
runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
+
+ // Newstackcall did not panic. Remove dabort.
+ if(g->defer != &dabort)
+ runtime·throw("bad defer entry in panic");
+ g->defer = dabort.link;
+
freedefer(d);
- if(p->recovered) {
- g->panic = p->link;
+ if(p.recovered) {
+ g->panic = p.link;
+ // Aborted panics are marked but remain on the g->panic list.
+ // Recovery will unwind the stack frames containing their Panic structs.
+ // Remove them from the list and free the associated defers.
+ while(g->panic && g->panic->aborted) {
+ freedefer(g->panic->defer);
+ g->panic = g->panic->link;
+ }
if(g->panic == nil) // must be done with signal
g->sig = 0;
- runtime·free(p);
// Pass information about recovering frame to recovery.
g->sigcode0 = (uintptr)argp;
g->sigcode1 = (uintptr)pc;
@@ -263,7 +275,14 @@ runtime·panic(Eface e)
// ran out of deferred calls - old-school panic now
runtime·startpanic();
printpanics(g->panic);
- runtime·dopanic(0);
+ runtime·dopanic(0); // should not return
+ runtime·exit(1); // not reached
+}
+
+static void
+abortpanic(Panic *p)
+{
+ p->aborted = true;
}
// Unwind the stack after a deferred function calls recover
@@ -320,10 +339,7 @@ runtime·unwindstack(G *gp, byte *sp)
gp->stackbase = top->stackbase;
gp->stackguard = top->stackguard;
gp->stackguard0 = gp->stackguard;
- if(top->free != 0) {
- gp->stacksize -= top->free;
- runtime·stackfree(stk, top->free);
- }
+ runtime·stackfree(gp, stk, top);
}
if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
@@ -337,10 +353,11 @@ runtime·unwindstack(G *gp, byte *sp)
// find the stack segment of its caller.
#pragma textflag NOSPLIT
void
-runtime·recover(byte *argp, Eface ret)
+runtime·recover(byte *argp, GoOutput retbase, ...)
{
Panic *p;
Stktop *top;
+ Eface *ret;
// Must be an unrecovered panic in progress.
// Must be on a stack segment created for a deferred call during a panic.
@@ -351,16 +368,16 @@ runtime·recover(byte *argp, Eface ret)
// do not count as official calls to adjust what we consider the top frame
// while they are active on the stack. The linker emits adjustments of
// g->panicwrap in the prologue and epilogue of functions marked as wrappers.
+ ret = (Eface*)&retbase;
top = (Stktop*)g->stackbase;
p = g->panic;
if(p != nil && !p->recovered && top->panic && argp == (byte*)top - top->argsize - g->panicwrap) {
p->recovered = 1;
- ret = p->arg;
+ *ret = p->arg;
} else {
- ret.type = nil;
- ret.data = nil;
+ ret->type = nil;
+ ret->data = nil;
}
- FLUSH(&ret);
}
void
@@ -371,18 +388,34 @@ runtime·startpanic(void)
m->mallocing = 1; // tell rest of panic not to try to malloc
} else if(m->mcache == nil) // can happen if called from signal handler or throw
m->mcache = runtime·allocmcache();
- if(m->dying) {
+ switch(m->dying) {
+ case 0:
+ m->dying = 1;
+ if(g != nil)
+ g->writebuf = nil;
+ runtime·xadd(&runtime·panicking, 1);
+ runtime·lock(&paniclk);
+ if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
+ runtime·schedtrace(true);
+ runtime·freezetheworld();
+ return;
+ case 1:
+ // Something failed while panicing, probably the print of the
+ // argument to panic(). Just print a stack trace and exit.
+ m->dying = 2;
runtime·printf("panic during panic\n");
+ runtime·dopanic(0);
runtime·exit(3);
+ case 2:
+ // This is a genuine bug in the runtime, we couldn't even
+ // print the stack trace successfully.
+ m->dying = 3;
+ runtime·printf("stack trace unavailable\n");
+ runtime·exit(4);
+ default:
+ // Can't even print! Just exit.
+ runtime·exit(5);
}
- m->dying = 1;
- if(g != nil)
- g->writebuf = nil;
- runtime·xadd(&runtime·panicking, 1);
- runtime·lock(&paniclk);
- if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
- runtime·schedtrace(true);
- runtime·freezetheworld();
}
void
@@ -453,6 +486,29 @@ runtime·throwinit(void)
runtime·throw("recursive call during initialization - linker skew");
}
+bool
+runtime·canpanic(G *gp)
+{
+ byte g;
+
+ USED(&g); // don't use global g, it points to gsignal
+
+ // Is it okay for gp to panic instead of crashing the program?
+ // Yes, as long as it is running Go code, not runtime code,
+ // and not stuck in a system call.
+ if(gp == nil || gp != m->curg)
+ return false;
+ if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
+ return false;
+ if(gp->status != Grunning || gp->syscallsp != 0)
+ return false;
+#ifdef GOOS_windows
+ if(m->libcallsp != 0)
+ return false;
+#endif
+ return true;
+}
+
void
runtime·throw(int8 *s)
{
@@ -470,6 +526,16 @@ runtime·panicstring(int8 *s)
{
Eface err;
+ // m->softfloat is set during software floating point,
+ // which might cause a fault during a memory load.
+ // It increments m->locks to avoid preemption.
+ // If we're panicking, the software floating point frames
+ // will be unwound, so decrement m->locks as they would.
+ if(m->softfloat) {
+ m->locks--;
+ m->softfloat = 0;
+ }
+
if(m->mallocing) {
runtime·printf("panic: %s\n", s);
runtime·throw("panic during malloc");
@@ -478,6 +544,10 @@ runtime·panicstring(int8 *s)
runtime·printf("panic: %s\n", s);
runtime·throw("panic during gc");
}
+ if(m->locks) {
+ runtime·printf("panic: %s\n", s);
+ runtime·throw("panic holding locks");
+ }
runtime·newErrorCString(s, &err);
runtime·panic(err);
}
@@ -488,3 +558,9 @@ runtime·Goexit(void)
rundefer();
runtime·goexit();
}
+
+void
+runtime·panicdivide(void)
+{
+ runtime·panicstring("integer divide by zero");
+}
diff --git a/src/pkg/runtime/parfor.c b/src/pkg/runtime/parfor.c
index ceaac8bc9..4706e0a43 100644
--- a/src/pkg/runtime/parfor.c
+++ b/src/pkg/runtime/parfor.c
@@ -33,15 +33,6 @@ runtime·parforalloc(uint32 nthrmax)
return desc;
}
-// For testing from Go
-// func parforalloc2(nthrmax uint32) *ParFor
-void
-runtime·parforalloc2(uint32 nthrmax, ParFor *desc)
-{
- desc = runtime·parforalloc(nthrmax);
- FLUSH(&desc);
-}
-
void
runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
{
@@ -75,14 +66,6 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait,
}
}
-// For testing from Go
-// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-void
-runtime·parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
-{
- runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
-}
-
void
runtime·parfordo(ParFor *desc)
{
@@ -207,13 +190,10 @@ exit:
me->nsleep = 0;
}
-// For testing from Go
-// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+// For testing from Go.
void
-runtime·parforiters(ParFor *desc, uintptr tid, uintptr start, uintptr end)
+runtime·parforiters(ParFor *desc, uintptr tid, uintptr *start, uintptr *end)
{
- start = (uint32)desc->thr[tid].pos;
- end = (uint32)(desc->thr[tid].pos>>32);
- FLUSH(&start);
- FLUSH(&end);
+ *start = (uint32)desc->thr[tid].pos;
+ *end = (uint32)(desc->thr[tid].pos>>32);
}
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
index 3b8428519..26aa0b8be 100644
--- a/src/pkg/runtime/pprof/pprof.go
+++ b/src/pkg/runtime/pprof/pprof.go
@@ -20,7 +20,7 @@ import (
"text/tabwriter"
)
-// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD, OpenBSD, and OS X.
+// BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
// See http://golang.org/issue/6047 for details.
// A Profile is a collection of stack traces showing the call sequences
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index eb76b93c4..aba538e75 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !nacl
+
package pprof_test
import (
@@ -138,7 +140,11 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
t.Logf("no CPU profile samples collected")
ok = false
}
- min := total / uintptr(len(have)) / 3
+ // We'd like to check a reasonable minimum, like
+ // total / len(have) / smallconstant, but this test is
+ // pretty flaky (see bug 7095). So we'll just test to
+ // make sure we got at least one sample.
+ min := uintptr(1)
for i, name := range need {
if have[i] < min {
t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
@@ -189,9 +195,6 @@ func TestCPUProfileWithFork(t *testing.T) {
// If it did, it would see inconsistent state and would either record an incorrect stack
// or crash because the stack was malformed.
func TestGoroutineSwitch(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("flaky test; see http://golang.org/issue/6417")
- }
// How much to try. These defaults take about 1 seconds
// on a 2012 MacBook Pro. The ones in short mode take
// about 0.1 seconds.
@@ -217,7 +220,7 @@ func TestGoroutineSwitch(t *testing.T) {
// exists to record a PC without a traceback. Those are okay.
if len(stk) == 2 {
f := runtime.FuncForPC(stk[1])
- if f != nil && f.Name() == "System" {
+ if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode") {
return
}
}
@@ -264,9 +267,9 @@ func TestMathBigDivide(t *testing.T) {
// Operating systems that are expected to fail the tests. See issue 6047.
var badOS = map[string]bool{
- "darwin": true,
- "netbsd": true,
- "openbsd": true,
+ "darwin": true,
+ "netbsd": true,
+ "plan9": true,
}
func TestBlockProfile(t *testing.T) {
@@ -278,31 +281,31 @@ func TestBlockProfile(t *testing.T) {
tests := [...]TestCase{
{"chan recv", blockChanRecv, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`},
{"chan send", blockChanSend, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`},
{"chan close", blockChanClose, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
+# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`},
{"select recv async", blockSelectRecvAsync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
+# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`},
{"select send sync", blockSelectSendSync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
+# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`},
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index 8de3ae4fa..a04708fae 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -63,67 +63,85 @@ runtime·printf(int8 *s, ...)
vprintf(s, arg);
}
+#pragma textflag NOSPLIT
+int32
+runtime·snprintf(byte *buf, int32 n, int8 *s, ...)
+{
+ byte *arg;
+ int32 m;
+
+ arg = (byte*)(&s+1);
+ g->writebuf = buf;
+ g->writenbuf = n-1;
+ vprintf(s, arg);
+ *g->writebuf = '\0';
+ m = g->writebuf - buf;
+ g->writenbuf = 0;
+ g->writebuf = nil;
+ return m;
+}
+
// Very simple printf. Only for debugging prints.
// Do not add to this without checking with Rob.
static void
vprintf(int8 *s, byte *base)
{
int8 *p, *lp;
- uintptr arg, narg;
+ uintptr arg, siz;
byte *v;
//runtime·lock(&debuglock);
lp = p = s;
- arg = 0;
+ arg = (uintptr)base;
for(; *p; p++) {
if(*p != '%')
continue;
if(p > lp)
gwrite(lp, p-lp);
p++;
- narg = 0;
+ siz = 0;
switch(*p) {
case 't':
case 'c':
- narg = arg + 1;
+ siz = 1;
break;
case 'd': // 32-bit
case 'x':
arg = ROUND(arg, 4);
- narg = arg + 4;
+ siz = 4;
break;
case 'D': // 64-bit
case 'U':
case 'X':
case 'f':
- arg = ROUND(arg, sizeof(uintptr));
- narg = arg + 8;
+ arg = ROUND(arg, sizeof(uintreg));
+ siz = 8;
break;
case 'C':
- arg = ROUND(arg, sizeof(uintptr));
- narg = arg + 16;
+ arg = ROUND(arg, sizeof(uintreg));
+ siz = 16;
break;
case 'p': // pointer-sized
case 's':
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(uintptr);
+ siz = sizeof(uintptr);
break;
case 'S': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(String);
+ siz = sizeof(String);
break;
case 'a': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(Slice);
+ siz = sizeof(Slice);
break;
case 'i': // pointer-aligned but bigger
case 'e':
arg = ROUND(arg, sizeof(uintptr));
- narg = arg + sizeof(Eface);
+ siz = sizeof(Eface);
break;
}
- v = base+arg;
+ v = (byte*)arg;
switch(*p) {
case 'a':
runtime·printslice(*(Slice*)v);
@@ -171,7 +189,7 @@ vprintf(int8 *s, byte *base)
runtime·printhex(*(uint64*)v);
break;
}
- arg = narg;
+ arg += siz;
lp = p+1;
}
if(p > lp)
@@ -236,7 +254,10 @@ runtime·printfloat(float64 v)
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
- if(v != 0) {
+ if(v == 0) {
+ if(1/v == runtime·neginf)
+ s = 1;
+ } else {
// sign
if(v < 0) {
v = -v;
@@ -345,7 +366,7 @@ runtime·printhex(uint64 v)
void
runtime·printpointer(void *p)
{
- runtime·printhex((uint64)p);
+ runtime·printhex((uintptr)p);
}
void
@@ -370,11 +391,3 @@ runtime·printnl(void)
{
gwrite("\n", 1);
}
-
-void
-runtime·typestring(Eface e, String s)
-{
- s = *e.type->string;
- FLUSH(&s);
-}
-
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index ed3e1e73e..914a02e0b 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -58,17 +58,23 @@ struct Sched {
int32 profilehz; // cpu profiling rate
};
-// The max value of GOMAXPROCS.
-// There are no fundamental restrictions on the value.
-enum { MaxGomaxprocs = 1<<8 };
+enum
+{
+ // The max value of GOMAXPROCS.
+ // There are no fundamental restrictions on the value.
+ MaxGomaxprocs = 1<<8,
+
+ // Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once.
+ // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
+ GoidCacheBatch = 16,
+};
Sched runtime·sched;
int32 runtime·gomaxprocs;
uint32 runtime·needextram;
bool runtime·iscgo;
M runtime·m0;
-G runtime·g0; // idle goroutine for m0
-G* runtime·allg;
+G runtime·g0; // idle goroutine for m0
G* runtime·lastg;
M* runtime·allm;
M* runtime·extram;
@@ -76,10 +82,15 @@ int8* runtime·goos;
int32 runtime·ncpu;
static int32 newprocs;
+static Lock allglock; // the following vars are protected by this lock or by stoptheworld
+G** runtime·allg;
+uintptr runtime·allglen;
+static uintptr allgcap;
+
void runtime·mstart(void);
static void runqput(P*, G*);
static G* runqget(P*);
-static void runqgrow(P*);
+static bool runqputslow(P*, G*, uint32, uint32);
static G* runqsteal(P*, P*);
static void mput(M*);
static M* mget(void);
@@ -106,6 +117,7 @@ static void gfput(P*, G*);
static G* gfget(P*);
static void gfpurge(P*);
static void globrunqput(G*);
+static void globrunqputbatch(G*, G*, int32);
static G* globrunqget(P*, int32);
static P* pidleget(void);
static void pidleput(P*);
@@ -114,6 +126,7 @@ static bool preemptall(void);
static bool preemptone(P*);
static bool exitsyscallfast(void);
static bool haveexperiment(int8*);
+static void allgadd(G*);
// The bootstrap sequence is:
//
@@ -131,9 +144,9 @@ runtime·schedinit(void)
Eface i;
runtime·sched.maxmcount = 10000;
- runtime·precisestack = haveexperiment("precisestack");
+ runtime·precisestack = true; // haveexperiment("precisestack");
- runtime·mprofinit();
+ runtime·symtabinit();
runtime·mallocinit();
mcommoninit(m);
@@ -142,14 +155,15 @@ runtime·schedinit(void)
// in a fault during a garbage collection, it will not
// need to allocated memory.
runtime·newErrorCString(0, &i);
+
+ // Initialize the cached gotraceback value, since
+ // gotraceback calls getenv, which mallocs on Plan 9.
+ runtime·gotraceback(nil);
runtime·goargs();
runtime·goenvs();
runtime·parsedebugvars();
- // Allocate internal symbol table representation now, we need it for GC anyway.
- runtime·symtabinit();
-
runtime·sched.lastpoll = runtime·nanotime();
procs = 1;
p = runtime·getenv("GOMAXPROCS");
@@ -161,6 +175,11 @@ runtime·schedinit(void)
runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]));
procresize(procs);
+ runtime·copystack = runtime·precisestack;
+ p = runtime·getenv("GOCOPYSTACK");
+ if(p != nil && !runtime·strcmp(p, (byte*)"0"))
+ runtime·copystack = false;
+
mstats.enablegc = 1;
if(raceenabled)
@@ -175,6 +194,15 @@ static FuncVal scavenger = {runtime·MHeap_Scavenger};
static FuncVal initDone = { runtime·unlockOSThread };
// The main goroutine.
+// Note: C frames in general are not copyable during stack growth, for two reasons:
+// 1) We don't know where in a frame to find pointers to other stack locations.
+// 2) There's no guarantee that globals or heap values do not point into the frame.
+//
+// The C frame for runtime.main is copyable, because:
+// 1) There are no pointers to other stack locations in the frame
+// (d.fn points at a global, d.link is nil, d.argp is -1).
+// 2) The only pointer into this frame is from the defer chain,
+// which is explicitly handled during stack copying.
void
runtime·main(void)
{
@@ -202,9 +230,8 @@ runtime·main(void)
d.fn = &initDone;
d.siz = 0;
d.link = g->defer;
- d.argp = (void*)-1;
+ d.argp = NoArgs;
d.special = true;
- d.free = false;
g->defer = &d;
if(m != &runtime·m0)
@@ -237,6 +264,7 @@ void
runtime·goroutineheader(G *gp)
{
int8 *status;
+ int64 waitfor;
switch(gp->status) {
case Gidle:
@@ -261,7 +289,16 @@ runtime·goroutineheader(G *gp)
status = "???";
break;
}
- runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
+
+ // approx time the G is blocked, in minutes
+ waitfor = 0;
+ if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0)
+ waitfor = (runtime·nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
+
+ if(waitfor < 1)
+ runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
+ else
+ runtime·printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor);
}
void
@@ -269,6 +306,7 @@ runtime·tracebackothers(G *me)
{
G *gp;
int32 traceback;
+ uintptr i;
traceback = runtime·gotraceback(nil);
@@ -279,7 +317,9 @@ runtime·tracebackothers(G *me)
runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
}
- for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
+ runtime·lock(&allglock);
+ for(i = 0; i < runtime·allglen; i++) {
+ gp = runtime·allg[i];
if(gp == me || gp == m->curg || gp->status == Gdead)
continue;
if(gp->issystem && traceback < 2)
@@ -292,6 +332,7 @@ runtime·tracebackothers(G *me)
} else
runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
}
+ runtime·unlock(&allglock);
}
static void
@@ -562,15 +603,6 @@ runtime·starttheworld(void)
void
runtime·mstart(void)
{
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- // It is used by windows-386 only. Unfortunately, seh needs
- // to be located on os stack, and mstart runs on os stack
- // for both m0 and m.
- SEH seh;
-#endif
-#endif
-
if(g != m->g0)
runtime·throw("bad runtime·mstart");
@@ -580,11 +612,6 @@ runtime·mstart(void)
runtime·gosave(&m->g0->sched);
m->g0->sched.pc = (uintptr)-1; // make sure it is never used
m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, copy it to stackguard
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- m->seh = &seh;
-#endif
-#endif
runtime·asminit();
runtime·minit();
@@ -620,6 +647,7 @@ struct CgoThreadStart
{
M *m;
G *g;
+ uintptr *tls;
void (*fn)(void);
};
@@ -643,9 +671,9 @@ runtime·allocm(P *p)
mp = runtime·cnew(mtype);
mcommoninit(mp);
- // In case of cgo, pthread_create will make us a stack.
+ // In case of cgo or Solaris, pthread_create will make us a stack.
// Windows will layout sched stack on OS stack.
- if(runtime·iscgo || Windows)
+ if(runtime·iscgo || Solaris || Windows)
mp->g0 = runtime·malg(-1);
else
mp->g0 = runtime·malg(8192);
@@ -659,6 +687,21 @@ runtime·allocm(P *p)
return mp;
}
+static G*
+allocg(void)
+{
+ G *gp;
+ static Type *gtype;
+
+ if(gtype == nil) {
+ Eface e;
+ runtime·gc_g_ptr(&e);
+ gtype = ((PtrType*)e.type)->elem;
+ }
+ gp = runtime·cnew(gtype);
+ return gp;
+}
+
static M* lockextra(bool nilokay);
static void unlockextra(M*);
@@ -735,16 +778,6 @@ runtime·needm(byte x)
g->stackguard = (uintptr)(&x - 32*1024);
g->stackguard0 = g->stackguard;
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- // On windows/386, we need to put an SEH frame (two words)
- // somewhere on the current stack. We are called from cgocallback_gofunc
- // and we know that it will leave two unused words below m->curg->sched.sp.
- // Use those.
- m->seh = (SEH*)((uintptr*)&x + 1);
-#endif
-#endif
-
// Initialize this thread to use the m.
runtime·asminit();
runtime·minit();
@@ -783,13 +816,7 @@ runtime·newextram(void)
if(raceenabled)
gp->racectx = runtime·racegostart(runtime·newextram);
// put on allg for garbage collector
- runtime·lock(&runtime·sched);
- if(runtime·lastg == nil)
- runtime·allg = gp;
- else
- runtime·lastg->alllink = gp;
- runtime·lastg = gp;
- runtime·unlock(&runtime·sched);
+ allgadd(gp);
// Add m to the extra list.
mnext = lockextra(true);
@@ -828,12 +855,6 @@ runtime·dropm(void)
// Undo whatever initialization minit did during needm.
runtime·unminit();
-#ifdef GOOS_windows
-#ifdef GOARCH_386
- m->seh = nil; // reset dangling typed pointer
-#endif
-#endif
-
// Clear m and g, and return m to the extra list.
// After the call to setmg we can only call nosplit functions.
mp = m;
@@ -904,6 +925,7 @@ newm(void(*fn)(void), P *p)
runtime·throw("_cgo_thread_start missing");
ts.m = mp;
ts.g = mp->g0;
+ ts.tls = mp->tls;
ts.fn = runtime·mstart;
runtime·asmcgocall(_cgo_thread_start, &ts);
return;
@@ -948,7 +970,7 @@ mspinning(void)
}
// Schedules some M to run the p (creates an M if necessary).
-// If p==nil, tries to get an idle P, if no idle P's returns false.
+// If p==nil, tries to get an idle P, if no idle P's does nothing.
static void
startm(P *p, bool spinning)
{
@@ -1112,6 +1134,7 @@ execute(G *gp)
runtime·throw("execute: bad g status");
}
gp->status = Grunning;
+ gp->waitsince = 0;
gp->preempt = false;
gp->stackguard0 = gp->stackguard;
m->p->schedtick++;
@@ -1140,6 +1163,8 @@ top:
gcstopm();
goto top;
}
+ if(runtime·fingwait && runtime·fingwake && (gp = runtime·wakefing()) != nil)
+ runtime·ready(gp);
// local runq
gp = runqget(m->p);
if(gp)
@@ -1331,28 +1356,52 @@ top:
execute(gp);
}
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling runtime·ready(gp).
+// Puts the current goroutine into a waiting state and calls unlockf.
+// If unlockf returns false, the goroutine is resumed.
void
-runtime·park(void(*unlockf)(Lock*), Lock *lock, int8 *reason)
+runtime·park(bool(*unlockf)(G*, void*), void *lock, int8 *reason)
{
+ if(g->status != Grunning)
+ runtime·throw("bad g status");
m->waitlock = lock;
m->waitunlockf = unlockf;
g->waitreason = reason;
runtime·mcall(park0);
}
+static bool
+parkunlock(G *gp, void *lock)
+{
+ USED(gp);
+ runtime·unlock(lock);
+ return true;
+}
+
+// Puts the current goroutine into a waiting state and unlocks the lock.
+// The goroutine can be made runnable again by calling runtime·ready(gp).
+void
+runtime·parkunlock(Lock *lock, int8 *reason)
+{
+ runtime·park(parkunlock, lock, reason);
+}
+
// runtime·park continuation on g0.
static void
park0(G *gp)
{
+ bool ok;
+
gp->status = Gwaiting;
gp->m = nil;
m->curg = nil;
if(m->waitunlockf) {
- m->waitunlockf(m->waitlock);
+ ok = m->waitunlockf(gp, m->waitlock);
m->waitunlockf = nil;
m->waitlock = nil;
+ if(!ok) {
+ gp->status = Grunnable;
+ execute(gp); // Schedule it back, never returns.
+ }
}
if(m->lockedg) {
stoplockedm();
@@ -1365,6 +1414,8 @@ park0(G *gp)
void
runtime·gosched(void)
{
+ if(g->status != Grunning)
+ runtime·throw("bad g status");
runtime·mcall(runtime·gosched0);
}
@@ -1393,6 +1444,8 @@ runtime·gosched0(G *gp)
void
runtime·goexit(void)
{
+ if(g->status != Grunning)
+ runtime·throw("bad g status");
if(raceenabled)
runtime·racegoend();
runtime·mcall(goexit0);
@@ -1405,6 +1458,13 @@ goexit0(G *gp)
gp->status = Gdead;
gp->m = nil;
gp->lockedm = nil;
+ gp->paniconfault = 0;
+ gp->defer = nil; // should be true already but just in case.
+ gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
+ gp->writenbuf = 0;
+ gp->writebuf = nil;
+ gp->waitreason = nil;
+ gp->param = nil;
m->curg = nil;
m->lockedg = nil;
if(m->locked & ~LockExternal) {
@@ -1535,6 +1595,7 @@ runtime·exitsyscall(void)
if(g->isbackground) // do not consider blocked scavenger for deadlock detection
incidlelocked(-1);
+ g->waitsince = 0;
if(exitsyscallfast()) {
// There's a cpu for us, so we can run.
m->p->syscalltick++;
@@ -1640,6 +1701,7 @@ exitsyscall0(G *gp)
}
// Called from syscall package before fork.
+#pragma textflag NOSPLIT
void
syscall·runtime_BeforeFork(void)
{
@@ -1648,14 +1710,28 @@ syscall·runtime_BeforeFork(void)
m->locks++;
if(m->profilehz != 0)
runtime·resetcpuprofiler(0);
+
+ // This function is called before fork in syscall package.
+ // Code between fork and exec must not allocate memory nor even try to grow stack.
+ // Here we spoil g->stackguard to reliably detect any attempts to grow stack.
+ // runtime_AfterFork will undo this in parent process, but not in child.
+ m->forkstackguard = g->stackguard;
+ g->stackguard0 = StackPreempt-1;
+ g->stackguard = StackPreempt-1;
}
// Called from syscall package after fork in parent.
+#pragma textflag NOSPLIT
void
syscall·runtime_AfterFork(void)
{
int32 hz;
+ // See the comment in runtime_BeforeFork.
+ g->stackguard0 = m->forkstackguard;
+ g->stackguard = m->forkstackguard;
+ m->forkstackguard = 0;
+
hz = runtime·sched.profilehz;
if(hz != 0)
runtime·resetcpuprofiler(hz);
@@ -1669,7 +1745,13 @@ syscall·runtime_AfterFork(void)
static void
mstackalloc(G *gp)
{
- gp->param = runtime·stackalloc((uintptr)gp->param);
+ G *newg;
+ uintptr size;
+
+ newg = (G*)gp->param;
+ size = newg->stacksize;
+ newg->stacksize = 0;
+ gp->param = runtime·stackalloc(newg, size);
runtime·gogo(&gp->sched);
}
@@ -1685,24 +1767,24 @@ runtime·malg(int32 stacksize)
runtime·throw("runtime: bad stack.h");
}
- newg = runtime·malloc(sizeof(G));
+ newg = allocg();
if(stacksize >= 0) {
+ stacksize = runtime·round2(StackSystem + stacksize);
if(g == m->g0) {
// running on scheduler stack already.
- stk = runtime·stackalloc(StackSystem + stacksize);
+ stk = runtime·stackalloc(newg, stacksize);
} else {
// have to call stackalloc on scheduler stack.
- g->param = (void*)(StackSystem + stacksize);
+ newg->stacksize = stacksize;
+ g->param = newg;
runtime·mcall(mstackalloc);
stk = g->param;
g->param = nil;
}
- newg->stacksize = StackSystem + stacksize;
newg->stack0 = (uintptr)stk;
newg->stackguard = (uintptr)stk + StackGuard;
newg->stackguard0 = newg->stackguard;
- newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop);
- runtime·memclr((byte*)newg->stackbase, sizeof(Stktop));
+ newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop);
}
return newg;
}
@@ -1736,9 +1818,14 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
{
byte *sp;
G *newg;
+ P *p;
int32 siz;
//runtime·printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret);
+ if(fn == nil) {
+ m->throwing = -1; // do not dump full stacks
+ runtime·throw("go of nil func value");
+ }
m->locks++; // disable preemption because it can be holding p in a local var
siz = narg + nret;
siz = (siz+7) & ~7;
@@ -1750,18 +1837,13 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
if(siz > StackMin - 1024)
runtime·throw("runtime.newproc: function arguments too large for new goroutine");
- if((newg = gfget(m->p)) != nil) {
+ p = m->p;
+ if((newg = gfget(p)) != nil) {
if(newg->stackguard - StackGuard != newg->stack0)
runtime·throw("invalid stack in newg");
} else {
newg = runtime·malg(StackMin);
- runtime·lock(&runtime·sched);
- if(runtime·lastg == nil)
- runtime·allg = newg;
- else
- runtime·lastg->alllink = newg;
- runtime·lastg = newg;
- runtime·unlock(&runtime·sched);
+ allgadd(newg);
}
sp = (byte*)newg->stackbase;
@@ -1780,11 +1862,15 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
runtime·gostartcallfn(&newg->sched, fn);
newg->gopc = (uintptr)callerpc;
newg->status = Grunnable;
- newg->goid = runtime·xadd64(&runtime·sched.goidgen, 1);
+ if(p->goidcache == p->goidcacheend) {
+ p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch);
+ p->goidcacheend = p->goidcache + GoidCacheBatch;
+ }
+ newg->goid = p->goidcache++;
newg->panicwrap = 0;
if(raceenabled)
newg->racectx = runtime·racegostart((void*)callerpc);
- runqput(m->p, newg);
+ runqput(p, newg);
if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main) // TODO: fast atomic
wakep();
@@ -1794,13 +1880,56 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
return newg;
}
+static void
+allgadd(G *gp)
+{
+ G **new;
+ uintptr cap;
+
+ runtime·lock(&allglock);
+ if(runtime·allglen >= allgcap) {
+ cap = 4096/sizeof(new[0]);
+ if(cap < 2*allgcap)
+ cap = 2*allgcap;
+ new = runtime·malloc(cap*sizeof(new[0]));
+ if(new == nil)
+ runtime·throw("runtime: cannot allocate memory");
+ if(runtime·allg != nil) {
+ runtime·memmove(new, runtime·allg, runtime·allglen*sizeof(new[0]));
+ runtime·free(runtime·allg);
+ }
+ runtime·allg = new;
+ allgcap = cap;
+ }
+ runtime·allg[runtime·allglen++] = gp;
+ runtime·unlock(&allglock);
+}
+
// Put on gfree list.
// If local list is too long, transfer a batch to the global list.
static void
gfput(P *p, G *gp)
{
+ uintptr stksize;
+ Stktop *top;
+
if(gp->stackguard - StackGuard != gp->stack0)
runtime·throw("invalid stack in gfput");
+ stksize = gp->stackbase + sizeof(Stktop) - gp->stack0;
+ if(stksize != gp->stacksize) {
+ runtime·printf("runtime: bad stacksize, goroutine %D, remain=%d, last=%d\n",
+ gp->goid, (int32)gp->stacksize, (int32)stksize);
+ runtime·throw("gfput: bad stacksize");
+ }
+ top = (Stktop*)gp->stackbase;
+ if(top->malloced) {
+ // non-standard stack size - free it.
+ runtime·stackfree(gp, (void*)gp->stack0, top);
+ gp->stack0 = 0;
+ gp->stackguard = 0;
+ gp->stackguard0 = 0;
+ gp->stackbase = 0;
+ }
gp->schedlink = p->gfree;
p->gfree = gp;
p->gfreecnt++;
@@ -1823,6 +1952,7 @@ static G*
gfget(P *p)
{
G *gp;
+ byte *stk;
retry:
gp = p->gfree;
@@ -1841,6 +1971,23 @@ retry:
if(gp) {
p->gfree = gp->schedlink;
p->gfreecnt--;
+
+ if(gp->stack0 == 0) {
+ // Stack was deallocated in gfput. Allocate a new one.
+ if(g == m->g0) {
+ stk = runtime·stackalloc(gp, FixedStack);
+ } else {
+ gp->stacksize = FixedStack;
+ g->param = gp;
+ runtime·mcall(mstackalloc);
+ stk = g->param;
+ g->param = nil;
+ }
+ gp->stack0 = (uintptr)stk;
+ gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stktop);
+ gp->stackguard = (uintptr)stk + StackGuard;
+ gp->stackguard0 = gp->stackguard;
+ }
}
return gp;
}
@@ -1963,39 +2110,26 @@ runtime·lockedOSThread(void)
return g->lockedm != nil && m->lockedg != nil;
}
-// for testing of callbacks
-void
-runtime·golockedOSThread(bool ret)
-{
- ret = runtime·lockedOSThread();
- FLUSH(&ret);
-}
-
-void
-runtime·NumGoroutine(intgo ret)
-{
- ret = runtime·gcount();
- FLUSH(&ret);
-}
-
int32
runtime·gcount(void)
{
G *gp;
int32 n, s;
+ uintptr i;
n = 0;
- runtime·lock(&runtime·sched);
+ runtime·lock(&allglock);
// TODO(dvyukov): runtime.NumGoroutine() is O(N).
// We do not want to increment/decrement centralized counter in newproc/goexit,
// just to make runtime.NumGoroutine() faster.
// Compromise solution is to introduce per-P counters of active goroutines.
- for(gp = runtime·allg; gp; gp = gp->alllink) {
+ for(i = 0; i < runtime·allglen; i++) {
+ gp = runtime·allg[i];
s = gp->status;
if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
n++;
}
- runtime·unlock(&runtime·sched);
+ runtime·unlock(&allglock);
return n;
}
@@ -2032,25 +2166,30 @@ static struct {
uintptr pcbuf[100];
} prof;
-static void
-System(void)
-{
-}
+static void System(void) {}
+static void ExternalCode(void) {}
+static void GC(void) {}
+extern byte etext[];
// Called if we receive a SIGPROF signal.
void
-runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
+runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
{
int32 n;
bool traceback;
+ // Do not use global m in this function, use mp instead.
+ // On windows one m is sending reports about all the g's, so m means a wrong thing.
+ byte m;
+
+ m = 0;
+ USED(m);
if(prof.fn == nil || prof.hz == 0)
return;
- traceback = true;
- // Windows does profiling in a dedicated thread w/o m.
- if(!Windows && (m == nil || m->mcache == nil))
- traceback = false;
-
+
+ // Profiling runs concurrently with GC, so it must not allocate.
+ mp->mallocing++;
+
// Define that a "user g" is a user-created goroutine, and a "system g"
// is one that is m->g0 or m->gsignal. We've only made sure that we
// can unwind user g's, so exclude the system g's.
@@ -2123,36 +2262,55 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
// To recap, there are no constraints on the assembly being used for the
// transition. We simply require that g and SP match and that the PC is not
// in runtime.gogo.
- //
- // On Windows, one m is sending reports about all the g's, so gp == m->curg
- // is not a useful comparison. The profilem function in os_windows.c has
- // already checked that gp is a user g.
- if(gp == nil ||
- (!Windows && gp != m->curg) ||
+ traceback = true;
+ if(gp == nil || gp != mp->curg ||
(uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr)sp ||
((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
traceback = false;
- // Race detector calls asmcgocall w/o entersyscall/exitsyscall,
- // we can not currently unwind through asmcgocall.
- if(m != nil && m->racecall)
- traceback = false;
-
runtime·lock(&prof);
if(prof.fn == nil) {
runtime·unlock(&prof);
+ mp->mallocing--;
return;
}
n = 0;
if(traceback)
n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
if(!traceback || n <= 0) {
- n = 2;
- prof.pcbuf[0] = (uintptr)pc;
- prof.pcbuf[1] = (uintptr)System + 1;
+ // Normal traceback is impossible or has failed.
+ // See if it falls into several common cases.
+ n = 0;
+ if(mp->ncgo > 0 && mp->curg != nil &&
+ mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
+ // Cgo, we can't unwind and symbolize arbitrary C code,
+ // so instead collect Go stack that leads to the cgo call.
+ // This is especially important on windows, since all syscalls are cgo calls.
+ n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+ }
+#ifdef GOOS_windows
+ if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
+ // Libcall, i.e. runtime syscall on windows.
+ // Collect Go stack that leads to the call.
+ n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+ }
+#endif
+ if(n == 0) {
+ // If all of the above has failed, account it against abstract "System" or "GC".
+ n = 2;
+ // "ExternalCode" is better than "etext".
+ if((uintptr)pc > (uintptr)etext)
+ pc = (byte*)ExternalCode + PCQuantum;
+ prof.pcbuf[0] = (uintptr)pc;
+ if(mp->gcing || mp->helpgc)
+ prof.pcbuf[1] = (uintptr)GC + PCQuantum;
+ else
+ prof.pcbuf[1] = (uintptr)System + PCQuantum;
+ }
}
prof.fn(prof.pcbuf, n);
runtime·unlock(&prof);
+ mp->mallocing--;
}
// Arrange to call fn with a traceback hz times a second.
@@ -2195,6 +2353,7 @@ static void
procresize(int32 new)
{
int32 i, old;
+ bool empty;
G *gp;
P *p;
@@ -2216,27 +2375,42 @@ procresize(int32 new)
else
p->mcache = runtime·allocmcache();
}
- if(p->runq == nil) {
- p->runqsize = 128;
- p->runq = (G**)runtime·mallocgc(p->runqsize*sizeof(G*), 0, FlagNoInvokeGC);
- }
}
// redistribute runnable G's evenly
- for(i = 0; i < old; i++) {
- p = runtime·allp[i];
- while(gp = runqget(p))
- globrunqput(gp);
+ // collect all runnable goroutines in global queue preserving FIFO order
+ // FIFO order is required to ensure fairness even during frequent GCs
+ // see http://golang.org/issue/7126
+ empty = false;
+ while(!empty) {
+ empty = true;
+ for(i = 0; i < old; i++) {
+ p = runtime·allp[i];
+ if(p->runqhead == p->runqtail)
+ continue;
+ empty = false;
+ // pop from tail of local queue
+ p->runqtail--;
+ gp = p->runq[p->runqtail%nelem(p->runq)];
+ // push onto head of global queue
+ gp->schedlink = runtime·sched.runqhead;
+ runtime·sched.runqhead = gp;
+ if(runtime·sched.runqtail == nil)
+ runtime·sched.runqtail = gp;
+ runtime·sched.runqsize++;
+ }
}
+ // fill local queues with at most nelem(p->runq)/2 goroutines
// start at 1 because current M already executes some G and will acquire allp[0] below,
// so if we have a spare G we want to put it into allp[1].
- for(i = 1; runtime·sched.runqhead; i++) {
+ for(i = 1; i < new * nelem(p->runq)/2 && runtime·sched.runqsize > 0; i++) {
gp = runtime·sched.runqhead;
runtime·sched.runqhead = gp->schedlink;
+ if(runtime·sched.runqhead == nil)
+ runtime·sched.runqtail = nil;
+ runtime·sched.runqsize--;
runqput(runtime·allp[i%new], gp);
}
- runtime·sched.runqtail = nil;
- runtime·sched.runqsize = 0;
// free unused P's
for(i = new; i < old; i++) {
@@ -2318,30 +2492,41 @@ checkdead(void)
{
G *gp;
int32 run, grunning, s;
+ uintptr i;
// -1 for sysmon
run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidlelocked - 1;
if(run > 0)
return;
+ // If we are dying because of a signal caught on an already idle thread,
+ // freezetheworld will cause all running threads to block.
+ // And runtime will essentially enter into deadlock state,
+ // except that there is a thread that will call runtime·exit soon.
+ if(runtime·panicking > 0)
+ return;
if(run < 0) {
- runtime·printf("checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
+ runtime·printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
runtime·sched.nmidle, runtime·sched.nmidlelocked, runtime·sched.mcount);
runtime·throw("checkdead: inconsistent counts");
}
grunning = 0;
- for(gp = runtime·allg; gp; gp = gp->alllink) {
+ runtime·lock(&allglock);
+ for(i = 0; i < runtime·allglen; i++) {
+ gp = runtime·allg[i];
if(gp->isbackground)
continue;
s = gp->status;
if(s == Gwaiting)
grunning++;
else if(s == Grunnable || s == Grunning || s == Gsyscall) {
- runtime·printf("checkdead: find g %D in status %d\n", gp->goid, s);
+ runtime·unlock(&allglock);
+ runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
runtime·throw("checkdead: runnable g");
}
}
+ runtime·unlock(&allglock);
if(grunning == 0) // possible if main goroutine calls runtime·Goexit()
- runtime·exit(0);
+ runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
m->throwing = -1; // do not dump full stacks
runtime·throw("all goroutines are asleep - deadlock!");
}
@@ -2418,6 +2603,7 @@ struct Pdesc
uint32 syscalltick;
int64 syscallwhen;
};
+#pragma dataflag NOPTR
static Pdesc pdesc[MaxGomaxprocs];
static uint32
@@ -2436,16 +2622,19 @@ retake(int64 now)
pd = &pdesc[i];
s = p->status;
if(s == Psyscall) {
- // Retake P from syscall if it's there for more than 1 sysmon tick (20us).
- // But only if there is other work to do.
+ // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
t = p->syscalltick;
if(pd->syscalltick != t) {
pd->syscalltick = t;
pd->syscallwhen = now;
continue;
}
+ // On the one hand we don't want to retake Ps if there is no other work to do,
+ // but on the other hand we want to retake them eventually
+ // because they can prevent the sysmon thread from deep sleep.
if(p->runqhead == p->runqtail &&
- runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0)
+ runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0 &&
+ pd->syscallwhen + 10*1000*1000 > now)
continue;
// Need to decrement number of idle locked M's
// (pretending that one more is running) before the CAS.
@@ -2525,7 +2714,8 @@ runtime·schedtrace(bool detailed)
static int64 starttime;
int64 now;
int64 id1, id2, id3;
- int32 i, q, t, h, s;
+ int32 i, t, h;
+ uintptr gi;
int8 *fmt;
M *mp, *lockedm;
G *gp, *lockedg;
@@ -2552,15 +2742,11 @@ runtime·schedtrace(bool detailed)
if(p == nil)
continue;
mp = p->m;
- t = p->runqtail;
- h = p->runqhead;
- s = p->runqsize;
- q = t - h;
- if(q < 0)
- q += s;
+ h = runtime·atomicload(&p->runqhead);
+ t = runtime·atomicload(&p->runqtail);
if(detailed)
- runtime·printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d/%d gfreecnt=%d\n",
- i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, q, s, p->gfreecnt);
+ runtime·printf(" P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
+ i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
else {
// In non-detailed mode format lengths of per-P run queues as:
// [len1 len2 len3 len4]
@@ -2571,7 +2757,7 @@ runtime·schedtrace(bool detailed)
fmt = " [%d";
else if(i == runtime·gomaxprocs-1)
fmt = " %d]\n";
- runtime·printf(fmt, q);
+ runtime·printf(fmt, t-h);
}
}
if(!detailed) {
@@ -2592,18 +2778,21 @@ runtime·schedtrace(bool detailed)
if(lockedg)
id3 = lockedg->goid;
runtime·printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
- " locks=%d dying=%d helpgc=%d spinning=%d lockedg=%D\n",
+ " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
mp->id, id1, id2,
mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
- mp->spinning, id3);
+ mp->spinning, m->blocked, id3);
}
- for(gp = runtime·allg; gp; gp = gp->alllink) {
+ runtime·lock(&allglock);
+ for(gi = 0; gi < runtime·allglen; gi++) {
+ gp = runtime·allg[gi];
mp = gp->m;
lockedm = gp->lockedm;
runtime·printf(" G%D: status=%d(%s) m=%d lockedm=%d\n",
gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1,
lockedm ? lockedm->id : -1);
}
+ runtime·unlock(&allglock);
runtime·unlock(&runtime·sched);
}
@@ -2646,6 +2835,20 @@ globrunqput(G *gp)
runtime·sched.runqsize++;
}
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+static void
+globrunqputbatch(G *ghead, G *gtail, int32 n)
+{
+ gtail->schedlink = nil;
+ if(runtime·sched.runqtail)
+ runtime·sched.runqtail->schedlink = ghead;
+ else
+ runtime·sched.runqhead = ghead;
+ runtime·sched.runqtail = gtail;
+ runtime·sched.runqsize += n;
+}
+
// Try get a batch of G's from the global runnable queue.
// Sched must be locked.
static G*
@@ -2661,6 +2864,8 @@ globrunqget(P *p, int32 max)
n = runtime·sched.runqsize;
if(max > 0 && n > max)
n = max;
+ if(n > nelem(p->runq)/2)
+ n = nelem(p->runq)/2;
runtime·sched.runqsize -= n;
if(runtime·sched.runqsize == 0)
runtime·sched.runqtail = nil;
@@ -2700,78 +2905,98 @@ pidleget(void)
return p;
}
-// Put g on local runnable queue.
-// TODO(dvyukov): consider using lock-free queue.
+// Try to put g on local runnable queue.
+// If it's full, put onto global queue.
+// Executed only by the owner P.
static void
runqput(P *p, G *gp)
{
- int32 h, t, s;
+ uint32 h, t;
- runtime·lock(p);
retry:
- h = p->runqhead;
+ h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with consumers
t = p->runqtail;
- s = p->runqsize;
- if(t == h-1 || (h == 0 && t == s-1)) {
- runqgrow(p);
- goto retry;
+ if(t - h < nelem(p->runq)) {
+ p->runq[t%nelem(p->runq)] = gp;
+ runtime·atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption
+ return;
}
- p->runq[t++] = gp;
- if(t == s)
- t = 0;
- p->runqtail = t;
- runtime·unlock(p);
+ if(runqputslow(p, gp, h, t))
+ return;
+ // the queue is not full, now the put above must suceed
+ goto retry;
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+static bool
+runqputslow(P *p, G *gp, uint32 h, uint32 t)
+{
+ G *batch[nelem(p->runq)/2+1];
+ uint32 n, i;
+
+ // First, grab a batch from local queue.
+ n = t-h;
+ n = n/2;
+ if(n != nelem(p->runq)/2)
+ runtime·throw("runqputslow: queue is not full");
+ for(i=0; i<n; i++)
+ batch[i] = p->runq[(h+i)%nelem(p->runq)];
+ if(!runtime·cas(&p->runqhead, h, h+n)) // cas-release, commits consume
+ return false;
+ batch[n] = gp;
+ // Link the goroutines.
+ for(i=0; i<n; i++)
+ batch[i]->schedlink = batch[i+1];
+ // Now put the batch on global queue.
+ runtime·lock(&runtime·sched);
+ globrunqputbatch(batch[0], batch[n], n+1);
+ runtime·unlock(&runtime·sched);
+ return true;
}
// Get g from local runnable queue.
+// Executed only by the owner P.
static G*
runqget(P *p)
{
G *gp;
- int32 t, h, s;
+ uint32 t, h;
- if(p->runqhead == p->runqtail)
- return nil;
- runtime·lock(p);
- h = p->runqhead;
- t = p->runqtail;
- s = p->runqsize;
- if(t == h) {
- runtime·unlock(p);
- return nil;
+ for(;;) {
+ h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
+ t = p->runqtail;
+ if(t == h)
+ return nil;
+ gp = p->runq[h%nelem(p->runq)];
+ if(runtime·cas(&p->runqhead, h, h+1)) // cas-release, commits consume
+ return gp;
}
- gp = p->runq[h++];
- if(h == s)
- h = 0;
- p->runqhead = h;
- runtime·unlock(p);
- return gp;
}
-// Grow local runnable queue.
-// TODO(dvyukov): consider using fixed-size array
-// and transfer excess to the global list (local queue can grow way too big).
-static void
-runqgrow(P *p)
+// Grabs a batch of goroutines from local runnable queue.
+// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
+// Can be executed by any P.
+static uint32
+runqgrab(P *p, G **batch)
{
- G **q;
- int32 s, t, h, t2;
+ uint32 t, h, n, i;
- h = p->runqhead;
- t = p->runqtail;
- s = p->runqsize;
- t2 = 0;
- q = runtime·malloc(2*s*sizeof(*q));
- while(t != h) {
- q[t2++] = p->runq[h++];
- if(h == s)
- h = 0;
+ for(;;) {
+ h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with other consumers
+ t = runtime·atomicload(&p->runqtail); // load-acquire, synchronize with the producer
+ n = t-h;
+ n = n - n/2;
+ if(n == 0)
+ break;
+ if(n > nelem(p->runq)/2) // read inconsistent h and t
+ continue;
+ for(i=0; i<n; i++)
+ batch[i] = p->runq[(h+i)%nelem(p->runq)];
+ if(runtime·cas(&p->runqhead, h, h+n)) // cas-release, commits consume
+ break;
}
- runtime·free(p->runq);
- p->runq = q;
- p->runqhead = 0;
- p->runqtail = t2;
- p->runqsize = 2*s;
+ return n;
}
// Steal half of elements from local runnable queue of p2
@@ -2780,57 +3005,24 @@ runqgrow(P *p)
static G*
runqsteal(P *p, P *p2)
{
- G *gp, *gp1;
- int32 t, h, s, t2, h2, s2, c, i;
+ G *gp;
+ G *batch[nelem(p->runq)/2];
+ uint32 t, h, n, i;
- if(p2->runqhead == p2->runqtail)
+ n = runqgrab(p2, batch);
+ if(n == 0)
return nil;
- // sort locks to prevent deadlocks
- if(p < p2)
- runtime·lock(p);
- runtime·lock(p2);
- if(p2->runqhead == p2->runqtail) {
- runtime·unlock(p2);
- if(p < p2)
- runtime·unlock(p);
- return nil;
- }
- if(p >= p2)
- runtime·lock(p);
- // now we've locked both queues and know the victim is not empty
- h = p->runqhead;
+ n--;
+ gp = batch[n];
+ if(n == 0)
+ return gp;
+ h = runtime·atomicload(&p->runqhead); // load-acquire, synchronize with consumers
t = p->runqtail;
- s = p->runqsize;
- h2 = p2->runqhead;
- t2 = p2->runqtail;
- s2 = p2->runqsize;
- gp = p2->runq[h2++]; // return value
- if(h2 == s2)
- h2 = 0;
- // steal roughly half
- if(t2 > h2)
- c = (t2 - h2) / 2;
- else
- c = (s2 - h2 + t2) / 2;
- // copy
- for(i = 0; i != c; i++) {
- // the target queue is full?
- if(t == h-1 || (h == 0 && t == s-1))
- break;
- // the victim queue is empty?
- if(t2 == h2)
- break;
- gp1 = p2->runq[h2++];
- if(h2 == s2)
- h2 = 0;
- p->runq[t++] = gp1;
- if(t == s)
- t = 0;
- }
- p->runqtail = t;
- p2->runqhead = h2;
- runtime·unlock(p2);
- runtime·unlock(p);
+ if(t - h + n >= nelem(p->runq))
+ runtime·throw("runqsteal: runq overflow");
+ for(i=0; i<n; i++, t++)
+ p->runq[t%nelem(p->runq)] = batch[i];
+ runtime·atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption
return gp;
}
@@ -2838,14 +3030,10 @@ void
runtime·testSchedLocalQueue(void)
{
P p;
- G gs[1000];
+ G gs[nelem(p.runq)];
int32 i, j;
runtime·memclr((byte*)&p, sizeof(p));
- p.runqsize = 1;
- p.runqhead = 0;
- p.runqtail = 0;
- p.runq = runtime·malloc(p.runqsize*sizeof(*p.runq));
for(i = 0; i < nelem(gs); i++) {
if(runqget(&p) != nil)
@@ -2867,20 +3055,11 @@ void
runtime·testSchedLocalQueueSteal(void)
{
P p1, p2;
- G gs[1000], *gp;
+ G gs[nelem(p1.runq)], *gp;
int32 i, j, s;
runtime·memclr((byte*)&p1, sizeof(p1));
- p1.runqsize = 1;
- p1.runqhead = 0;
- p1.runqtail = 0;
- p1.runq = runtime·malloc(p1.runqsize*sizeof(*p1.runq));
-
runtime·memclr((byte*)&p2, sizeof(p2));
- p2.runqsize = nelem(gs);
- p2.runqhead = 0;
- p2.runqtail = 0;
- p2.runq = runtime·malloc(p2.runqsize*sizeof(*p2.runq));
for(i = 0; i < nelem(gs); i++) {
for(j = 0; j < i; j++) {
@@ -2914,6 +3093,7 @@ runtime·testSchedLocalQueueSteal(void)
}
extern void runtime·morestack(void);
+uintptr runtime·externalthreadhandlerp;
// Does f mark the top of a goroutine stack?
bool
@@ -2924,18 +3104,21 @@ runtime·topofstack(Func *f)
f->entry == (uintptr)runtime·mcall ||
f->entry == (uintptr)runtime·morestack ||
f->entry == (uintptr)runtime·lessstack ||
- f->entry == (uintptr)_rt0_go;
+ f->entry == (uintptr)_rt0_go ||
+ (runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
}
-void
-runtime∕debug·setMaxThreads(intgo in, intgo out)
+int32
+runtime·setmaxthreads(int32 in)
{
+ int32 out;
+
runtime·lock(&runtime·sched);
out = runtime·sched.maxmcount;
runtime·sched.maxmcount = in;
checkmcount();
runtime·unlock(&runtime·sched);
- FLUSH(&out);
+ return out;
}
static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
diff --git a/src/pkg/runtime/proc.p b/src/pkg/runtime/proc.p
deleted file mode 100644
index f0b46de61..000000000
--- a/src/pkg/runtime/proc.p
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-model for proc.c as of 2011/07/22.
-
-takes 4900 seconds to explore 1189070 states
-with G=3, var_gomaxprocs=1
-on a Core i7 L640 2.13 GHz Lenovo X201s.
-
-rm -f proc.p.trail pan.* pan
-spin -a proc.p
-gcc -DSAFETY -DREACH -DMEMLIM'='4000 -o pan pan.c
-pan -w28 -n -i -m500000
-test -f proc.p.trail && pan -r proc.p.trail
-*/
-
-/*
- * scheduling parameters
- */
-
-/*
- * the number of goroutines G doubles as the maximum
- * number of OS threads; the max is reachable when all
- * the goroutines are blocked in system calls.
- */
-#define G 3
-
-/*
- * whether to allow gomaxprocs to vary during execution.
- * enabling this checks the scheduler even when code is
- * calling GOMAXPROCS, but it also slows down the verification
- * by about 10x.
- */
-#define var_gomaxprocs 1 /* allow gomaxprocs to vary */
-
-/* gomaxprocs */
-#if var_gomaxprocs
-byte gomaxprocs = 3;
-#else
-#define gomaxprocs 3
-#endif
-
-/* queue of waiting M's: sched_mhead[:mwait] */
-byte mwait;
-byte sched_mhead[G];
-
-/* garbage collector state */
-bit gc_lock, gcwaiting;
-
-/* goroutines sleeping, waiting to run */
-byte gsleep, gwait;
-
-/* scheduler state */
-bit sched_lock;
-bit sched_stopped;
-bit atomic_gwaiting, atomic_waitstop;
-byte atomic_mcpu, atomic_mcpumax;
-
-/* M struct fields - state for handing off g to m. */
-bit m_waitnextg[G];
-bit m_havenextg[G];
-bit m_nextg[G];
-
-/*
- * opt_atomic/opt_dstep mark atomic/deterministics
- * sequences that are marked only for reasons of
- * optimization, not for correctness of the algorithms.
- *
- * in general any code that runs while holding the
- * schedlock and does not refer to or modify the atomic_*
- * fields can be marked atomic/dstep without affecting
- * the usefulness of the model. since we trust the lock
- * implementation, what we really want to test is the
- * interleaving of the atomic fast paths with entersyscall
- * and exitsyscall.
- */
-#define opt_atomic atomic
-#define opt_dstep d_step
-
-/* locks */
-inline lock(x) {
- d_step { x == 0; x = 1 }
-}
-
-inline unlock(x) {
- d_step { assert x == 1; x = 0 }
-}
-
-/* notes */
-inline noteclear(x) {
- x = 0
-}
-
-inline notesleep(x) {
- x == 1
-}
-
-inline notewakeup(x) {
- opt_dstep { assert x == 0; x = 1 }
-}
-
-/*
- * scheduler
- */
-inline schedlock() {
- lock(sched_lock)
-}
-
-inline schedunlock() {
- unlock(sched_lock)
-}
-
-/*
- * canaddmcpu is like the C function but takes
- * an extra argument to include in the test, to model
- * "cannget() && canaddmcpu()" as "canaddmcpu(cangget())"
- */
-inline canaddmcpu(g) {
- d_step {
- g && atomic_mcpu < atomic_mcpumax;
- atomic_mcpu++;
- }
-}
-
-/*
- * gput is like the C function.
- * instead of tracking goroutines explicitly we
- * maintain only the count of the number of
- * waiting goroutines.
- */
-inline gput() {
- /* omitted: lockedm, idlem concerns */
- opt_dstep {
- gwait++;
- if
- :: gwait == 1 ->
- atomic_gwaiting = 1
- :: else
- fi
- }
-}
-
-/*
- * cangget is a macro so it can be passed to
- * canaddmcpu (see above).
- */
-#define cangget() (gwait>0)
-
-/*
- * gget is like the C function.
- */
-inline gget() {
- opt_dstep {
- assert gwait > 0;
- gwait--;
- if
- :: gwait == 0 ->
- atomic_gwaiting = 0
- :: else
- fi
- }
-}
-
-/*
- * mput is like the C function.
- * here we do keep an explicit list of waiting M's,
- * so that we know which ones can be awakened.
- * we use _pid-1 because the monitor is proc 0.
- */
-inline mput() {
- opt_dstep {
- sched_mhead[mwait] = _pid - 1;
- mwait++
- }
-}
-
-/*
- * mnextg is like the C function mnextg(m, g).
- * it passes an unspecified goroutine to m to start running.
- */
-inline mnextg(m) {
- opt_dstep {
- m_nextg[m] = 1;
- if
- :: m_waitnextg[m] ->
- m_waitnextg[m] = 0;
- notewakeup(m_havenextg[m])
- :: else
- fi
- }
-}
-
-/*
- * mgetnextg handles the main m handoff in matchmg.
- * it is like mget() || new M followed by mnextg(m, g),
- * but combined to avoid a local variable.
- * unlike the C code, a new M simply assumes it is
- * running a g instead of using the mnextg coordination
- * to obtain one.
- */
-inline mgetnextg() {
- opt_atomic {
- if
- :: mwait > 0 ->
- mwait--;
- mnextg(sched_mhead[mwait]);
- sched_mhead[mwait] = 0;
- :: else ->
- run mstart();
- fi
- }
-}
-
-/*
- * nextgandunlock is like the C function.
- * it pulls a g off the queue or else waits for one.
- */
-inline nextgandunlock() {
- assert atomic_mcpu <= G;
-
- if
- :: m_nextg[_pid-1] ->
- m_nextg[_pid-1] = 0;
- schedunlock();
- :: canaddmcpu(!m_nextg[_pid-1] && cangget()) ->
- gget();
- schedunlock();
- :: else ->
- opt_dstep {
- mput();
- m_nextg[_pid-1] = 0;
- m_waitnextg[_pid-1] = 1;
- noteclear(m_havenextg[_pid-1]);
- }
- if
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- atomic_waitstop = 0;
- notewakeup(sched_stopped)
- :: else
- fi;
- schedunlock();
- opt_dstep {
- notesleep(m_havenextg[_pid-1]);
- assert m_nextg[_pid-1];
- m_nextg[_pid-1] = 0;
- }
- fi
-}
-
-/*
- * stoptheworld is like the C function.
- */
-inline stoptheworld() {
- schedlock();
- gcwaiting = 1;
- atomic_mcpumax = 1;
- do
- :: d_step { atomic_mcpu > 1 ->
- noteclear(sched_stopped);
- assert !atomic_waitstop;
- atomic_waitstop = 1 }
- schedunlock();
- notesleep(sched_stopped);
- schedlock();
- :: else ->
- break
- od;
- schedunlock();
-}
-
-/*
- * starttheworld is like the C function.
- */
-inline starttheworld() {
- schedlock();
- gcwaiting = 0;
- atomic_mcpumax = gomaxprocs;
- matchmg();
- schedunlock();
-}
-
-/*
- * matchmg is like the C function.
- */
-inline matchmg() {
- do
- :: canaddmcpu(cangget()) ->
- gget();
- mgetnextg();
- :: else -> break
- od
-}
-
-/*
- * ready is like the C function.
- * it puts a g on the run queue.
- */
-inline ready() {
- schedlock();
- gput()
- matchmg()
- schedunlock()
-}
-
-/*
- * schedule simulates the C scheduler.
- * it assumes that there is always a goroutine
- * running already, and the goroutine has entered
- * the scheduler for an unspecified reason,
- * either to yield or to block.
- */
-inline schedule() {
- schedlock();
-
- mustsched = 0;
- atomic_mcpu--;
- assert atomic_mcpu <= G;
- if
- :: skip ->
- // goroutine yields, still runnable
- gput();
- :: gsleep+1 < G ->
- // goroutine goes to sleep (but there is another that can wake it)
- gsleep++
- fi;
-
- // Find goroutine to run.
- nextgandunlock()
-}
-
-/*
- * schedpend is > 0 if a goroutine is about to committed to
- * entering the scheduler but has not yet done so.
- * Just as we don't test for the undesirable conditions when a
- * goroutine is in the scheduler, we don't test for them when
- * a goroutine will be in the scheduler shortly.
- * Modeling this state lets us replace mcpu cas loops with
- * simpler mcpu atomic adds.
- */
-byte schedpend;
-
-/*
- * entersyscall is like the C function.
- */
-inline entersyscall() {
- bit willsched;
-
- /*
- * Fast path. Check all the conditions tested during schedlock/schedunlock
- * below, and if we can get through the whole thing without stopping, run it
- * in one atomic cas-based step.
- */
- atomic {
- atomic_mcpu--;
- if
- :: atomic_gwaiting ->
- skip
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- skip
- :: else ->
- goto Lreturn_entersyscall;
- fi;
- willsched = 1;
- schedpend++;
- }
-
- /*
- * Normal path.
- */
- schedlock()
- opt_dstep {
- if
- :: willsched ->
- schedpend--;
- willsched = 0
- :: else
- fi
- }
- if
- :: atomic_gwaiting ->
- matchmg()
- :: else
- fi;
- if
- :: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- atomic_waitstop = 0;
- notewakeup(sched_stopped)
- :: else
- fi;
- schedunlock();
-Lreturn_entersyscall:
- skip
-}
-
-/*
- * exitsyscall is like the C function.
- */
-inline exitsyscall() {
- /*
- * Fast path. If there's a cpu available, use it.
- */
- atomic {
- // omitted profilehz check
- atomic_mcpu++;
- if
- :: atomic_mcpu >= atomic_mcpumax ->
- skip
- :: else ->
- goto Lreturn_exitsyscall
- fi
- }
-
- /*
- * Normal path.
- */
- schedlock();
- d_step {
- if
- :: atomic_mcpu <= atomic_mcpumax ->
- skip
- :: else ->
- mustsched = 1
- fi
- }
- schedunlock()
-Lreturn_exitsyscall:
- skip
-}
-
-#if var_gomaxprocs
-inline gomaxprocsfunc() {
- schedlock();
- opt_atomic {
- if
- :: gomaxprocs != 1 -> gomaxprocs = 1
- :: gomaxprocs != 2 -> gomaxprocs = 2
- :: gomaxprocs != 3 -> gomaxprocs = 3
- fi;
- }
- if
- :: gcwaiting != 0 ->
- assert atomic_mcpumax == 1
- :: else ->
- atomic_mcpumax = gomaxprocs;
- if
- :: atomic_mcpu > gomaxprocs ->
- mustsched = 1
- :: else ->
- matchmg()
- fi
- fi;
- schedunlock();
-}
-#endif
-
-/*
- * mstart is the entry point for a new M.
- * our model of an M is always running some
- * unspecified goroutine.
- */
-proctype mstart() {
- /*
- * mustsched is true if the goroutine must enter the
- * scheduler instead of continuing to execute.
- */
- bit mustsched;
-
- do
- :: skip ->
- // goroutine reschedules.
- schedule()
- :: !mustsched ->
- // goroutine does something.
- if
- :: skip ->
- // goroutine executes system call
- entersyscall();
- exitsyscall()
- :: atomic { gsleep > 0; gsleep-- } ->
- // goroutine wakes another goroutine
- ready()
- :: lock(gc_lock) ->
- // goroutine runs a garbage collection
- stoptheworld();
- starttheworld();
- unlock(gc_lock)
-#if var_gomaxprocs
- :: skip ->
- // goroutine picks a new gomaxprocs
- gomaxprocsfunc()
-#endif
- fi
- od;
-
- assert 0;
-}
-
-/*
- * monitor initializes the scheduler state
- * and then watches for impossible conditions.
- */
-active proctype monitor() {
- opt_dstep {
- byte i = 1;
- do
- :: i < G ->
- gput();
- i++
- :: else -> break
- od;
- atomic_mcpu = 1;
- atomic_mcpumax = 1;
- }
- run mstart();
-
- do
- // Should never have goroutines waiting with procs available.
- :: !sched_lock && schedpend==0 && gwait > 0 && atomic_mcpu < atomic_mcpumax ->
- assert 0
- // Should never have gc waiting for stop if things have already stopped.
- :: !sched_lock && schedpend==0 && atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
- assert 0
- od
-}
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
index dd70ed97d..5be355195 100644
--- a/src/pkg/runtime/proc_test.go
+++ b/src/pkg/runtime/proc_test.go
@@ -244,6 +244,49 @@ func TestPreemptionGC(t *testing.T) {
atomic.StoreUint32(&stop, 1)
}
+func TestGCFairness(t *testing.T) {
+ output := executeTest(t, testGCFairnessSource, nil)
+ want := "OK\n"
+ if output != want {
+ t.Fatalf("want %s, got %s\n", want, output)
+ }
+}
+
+const testGCFairnessSource = `
+package main
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "time"
+)
+
+func main() {
+ runtime.GOMAXPROCS(1)
+ f, err := os.Open("/dev/null")
+ if os.IsNotExist(err) {
+ // This test tests what it is intended to test only if writes are fast.
+ // If there is no /dev/null, we just don't execute the test.
+ fmt.Println("OK")
+ return
+ }
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ for i := 0; i < 2; i++ {
+ go func() {
+ for {
+ f.Write([]byte("."))
+ }
+ }()
+ }
+ time.Sleep(10 * time.Millisecond)
+ fmt.Println("OK")
+}
+`
+
func stackGrowthRecursive(i int) {
var pad [128]uint64
if i != 0 && pad[0] == 0 {
@@ -327,24 +370,11 @@ func TestSchedLocalQueueSteal(t *testing.T) {
}
func benchmarkStackGrowth(b *testing.B, rec int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- stackGrowthRecursive(rec)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ stackGrowthRecursive(rec)
+ }
+ })
}
func BenchmarkStackGrowth(b *testing.B) {
diff --git a/src/pkg/runtime/race.c b/src/pkg/runtime/race.c
index 6ee55beff..eb0be7fa6 100644
--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -9,178 +9,96 @@
#include "arch_GOARCH.h"
#include "malloc.h"
#include "race.h"
-#include "../../cmd/ld/textflag.h"
-
-void runtime∕race·Initialize(uintptr *racectx);
-void runtime∕race·MapShadow(void *addr, uintptr size);
-void runtime∕race·Finalize(void);
-void runtime∕race·FinalizerGoroutine(uintptr racectx);
-void runtime∕race·Read(uintptr racectx, void *addr, void *pc);
-void runtime∕race·Write(uintptr racectx, void *addr, void *pc);
-void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·FuncEnter(uintptr racectx, void *pc);
-void runtime∕race·FuncExit(uintptr racectx);
-void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);
-void runtime∕race·Free(void *p);
-void runtime∕race·GoStart(uintptr racectx, uintptr *chracectx, void *pc);
-void runtime∕race·GoEnd(uintptr racectx);
-void runtime∕race·Acquire(uintptr racectx, void *addr);
-void runtime∕race·Release(uintptr racectx, void *addr);
-void runtime∕race·ReleaseMerge(uintptr racectx, void *addr);
+#include "type.h"
+#include "typekind.h"
+
+// Race runtime functions called via runtime·racecall.
+void __tsan_init(void);
+void __tsan_fini(void);
+void __tsan_map_shadow(void);
+void __tsan_finalizer_goroutine(void);
+void __tsan_go_start(void);
+void __tsan_go_end(void);
+void __tsan_malloc(void);
+void __tsan_acquire(void);
+void __tsan_release(void);
+void __tsan_release_merge(void);
+
+// Mimic what cmd/cgo would do.
+#pragma cgo_import_static __tsan_init
+#pragma cgo_import_static __tsan_fini
+#pragma cgo_import_static __tsan_map_shadow
+#pragma cgo_import_static __tsan_finalizer_goroutine
+#pragma cgo_import_static __tsan_go_start
+#pragma cgo_import_static __tsan_go_end
+#pragma cgo_import_static __tsan_malloc
+#pragma cgo_import_static __tsan_acquire
+#pragma cgo_import_static __tsan_release
+#pragma cgo_import_static __tsan_release_merge
+
+// These are called from race_amd64.s.
+#pragma cgo_import_static __tsan_read
+#pragma cgo_import_static __tsan_read_pc
+#pragma cgo_import_static __tsan_read_range
+#pragma cgo_import_static __tsan_write
+#pragma cgo_import_static __tsan_write_pc
+#pragma cgo_import_static __tsan_write_range
+#pragma cgo_import_static __tsan_func_enter
+#pragma cgo_import_static __tsan_func_exit
extern byte noptrdata[];
extern byte enoptrbss[];
+
+// start/end of heap for race_amd64.s
+uintptr runtime·racearenastart;
+uintptr runtime·racearenaend;
-static bool onstack(uintptr argp);
+void runtime·racefuncenter(void *callpc);
+void runtime·racefuncexit(void);
+void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racesymbolizethunk(void*);
-// We set m->racecall around all calls into race library to trigger fast path in cgocall.
-// Also we increment m->locks to disable preemption and potential rescheduling
-// to ensure that we reset m->racecall on the correct m.
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+void runtime·racecall(void(*f)(void), ...);
uintptr
runtime·raceinit(void)
{
uintptr racectx, start, size;
- m->racecall = true;
- m->locks++;
- runtime∕race·Initialize(&racectx);
+ // cgo is required to initialize libc, which is used by race runtime
+ if(!runtime·iscgo)
+ runtime·throw("raceinit: race build must use cgo");
+ runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
// Round data segment to page boundaries, because it's used in mmap().
start = (uintptr)noptrdata & ~(PageSize-1);
size = ROUND((uintptr)enoptrbss - start, PageSize);
- runtime∕race·MapShadow((void*)start, size);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_map_shadow, start, size);
return racectx;
}
void
runtime·racefini(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·Finalize();
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_fini);
}
void
runtime·racemapshadow(void *addr, uintptr size)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·MapShadow(addr, size);
- m->locks--;
- m->racecall = false;
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·racewrite(uintptr addr)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·Write(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterange(uintptr addr, uintptr sz)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·WriteRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·raceread(uintptr addr)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·Read(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrange(uintptr addr, uintptr sz)
-{
- if(!onstack(addr)) {
- m->racecall = true;
- m->locks++;
- runtime∕race·ReadRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
- m->locks--;
- m->racecall = false;
- }
-}
-
-// Called from runtime·racefuncenter (assembly).
-#pragma textflag NOSPLIT
-void
-runtime·racefuncenter1(uintptr pc)
-{
- // If the caller PC is lessstack, use slower runtime·callers
- // to walk across the stack split to find the real caller.
- if(pc == (uintptr)runtime·lessstack)
- runtime·callers(2, &pc, 1);
-
- m->racecall = true;
- m->locks++;
- runtime∕race·FuncEnter(g->racectx, (void*)pc);
- m->locks--;
- m->racecall = false;
-}
-
-// Called from instrumented code.
-#pragma textflag NOSPLIT
-void
-runtime·racefuncexit(void)
-{
- m->racecall = true;
- m->locks++;
- runtime∕race·FuncExit(g->racectx);
- m->locks--;
- m->racecall = false;
+ if(runtime·racearenastart == 0)
+ runtime·racearenastart = (uintptr)addr;
+ if(runtime·racearenaend < (uintptr)addr+size)
+ runtime·racearenaend = (uintptr)addr+size;
+ runtime·racecall(__tsan_map_shadow, addr, size);
}
void
runtime·racemalloc(void *p, uintptr sz)
{
- // use m->curg because runtime·stackalloc() is called from g0
- if(m->curg == nil)
- return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Malloc(m->curg->racectx, p, sz, /* unused pc */ 0);
- m->locks--;
- m->racecall = false;
-}
-
-void
-runtime·racefree(void *p)
-{
- m->racecall = true;
- m->locks++;
- runtime∕race·Free(p);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_malloc, p, sz);
}
uintptr
@@ -188,96 +106,58 @@ runtime·racegostart(void *pc)
{
uintptr racectx;
- m->racecall = true;
- m->locks++;
- runtime∕race·GoStart(g->racectx, &racectx, pc);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc);
return racectx;
}
void
runtime·racegoend(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·GoEnd(g->racectx);
- m->locks--;
- m->racecall = false;
-}
-
-static void
-memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write)
-{
- uintptr racectx;
-
- if(!onstack((uintptr)addr)) {
- m->racecall = true;
- m->locks++;
- racectx = g->racectx;
- if(callpc) {
- if(callpc == (uintptr)runtime·lessstack)
- runtime·callers(3, &callpc, 1);
- runtime∕race·FuncEnter(racectx, (void*)callpc);
- }
- if(write)
- runtime∕race·Write(racectx, addr, (void*)pc);
- else
- runtime∕race·Read(racectx, addr, (void*)pc);
- if(callpc)
- runtime∕race·FuncExit(racectx);
- m->locks--;
- m->racecall = false;
- }
+ runtime·racecall(__tsan_go_end, g->racectx);
}
void
-runtime·racewritepc(void *addr, void *callpc, void *pc)
+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
- memoryaccess(addr, (uintptr)callpc, (uintptr)pc, true);
+ if(callpc != nil)
+ runtime·racefuncenter(callpc);
+ runtime·racewriterangepc1(addr, sz, pc);
+ if(callpc != nil)
+ runtime·racefuncexit();
}
void
-runtime·racereadpc(void *addr, void *callpc, void *pc)
+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
{
- memoryaccess(addr, (uintptr)callpc, (uintptr)pc, false);
+ if(callpc != nil)
+ runtime·racefuncenter(callpc);
+ runtime·racereadrangepc1(addr, sz, pc);
+ if(callpc != nil)
+ runtime·racefuncexit();
}
-static void
-rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)
+void
+runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
- uintptr racectx;
+ uint8 kind;
- if(!onstack((uintptr)addr)) {
- m->racecall = true;
- m->locks++;
- racectx = g->racectx;
- if(callpc) {
- if(callpc == (uintptr)runtime·lessstack)
- runtime·callers(3, &callpc, 1);
- runtime∕race·FuncEnter(racectx, (void*)callpc);
- }
- if(write)
- runtime∕race·WriteRange(racectx, addr, size, (void*)pc);
- else
- runtime∕race·ReadRange(racectx, addr, size, (void*)pc);
- if(callpc)
- runtime∕race·FuncExit(racectx);
- m->locks--;
- m->racecall = false;
- }
+ kind = t->kind & ~KindNoPointers;
+ if(kind == KindArray || kind == KindStruct)
+ runtime·racewriterangepc(addr, t->size, callpc, pc);
+ else
+ runtime·racewritepc(addr, callpc, pc);
}
void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
+runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
{
- rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);
-}
+ uint8 kind;
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
- rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, false);
+ kind = t->kind & ~KindNoPointers;
+ if(kind == KindArray || kind == KindStruct)
+ runtime·racereadrangepc(addr, t->size, callpc, pc);
+ else
+ runtime·racereadpc(addr, callpc, pc);
}
void
@@ -291,11 +171,7 @@ runtime·raceacquireg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Acquire(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_acquire, gp->racectx, addr);
}
void
@@ -309,11 +185,7 @@ runtime·racereleaseg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·Release(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_release, gp->racectx, addr);
}
void
@@ -327,21 +199,13 @@ runtime·racereleasemergeg(G *gp, void *addr)
{
if(g->raceignore)
return;
- m->racecall = true;
- m->locks++;
- runtime∕race·ReleaseMerge(gp->racectx, addr);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_release_merge, gp->racectx, addr);
}
void
runtime·racefingo(void)
{
- m->racecall = true;
- m->locks++;
- runtime∕race·FinalizerGoroutine(g->racectx);
- m->locks--;
- m->racecall = false;
+ runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
}
// func RaceAcquire(addr unsafe.Pointer)
@@ -379,38 +243,6 @@ runtime·RaceSemrelease(uint32 *s)
runtime·semrelease(s);
}
-// func RaceRead(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRead(void *addr)
-{
- memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWrite(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWrite(void *addr)
-{
- memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
-// func RaceReadRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReadRange(void *addr, intgo len)
-{
- rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWriteRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWriteRange(void *addr, intgo len)
-{
- rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
// func RaceDisable()
void
runtime·RaceDisable(void)
@@ -425,14 +257,36 @@ runtime·RaceEnable(void)
g->raceignore--;
}
-static bool
-onstack(uintptr argp)
+typedef struct SymbolizeContext SymbolizeContext;
+struct SymbolizeContext
+{
+ uintptr pc;
+ int8* func;
+ int8* file;
+ uintptr line;
+ uintptr off;
+ uintptr res;
+};
+
+// Callback from C into Go, runs on g0.
+void
+runtime·racesymbolize(SymbolizeContext *ctx)
{
- // noptrdata, data, bss, noptrbss
- // the layout is in ../../cmd/ld/data.c
- if((byte*)argp >= noptrdata && (byte*)argp < enoptrbss)
- return false;
- if((byte*)argp >= runtime·mheap.arena_start && (byte*)argp < runtime·mheap.arena_used)
- return false;
- return true;
+ Func *f;
+ String file;
+
+ f = runtime·findfunc(ctx->pc);
+ if(f == nil) {
+ ctx->func = "??";
+ ctx->file = "-";
+ ctx->line = 0;
+ ctx->off = ctx->pc;
+ ctx->res = 1;
+ return;
+ }
+ ctx->func = runtime·funcname(f);
+ ctx->line = runtime·funcline(f, ctx->pc, &file);
+ ctx->file = (int8*)file.str; // assume zero-terminated
+ ctx->off = ctx->pc - f->entry;
+ ctx->res = 1;
}
diff --git a/src/pkg/runtime/race.h b/src/pkg/runtime/race.h
index f7aa99dc2..fee31e09f 100644
--- a/src/pkg/runtime/race.h
+++ b/src/pkg/runtime/race.h
@@ -17,13 +17,14 @@ void runtime·racefini(void);
void runtime·racemapshadow(void *addr, uintptr size);
void runtime·racemalloc(void *p, uintptr sz);
-void runtime·racefree(void *p);
uintptr runtime·racegostart(void *pc);
void runtime·racegoend(void);
void runtime·racewritepc(void *addr, void *callpc, void *pc);
void runtime·racereadpc(void *addr, void *callpc, void *pc);
void runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
void runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
+void runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
+void runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
void runtime·racefingo(void);
void runtime·raceacquire(void *addr);
void runtime·raceacquireg(G *gp, void *addr);
diff --git a/src/pkg/runtime/race/README b/src/pkg/runtime/race/README
index 0b73bd857..785640607 100644
--- a/src/pkg/runtime/race/README
+++ b/src/pkg/runtime/race/README
@@ -9,4 +9,4 @@ $ ./buildgo.sh
Tested with gcc 4.6.1 and 4.7.0. On Windows it's built with 64-bit MinGW.
-Current runtime is built on rev 191161.
+Current runtime is built on rev 203116.
diff --git a/src/pkg/runtime/race/race.go b/src/pkg/runtime/race/race.go
index 5b44bde83..e53cacf4a 100644
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -6,116 +6,10 @@
package race
-/*
-void __tsan_init(void **racectx);
-void __tsan_fini(void);
-void __tsan_map_shadow(void *addr, void *size);
-void __tsan_go_start(void *racectx, void **chracectx, void *pc);
-void __tsan_go_end(void *racectx);
-void __tsan_read(void *racectx, void *addr, void *pc);
-void __tsan_write(void *racectx, void *addr, void *pc);
-void __tsan_read_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_write_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_func_enter(void *racectx, void *pc);
-void __tsan_func_exit(void *racectx);
-void __tsan_malloc(void *racectx, void *p, long sz, void *pc);
-void __tsan_free(void *p);
-void __tsan_acquire(void *racectx, void *addr);
-void __tsan_release(void *racectx, void *addr);
-void __tsan_release_merge(void *racectx, void *addr);
-void __tsan_finalizer_goroutine(void *racectx);
-*/
-import "C"
-
-import (
- "runtime"
- "unsafe"
-)
-
-func Initialize(racectx *uintptr) {
- C.__tsan_init((*unsafe.Pointer)(unsafe.Pointer(racectx)))
-}
-
-func Finalize() {
- C.__tsan_fini()
-}
-
-func MapShadow(addr, size uintptr) {
- C.__tsan_map_shadow(unsafe.Pointer(addr), unsafe.Pointer(size))
-}
-
-func FinalizerGoroutine(racectx uintptr) {
- C.__tsan_finalizer_goroutine(unsafe.Pointer(racectx))
-}
-
-func Read(racectx uintptr, addr, pc uintptr) {
- C.__tsan_read(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func Write(racectx uintptr, addr, pc uintptr) {
- C.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func ReadRange(racectx uintptr, addr, sz, pc uintptr) {
- C.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
- C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
-
-func WriteRange(racectx uintptr, addr, sz, pc uintptr) {
- C.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
- C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
+// This file merely ensures that we link in runtime/cgo in race build,
+// this is turn ensures that runtime uses pthread_create to create threads.
+// The prebuilt race runtime lives in race_GOOS_GOARCH.syso.
+// Calls to the runtime are done directly from src/pkg/runtime/race.c.
-func FuncEnter(racectx uintptr, pc uintptr) {
- C.__tsan_func_enter(unsafe.Pointer(racectx), unsafe.Pointer(pc))
-}
-
-func FuncExit(racectx uintptr) {
- C.__tsan_func_exit(unsafe.Pointer(racectx))
-}
-
-func Malloc(racectx uintptr, p, sz, pc uintptr) {
- C.__tsan_malloc(unsafe.Pointer(racectx), unsafe.Pointer(p), C.long(sz), unsafe.Pointer(pc))
-}
-
-func Free(p uintptr) {
- C.__tsan_free(unsafe.Pointer(p))
-}
-
-func GoStart(racectx uintptr, chracectx *uintptr, pc uintptr) {
- C.__tsan_go_start(unsafe.Pointer(racectx), (*unsafe.Pointer)(unsafe.Pointer(chracectx)), unsafe.Pointer(pc))
-}
-
-func GoEnd(racectx uintptr) {
- C.__tsan_go_end(unsafe.Pointer(racectx))
-}
-
-func Acquire(racectx uintptr, addr uintptr) {
- C.__tsan_acquire(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func Release(racectx uintptr, addr uintptr) {
- C.__tsan_release(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func ReleaseMerge(racectx uintptr, addr uintptr) {
- C.__tsan_release_merge(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-//export __tsan_symbolize
-func __tsan_symbolize(pc uintptr, fun, file **C.char, line, off *C.int) C.int {
- f := runtime.FuncForPC(pc)
- if f == nil {
- *fun = C.CString("??")
- *file = C.CString("-")
- *line = 0
- *off = C.int(pc)
- return 1
- }
- fi, l := f.FileLine(pc)
- *fun = C.CString(f.Name())
- *file = C.CString(fi)
- *line = C.int(l)
- *off = C.int(pc - f.Entry())
- return 1
-}
+// void __race_unused_func(void);
+import "C"
diff --git a/src/pkg/runtime/race/race_darwin_amd64.syso b/src/pkg/runtime/race/race_darwin_amd64.syso
index 96a43c9a9..249a878ef 100644
--- a/src/pkg/runtime/race/race_darwin_amd64.syso
+++ b/src/pkg/runtime/race/race_darwin_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/race_linux_amd64.syso b/src/pkg/runtime/race/race_linux_amd64.syso
index 50bde9648..8120484d4 100644
--- a/src/pkg/runtime/race/race_linux_amd64.syso
+++ b/src/pkg/runtime/race/race_linux_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go
index 4776ae22d..7e0ee866a 100644
--- a/src/pkg/runtime/race/race_test.go
+++ b/src/pkg/runtime/race/race_test.go
@@ -44,7 +44,7 @@ func TestRace(t *testing.T) {
if err != nil {
t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
}
- reader := bufio.NewReader(bytes.NewBuffer(testOutput))
+ reader := bufio.NewReader(bytes.NewReader(testOutput))
funcName := ""
var tsanLog []string
@@ -155,3 +155,18 @@ func runTests() ([]byte, error) {
cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
return cmd.CombinedOutput()
}
+
+func TestIssue8102(t *testing.T) {
+ // If this compiles with -race, the test passes.
+ type S struct {
+ x interface{}
+ i int
+ }
+ c := make(chan int)
+ a := [2]*int{}
+ for ; ; c <- *a[S{}.i] {
+ if t != nil {
+ break
+ }
+ }
+}
diff --git a/src/pkg/runtime/race/race_windows_amd64.syso b/src/pkg/runtime/race/race_windows_amd64.syso
index 46eb1274f..67db40f21 100644
--- a/src/pkg/runtime/race/race_windows_amd64.syso
+++ b/src/pkg/runtime/race/race_windows_amd64.syso
Binary files differ
diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go
index 614ba4a4e..4a3d5290f 100644
--- a/src/pkg/runtime/race/testdata/chan_test.go
+++ b/src/pkg/runtime/race/testdata/chan_test.go
@@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) {
<-compl
}
+func TestRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c3 := make(chan int)
+ c2 <- 1
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestRaceSelectReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ c3 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 1
+ }()
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestNoRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ select {
+ case c1 <- x: // read of x does not race with...
+ case c2 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c1: // ... write to x here
+ case c2 <- 1:
+ }
+ <-done
+}
+
+func TestRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c2 <- 10
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestRaceChanReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int)
+ c2 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 10
+ }()
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestNoRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ x := 0
+ go func() {
+ c1 <- x // read of x does not race with...
+ done <- true
+ }()
+ x = <-c1 // ... write to x here
+ <-done
+}
+
func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
type Task struct {
f func()
@@ -454,20 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
v = 2
}
-func TestRaceChanSameCell(t *testing.T) {
- c := make(chan int, 1)
- v := 0
- go func() {
- v = 1
- c <- 42
- <-c
- }()
- time.Sleep(1e7)
- c <- 43
- <-c
- _ = v
-}
-
func TestRaceChanCloseSend(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int, 10)
@@ -478,3 +577,83 @@ func TestRaceChanCloseSend(t *testing.T) {
c <- 0
<-compl
}
+
+func TestNoRaceChanMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ data := 0
+ go func() {
+ mtx <- struct{}{}
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- struct{}{}
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceSelectMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ aux := make(chan bool)
+ data := 0
+ go func() {
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 42
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ done <- struct{}{}
+ }()
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 43
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ <-done
+}
+
+func TestRaceChanSem(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan bool, 2)
+ data := 0
+ go func() {
+ mtx <- true
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- true
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceChanWaitGroup(t *testing.T) {
+ const N = 10
+ chanWg := make(chan bool, N/2)
+ data := make([]int, N)
+ for i := 0; i < N; i++ {
+ chanWg <- true
+ go func(i int) {
+ data[i] = 42
+ <-chanWg
+ }(i)
+ }
+ for i := 0; i < cap(chanWg); i++ {
+ chanWg <- true
+ }
+ for i := 0; i < N; i++ {
+ _ = data[i]
+ }
+}
diff --git a/src/pkg/runtime/race/testdata/finalizer_test.go b/src/pkg/runtime/race/testdata/finalizer_test.go
index 2b2607689..222cbf67a 100644
--- a/src/pkg/runtime/race/testdata/finalizer_test.go
+++ b/src/pkg/runtime/race/testdata/finalizer_test.go
@@ -14,16 +14,16 @@ import (
func TestNoRaceFin(t *testing.T) {
c := make(chan bool)
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
- *x = 42
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
+ *x = "foo"
})
- *x = 66
+ *x = "bar"
c <- true
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
}
var finVar struct {
@@ -34,8 +34,8 @@ var finVar struct {
func TestNoRaceFinGlobal(t *testing.T) {
c := make(chan bool)
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
finVar.Lock()
finVar.cnt++
finVar.Unlock()
@@ -44,7 +44,7 @@ func TestNoRaceFinGlobal(t *testing.T) {
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
finVar.Lock()
finVar.cnt++
finVar.Unlock()
@@ -54,14 +54,14 @@ func TestRaceFin(t *testing.T) {
c := make(chan bool)
y := 0
go func() {
- x := new(int)
- runtime.SetFinalizer(x, func(x *int) {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
y = 42
})
c <- true
}()
<-c
runtime.GC()
- time.Sleep(1e8)
+ time.Sleep(100 * time.Millisecond)
y = 66
}
diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go
index 35db8db69..98e2a5f10 100644
--- a/src/pkg/runtime/race/testdata/map_test.go
+++ b/src/pkg/runtime/race/testdata/map_test.go
@@ -159,3 +159,82 @@ func TestRaceMapVariable3(t *testing.T) {
m = make(map[int]int)
<-ch
}
+
+type Big struct {
+ x [17]int32
+}
+
+func TestRaceMapLookupPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _ = m[*k]
+ <-ch
+}
+
+func TestRaceMapLookupPartKey2(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _, _ = m[*k]
+ <-ch
+}
+func TestRaceMapDeletePartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ delete(m, *k)
+ <-ch
+}
+
+func TestRaceMapInsertPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ m[*k] = true
+ <-ch
+}
+
+func TestRaceMapInsertPartVal(t *testing.T) {
+ v := &Big{}
+ m := make(map[int]Big)
+ ch := make(chan bool, 1)
+ go func() {
+ v.x[8] = 1
+ ch <- true
+ }()
+ m[1] = *v
+ <-ch
+}
+
+// Test for issue 7561.
+func TestRaceMapAssignMultipleReturn(t *testing.T) {
+ connect := func() (int, error) { return 42, nil }
+ conns := make(map[int][]int)
+ conns[1] = []int{0}
+ ch := make(chan bool, 1)
+ var err error
+ go func() {
+ conns[1][0], err = connect()
+ ch <- true
+ }()
+ x := conns[1][0]
+ _ = x
+ <-ch
+}
diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go
index b0b66562c..14591b184 100644
--- a/src/pkg/runtime/race/testdata/mop_test.go
+++ b/src/pkg/runtime/race/testdata/mop_test.go
@@ -1933,3 +1933,25 @@ func TestRaceMethodThunk4(t *testing.T) {
*(*int)(d.Base) = 42
<-done
}
+
+func TestNoRaceTinyAlloc(t *testing.T) {
+ const P = 4
+ const N = 1e6
+ var tinySink *byte
+ done := make(chan bool)
+ for p := 0; p < P; p++ {
+ go func() {
+ for i := 0; i < N; i++ {
+ var b byte
+ if b != 0 {
+ tinySink = &b // make it heap allocated
+ }
+ b = 42
+ }
+ done <- true
+ }()
+ }
+ for p := 0; p < P; p++ {
+ <-done
+ }
+}
diff --git a/src/pkg/runtime/race0.c b/src/pkg/runtime/race0.c
index b74b03583..eddb0be79 100644
--- a/src/pkg/runtime/race0.c
+++ b/src/pkg/runtime/race0.c
@@ -111,12 +111,6 @@ runtime·racemalloc(void *p, uintptr sz)
USED(sz);
}
-void
-runtime·racefree(void *p)
-{
- USED(p);
-}
-
uintptr
runtime·racegostart(void *pc)
{
diff --git a/src/pkg/runtime/race_amd64.s b/src/pkg/runtime/race_amd64.s
index a33b77a50..d60cf899b 100644
--- a/src/pkg/runtime/race_amd64.s
+++ b/src/pkg/runtime/race_amd64.s
@@ -4,13 +4,241 @@
// +build race
+#include "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
#include "../../cmd/ld/textflag.h"
+// The following thunks allow calling the gcc-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the amd64 calling convention.
+// Arguments are passed in DI, SI, DX, CX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, R12-R15.
+// SP must be 16-byte aligned.
+// On Windows:
+// Arguments are passed in CX, DX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, DI, SI, R12-R15.
+// SP must be 16-byte aligned. Windows also requires "stack-backing" for the 4 register arguments:
+// http://msdn.microsoft.com/en-us/library/ms235286.aspx
+// We do not do this, because it seems to be intended for vararg/unprototyped functions.
+// Gcc-compiled race runtime does not try to use that space.
+
+#ifdef GOOS_windows
+#define RARG0 CX
+#define RARG1 DX
+#define RARG2 R8
+#define RARG3 R9
+#else
+#define RARG0 DI
+#define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
+#endif
+
+// func runtime·raceread(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·raceread(SB), NOSPLIT, $0-8
+ MOVQ addr+0(FP), RARG1
+ MOVQ (SP), RARG2
+ // void __tsan_read(ThreadState *thr, void *addr, void *pc);
+ MOVQ $__tsan_read(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceRead(addr uintptr)
+TEXT runtime·RaceRead(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because raceread reads caller pc.
+ JMP runtime·raceread(SB)
+
+// void runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ callpc+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVQ $__tsan_read_pc(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewrite(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·racewrite(SB), NOSPLIT, $0-8
+ MOVQ addr+0(FP), RARG1
+ MOVQ (SP), RARG2
+ // void __tsan_write(ThreadState *thr, void *addr, void *pc);
+ MOVQ $__tsan_write(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because racewrite reads caller pc.
+ JMP runtime·racewrite(SB)
+
+// void runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ callpc+8(FP), RARG2
+ MOVQ cp+16(FP), RARG3
+ // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVQ $__tsan_write_pc(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racereadrange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ (SP), RARG3
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_read_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racereadrange reads caller pc.
+ JMP runtime·racereadrange(SB)
+
+// void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_read_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewriterange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ (SP), RARG3
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_write_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racewriterange reads caller pc.
+ JMP runtime·racewriterange(SB)
+
+// void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+ MOVQ addr+0(FP), RARG1
+ MOVQ size+8(FP), RARG2
+ MOVQ pc+16(FP), RARG3
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVQ $__tsan_write_range(SB), AX
+ JMP racecalladdr<>(SB)
+
+// If addr (RARG1) is out of range, do nothing.
+// Otherwise, setup goroutine context and invoke racecall. Other arguments already set.
+TEXT racecalladdr<>(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss).
+ CMPQ RARG1, runtime·racearenastart(SB)
+ JB racecalladdr_data
+ CMPQ RARG1, runtime·racearenaend(SB)
+ JB racecalladdr_call
+racecalladdr_data:
+ CMPQ RARG1, $noptrdata(SB)
+ JB racecalladdr_ret
+ CMPQ RARG1, $enoptrbss(SB)
+ JAE racecalladdr_ret
+racecalladdr_call:
+ MOVQ AX, AX // w/o this 6a miscompiles this function
+ JMP racecall<>(SB)
+racecalladdr_ret:
+ RET
+
// func runtime·racefuncenter(pc uintptr)
-TEXT runtime·racefuncenter(SB), NOSPLIT, $16-8
- MOVQ DX, saved-8(SP) // save function entry context (for closures)
- MOVQ pc+0(FP), DX
- MOVQ DX, arg-16(SP)
- CALL runtime·racefuncenter1(SB)
- MOVQ saved-8(SP), DX
+// Called from instrumented code.
+TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVQ DX, R15 // save function entry context (for closures)
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ MOVQ callpc+0(FP), RARG1
+ // void __tsan_func_enter(ThreadState *thr, void *pc);
+ MOVQ $__tsan_func_enter(SB), AX
+ CALL racecall<>(SB)
+ MOVQ R15, DX // restore function entry context
+ RET
+
+// func runtime·racefuncexit()
+// Called from instrumented code.
+TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ // void __tsan_func_exit(ThreadState *thr);
+ MOVQ $__tsan_func_exit(SB), AX
+ JMP racecall<>(SB)
+
+// void runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there are no arguments.
+TEXT runtime·racecall(SB), NOSPLIT, $0-0
+ MOVQ fn+0(FP), AX
+ MOVQ arg0+8(FP), RARG0
+ MOVQ arg1+16(FP), RARG1
+ MOVQ arg2+24(FP), RARG2
+ MOVQ arg3+32(FP), RARG3
+ JMP racecall<>(SB)
+
+// Switches SP to g0 stack and calls (AX). Arguments already set.
+TEXT racecall<>(SB), NOSPLIT, $0-0
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ g(R12), R14
+ // Switch to g0 stack.
+ MOVQ SP, R12 // callee-saved, preserved across the CALL
+ MOVQ m_g0(R13), R10
+ CMPQ R10, R14
+ JE racecall_cont // already on g0
+ MOVQ (g_sched+gobuf_sp)(R10), SP
+racecall_cont:
+ ANDQ $~15, SP // alignment for gcc ABI
+ CALL AX
+ MOVQ R12, SP
+ RET
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C code.
+// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
+// The overall effect of Go->C->Go call chain is similar to that of mcall.
+TEXT runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
+ // Save callee-saved registers (Go code won't respect that).
+ // This is superset of darwin/linux/windows registers.
+ PUSHQ BX
+ PUSHQ BP
+ PUSHQ DI
+ PUSHQ SI
+ PUSHQ R12
+ PUSHQ R13
+ PUSHQ R14
+ PUSHQ R15
+ // Set g = g0.
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ m_g0(R13), R14
+ MOVQ R14, g(R12) // g = m->g0
+ MOVQ RARG0, 0(SP) // func arg
+ CALL runtime·racesymbolize(SB)
+ // All registers are smashed after Go code, reload.
+ get_tls(R12)
+ MOVQ m(R12), R13
+ MOVQ m_curg(R13), R14
+ MOVQ R14, g(R12) // g = m->curg
+ // Restore callee-saved registers.
+ POPQ R15
+ POPQ R14
+ POPQ R13
+ POPQ R12
+ POPQ SI
+ POPQ DI
+ POPQ BP
+ POPQ BX
RET
diff --git a/src/pkg/runtime/rdebug.goc b/src/pkg/runtime/rdebug.goc
new file mode 100644
index 000000000..042b30ace
--- /dev/null
+++ b/src/pkg/runtime/rdebug.goc
@@ -0,0 +1,27 @@
+// 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 runtime∕debug
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "stack.h"
+
+func setMaxStack(in int) (out int) {
+ out = runtime·maxstacksize;
+ runtime·maxstacksize = in;
+}
+
+func setGCPercent(in int) (out int) {
+ out = runtime·setgcpercent(in);
+}
+
+func setMaxThreads(in int) (out int) {
+ out = runtime·setmaxthreads(in);
+}
+
+func SetPanicOnFault(enabled bool) (old bool) {
+ old = g->paniconfault;
+ g->paniconfault = enabled;
+}
diff --git a/src/pkg/runtime/rt0_freebsd_arm.s b/src/pkg/runtime/rt0_freebsd_arm.s
index d11087639..56219f899 100644
--- a/src/pkg/runtime/rt0_freebsd_arm.s
+++ b/src/pkg/runtime/rt0_freebsd_arm.s
@@ -11,3 +11,8 @@ TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
B _rt0_go(SB)
+
+TEXT main(SB),NOSPLIT,$-4
+ MOVM.DB.W [R0-R1], (R13)
+ MOVW $_rt0_go(SB), R4
+ B (R4)
diff --git a/src/pkg/runtime/rt0_nacl_386.s b/src/pkg/runtime/rt0_nacl_386.s
new file mode 100644
index 000000000..8b713548f
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_386.s
@@ -0,0 +1,22 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// NaCl entry has:
+// 0(FP) - arg block == SP+8
+// 4(FP) - cleanup function pointer, always 0
+// 8(FP) - envc
+// 12(FP) - argc
+// 16(FP) - argv, then 0, then envv, then 0, then auxv
+TEXT _rt0_386_nacl(SB),NOSPLIT,$8
+ MOVL argc+12(FP), AX
+ LEAL argv+16(FP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),NOSPLIT,$0
+ JMP _rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_nacl_amd64p32.s b/src/pkg/runtime/rt0_nacl_amd64p32.s
new file mode 100644
index 000000000..502d2e2bf
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_amd64p32.s
@@ -0,0 +1,30 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// NaCl entry on 32-bit x86 has DI pointing at the arg block, which contains:
+//
+// 0(DI) - cleanup function pointer, always 0
+// 4(DI) - envc
+// 8(DI) - argc
+// 12(DI) - argv, then 0, then envv, then 0, then auxv
+// NaCl entry here is almost the same, except that there
+// is no saved caller PC, so 0(FP) is -8(FP) and so on.
+TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
+ MOVL DI, 0(SP)
+ CALL runtime·nacl_sysinfo(SB)
+ MOVL 0(SP), DI
+ MOVL 8(DI), AX
+ LEAL 12(DI), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),NOSPLIT,$0
+ // Uncomment for fake time like on Go Playground.
+ //MOVQ $1257894000000000000, AX
+ //MOVQ AX, runtime·timens(SB)
+ JMP _rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_solaris_amd64.s b/src/pkg/runtime/rt0_solaris_amd64.s
new file mode 100644
index 000000000..4aca991f0
--- /dev/null
+++ b/src/pkg/runtime/rt0_solaris_amd64.s
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_amd64_solaris(SB),NOSPLIT,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),NOSPLIT,$-8
+ MOVQ $_rt0_go(SB), AX
+ JMP AX
+
+DATA runtime·issolaris(SB)/4, $1
+GLOBL runtime·issolaris(SB), $4
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index e704f4c4b..eedac7cf4 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -15,10 +15,14 @@ path to this file based on the path to the runtime package.
# circumventing the pretty print triggering.
-import sys, re
-
-print >>sys.stderr, "Loading Go Runtime support."
-
+from __future__ import print_function
+import re
+import sys
+
+print("Loading Go Runtime support.", file=sys.stderr)
+#http://python3porting.com/differences.html
+if sys.version > '3':
+ xrange = range
# allow to manually reload while developing
goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
goobjfile.pretty_printers = []
@@ -27,6 +31,7 @@ goobjfile.pretty_printers = []
# Pretty Printers
#
+
class StringTypePrinter:
"Pretty print Go strings."
@@ -61,8 +66,8 @@ class SliceTypePrinter:
if self.val["len"] > self.val["cap"]:
return
ptr = self.val["array"]
- for idx in range(self.val["len"]):
- yield ('[%d]' % idx, (ptr + idx).dereference())
+ for idx in range(int(self.val["len"])):
+ yield ('[{0}]'.format(idx), (ptr + idx).dereference())
class MapTypePrinter:
@@ -72,7 +77,7 @@ class MapTypePrinter:
to inspect their contents with this pretty printer.
"""
- pattern = re.compile(r'^struct hash<.*>$')
+ pattern = re.compile(r'^map\[.*\].*$')
def __init__(self, val):
self.val = val
@@ -90,14 +95,15 @@ class MapTypePrinter:
flags = self.val['flags']
inttype = self.val['hash0'].type
cnt = 0
- for bucket in xrange(2 ** B):
+ for bucket in xrange(2 ** int(B)):
bp = buckets + bucket
if oldbuckets:
oldbucket = bucket & (2 ** (B - 1) - 1)
oldbp = oldbuckets + oldbucket
oldb = oldbp.dereference()
- if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
- if bucket >= 2 ** (B - 1): continue # already did old bucket
+ if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
+ if bucket >= 2 ** (B - 1):
+ continue # already did old bucket
bp = oldbp
while bp:
b = bp.dereference()
@@ -109,11 +115,12 @@ class MapTypePrinter:
k = k.dereference()
if flags & 2:
v = v.dereference()
- yield '%d' % cnt, k
- yield '%d' % (cnt + 1), v
+ yield str(cnt), k
+ yield str(cnt + 1), v
cnt += 2
bp = b['overflow']
+
class ChanTypePrinter:
"""Pretty print chan[T] types.
@@ -138,7 +145,7 @@ class ChanTypePrinter:
ptr = (self.val.address + 1).cast(et.pointer())
for i in range(self.val["qcount"]):
j = (self.val["recvx"] + i) % self.val["dataqsiz"]
- yield ('[%d]' % i, (ptr + j).dereference())
+ yield ('[{0}]'.format(i), (ptr + j).dereference())
#
@@ -150,11 +157,11 @@ def makematcher(klass):
try:
if klass.pattern.match(str(val.type)):
return klass(val)
- except:
+ except Exception:
pass
return matcher
-goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
+goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
#
# For reference, this is what we're trying to do:
@@ -169,34 +176,35 @@ goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if has
def is_iface(val):
try:
- return str(val['tab'].type) == "struct runtime.itab *" \
- and str(val['data'].type) == "void *"
- except:
+ return str(val['tab'].type) == "struct runtime.itab *" and str(val['data'].type) == "void *"
+ except gdb.error:
pass
+
def is_eface(val):
try:
- return str(val['_type'].type) == "struct runtime._type *" \
- and str(val['data'].type) == "void *"
- except:
+ return str(val['_type'].type) == "struct runtime._type *" and str(val['data'].type) == "void *"
+ except gdb.error:
pass
+
def lookup_type(name):
try:
return gdb.lookup_type(name)
- except:
+ except gdb.error:
pass
try:
return gdb.lookup_type('struct ' + name)
- except:
+ except gdb.error:
pass
try:
return gdb.lookup_type('struct ' + name[1:]).pointer()
- except:
+ except gdb.error:
pass
_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
+
def iface_commontype(obj):
if is_iface(obj):
go_type_ptr = obj['tab']['_type']
@@ -204,9 +212,9 @@ def iface_commontype(obj):
go_type_ptr = obj['_type']
else:
return
-
+
return go_type_ptr.cast(_rctp_type).dereference()
-
+
def iface_dtype(obj):
"Decode type of the data field of an eface or iface struct."
@@ -221,7 +229,7 @@ def iface_dtype(obj):
dynamic_gdb_type = lookup_type(dtype_name)
if dynamic_gdb_type is None:
return
-
+
type_size = int(dynamic_go_type['size'])
uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
if type_size > uintptr_size:
@@ -229,6 +237,7 @@ def iface_dtype(obj):
return dynamic_gdb_type
+
def iface_dtype_name(obj):
"Decode type name of the data field of an eface or iface struct."
@@ -254,15 +263,15 @@ class IfacePrinter:
return 0x0
try:
dtype = iface_dtype(self.val)
- except:
+ except Exception:
return "<bad dynamic type>"
if dtype is None: # trouble looking up, print something reasonable
- return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
+ return "({0}){0}".format(iface_dtype_name(self.val), self.val['data'])
try:
return self.val['data'].cast(dtype).dereference()
- except:
+ except Exception:
pass
return self.val['data'].cast(dtype)
@@ -277,16 +286,14 @@ goobjfile.pretty_printers.append(ifacematcher)
# Convenience Functions
#
+
class GoLenFunc(gdb.Function):
"Length of strings, slices, maps or channels"
- how = ((StringTypePrinter, 'len'),
- (SliceTypePrinter, 'len'),
- (MapTypePrinter, 'count'),
- (ChanTypePrinter, 'qcount'))
+ how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount'))
def __init__(self):
- super(GoLenFunc, self).__init__("len")
+ gdb.Function.__init__(self, "len")
def invoke(self, obj):
typename = str(obj.type)
@@ -294,14 +301,14 @@ class GoLenFunc(gdb.Function):
if klass.pattern.match(typename):
return obj[fld]
+
class GoCapFunc(gdb.Function):
"Capacity of slices or channels"
- how = ((SliceTypePrinter, 'cap'),
- (ChanTypePrinter, 'dataqsiz'))
+ how = ((SliceTypePrinter, 'cap'), (ChanTypePrinter, 'dataqsiz'))
def __init__(self):
- super(GoCapFunc, self).__init__("cap")
+ gdb.Function.__init__(self, "cap")
def invoke(self, obj):
typename = str(obj.type)
@@ -309,6 +316,7 @@ class GoCapFunc(gdb.Function):
if klass.pattern.match(typename):
return obj[fld]
+
class DTypeFunc(gdb.Function):
"""Cast Interface values to their dynamic type.
@@ -316,12 +324,12 @@ class DTypeFunc(gdb.Function):
"""
def __init__(self):
- super(DTypeFunc, self).__init__("dtype")
+ gdb.Function.__init__(self, "dtype")
def invoke(self, obj):
try:
return obj['data'].cast(iface_dtype(obj))
- except:
+ except gdb.error:
pass
return obj
@@ -331,6 +339,7 @@ class DTypeFunc(gdb.Function):
sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+
def linked_list(ptr, linkfield):
while ptr:
yield ptr
@@ -341,29 +350,47 @@ class GoroutinesCmd(gdb.Command):
"List all goroutines."
def __init__(self):
- super(GoroutinesCmd, self).__init__("info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+ gdb.Command.__init__(self, "info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
- def invoke(self, arg, from_tty):
+ def invoke(self, _arg, _from_tty):
# args = gdb.string_to_argv(arg)
vp = gdb.lookup_type('void').pointer()
for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ if ptr['status'] == 6: # 'gdead'
continue
s = ' '
if ptr['m']:
s = '*'
pc = ptr['sched']['pc'].cast(vp)
- sp = ptr['sched']['sp'].cast(vp)
- blk = gdb.block_for_pc(long((pc)))
- print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
+ # python2 will not cast pc (type void*) to an int cleanly
+ # instead python2 and python3 work with the hex string representation
+ # of the void pointer which we can parse back into an int.
+ # int(pc) will not work.
+ try:
+ #python3 / newer versions of gdb
+ pc = int(pc)
+ except gdb.error:
+ pc = int(str(pc), 16)
+ blk = gdb.block_for_pc(pc)
+ print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
+
def find_goroutine(goid):
+ """
+ find_goroutine attempts to find the goroutine identified by goid.
+ It returns a touple of gdv.Value's representing the stack pointer
+ and program counter pointer for the goroutine.
+
+ @param int goid
+
+ @return tuple (gdb.Value, gdb.Value)
+ """
vp = gdb.lookup_type('void').pointer()
for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ if ptr['status'] == 6: # 'gdead'
continue
if ptr['goid'] == goid:
- return [ptr['sched'][x].cast(vp) for x in 'pc', 'sp']
+ return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
return None, None
@@ -380,20 +407,25 @@ class GoroutineCmd(gdb.Command):
"""
def __init__(self):
- super(GoroutineCmd, self).__init__("goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+ gdb.Command.__init__(self, "goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
- def invoke(self, arg, from_tty):
+ def invoke(self, arg, _from_tty):
goid, cmd = arg.split(None, 1)
goid = gdb.parse_and_eval(goid)
pc, sp = find_goroutine(int(goid))
if not pc:
- print "No such goroutine: ", goid
+ print("No such goroutine: ", goid)
return
+ try:
+ #python3 / newer versions of gdb
+ pc = int(pc)
+ except gdb.error:
+ pc = int(str(pc), 16)
save_frame = gdb.selected_frame()
gdb.parse_and_eval('$save_pc = $pc')
gdb.parse_and_eval('$save_sp = $sp')
- gdb.parse_and_eval('$pc = 0x%x' % long(pc))
- gdb.parse_and_eval('$sp = 0x%x' % long(sp))
+ gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
+ gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
try:
gdb.execute(cmd)
finally:
@@ -406,31 +438,33 @@ class GoIfaceCmd(gdb.Command):
"Print Static and dynamic interface types"
def __init__(self):
- super(GoIfaceCmd, self).__init__("iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+ gdb.Command.__init__(self, "iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
- def invoke(self, arg, from_tty):
+ def invoke(self, arg, _from_tty):
for obj in gdb.string_to_argv(arg):
try:
#TODO fix quoting for qualified variable names
- obj = gdb.parse_and_eval("%s" % obj)
- except Exception, e:
- print "Can't parse ", obj, ": ", e
+ obj = gdb.parse_and_eval(str(obj))
+ except Exception as e:
+ print("Can't parse ", obj, ": ", e)
continue
if obj['data'] == 0:
dtype = "nil"
else:
dtype = iface_dtype(obj)
-
+
if dtype is None:
- print "Not an interface: ", obj.type
+ print("Not an interface: ", obj.type)
continue
- print "%s: %s" % (obj.type, dtype)
+ print("{0}: {1}".format(obj.type, dtype))
# TODO: print interface's methods and dynamic type's func pointers thereof.
-#rsc: "to find the number of entries in the itab's Fn field look at itab.inter->numMethods
-#i am sure i have the names wrong but look at the interface type and its method count"
+#rsc: "to find the number of entries in the itab's Fn field look at
+# itab.inter->numMethods
+# i am sure i have the names wrong but look at the interface type
+# and its method count"
# so Itype will start with a commontype which has kind = interface
#
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index ab9fed805..3a4f7199e 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "stack.h"
#include "arch_GOARCH.h"
#include "../../cmd/ld/textflag.h"
@@ -10,13 +11,12 @@ enum {
maxround = sizeof(uintptr),
};
-/*
- * We assume that all architectures turn faults and the like
- * into apparent calls to runtime.sigpanic. If we see a "call"
- * to runtime.sigpanic, we do not back up the PC to find the
- * line number of the CALL instruction, because there is no CALL.
- */
-void runtime·sigpanic(void);
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bit
+// is the "crash" setting and the top 31 bits are the
+// gotraceback value.
+static uint32 traceback_cache = ~(uint32)0;
// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
@@ -28,18 +28,28 @@ int32
runtime·gotraceback(bool *crash)
{
byte *p;
+ uint32 x;
if(crash != nil)
*crash = false;
- p = runtime·getenv("GOTRACEBACK");
- if(p == nil || p[0] == '\0')
- return 1; // default is on
- if(runtime·strcmp(p, (byte*)"crash") == 0) {
- if(crash != nil)
- *crash = true;
- return 2; // extra information
+ if(m->traceback != 0)
+ return m->traceback;
+ x = runtime·atomicload(&traceback_cache);
+ if(x == ~(uint32)0) {
+ p = runtime·getenv("GOTRACEBACK");
+ if(p == nil)
+ p = (byte*)"";
+ if(p[0] == '\0')
+ x = 1<<1;
+ else if(runtime·strcmp(p, (byte*)"crash") == 0)
+ x = (2<<1) | 1;
+ else
+ x = runtime·atoi(p)<<1;
+ runtime·atomicstore(&traceback_cache, x);
}
- return runtime·atoi(p);
+ if(crash != nil)
+ *crash = x&1;
+ return x>>1;
}
int32
@@ -87,6 +97,7 @@ runtime·args(int32 c, uint8 **v)
}
int32 runtime·isplan9;
+int32 runtime·issolaris;
int32 runtime·iswindows;
// Information about what cpu features are available.
@@ -127,16 +138,8 @@ runtime·goenvs_unix(void)
syscall·envs.array = (byte*)s;
syscall·envs.len = n;
syscall·envs.cap = n;
-}
-void
-runtime·getgoroot(String out)
-{
- byte *p;
-
- p = runtime·getenv("GOROOT");
- out = runtime·gostringnocopy(p);
- FLUSH(&out);
+ traceback_cache = ~(uint32)0;
}
int32
@@ -273,62 +276,9 @@ runtime·check(void)
runtime·throw("float32nan3");
TestAtomic64();
-}
-
-void
-runtime·Caller(intgo skip, uintptr retpc, String retfile, intgo retline, bool retbool)
-{
- Func *f, *g;
- uintptr pc;
- uintptr rpc[2];
-
- /*
- * Ask for two PCs: the one we were asked for
- * and what it called, so that we can see if it
- * "called" sigpanic.
- */
- retpc = 0;
- if(runtime·callers(1+skip-1, rpc, 2) < 2) {
- retfile = runtime·emptystring;
- retline = 0;
- retbool = false;
- } else if((f = runtime·findfunc(rpc[1])) == nil) {
- retfile = runtime·emptystring;
- retline = 0;
- retbool = true; // have retpc at least
- } else {
- retpc = rpc[1];
- pc = retpc;
- g = runtime·findfunc(rpc[0]);
- if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
- pc--;
- retline = runtime·funcline(f, pc, &retfile);
- retbool = true;
- }
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
-}
-void
-runtime·Callers(intgo skip, Slice pc, intgo retn)
-{
- // runtime.callers uses pc.array==nil as a signal
- // to print a stack trace. Pick off 0-length pc here
- // so that we don't let a nil pc slice get to it.
- if(pc.len == 0)
- retn = 0;
- else
- retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
- FLUSH(&retn);
-}
-
-void
-runtime·FuncForPC(uintptr pc, void *retf)
-{
- retf = runtime·findfunc(pc);
- FLUSH(&retf);
+ if(FixedStack != runtime·round2(FixedStack))
+ runtime·throw("FixedStack is not power-of-2");
}
uint32
@@ -374,22 +324,18 @@ runtime·tickspersecond(void)
return res;
}
-void
-runtime∕pprof·runtime_cyclesPerSecond(int64 res)
-{
- res = runtime·tickspersecond();
- FLUSH(&res);
-}
-
DebugVars runtime·debug;
static struct {
int8* name;
int32* value;
} dbgvar[] = {
+ {"allocfreetrace", &runtime·debug.allocfreetrace},
+ {"efence", &runtime·debug.efence},
{"gctrace", &runtime·debug.gctrace},
- {"schedtrace", &runtime·debug.schedtrace},
+ {"gcdead", &runtime·debug.gcdead},
{"scheddetail", &runtime·debug.scheddetail},
+ {"schedtrace", &runtime·debug.schedtrace},
};
void
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index f7c2adb12..511550378 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -28,6 +28,12 @@ typedef int32 intgo; // Go's int
typedef uint32 uintgo; // Go's uint
#endif
+#ifdef _64BITREG
+typedef uint64 uintreg;
+#else
+typedef uint32 uintreg;
+#endif
+
/*
* get rid of C types
* the / / / forces a syntax error immediately,
@@ -66,17 +72,17 @@ typedef struct Itab Itab;
typedef struct InterfaceType InterfaceType;
typedef struct Eface Eface;
typedef struct Type Type;
+typedef struct PtrType PtrType;
typedef struct ChanType ChanType;
typedef struct MapType MapType;
typedef struct Defer Defer;
-typedef struct DeferChunk DeferChunk;
typedef struct Panic Panic;
typedef struct Hmap Hmap;
+typedef struct Hiter Hiter;
typedef struct Hchan Hchan;
typedef struct Complex64 Complex64;
typedef struct Complex128 Complex128;
-typedef struct WinCall WinCall;
-typedef struct SEH SEH;
+typedef struct LibCall LibCall;
typedef struct WinCallbackContext WinCallbackContext;
typedef struct Timers Timers;
typedef struct Timer Timer;
@@ -93,10 +99,10 @@ typedef struct DebugVars DebugVars;
*
* "extern register" is a special storage class implemented by 6c, 8c, etc.
* On the ARM, it is an actual register; elsewhere it is a slot in thread-
- * local storage indexed by a segment register. See zasmhdr in
+ * local storage indexed by a pseudo-register TLS. See zasmhdr in
* src/cmd/dist/buildruntime.c for details, and be aware that the linker may
* make further OS-specific changes to the compiler's output. For example,
- * 6l/linux rewrites 0(GS) as -16(FS).
+ * 6l/linux rewrites 0(TLS) as -16(FS).
*
* Every C file linked into a Go program must include runtime.h so that the
* C compiler (6c, 8c, etc.) knows to avoid other uses of these dedicated
@@ -208,8 +214,8 @@ struct Gobuf
uintptr sp;
uintptr pc;
G* g;
- uintptr ret;
void* ctxt;
+ uintreg ret;
uintptr lr;
};
struct GCStats
@@ -223,7 +229,7 @@ struct GCStats
uint64 nsleep;
};
-struct WinCall
+struct LibCall
{
void (*fn)(void*);
uintptr n; // number of parameters
@@ -232,17 +238,14 @@ struct WinCall
uintptr r2;
uintptr err; // error number
};
-struct SEH
-{
- void* prev;
- void* handler;
-};
+
// describes how to handle callback
struct WinCallbackContext
{
void* gobody; // Go function to call
uintptr argsize; // callback arguments size (in bytes)
uintptr restorestack; // adjust stack on return by (in bytes) (386 only)
+ bool cleanstack;
};
struct G
@@ -251,7 +254,6 @@ struct G
uintptr stackguard0; // cannot move - also known to linker, libmach, runtime/cgo
uintptr stackbase; // cannot move - also known to libmach, runtime/cgo
uint32 panicwrap; // cannot move - also known to linker
- uint32 selgen; // valid sudog pointer
Defer* defer;
Panic* panic;
Gobuf sched;
@@ -262,24 +264,23 @@ struct G
uintptr stackguard; // same as stackguard0, but not set to StackPreempt
uintptr stack0;
uintptr stacksize;
- G* alllink; // on allg
void* param; // passed parameter on wakeup
int16 status;
int64 goid;
+ int64 waitsince; // approx time when the G become blocked
int8* waitreason; // if status==Gwaiting
G* schedlink;
bool ispanic;
bool issystem; // do not output in stack dump
bool isbackground; // ignore in deadlock detector
bool preempt; // preemption signal, duplicates stackguard0 = StackPreempt
+ bool paniconfault; // panic (instead of crash) on unexpected fault address
int8 raceignore; // ignore race detection events
M* m; // for debuggers, but offset not hard-coded
M* lockedm;
int32 sig;
int32 writenbuf;
byte* writebuf;
- DeferChunk* dchunk;
- DeferChunk* dchunknext;
uintptr sigcode0;
uintptr sigcode1;
uintptr sigpc;
@@ -287,6 +288,7 @@ struct G
uintptr racectx;
uintptr end[];
};
+
struct M
{
G* g0; // goroutine with scheduling stack
@@ -295,8 +297,8 @@ struct M
// Fields not known to debuggers.
uint32 moreframesize; // size arguments to morestack
- uint32 moreargsize;
- uintptr cret; // return value from C
+ uint32 moreargsize; // known by amd64 asm to follow moreframesize
+ uintreg cret; // return value from C
uint64 procid; // for debuggers, but offset not hard-coded
G* gsignal; // signal-handling G
uintptr tls[4]; // thread-local storage (for x86 extern register)
@@ -310,10 +312,12 @@ struct M
int32 throwing;
int32 gcing;
int32 locks;
+ int32 softfloat;
int32 dying;
int32 profilehz;
int32 helpgc;
- bool spinning;
+ bool spinning; // M is out of work and is actively looking for work
+ bool blocked; // M is blocked on a Note
uint32 fastrand;
uint64 ncgocall; // number of cgo calls in total
int32 ncgo; // number of cgo calls currently in progress
@@ -338,23 +342,37 @@ struct M
uint32 waitsemacount;
uint32 waitsemalock;
GCStats gcstats;
- bool racecall;
bool needextram;
- void (*waitunlockf)(Lock*);
+ uint8 traceback;
+ bool (*waitunlockf)(G*, void*);
void* waitlock;
-
- uintptr settype_buf[1024];
- uintptr settype_bufsize;
-
+ uintptr forkstackguard;
#ifdef GOOS_windows
void* thread; // thread handle
- WinCall wincall;
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ LibCall libcall;
+ uintptr libcallpc; // for cpu profiler
+ uintptr libcallsp;
+ G* libcallg;
+#endif
+#ifdef GOOS_solaris
+ int32* perrno; // pointer to TLS errno
+ // these are here because they are too large to be on the stack
+ // of low-level NOSPLIT functions.
+ LibCall libcall;
+ struct {
+ int64 tv_sec;
+ int64 tv_nsec;
+ } ts;
+ struct {
+ uintptr v[6];
+ } scratch;
#endif
#ifdef GOOS_plan9
int8* notesig;
byte* errstr;
#endif
- SEH* seh;
uintptr end[];
};
@@ -369,12 +387,16 @@ struct P
uint32 syscalltick; // incremented on every system call
M* m; // back-link to associated M (nil if idle)
MCache* mcache;
+ Defer* deferpool[5]; // pool of available Defer structs of different sizes (see panic.c)
+
+ // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
+ uint64 goidcache;
+ uint64 goidcacheend;
// Queue of runnable goroutines.
- G** runq;
- int32 runqhead;
- int32 runqtail;
- int32 runqsize;
+ uint32 runqhead;
+ uint32 runqtail;
+ G* runq[256];
// Available G's (status == Gdead)
G* gfree;
@@ -406,8 +428,8 @@ struct Stktop
uint32 panicwrap;
uint8* argp; // pointer to arguments in old frame
- uintptr free; // if free>0, call stackfree using free as size
bool panic; // is this frame the top of a panic?
+ bool malloced;
};
struct SigTab
{
@@ -423,6 +445,7 @@ enum
SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
SigHandling = 1<<5, // our signal handler is registered
SigIgnored = 1<<6, // the signal was ignored before we registered for it
+ SigGoExit = 1<<7, // cause all runtime procs to exit (only used on Plan 9).
};
// Layout of in-memory per-function information prepared by linker
@@ -456,6 +479,16 @@ struct Itab
void (*fun[])(void);
};
+#ifdef GOOS_nacl
+enum {
+ NaCl = 1,
+};
+#else
+enum {
+ NaCl = 0,
+};
+#endif
+
#ifdef GOOS_windows
enum {
Windows = 1
@@ -465,6 +498,15 @@ enum {
Windows = 0
};
#endif
+#ifdef GOOS_solaris
+enum {
+ Solaris = 1
+};
+#else
+enum {
+ Solaris = 0
+};
+#endif
struct Timers
{
@@ -480,6 +522,8 @@ struct Timers
// Package time knows the layout of this structure.
// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
struct Timer
{
int32 i; // heap index
@@ -533,12 +577,16 @@ struct CgoMal
// Holds variables parsed from GODEBUG env var.
struct DebugVars
{
+ int32 allocfreetrace;
+ int32 efence;
int32 gctrace;
- int32 schedtrace;
+ int32 gcdead;
int32 scheddetail;
+ int32 schedtrace;
};
extern bool runtime·precisestack;
+extern bool runtime·copystack;
/*
* defined macros
@@ -548,13 +596,13 @@ extern bool runtime·precisestack;
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
#define offsetof(s,m) (uint32)(&(((s*)0)->m))
-#define ROUND(x, n) (((x)+(n)-1)&~((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
+#define ROUND(x, n) (((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
/*
* known to compiler
*/
enum {
- Structrnd = sizeof(uintptr)
+ Structrnd = sizeof(uintreg),
};
/*
@@ -648,7 +696,6 @@ struct Defer
{
int32 siz;
bool special; // not part of defer frame
- bool free; // if special, free when done
byte* argp; // where args were copied from
byte* pc;
FuncVal* fn;
@@ -656,11 +703,10 @@ struct Defer
void* args[1]; // padded to actual size
};
-struct DeferChunk
-{
- DeferChunk *prev;
- uintptr off;
-};
+// argp used in Defer structs when there is no argp.
+// TODO(rsc): Maybe we could use nil instead, but we've always used -1
+// and I don't want to change this days before the Go 1.3 release.
+#define NoArgs ((byte*)-1)
/*
* panics
@@ -670,7 +716,9 @@ struct Panic
Eface arg; // argument to panic
uintptr stackbase; // g->stackbase in panic
Panic* link; // link to earlier panic
+ Defer* defer; // current executing defer
bool recovered; // whether this panic is over
+ bool aborted; // the panic was aborted
};
/*
@@ -681,6 +729,7 @@ struct Stkframe
{
Func* fn; // function being run
uintptr pc; // program counter within fn
+ uintptr continpc; // program counter where execution can continue, or 0 if not
uintptr lr; // program counter at caller aka link register
uintptr sp; // stack pointer at pc
uintptr fp; // stack pointer at caller aka frame pointer
@@ -689,18 +738,24 @@ struct Stkframe
uintptr arglen; // number of bytes at argp
};
-int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
+int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, bool(*)(Stkframe*, void*), void*, bool);
void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebackothers(G*);
bool runtime·haszeroargs(uintptr pc);
bool runtime·topofstack(Func*);
+enum
+{
+ // The maximum number of frames we print for a traceback
+ TracebackMaxFrames = 100,
+};
/*
* external data
*/
extern String runtime·emptystring;
extern uintptr runtime·zerobase;
-extern G* runtime·allg;
+extern G** runtime·allg;
+extern uintptr runtime·allglen;
extern G* runtime·lastg;
extern M* runtime·allm;
extern P** runtime·allp;
@@ -722,6 +777,7 @@ extern uintptr runtime·maxstacksize;
* common functions and data
*/
int32 runtime·strcmp(byte*, byte*);
+int32 runtime·strncmp(byte*, byte*, uintptr);
byte* runtime·strstr(byte*, byte*);
intgo runtime·findnull(byte*);
intgo runtime·findnullw(uint16*);
@@ -729,11 +785,33 @@ void runtime·dump(byte*, int32);
int32 runtime·runetochar(byte*, int32);
int32 runtime·charntorune(int32*, uint8*, int32);
+
/*
- * very low level c-called
- */
+ * This macro is used when writing C functions
+ * called as if they were Go functions.
+ * Passed the address of a result before a return statement,
+ * it makes sure the result has been flushed to memory
+ * before the return.
+ *
+ * It is difficult to write such functions portably, because
+ * of the varying requirements on the alignment of the
+ * first output value. Almost all code should write such
+ * functions in .goc files, where goc2c (part of cmd/dist)
+ * can arrange the correct alignment for the target system.
+ * Goc2c also takes care of conveying to the garbage collector
+ * which parts of the argument list are inputs vs outputs.
+ *
+ * Therefore, do NOT use this macro if at all possible.
+ */
#define FLUSH(x) USED(x)
+/*
+ * GoOutput is a type with the same alignment requirements as the
+ * initial output argument from a Go function. Only for use in cases
+ * where using goc2c is not possible. See comment on FLUSH above.
+ */
+typedef uint64 GoOutput;
+
void runtime·gogo(Gobuf*);
void runtime·gostartcall(Gobuf*, void(*)(void), void*);
void runtime·gostartcallfn(Gobuf*, FuncVal*);
@@ -745,8 +823,10 @@ void runtime·goenvs_unix(void);
void* runtime·getu(void);
void runtime·throw(int8*);
void runtime·panicstring(int8*);
+bool runtime·canpanic(G*);
void runtime·prints(int8*);
void runtime·printf(int8*, ...);
+int32 runtime·snprintf(byte*, int32, int8*, ...);
byte* runtime·mchr(byte*, byte, byte*);
int32 runtime·mcmp(byte*, byte*, uintptr);
void runtime·memmove(void*, void*, uintptr);
@@ -764,24 +844,9 @@ int32 runtime·gotraceback(bool *crash);
void runtime·goroutineheader(G*);
int32 runtime·open(int8*, int32, int32);
int32 runtime·read(int32, void*, int32);
-int32 runtime·write(int32, void*, int32);
+int32 runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
int32 runtime·close(int32);
int32 runtime·mincore(void*, uintptr, byte*);
-bool runtime·cas(uint32*, uint32, uint32);
-bool runtime·cas64(uint64*, uint64, uint64);
-bool runtime·casp(void**, void*, void*);
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-uint32 runtime·xadd(uint32 volatile*, int32);
-uint64 runtime·xadd64(uint64 volatile*, int64);
-uint32 runtime·xchg(uint32 volatile*, uint32);
-uint64 runtime·xchg64(uint64 volatile*, uint64);
-uint32 runtime·atomicload(uint32 volatile*);
-void runtime·atomicstore(uint32 volatile*, uint32);
-void runtime·atomicstore64(uint64 volatile*, uint64);
-uint64 runtime·atomicload64(uint64 volatile*);
-void* runtime·atomicloadp(void* volatile*);
-void runtime·atomicstorep(void* volatile*, void*);
void runtime·jmpdefer(FuncVal*, void*);
void runtime·exit1(int32);
void runtime·ready(G*);
@@ -802,12 +867,12 @@ int32 runtime·funcarglen(Func*, uintptr);
int32 runtime·funcspdelta(Func*, uintptr);
int8* runtime·funcname(Func*);
int32 runtime·pcdatavalue(Func*, int32, uintptr);
-void* runtime·stackalloc(uint32);
-void runtime·stackfree(void*, uintptr);
+void* runtime·stackalloc(G*, uint32);
+void runtime·stackfree(G*, void*, Stktop*);
+void runtime·shrinkstack(G*);
MCache* runtime·allocmcache(void);
void runtime·freemcache(MCache*);
void runtime·mallocinit(void);
-void runtime·mprofinit(void);
bool runtime·ifaceeq_c(Iface, Iface);
bool runtime·efaceeq_c(Eface, Eface);
uintptr runtime·ifacehash(Iface, uintptr);
@@ -822,15 +887,35 @@ void runtime·mcall(void(*)(G*));
uint32 runtime·fastrand1(void);
void runtime·rewindmorestack(Gobuf*);
int32 runtime·timediv(int64, int32, int32*);
+int32 runtime·round2(int32 x); // round x up to a power of 2.
+
+// atomic operations
+bool runtime·cas(uint32*, uint32, uint32);
+bool runtime·cas64(uint64*, uint64, uint64);
+bool runtime·casp(void**, void*, void*);
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
+uint32 runtime·xadd(uint32 volatile*, int32);
+uint64 runtime·xadd64(uint64 volatile*, int64);
+uint32 runtime·xchg(uint32 volatile*, uint32);
+uint64 runtime·xchg64(uint64 volatile*, uint64);
+void* runtime·xchgp(void* volatile*, void*);
+uint32 runtime·atomicload(uint32 volatile*);
+void runtime·atomicstore(uint32 volatile*, uint32);
+void runtime·atomicstore64(uint64 volatile*, uint64);
+uint64 runtime·atomicload64(uint64 volatile*);
+void* runtime·atomicloadp(void* volatile*);
+void runtime·atomicstorep(void* volatile*, void*);
-void runtime·setmg(M*, G*);
-void runtime·newextram(void);
+void runtime·setmg(M*, G*);
+void runtime·newextram(void);
void runtime·exit(int32);
void runtime·breakpoint(void);
void runtime·gosched(void);
void runtime·gosched0(G*);
void runtime·schedtrace(bool);
-void runtime·park(void(*)(Lock*), Lock*, int8*);
+void runtime·park(bool(*)(G*, void*), void*, int8*);
+void runtime·parkunlock(Lock*, int8*);
void runtime·tsleep(int64, int8*);
M* runtime·newm(void);
void runtime·goexit(void);
@@ -841,12 +926,13 @@ void runtime·exitsyscall(void);
G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
bool runtime·sigsend(int32 sig);
int32 runtime·callers(int32, uintptr*, int32);
-int64 runtime·nanotime(void);
+int64 runtime·nanotime(void); // monotonic time
+int64 runtime·unixnanotime(void); // real time, can skip
void runtime·dopanic(int32);
void runtime·startpanic(void);
void runtime·freezetheworld(void);
void runtime·unwindstack(G*, byte*);
-void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
+void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
void runtime·resetcpuprofiler(int32);
void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
void runtime·usleep(uint32);
@@ -862,10 +948,19 @@ int32 runtime·netpollopen(uintptr, PollDesc*);
int32 runtime·netpollclose(uintptr);
void runtime·netpollready(G**, PollDesc*, int32);
uintptr runtime·netpollfd(PollDesc*);
+void runtime·netpollarm(PollDesc*, int32);
+void** runtime·netpolluser(PollDesc*);
+bool runtime·netpollclosing(PollDesc*);
+void runtime·netpolllock(PollDesc*);
+void runtime·netpollunlock(PollDesc*);
void runtime·crash(void);
void runtime·parsedebugvars(void);
void _rt0_go(void);
void* runtime·funcdata(Func*, int32);
+int32 runtime·setmaxthreads(int32);
+G* runtime·timejump(void);
+void runtime·iterate_itabs(void (*callback)(Itab*));
+void runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
#pragma varargck argpos runtime·printf 1
#pragma varargck type "c" int32
@@ -954,13 +1049,7 @@ LFNode* runtime·lfstackpop(uint64 *head);
ParFor* runtime·parforalloc(uint32 nthrmax);
void runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
void runtime·parfordo(ParFor *desc);
-
-/*
- * This is consistent across Linux and BSD.
- * If a new OS is added that is different, move this to
- * $GOOS/$GOARCH/defs.h.
- */
-#define EACCES 13
+void runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
/*
* low level C-called
@@ -992,10 +1081,11 @@ void runtime·printhex(uint64);
void runtime·printslice(Slice);
void runtime·printcomplex(Complex128);
void runtime·newstackcall(FuncVal*, byte*, uint32);
-void reflect·call(FuncVal*, byte*, uint32);
+void reflect·call(FuncVal*, byte*, uint32, uint32);
void runtime·panic(Eface);
void runtime·panicindex(void);
void runtime·panicslice(void);
+void runtime·panicdivide(void);
/*
* runtime c-called (but written in Go)
@@ -1036,16 +1126,8 @@ void runtime·procyield(uint32);
void runtime·osyield(void);
void runtime·lockOSThread(void);
void runtime·unlockOSThread(void);
+bool runtime·lockedOSThread(void);
-void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
-void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
-void runtime·mapiternext(struct hash_iter*);
-bool runtime·mapiterkey(struct hash_iter*, void*);
-Hmap* runtime·makemap_c(MapType*, int64);
-
-Hchan* runtime·makechan_c(ChanType*, int64);
-void runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
-void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
bool runtime·showframe(Func*, G*);
void runtime·printcreatedby(G*);
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index d2c38dfef..c6f6b626a 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -4,6 +4,8 @@
package runtime
#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
func GOMAXPROCS(n int) (ret int) {
ret = runtime·gomaxprocsfunc(n);
@@ -12,3 +14,115 @@ func GOMAXPROCS(n int) (ret int) {
func NumCPU() (ret int) {
ret = runtime·ncpu;
}
+
+func NumCgoCall() (ret int64) {
+ M *mp;
+
+ ret = 0;
+ for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
+ ret += mp->ncgocall;
+}
+
+func newParFor(nthrmax uint32) (desc *ParFor) {
+ desc = runtime·parforalloc(nthrmax);
+}
+
+func parForSetup(desc *ParFor, nthr uint32, n uint32, ctx *byte, wait bool, body *byte) {
+ runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
+}
+
+func parForDo(desc *ParFor) {
+ runtime·parfordo(desc);
+}
+
+func parForIters(desc *ParFor, tid uintptr) (start uintptr, end uintptr) {
+ runtime·parforiters(desc, tid, &start, &end);
+}
+
+func gogoBytes() (x int32) {
+ x = RuntimeGogoBytes;
+}
+
+func typestring(e Eface) (s String) {
+ s = *e.type->string;
+}
+
+func golockedOSThread() (ret bool) {
+ ret = runtime·lockedOSThread();
+}
+
+func NumGoroutine() (ret int) {
+ ret = runtime·gcount();
+}
+
+func getgoroot() (out String) {
+ byte *p;
+
+ p = runtime·getenv("GOROOT");
+ out = runtime·gostringnocopy(p);
+}
+
+/*
+ * We assume that all architectures turn faults and the like
+ * into apparent calls to runtime.sigpanic. If we see a "call"
+ * to runtime.sigpanic, we do not back up the PC to find the
+ * line number of the CALL instruction, because there is no CALL.
+ */
+void runtime·sigpanic(void);
+
+func Caller(skip int) (retpc uintptr, retfile String, retline int, retbool bool) {
+ Func *f, *g;
+ uintptr pc;
+ uintptr rpc[2];
+
+ /*
+ * Ask for two PCs: the one we were asked for
+ * and what it called, so that we can see if it
+ * "called" sigpanic.
+ */
+ retpc = 0;
+ if(runtime·callers(1+skip-1, rpc, 2) < 2) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = false;
+ } else if((f = runtime·findfunc(rpc[1])) == nil) {
+ retfile = runtime·emptystring;
+ retline = 0;
+ retbool = true; // have retpc at least
+ } else {
+ retpc = rpc[1];
+ pc = retpc;
+ g = runtime·findfunc(rpc[0]);
+ if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
+ pc--;
+ retline = runtime·funcline(f, pc, &retfile);
+ retbool = true;
+ }
+}
+
+func Callers(skip int, pc Slice) (retn int) {
+ // runtime.callers uses pc.array==nil as a signal
+ // to print a stack trace. Pick off 0-length pc here
+ // so that we don't let a nil pc slice get to it.
+ if(pc.len == 0)
+ retn = 0;
+ else
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
+}
+
+func runtime∕pprof·runtime_cyclesPerSecond() (res int64) {
+ res = runtime·tickspersecond();
+}
+
+func sync·runtime_procPin() (p int) {
+ M *mp;
+
+ mp = m;
+ // Disable preemption.
+ mp->locks++;
+ p = mp->p->id;
+}
+
+func sync·runtime_procUnpin() {
+ m->locks--;
+}
diff --git a/src/pkg/runtime/runtime_test.go b/src/pkg/runtime/runtime_test.go
index de6e5498e..5a9f52fe0 100644
--- a/src/pkg/runtime/runtime_test.go
+++ b/src/pkg/runtime/runtime_test.go
@@ -10,9 +10,11 @@ import (
"os"
"os/exec"
. "runtime"
+ "runtime/debug"
"strconv"
"strings"
"testing"
+ "unsafe"
)
var errf error
@@ -93,6 +95,10 @@ func BenchmarkDeferMany(b *testing.B) {
// The value reported will include the padding between runtime.gogo and the
// next function in memory. That's fine.
func TestRuntimeGogoBytes(t *testing.T) {
+ if GOOS == "nacl" {
+ t.Skip("skipping on nacl")
+ }
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
@@ -104,7 +110,7 @@ func TestRuntimeGogoBytes(t *testing.T) {
t.Fatalf("building hello world: %v\n%s", err, out)
}
- out, err = exec.Command("go", "tool", "nm", "-S", dir+"/hello").CombinedOutput()
+ out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
if err != nil {
t.Fatalf("go tool nm: %v\n%s", err, out)
}
@@ -122,3 +128,77 @@ func TestRuntimeGogoBytes(t *testing.T) {
t.Fatalf("go tool nm did not report size for runtime.gogo")
}
+
+// golang.org/issue/7063
+func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
+ SetCPUProfileRate(0)
+}
+
+// Addresses to test for faulting behavior.
+// This is less a test of SetPanicOnFault and more a check that
+// the operating system and the runtime can process these faults
+// correctly. That is, we're indirectly testing that without SetPanicOnFault
+// these would manage to turn into ordinary crashes.
+// Note that these are truncated on 32-bit systems, so the bottom 32 bits
+// of the larger addresses must themselves be invalid addresses.
+// We might get unlucky and the OS might have mapped one of these
+// addresses, but probably not: they're all in the first page, very high
+// adderesses that normally an OS would reserve for itself, or malformed
+// addresses. Even so, we might have to remove one or two on different
+// systems. We will see.
+
+var faultAddrs = []uint64{
+ // low addresses
+ 0,
+ 1,
+ 0xfff,
+ // high (kernel) addresses
+ // or else malformed.
+ 0xffffffffffffffff,
+ 0xfffffffffffff001,
+ // no 0xffffffffffff0001; 0xffff0001 is mapped for 32-bit user space on OS X
+ // no 0xfffffffffff00001; 0xfff00001 is mapped for 32-bit user space sometimes on Linux
+ 0xffffffffff000001,
+ 0xfffffffff0000001,
+ 0xffffffff00000001,
+ 0xfffffff000000001,
+ 0xffffff0000000001,
+ 0xfffff00000000001,
+ 0xffff000000000001,
+ 0xfff0000000000001,
+ 0xff00000000000001,
+ 0xf000000000000001,
+ 0x8000000000000001,
+}
+
+func TestSetPanicOnFault(t *testing.T) {
+ // This currently results in a fault in the signal trampoline on
+ // dragonfly/386 - see issue 7421.
+ if GOOS == "dragonfly" && GOARCH == "386" {
+ t.Skip("skipping test on dragonfly/386")
+ }
+
+ old := debug.SetPanicOnFault(true)
+ defer debug.SetPanicOnFault(old)
+
+ for _, addr := range faultAddrs {
+ testSetPanicOnFault(t, uintptr(addr))
+ }
+}
+
+func testSetPanicOnFault(t *testing.T, addr uintptr) {
+ if GOOS == "nacl" {
+ t.Skip("nacl doesn't seem to fault on high addresses")
+ }
+
+ defer func() {
+ if err := recover(); err == nil {
+ t.Fatalf("did not find error in recover")
+ }
+ }()
+
+ var p *int
+ p = (*int)(unsafe.Pointer(addr))
+ println(*p)
+ t.Fatalf("still here - should have faulted on address %#x", addr)
+}
diff --git a/src/pkg/runtime/runtime_unix_test.go b/src/pkg/runtime/runtime_unix_test.go
new file mode 100644
index 000000000..963de8cdb
--- /dev/null
+++ b/src/pkg/runtime/runtime_unix_test.go
@@ -0,0 +1,56 @@
+// 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.
+
+// Only works on systems with syscall.Close.
+// We need a fast system call to provoke the race,
+// and Close(-1) is nearly universally fast.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd plan9
+
+package runtime_test
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "testing"
+)
+
+func TestGoroutineProfile(t *testing.T) {
+ // GoroutineProfile used to use the wrong starting sp for
+ // goroutines coming out of system calls, causing possible
+ // crashes.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(100))
+
+ var stop uint32
+ defer atomic.StoreUint32(&stop, 1) // in case of panic
+
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ for atomic.LoadUint32(&stop) == 0 {
+ syscall.Close(-1)
+ }
+ wg.Done()
+ }()
+ }
+
+ max := 10000
+ if testing.Short() {
+ max = 100
+ }
+ stk := make([]runtime.StackRecord, 100)
+ for n := 0; n < max; n++ {
+ _, ok := runtime.GoroutineProfile(stk)
+ if !ok {
+ t.Fatalf("GoroutineProfile failed")
+ }
+ }
+
+ // If the program didn't crash, we passed.
+ atomic.StoreUint32(&stop, 1)
+ wg.Wait()
+}
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 57f32a0dd..c1e8e4e18 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -137,7 +137,7 @@ runtime·semacquire(uint32 volatile *addr, bool profile)
// Any semrelease after the cansemacquire knows we're waiting
// (we set nwait above), so go to sleep.
semqueue(root, addr, &s);
- runtime·park(runtime·unlock, root, "semacquire");
+ runtime·parkunlock(root, "semacquire");
if(cansemacquire(addr)) {
if(t0)
runtime·blockevent(s.releasetime - t0, 3);
@@ -254,7 +254,7 @@ func runtime_Syncsemacquire(s *SyncSema) {
else
s->tail->next = &w;
s->tail = &w;
- runtime·park(runtime·unlock, s, "semacquire");
+ runtime·parkunlock(s, "semacquire");
if(t0)
runtime·blockevent(w.releasetime - t0, 2);
}
@@ -288,7 +288,7 @@ func runtime_Syncsemrelease(s *SyncSema, n uint32) {
else
s->tail->next = &w;
s->tail = &w;
- runtime·park(runtime·unlock, s, "semarelease");
+ runtime·parkunlock(s, "semarelease");
} else
runtime·unlock(s);
}
diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c
index 5a913c646..70fcc6a63 100644
--- a/src/pkg/runtime/signal_386.c
+++ b/src/pkg/runtime/signal_386.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -39,15 +39,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp);
+ runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, m);
return;
}
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -94,7 +91,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
@@ -112,6 +108,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_amd64.c b/src/pkg/runtime/signal_amd64x.c
index f0cbb1f8c..04026f32f 100644
--- a/src/pkg/runtime/signal_amd64.c
+++ b/src/pkg/runtime/signal_amd64x.c
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -47,15 +48,33 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp);
+ runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, m);
return;
}
+#ifdef GOOS_darwin
+ // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+ // The hardware delivers a different kind of fault for a malformed address
+ // than it does for an attempt to access a valid but unmapped address.
+ // OS X 10.9.2 mishandles the malformed address case, making it look like
+ // a user-generated signal (like someone ran kill -SEGV ourpid).
+ // We pass user-generated signals to os/signal, or else ignore them.
+ // Doing that here - and returning to the faulting code - results in an
+ // infinite loop. It appears the best we can do is rewrite what the kernel
+ // delivers into something more like the truth. The address used below
+ // has very little chance of being the one that caused the fault, but it is
+ // malformed, it is clearly not a real pointer, and if it does get printed
+ // in real life, people will probably search for it and find this code.
+ // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+ // as I type this comment.
+ if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) {
+ SIG_CODE0(info, ctxt) = SI_USER+1;
+ info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL;
+ }
+#endif
+
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -89,6 +108,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
// won't get to see who faulted.)
if(SIG_RIP(info, ctxt) != 0) {
sp = (uintptr*)SIG_RSP(info, ctxt);
+ if(sizeof(uintreg) > sizeof(uintptr))
+ *--sp = 0;
*--sp = SIG_RIP(info, ctxt);
SIG_RSP(info, ctxt) = (uintptr)sp;
}
@@ -104,7 +125,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
runtime·startpanic();
@@ -122,6 +142,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c
index a6e239601..9b2a43d9b 100644
--- a/src/pkg/runtime/signal_arm.c
+++ b/src/pkg/runtime/signal_arm.c
@@ -46,15 +46,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
bool crash;
if(sig == SIGPROF) {
- runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp);
+ runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, m);
return;
}
t = &runtime·sigtab[sig];
if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
-
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -92,7 +89,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(!(t->flags & SigThrow))
return;
-Throw:
m->throwing = 1;
m->caughtsig = gp;
if(runtime·panicking) // traceback already printed
@@ -112,6 +108,7 @@ Throw:
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
+ runtime·goroutineheader(gp);
runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_nacl_386.h b/src/pkg/runtime/signal_nacl_386.h
new file mode 100644
index 000000000..c9481b5f4
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h
new file mode 100644
index 000000000..c58593a29
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_amd64p32.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_solaris_amd64.h b/src/pkg/runtime/signal_solaris_amd64.h
new file mode 100644
index 000000000..c2e0a1549
--- /dev/null
+++ b/src/pkg/runtime/signal_solaris_amd64.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RAX])
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBX])
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RCX])
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDX])
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDI])
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSI])
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBP])
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSP])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R10])
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R11])
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R12])
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R13])
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R14])
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R15])
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RIP])
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RFLAGS])
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_CS])
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_FS])
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_GS])
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->__data[0])
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
index 4d14b2208..246a1eb25 100644
--- a/src/pkg/runtime/signal_unix.c
+++ b/src/pkg/runtime/signal_unix.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux openbsd netbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -113,6 +113,7 @@ runtime·crash(void)
return;
#endif
+ runtime·unblocksignals();
runtime·setsig(SIGABRT, SIG_DFL, false);
runtime·raise(SIGABRT);
}
diff --git a/src/pkg/runtime/signals_freebsd.h b/src/pkg/runtime/signals_freebsd.h
index 4d27e050d..8d45c50c3 100644
--- a/src/pkg/runtime/signals_freebsd.h
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -21,7 +21,7 @@ SigTab runtime·sigtab[] = {
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ P, "SIGBUS: bus error",
/* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
+ /* 12 */ N, "SIGSYS: bad system call",
/* 13 */ N, "SIGPIPE: write to broken pipe",
/* 14 */ N, "SIGALRM: alarm clock",
/* 15 */ N+K, "SIGTERM: termination",
diff --git a/src/pkg/runtime/signals_linux.h b/src/pkg/runtime/signals_linux.h
index 9c3567007..368afc1c8 100644
--- a/src/pkg/runtime/signals_linux.h
+++ b/src/pkg/runtime/signals_linux.h
@@ -41,7 +41,7 @@ SigTab runtime·sigtab[] = {
/* 29 */ N, "SIGIO: i/o now possible",
/* 30 */ N, "SIGPWR: power failure restart",
/* 31 */ N, "SIGSYS: bad system call",
- /* 32 */ N, "signal 32",
+ /* 32 */ 0, "signal 32", /* SIGCANCEL; see issue 6997 */
/* 33 */ 0, "signal 33", /* SIGSETXID; see issue 3871 */
/* 34 */ N, "signal 34",
/* 35 */ N, "signal 35",
diff --git a/src/pkg/runtime/signals_nacl.h b/src/pkg/runtime/signals_nacl.h
new file mode 100644
index 000000000..229b58590
--- /dev/null
+++ b/src/pkg/runtime/signals_nacl.h
@@ -0,0 +1,50 @@
+// 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.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_plan9.h b/src/pkg/runtime/signals_plan9.h
index f9bec65fc..818f508cf 100644
--- a/src/pkg/runtime/signals_plan9.h
+++ b/src/pkg/runtime/signals_plan9.h
@@ -3,26 +3,58 @@
// license that can be found in the LICENSE file.
#define N SigNotify
+#define K SigKill
#define T SigThrow
#define P SigPanic
+#define E SigGoExit
+
+// Incoming notes are compared against this table using strncmp, so the
+// order matters: longer patterns must appear before their prefixes.
+// There are #defined SIG constants in os_plan9.h for the table index of
+// some of these.
+//
+// If you add entries to this table, you must respect the prefix ordering
+// and also update the constant values is os_plan9.h.
SigTab runtime·sigtab[] = {
- P, "sys: fp:",
-
- // Go libraries expect to be able
- // to recover from memory
- // read/write errors, so we flag
- // those as panics. All other traps
- // are generally more serious and
- // should immediately throw an
- // exception.
- P, "sys: trap: fault read addr",
- P, "sys: trap: fault write addr",
- T, "sys: trap:",
-
- N, "sys: bad sys call",
+ // Traps that we cannot be recovered.
+ T, "sys: trap: debug exception",
+ T, "sys: trap: invalid opcode",
+
+ // We can recover from some memory errors in runtime·sigpanic.
+ P, "sys: trap: fault read addr", // SIGRFAULT
+ P, "sys: trap: fault write addr", // SIGWFAULT
+
+ // We can also recover from math errors.
+ P, "sys: trap: divide error", // SIGINTDIV
+ P, "sys: fp:", // SIGFLOAT
+
+ // All other traps are normally handled as if they were marked SigThrow.
+ // We mark them SigPanic here so that debug.SetPanicOnFault will work.
+ P, "sys: trap:", // SIGTRAP
+
+ // Writes to a closed pipe can be handled if desired, otherwise they're ignored.
+ N, "sys: write on closed pipe",
+
+ // Other system notes are more serious and cannot be recovered.
+ T, "sys:",
+
+ // Issued to all other procs when calling runtime·exit.
+ E, "go: exit ",
+
+ // Kill is sent by external programs to cause an exit.
+ K, "kill",
+
+ // Interrupts can be handled if desired, otherwise they cause an exit.
+ N+K, "interrupt",
+ N+K, "hangup",
+
+ // Alarms can be handled if desired, otherwise they're ignored.
+ N, "alarm",
};
#undef N
+#undef K
#undef T
#undef P
+#undef E
diff --git a/src/pkg/runtime/signals_solaris.h b/src/pkg/runtime/signals_solaris.h
new file mode 100644
index 000000000..c272cad29
--- /dev/null
+++ b/src/pkg/runtime/signals_solaris.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: hangup",
+ /* 2 */ N+K, "SIGINT: interrupt (rubout)",
+ /* 3 */ N+T, "SIGQUIT: quit (ASCII FS)",
+ /* 4 */ T, "SIGILL: illegal instruction (not reset when caught)",
+ /* 5 */ T, "SIGTRAP: trace trap (not reset when caught)",
+ /* 6 */ N+T, "SIGABRT: used by abort, replace SIGIOT in the future",
+ /* 7 */ T, "SIGEMT: EMT instruction",
+ /* 8 */ P, "SIGFPE: floating point exception",
+ /* 9 */ 0, "SIGKILL: kill (cannot be caught or ignored)",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad argument to system call",
+ /* 13 */ N, "SIGPIPE: write on a pipe with no one to read it",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: software termination signal from kill",
+ /* 16 */ N, "SIGUSR1: user defined signal 1",
+ /* 17 */ N, "SIGUSR2: user defined signal 2",
+ /* 18 */ N, "SIGCLD: child status change",
+ /* 18 */ N, "SIGCHLD: child status change alias (POSIX)",
+ /* 19 */ N, "SIGPWR: power-fail restart",
+ /* 20 */ N, "SIGWINCH: window size change",
+ /* 21 */ N, "SIGURG: urgent socket condition",
+ /* 22 */ N, "SIGPOLL: pollable event occured",
+ /* 23 */ N+D, "SIGSTOP: stop (cannot be caught or ignored)",
+ /* 24 */ 0, "SIGTSTP: user stop requested from tty",
+ /* 25 */ 0, "SIGCONT: stopped process has been continued",
+ /* 26 */ N+D, "SIGTTIN: background tty read attempted",
+ /* 27 */ N+D, "SIGTTOU: background tty write attempted",
+ /* 28 */ N, "SIGVTALRM: virtual timer expired",
+ /* 29 */ N, "SIGPROF: profiling timer expired",
+ /* 30 */ N, "SIGXCPU: exceeded cpu limit",
+ /* 31 */ N, "SIGXFSZ: exceeded file size limit",
+ /* 32 */ N, "SIGWAITING: reserved signal no longer used by",
+ /* 33 */ N, "SIGLWP: reserved signal no longer used by",
+ /* 34 */ N, "SIGFREEZE: special signal used by CPR",
+ /* 35 */ N, "SIGTHAW: special signal used by CPR",
+ /* 36 */ 0, "SIGCANCEL: reserved signal for thread cancellation",
+ /* 37 */ N, "SIGLOST: resource lost (eg, record-lock lost)",
+ /* 38 */ N, "SIGXRES: resource control exceeded",
+ /* 39 */ N, "SIGJVM1: reserved signal for Java Virtual Machine",
+ /* 40 */ N, "SIGJVM2: reserved signal for Java Virtual Machine",
+
+ /* TODO(aram): what should be do about these signals? D or N? is this set static? */
+ /* 41 */ N, "real time signal",
+ /* 42 */ N, "real time signal",
+ /* 43 */ N, "real time signal",
+ /* 44 */ N, "real time signal",
+ /* 45 */ N, "real time signal",
+ /* 46 */ N, "real time signal",
+ /* 47 */ N, "real time signal",
+ /* 48 */ N, "real time signal",
+ /* 49 */ N, "real time signal",
+ /* 50 */ N, "real time signal",
+ /* 51 */ N, "real time signal",
+ /* 52 */ N, "real time signal",
+ /* 53 */ N, "real time signal",
+ /* 54 */ N, "real time signal",
+ /* 55 */ N, "real time signal",
+ /* 56 */ N, "real time signal",
+ /* 57 */ N, "real time signal",
+ /* 58 */ N, "real time signal",
+ /* 59 */ N, "real time signal",
+ /* 60 */ N, "real time signal",
+ /* 61 */ N, "real time signal",
+ /* 62 */ N, "real time signal",
+ /* 63 */ N, "real time signal",
+ /* 64 */ N, "real time signal",
+ /* 65 */ N, "real time signal",
+ /* 66 */ N, "real time signal",
+ /* 67 */ N, "real time signal",
+ /* 68 */ N, "real time signal",
+ /* 69 */ N, "real time signal",
+ /* 70 */ N, "real time signal",
+ /* 71 */ N, "real time signal",
+ /* 72 */ N, "real time signal",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.goc
index ef8ab7fe0..2a14dafab 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.goc
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "type.h"
#include "typekind.h"
#include "malloc.h"
#include "race.h"
+#include "stack.h"
#include "../../cmd/ld/textflag.h"
enum
@@ -17,13 +19,9 @@ enum
static void makeslice1(SliceType*, intgo, intgo, Slice*);
static void growslice1(SliceType*, Slice, intgo, Slice *);
- void runtime·copy(Slice to, Slice fm, uintptr width, intgo ret);
// see also unsafe·NewArray
-// makeslice(typ *Type, len, cap int64) (ary []any);
-void
-runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
-{
+func makeslice(t *SliceType, len int64, cap int64) (ret Slice) {
// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
// but it produces a 'len out of range' error instead of a 'cap out of range' error
// when someone does make([]T, bignumber). 'cap out of range' is true too,
@@ -58,9 +56,7 @@ makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret)
}
// growslice(type *Type, x, []T, n int64) []T
-void
-runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
-{
+func growslice(t *SliceType, old Slice, n int64) (ret Slice) {
int64 cap;
void *pc;
@@ -69,7 +65,7 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
cap = old.cap + n;
- if((intgo)cap != cap || cap < old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
+ if((intgo)cap != cap || cap < (int64)old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
runtime·panicstring("growslice: cap out of range");
if(raceenabled) {
@@ -79,8 +75,6 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
growslice1(t, old, cap, &ret);
- FLUSH(&ret);
-
if(debug) {
runtime·printf("growslice(%S,", *t->string);
runtime·printslice(old);
@@ -92,33 +86,53 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
static void
growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
{
- intgo m;
+ intgo newcap1;
+ uintptr capmem, lenmem;
+ int32 flag;
+ Type *typ;
+
+ typ = t->elem;
+ if(typ->size == 0) {
+ *ret = x;
+ ret->cap = newcap;
+ return;
+ }
- m = x.cap;
+ newcap1 = x.cap;
// Using newcap directly for m+m < newcap handles
// both the case where m == 0 and also the case where
// m+m/4 wraps around, in which case the loop
// below might never terminate.
- if(m+m < newcap)
- m = newcap;
+ if(newcap1+newcap1 < newcap)
+ newcap1 = newcap;
else {
do {
if(x.len < 1024)
- m += m;
+ newcap1 += newcap1;
else
- m += m/4;
- } while(m < newcap);
+ newcap1 += newcap1/4;
+ } while(newcap1 < newcap);
}
- makeslice1(t, x.len, m, ret);
- runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
+
+ if(newcap1 > MaxMem/typ->size)
+ runtime·panicstring("growslice: cap out of range");
+ capmem = runtime·roundupsize(newcap1*typ->size);
+ flag = 0;
+ // Can't use FlagNoZero w/o FlagNoScan, because otherwise GC can scan unitialized memory.
+ if(typ->kind&KindNoPointers)
+ flag = FlagNoScan|FlagNoZero;
+ ret->array = runtime·mallocgc(capmem, (uintptr)typ|TypeInfo_Array, flag);
+ ret->len = x.len;
+ ret->cap = capmem/typ->size;
+ lenmem = x.len*typ->size;
+ runtime·memmove(ret->array, x.array, lenmem);
+ if(typ->kind&KindNoPointers)
+ runtime·memclr(ret->array+lenmem, capmem-lenmem);
}
-// copy(to any, fr any, wid uintptr) int
#pragma textflag NOSPLIT
-void
-runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
-{
+func copy(to Slice, fm Slice, width uintptr) (ret int) {
void *pc;
if(fm.len == 0 || to.len == 0 || width == 0) {
@@ -143,7 +157,6 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
}
out:
- FLUSH(&ret);
if(debug) {
runtime·prints("main·copy: to=");
@@ -159,9 +172,7 @@ out:
}
#pragma textflag NOSPLIT
-void
-runtime·slicestringcopy(Slice to, String fm, intgo ret)
-{
+func slicestringcopy(to Slice, fm String) (ret int) {
void *pc;
if(fm.len == 0 || to.len == 0) {
@@ -180,13 +191,10 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret)
runtime·memmove(to.array, fm.str, ret);
-out:
- FLUSH(&ret);
+out:;
}
-void
-runtime·printslice(Slice a)
-{
+func printslice(a Slice) {
runtime·prints("[");
runtime·printint(a.len);
runtime·prints("/");
diff --git a/src/pkg/runtime/softfloat_arm.c b/src/pkg/runtime/softfloat_arm.c
index f5801dde4..29a52bd0e 100644
--- a/src/pkg/runtime/softfloat_arm.c
+++ b/src/pkg/runtime/softfloat_arm.c
@@ -16,7 +16,7 @@
#define FLAGS_V (1U << 28)
void runtime·abort(void);
-void math·sqrtC(uint64, uint64*);
+void runtime·sqrtC(uint64, uint64*);
static uint32 trace = 0;
@@ -413,7 +413,7 @@ stage3: // regd, regm are 4bit variables
break;
case 0xeeb10bc0: // D[regd] = sqrt D[regm]
- math·sqrtC(getd(regm), &uval);
+ runtime·sqrtC(getd(regm), &uval);
putd(regd, uval);
if(trace)
diff --git a/src/pkg/runtime/sqrt.go b/src/pkg/runtime/sqrt.go
new file mode 100644
index 000000000..34a8c3806
--- /dev/null
+++ b/src/pkg/runtime/sqrt.go
@@ -0,0 +1,150 @@
+// 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.
+
+// Copy of math/sqrt.go, here for use by ARM softfloat.
+
+package runtime
+
+import "unsafe"
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
+// sqrt(x) = 2**k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebraic manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted.
+
+const (
+ uvnan = 0x7FF8000000000001
+ uvinf = 0x7FF0000000000000
+ uvneginf = 0xFFF0000000000000
+ mask = 0x7FF
+ shift = 64 - 11 - 1
+ bias = 1023
+ maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+)
+
+func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
+func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
+
+func sqrt(x float64) float64 {
+ // special cases
+ switch {
+ case x == 0 || x != x || x > maxFloat64:
+ return x
+ case x < 0:
+ return nan
+ }
+ ix := float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
+ }
+ exp -= bias // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
+ }
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
+ }
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
+ }
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+ return float64frombits(ix)
+}
+
+func sqrtC(f float64, r *float64) {
+ *r = sqrt(f)
+}
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index 634706051..1680f004e 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -6,10 +6,21 @@
#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
+#include "funcdata.h"
+#include "typekind.h"
+#include "type.h"
+#include "../../cmd/ld/textflag.h"
enum
{
+ // StackDebug == 0: no logging
+ // == 1: logging of per-stack operations
+ // == 2: logging of per-frame operations
+ // == 3: logging of per-word updates
+ // == 4: logging of per-word reads
StackDebug = 0,
+ StackFromSystem = 0, // allocate stacks from system memory instead of the heap
+ StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free
};
typedef struct StackCacheNode StackCacheNode;
@@ -74,22 +85,37 @@ stackcacherelease(void)
}
void*
-runtime·stackalloc(uint32 n)
+runtime·stackalloc(G *gp, uint32 n)
{
uint32 pos;
void *v;
+ bool malloced;
+ Stktop *top;
// Stackalloc must be called on scheduler stack, so that we
// never try to grow the stack during the code that stackalloc runs.
// Doing so would cause a deadlock (issue 1547).
if(g != m->g0)
runtime·throw("stackalloc not on scheduler stack");
+ if((n & (n-1)) != 0)
+ runtime·throw("stack size not a power of 2");
+ if(StackDebug >= 1)
+ runtime·printf("stackalloc %d\n", n);
+
+ gp->stacksize += n;
+ if(runtime·debug.efence || StackFromSystem) {
+ v = runtime·SysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
+ if(v == nil)
+ runtime·throw("out of memory (stackalloc)");
+ return v;
+ }
- // Stacks are usually allocated with a fixed-size free-list allocator,
- // but if we need a stack of non-standard size, we fall back on malloc
- // (assuming that inside malloc and GC all the stack frames are small,
+ // Minimum-sized stacks are allocated with a fixed-size free-list allocator,
+ // but if we need a stack of a bigger size, we fall back on malloc
+ // (assuming that inside malloc all the stack frames are small,
// so that we do not deadlock).
- if(n == FixedStack || m->mallocing || m->gcing) {
+ malloced = true;
+ if(n == FixedStack || m->mallocing) {
if(n != FixedStack) {
runtime·printf("stackalloc: in malloc, size=%d want %d\n", FixedStack, n);
runtime·throw("stackalloc");
@@ -102,27 +128,46 @@ runtime·stackalloc(uint32 n)
m->stackcachepos = pos;
m->stackcachecnt--;
m->stackinuse++;
- return v;
- }
- return runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+ malloced = false;
+ } else
+ v = runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+
+ top = (Stktop*)((byte*)v+n-sizeof(Stktop));
+ runtime·memclr((byte*)top, sizeof(*top));
+ top->malloced = malloced;
+ return v;
}
void
-runtime·stackfree(void *v, uintptr n)
+runtime·stackfree(G *gp, void *v, Stktop *top)
{
uint32 pos;
-
- if(n == FixedStack || m->mallocing || m->gcing) {
- if(m->stackcachecnt == StackCacheSize)
- stackcacherelease();
- pos = m->stackcachepos;
- m->stackcache[pos] = v;
- m->stackcachepos = (pos + 1) % StackCacheSize;
- m->stackcachecnt++;
- m->stackinuse--;
+ uintptr n;
+
+ n = (uintptr)(top+1) - (uintptr)v;
+ if(StackDebug >= 1)
+ runtime·printf("stackfree %p %d\n", v, (int32)n);
+ gp->stacksize -= n;
+ if(runtime·debug.efence || StackFromSystem) {
+ if(runtime·debug.efence || StackFaultOnFree)
+ runtime·SysFault(v, n);
+ else
+ runtime·SysFree(v, n, &mstats.stacks_sys);
+ return;
+ }
+ if(top->malloced) {
+ runtime·free(v);
return;
}
- runtime·free(v);
+ if(n != FixedStack)
+ runtime·throw("stackfree: bad fixed size");
+ if(m->stackcachecnt == StackCacheSize)
+ stackcacherelease();
+ pos = m->stackcachepos;
+ m->stackcache[pos] = v;
+ m->stackcachepos = (pos + 1) % StackCacheSize;
+ m->stackcachecnt++;
+ m->stackinuse--;
}
// Called from runtime·lessstack when returning from a function which
@@ -145,12 +190,12 @@ runtime·oldstack(void)
sp = (byte*)top;
argsize = top->argsize;
- if(StackDebug) {
+ if(StackDebug >= 1) {
runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n",
- top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize);
+ top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)m->cret, (uintptr)argsize);
}
- // gp->status is usually Grunning, but it could be Gsyscall if a stack split
+ // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
// happens during a function call inside entersyscall.
oldstatus = gp->status;
@@ -175,11 +220,7 @@ runtime·oldstack(void)
gp->stackguard = top->stackguard;
gp->stackguard0 = gp->stackguard;
gp->panicwrap = top->panicwrap;
-
- if(top->free != 0) {
- gp->stacksize -= top->free;
- runtime·stackfree(old, top->free);
- }
+ runtime·stackfree(gp, old, top);
gp->status = oldstatus;
runtime·gogo(&gp->sched);
@@ -187,6 +228,435 @@ runtime·oldstack(void)
uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real
+static uint8*
+mapnames[] = {
+ (uint8*)"---",
+ (uint8*)"scalar",
+ (uint8*)"ptr",
+ (uint8*)"multi",
+};
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | return address |
+// +------------------+ <- frame->varp
+// | locals |
+// +------------------+
+// | args to callee |
+// +------------------+ <- frame->sp
+//
+// (arm: TODO)
+
+typedef struct CopyableInfo CopyableInfo;
+struct CopyableInfo {
+ byte *stk; // bottom address of segment
+ byte *base; // top address of segment (including Stktop)
+ int32 frames; // count of copyable frames (-1 = not copyable)
+};
+
+void runtime·main(void);
+
+static bool
+checkframecopy(Stkframe *frame, void *arg)
+{
+ CopyableInfo *cinfo;
+ Func *f;
+ StackMap *stackmap;
+
+ cinfo = arg;
+ f = frame->fn;
+ if(StackDebug >= 2)
+ runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base);
+ // if we're not in the segment any more, return immediately.
+ if(frame->varp < cinfo->stk || frame->varp >= cinfo->base) {
+ if(StackDebug >= 2)
+ runtime·printf(" <next segment>\n");
+ return false; // stop traceback
+ }
+ if(f->entry == (uintptr)runtime·main) {
+ // A special routine at the TOS of the main routine.
+ // We will allow it to be copied even though we don't
+ // have full GC info for it (because it is written in C).
+ cinfo->frames++;
+ return false; // stop traceback
+ }
+ if(frame->varp != (byte*)frame->sp) { // not in prologue (and has at least one local or outarg)
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: no locals info for %s\n", runtime·funcname(f));
+ return false;
+ }
+ if(stackmap->n <= 0) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: locals size info only for %s\n", runtime·funcname(f));
+ return false;
+ }
+ }
+ if(frame->arglen != 0) {
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil) {
+ cinfo->frames = -1;
+ if(StackDebug >= 1)
+ runtime·printf("copystack: no arg info for %s\n", runtime·funcname(f));
+ return false;
+ }
+ }
+ cinfo->frames++;
+ return true; // this frame is ok; keep going
+}
+
+// If the top segment of the stack contains an uncopyable
+// frame, return -1. Otherwise return the number of frames
+// in the top segment, all of which are copyable.
+static int32
+copyabletopsegment(G *gp)
+{
+ CopyableInfo cinfo;
+ Defer *d;
+ Func *f;
+ FuncVal *fn;
+ StackMap *stackmap;
+
+ cinfo.stk = (byte*)gp->stackguard - StackGuard;
+ cinfo.base = (byte*)gp->stackbase + sizeof(Stktop);
+ cinfo.frames = 0;
+
+ // Check that each frame is copyable. As a side effect,
+ // count the frames.
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, checkframecopy, &cinfo, false);
+ if(StackDebug >= 1 && cinfo.frames != -1)
+ runtime·printf("copystack: %d copyable frames\n", cinfo.frames);
+
+ // Check to make sure all Defers are copyable
+ for(d = gp->defer; d != nil; d = d->link) {
+ if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) {
+ // Defer is on the stack. Its copyableness has
+ // been established during stack walking.
+ // For now, this only happens with the Defer in runtime.main.
+ continue;
+ }
+ if(d->argp < cinfo.stk || cinfo.base <= d->argp)
+ break; // a defer for the next segment
+ fn = d->fn;
+ if(fn == nil) // See issue 8047
+ continue;
+ f = runtime·findfunc((uintptr)fn->fn);
+ if(f == nil)
+ return -1;
+
+ // Check to make sure we have an args pointer map for the defer's args.
+ // We only need the args map, but we check
+ // for the locals map also, because when the locals map
+ // isn't provided it means the ptr map came from C and
+ // C (particularly, cgo) lies to us. See issue 7695.
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil || stackmap->n <= 0)
+ return -1;
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil || stackmap->n <= 0)
+ return -1;
+
+ if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) {
+ // FuncVal is on the stack. Again, its copyableness
+ // was established during stack walking.
+ continue;
+ }
+ // The FuncVal may have pointers in it, but fortunately for us
+ // the compiler won't put pointers into the stack in a
+ // heap-allocated FuncVal.
+ // One day if we do need to check this, we'll need maps of the
+ // pointerness of the closure args. The only place we have that map
+ // right now is in the gc program for the FuncVal. Ugh.
+ }
+
+ return cinfo.frames;
+}
+
+typedef struct AdjustInfo AdjustInfo;
+struct AdjustInfo {
+ byte *oldstk; // bottom address of segment
+ byte *oldbase; // top address of segment (after Stktop)
+ uintptr delta; // ptr distance from old to new stack (newbase - oldbase)
+};
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+static void
+adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
+{
+ uintptr delta;
+ int32 num, i;
+ byte *p, *minp, *maxp;
+ Type *t;
+ Itab *tab;
+
+ minp = adjinfo->oldstk;
+ maxp = adjinfo->oldbase;
+ delta = adjinfo->delta;
+ num = bv->n / BitsPerPointer;
+ for(i = 0; i < num; i++) {
+ if(StackDebug >= 4)
+ runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3], scanp[i]);
+ switch(bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3) {
+ case BitsDead:
+ if(runtime·debug.gcdead)
+ scanp[i] = (byte*)PoisonStack;
+ break;
+ case BitsScalar:
+ break;
+ case BitsPointer:
+ p = scanp[i];
+ if(f != nil && (byte*)0 < p && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+ // Looks like a junk value in a pointer slot.
+ // Live analysis wrong?
+ m->traceback = 2;
+ runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
+ runtime·throw("bad pointer!");
+ }
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust ptr %p %s\n", p, runtime·funcname(f));
+ scanp[i] = p + delta;
+ }
+ break;
+ case BitsMultiWord:
+ switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
+ case BitsString:
+ // string referents are never on the stack, never need to be adjusted
+ i++; // skip len
+ break;
+ case BitsSlice:
+ p = scanp[i];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust slice %p\n", p);
+ scanp[i] = p + delta;
+ }
+ i += 2; // skip len, cap
+ break;
+ case BitsEface:
+ t = (Type*)scanp[i];
+ if(t != nil && (t->size > PtrSize || (t->kind & KindNoPointers) == 0)) {
+ p = scanp[i+1];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust eface %p\n", p);
+ if(t->size > PtrSize) // currently we always allocate such objects on the heap
+ runtime·throw("large interface value found on stack");
+ scanp[i+1] = p + delta;
+ }
+ }
+ i++;
+ break;
+ case BitsIface:
+ tab = (Itab*)scanp[i];
+ if(tab != nil) {
+ t = tab->type;
+ //runtime·printf(" type=%p\n", t);
+ if(t->size > PtrSize || (t->kind & KindNoPointers) == 0) {
+ p = scanp[i+1];
+ if(minp <= p && p < maxp) {
+ if(StackDebug >= 3)
+ runtime·printf("adjust iface %p\n", p);
+ if(t->size > PtrSize) // currently we always allocate such objects on the heap
+ runtime·throw("large interface value found on stack");
+ scanp[i+1] = p + delta;
+ }
+ }
+ }
+ i++;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+// Note: the argument/return area is adjusted by the callee.
+static bool
+adjustframe(Stkframe *frame, void *arg)
+{
+ AdjustInfo *adjinfo;
+ Func *f;
+ StackMap *stackmap;
+ int32 pcdata;
+ BitVector bv;
+ uintptr targetpc;
+
+ adjinfo = arg;
+ f = frame->fn;
+ if(StackDebug >= 2)
+ runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc);
+ if(f->entry == (uintptr)runtime·main)
+ return true;
+ targetpc = frame->continpc;
+ if(targetpc == 0) {
+ // Frame is dead.
+ return true;
+ }
+ if(targetpc != f->entry)
+ targetpc--;
+ pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+ if(pcdata == -1)
+ pcdata = 0; // in prologue
+
+ // adjust local pointers
+ if(frame->varp != (byte*)frame->sp) {
+ stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("no locals info");
+ if(stackmap->n <= 0)
+ runtime·throw("locals size info only");
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ if(StackDebug >= 3)
+ runtime·printf(" locals\n");
+ adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv, adjinfo, f);
+ }
+ // adjust inargs and outargs
+ if(frame->arglen != 0) {
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("no arg info");
+ bv = runtime·stackmapdata(stackmap, pcdata);
+ if(StackDebug >= 3)
+ runtime·printf(" args\n");
+ adjustpointers((byte**)frame->argp, &bv, adjinfo, nil);
+ }
+ return true;
+}
+
+static void
+adjustctxt(G *gp, AdjustInfo *adjinfo)
+{
+ if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < adjinfo->oldbase)
+ gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta;
+}
+
+static void
+adjustdefers(G *gp, AdjustInfo *adjinfo)
+{
+ Defer *d, **dp;
+ Func *f;
+ FuncVal *fn;
+ StackMap *stackmap;
+ BitVector bv;
+
+ for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) {
+ if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) {
+ // The Defer record is on the stack. Its fields will
+ // get adjusted appropriately.
+ // This only happens for runtime.main now, but a compiler
+ // optimization could do more of this.
+ *dp = (Defer*)((byte*)d + adjinfo->delta);
+ continue;
+ }
+ if(d->argp < adjinfo->oldstk || adjinfo->oldbase <= d->argp)
+ break; // a defer for the next segment
+ fn = d->fn;
+ if(fn == nil) {
+ // Defer of nil function. It will panic when run, and there
+ // aren't any args to adjust. See issue 8047.
+ d->argp += adjinfo->delta;
+ continue;
+ }
+ f = runtime·findfunc((uintptr)fn->fn);
+ if(f == nil)
+ runtime·throw("can't adjust unknown defer");
+ if(StackDebug >= 4)
+ runtime·printf(" checking defer %s\n", runtime·funcname(f));
+ // Defer's FuncVal might be on the stack
+ if(adjinfo->oldstk <= (byte*)fn && (byte*)fn < adjinfo->oldbase) {
+ if(StackDebug >= 3)
+ runtime·printf(" adjust defer fn %s\n", runtime·funcname(f));
+ d->fn = (FuncVal*)((byte*)fn + adjinfo->delta);
+ } else {
+ // deferred function's args might point into the stack.
+ if(StackDebug >= 3)
+ runtime·printf(" adjust deferred args for %s\n", runtime·funcname(f));
+ stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+ if(stackmap == nil)
+ runtime·throw("runtime: deferred function has no arg ptr map");
+ bv = runtime·stackmapdata(stackmap, 0);
+ adjustpointers(d->args, &bv, adjinfo, f);
+ }
+ d->argp += adjinfo->delta;
+ }
+}
+
+// Copies the top stack segment of gp to a new stack segment of a
+// different size. The top segment must contain nframes frames.
+static void
+copystack(G *gp, uintptr nframes, uintptr newsize)
+{
+ byte *oldstk, *oldbase, *newstk, *newbase;
+ uintptr oldsize, used;
+ AdjustInfo adjinfo;
+ Stktop *oldtop, *newtop;
+ bool malloced;
+
+ if(gp->syscallstack != 0)
+ runtime·throw("can't handle stack copy in syscall yet");
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ used = oldbase - (byte*)gp->sched.sp;
+ oldtop = (Stktop*)gp->stackbase;
+
+ // allocate new stack
+ newstk = runtime·stackalloc(gp, newsize);
+ newbase = newstk + newsize;
+ newtop = (Stktop*)(newbase - sizeof(Stktop));
+ malloced = newtop->malloced;
+
+ if(StackDebug >= 1)
+ runtime·printf("copystack [%p %p]/%d -> [%p %p]/%d\n", oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize);
+ USED(oldsize);
+
+ // adjust pointers in the to-be-copied frames
+ adjinfo.oldstk = oldstk;
+ adjinfo.oldbase = oldbase;
+ adjinfo.delta = newbase - oldbase;
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, adjustframe, &adjinfo, false);
+
+ // adjust other miscellaneous things that have pointers into stacks.
+ adjustctxt(gp, &adjinfo);
+ adjustdefers(gp, &adjinfo);
+
+ // copy the stack (including Stktop) to the new location
+ runtime·memmove(newbase - used, oldbase - used, used);
+ newtop->malloced = malloced;
+
+ // Swap out old stack for new one
+ gp->stackbase = (uintptr)newtop;
+ gp->stackguard = (uintptr)newstk + StackGuard;
+ gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a preempt request
+ if(gp->stack0 == (uintptr)oldstk)
+ gp->stack0 = (uintptr)newstk;
+ gp->sched.sp = (uintptr)(newbase - used);
+
+ // free old stack
+ runtime·stackfree(gp, oldstk, oldtop);
+}
+
+// round x up to a power of 2.
+int32
+runtime·round2(int32 x)
+{
+ int32 s;
+
+ s = 0;
+ while((1 << s) < x)
+ s++;
+ return 1 << s;
+}
+
// Called from runtime·newstackcall or from runtime·morestack when a new
// stack segment is needed. Allocate a new stack big enough for
// m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
@@ -195,16 +665,18 @@ uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for
void
runtime·newstack(void)
{
- int32 framesize, argsize, oldstatus;
+ int32 framesize, argsize, oldstatus, oldsize, newsize, nframes;
Stktop *top, *oldtop;
- byte *stk;
+ byte *stk, *oldstk, *oldbase;
uintptr sp;
uintptr *src, *dst, *dstend;
G *gp;
- Gobuf label;
+ Gobuf label, morebuf;
+ void *moreargp;
bool newstackcall;
- uintptr free;
+ if(m->forkstackguard)
+ runtime·throw("split stack after fork");
if(m->morebuf.g != m->curg) {
runtime·printf("runtime: newstack called from g=%p\n"
"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
@@ -212,15 +684,21 @@ runtime·newstack(void)
runtime·throw("runtime: wrong goroutine in newstack");
}
- // gp->status is usually Grunning, but it could be Gsyscall if a stack split
+ // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
// happens during a function call inside entersyscall.
gp = m->curg;
oldstatus = gp->status;
framesize = m->moreframesize;
argsize = m->moreargsize;
+ moreargp = m->moreargp;
+ m->moreargp = nil;
+ morebuf = m->morebuf;
+ m->morebuf.pc = (uintptr)nil;
+ m->morebuf.lr = (uintptr)nil;
+ m->morebuf.sp = (uintptr)nil;
gp->status = Gwaiting;
- gp->waitreason = "stack split";
+ gp->waitreason = "stack growth";
newstackcall = framesize==1;
if(newstackcall)
framesize = 0;
@@ -234,7 +712,7 @@ runtime·newstack(void)
// The call to morestack cost a word.
sp -= sizeof(uintptr);
}
- if(StackDebug || sp < gp->stackguard - StackGuard) {
+ if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) {
runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n"
"\tmorebuf={pc:%p sp:%p lr:%p}\n"
"\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
@@ -248,8 +726,8 @@ runtime·newstack(void)
}
if(argsize % sizeof(uintptr) != 0) {
- runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
- runtime·throw("runtime: stack split argsize");
+ runtime·printf("runtime: stack growth with misaligned argsize %d\n", argsize);
+ runtime·throw("runtime: stack growth argsize");
}
if(gp->stackguard0 == (uintptr)StackPreempt) {
@@ -258,7 +736,7 @@ runtime·newstack(void)
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");
+ runtime·throw("runtime: stack growth during syscall");
// Be conservative about where we preempt.
// We are interested in preempting user Go code, not runtime code.
if(oldstatus != Grunning || m->locks || m->mallocing || m->gcing || m->p->status != Prunning) {
@@ -273,46 +751,55 @@ runtime·newstack(void)
runtime·gosched0(gp); // never return
}
- if(newstackcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
- // special case: called from runtime.newstackcall (framesize==1)
- // to call code with an arbitrary argument size,
- // and we have enough space on the current stack.
- // the new Stktop* is necessary to unwind, but
- // we don't need to create a new segment.
- top = (Stktop*)(m->morebuf.sp - sizeof(*top));
- stk = (byte*)gp->stackguard - StackGuard;
- free = 0;
- } else {
- // allocate new segment.
- framesize += argsize;
- framesize += StackExtra; // room for more functions, Stktop.
- if(framesize < StackMin)
- framesize = StackMin;
- framesize += StackSystem;
- gp->stacksize += framesize;
- if(gp->stacksize > runtime·maxstacksize) {
- runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
- runtime·throw("stack overflow");
+ // If every frame on the top segment is copyable, allocate a bigger segment
+ // and move the segment instead of allocating a new segment.
+ if(runtime·copystack) {
+ if(!runtime·precisestack)
+ runtime·throw("can't copy stacks without precise stacks");
+ nframes = copyabletopsegment(gp);
+ if(nframes != -1) {
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ newsize = oldsize * 2;
+ copystack(gp, nframes, newsize);
+ if(StackDebug >= 1)
+ runtime·printf("stack grow done\n");
+ if(gp->stacksize > runtime·maxstacksize) {
+ runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+ runtime·throw("stack overflow");
+ }
+ gp->status = oldstatus;
+ runtime·gogo(&gp->sched);
}
- stk = runtime·stackalloc(framesize);
- top = (Stktop*)(stk+framesize-sizeof(*top));
- free = framesize;
+ // TODO: if stack is uncopyable because we're in C code, patch return value at
+ // end of C code to trigger a copy as soon as C code exits. That way, we'll
+ // have stack available if we get this deep again.
}
- if(StackDebug) {
+ // allocate new segment.
+ framesize += argsize;
+ framesize += StackExtra; // room for more functions, Stktop.
+ if(framesize < StackMin)
+ framesize = StackMin;
+ framesize += StackSystem;
+ framesize = runtime·round2(framesize);
+ stk = runtime·stackalloc(gp, framesize);
+ if(gp->stacksize > runtime·maxstacksize) {
+ runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+ runtime·throw("stack overflow");
+ }
+ top = (Stktop*)(stk+framesize-sizeof(*top));
+
+ if(StackDebug >= 1) {
runtime·printf("\t-> new stack [%p, %p]\n", stk, top);
}
top->stackbase = gp->stackbase;
top->stackguard = gp->stackguard;
- top->gobuf = m->morebuf;
- top->argp = m->moreargp;
+ top->gobuf = morebuf;
+ top->argp = moreargp;
top->argsize = argsize;
- top->free = free;
- m->moreargp = nil;
- m->morebuf.pc = (uintptr)nil;
- m->morebuf.lr = (uintptr)nil;
- m->morebuf.sp = (uintptr)nil;
// copy flag from panic
top->panic = gp->ispanic;
@@ -365,18 +852,96 @@ runtime·newstack(void)
*(int32*)345 = 123; // never return
}
+#pragma textflag NOSPLIT
+void
+runtime·nilfunc(void)
+{
+ *(byte*)0 = 0;
+}
+
// adjust Gobuf as if it executed a call to fn
// and then did an immediate gosave.
void
runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
{
- runtime·gostartcall(gobuf, fv->fn, fv);
+ void *fn;
+
+ if(fv != nil)
+ fn = fv->fn;
+ else
+ fn = runtime·nilfunc;
+ runtime·gostartcall(gobuf, fn, fv);
}
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
void
-runtime∕debug·setMaxStack(intgo in, intgo out)
+runtime·shrinkstack(G *gp)
{
- out = runtime·maxstacksize;
- runtime·maxstacksize = in;
- FLUSH(&out);
+ int32 nframes;
+ byte *oldstk, *oldbase;
+ uintptr used, oldsize, newsize;
+ MSpan *span;
+
+ if(!runtime·copystack)
+ return;
+ oldstk = (byte*)gp->stackguard - StackGuard;
+ oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+ oldsize = oldbase - oldstk;
+ newsize = oldsize / 2;
+ if(newsize < FixedStack)
+ return; // don't shrink below the minimum-sized stack
+ used = oldbase - (byte*)gp->sched.sp;
+ if(used >= oldsize / 4)
+ return; // still using at least 1/4 of the segment.
+
+ // To shrink to less than 1/2 a page, we need to copy.
+ if(newsize < PageSize/2) {
+ if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case?
+ return;
+#ifdef GOOS_windows
+ if(gp->m != nil && gp->m->libcallsp != 0)
+ return;
+#endif
+ nframes = copyabletopsegment(gp);
+ if(nframes == -1)
+ return;
+ copystack(gp, nframes, newsize);
+ return;
+ }
+
+ // To shrink a stack of one page size or more, we can shrink it
+ // without copying. Just deallocate the lower half.
+ span = runtime·MHeap_LookupMaybe(&runtime·mheap, oldstk);
+ if(span == nil)
+ return; // stack allocated outside heap. Can't shrink it. Can happen if stack is allocated while inside malloc. TODO: shrink by copying?
+ if(span->elemsize != oldsize)
+ runtime·throw("span element size doesn't match stack size");
+ if((uintptr)oldstk != span->start << PageShift)
+ runtime·throw("stack not at start of span");
+
+ if(StackDebug)
+ runtime·printf("shrinking stack in place %p %X->%X\n", oldstk, oldsize, newsize);
+
+ // new stack guard for smaller stack
+ gp->stackguard = (uintptr)oldstk + newsize + StackGuard;
+ gp->stackguard0 = (uintptr)oldstk + newsize + StackGuard;
+ if(gp->stack0 == (uintptr)oldstk)
+ gp->stack0 = (uintptr)oldstk + newsize;
+ gp->stacksize -= oldsize - newsize;
+
+ // Free bottom half of the stack.
+ if(runtime·debug.efence || StackFromSystem) {
+ if(runtime·debug.efence || StackFaultOnFree)
+ runtime·SysFault(oldstk, newsize);
+ else
+ runtime·SysFree(oldstk, newsize, &mstats.stacks_sys);
+ return;
+ }
+ // First, we trick malloc into thinking
+ // we allocated the stack as two separate half-size allocs. Then the
+ // free() call does the rest of the work for us.
+ runtime·MSpan_EnsureSwept(span);
+ runtime·MHeap_SplitSpan(&runtime·mheap, span);
+ runtime·free(oldstk);
}
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index 296eb688d..18ab30b69 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -77,7 +77,8 @@ enum {
// If the amount needed for the splitting frame + StackExtra
// is less than this number, the stack will have this size instead.
StackMin = 8192,
- FixedStack = StackMin + StackSystem,
+ StackSystemRounded = StackSystem + (-StackSystem & (StackMin-1)),
+ FixedStack = StackMin + StackSystemRounded,
// Functions that need frames bigger than this use an extra
// instruction to do the stack split check, to avoid overflow
@@ -102,7 +103,7 @@ enum {
// The assumed size of the top-of-stack data block.
// The actual size can be smaller than this but cannot be larger.
// Checked in proc.c's runtime.malg.
- StackTop = 96,
+ StackTop = 88,
};
// Goroutine preemption request.
diff --git a/src/pkg/runtime/stack_gen_test.go b/src/pkg/runtime/stack_gen_test.go
new file mode 100644
index 000000000..28101062c
--- /dev/null
+++ b/src/pkg/runtime/stack_gen_test.go
@@ -0,0 +1,1473 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ . "runtime"
+)
+
+var splitTests = []func() (uintptr, uintptr){
+ // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt
+ stack4, stack8, stack12, stack16, stack20, stack24, stack28,
+ stack32, stack36, stack40, stack44, stack48, stack52, stack56,
+ stack60, stack64, stack68, stack72, stack76, stack80, stack84,
+ stack88, stack92, stack96, stack100, stack104, stack108, stack112,
+ stack116, stack120, stack124, stack128, stack132, stack136,
+ stack140, stack144, stack148, stack152, stack156, stack160,
+ stack164, stack168, stack172, stack176, stack180, stack184,
+ stack188, stack192, stack196, stack200, stack204, stack208,
+ stack212, stack216, stack220, stack224, stack228, stack232,
+ stack236, stack240, stack244, stack248, stack252, stack256,
+ stack260, stack264, stack268, stack272, stack276, stack280,
+ stack284, stack288, stack292, stack296, stack300, stack304,
+ stack308, stack312, stack316, stack320, stack324, stack328,
+ stack332, stack336, stack340, stack344, stack348, stack352,
+ stack356, stack360, stack364, stack368, stack372, stack376,
+ stack380, stack384, stack388, stack392, stack396, stack400,
+ stack404, stack408, stack412, stack416, stack420, stack424,
+ stack428, stack432, stack436, stack440, stack444, stack448,
+ stack452, stack456, stack460, stack464, stack468, stack472,
+ stack476, stack480, stack484, stack488, stack492, stack496,
+ stack500, stack504, stack508, stack512, stack516, stack520,
+ stack524, stack528, stack532, stack536, stack540, stack544,
+ stack548, stack552, stack556, stack560, stack564, stack568,
+ stack572, stack576, stack580, stack584, stack588, stack592,
+ stack596, stack600, stack604, stack608, stack612, stack616,
+ stack620, stack624, stack628, stack632, stack636, stack640,
+ stack644, stack648, stack652, stack656, stack660, stack664,
+ stack668, stack672, stack676, stack680, stack684, stack688,
+ stack692, stack696, stack700, stack704, stack708, stack712,
+ stack716, stack720, stack724, stack728, stack732, stack736,
+ stack740, stack744, stack748, stack752, stack756, stack760,
+ stack764, stack768, stack772, stack776, stack780, stack784,
+ stack788, stack792, stack796, stack800, stack804, stack808,
+ stack812, stack816, stack820, stack824, stack828, stack832,
+ stack836, stack840, stack844, stack848, stack852, stack856,
+ stack860, stack864, stack868, stack872, stack876, stack880,
+ stack884, stack888, stack892, stack896, stack900, stack904,
+ stack908, stack912, stack916, stack920, stack924, stack928,
+ stack932, stack936, stack940, stack944, stack948, stack952,
+ stack956, stack960, stack964, stack968, stack972, stack976,
+ stack980, stack984, stack988, stack992, stack996, stack1000,
+ stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
+ stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
+ stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
+ stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
+ stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
+ stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
+ stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
+ stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
+ stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
+ stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
+ stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
+ stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
+ stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
+ stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
+ stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
+ stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
+ stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
+ stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
+ stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
+ stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
+ stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
+ stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
+ stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
+ stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
+ stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
+ stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
+ stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
+ stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
+ stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
+ stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
+ stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
+ stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
+ stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
+ stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
+ stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
+ stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
+ stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
+ stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
+ stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
+ stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
+ stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
+ stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
+ stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
+ stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
+ stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
+ stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
+ stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
+ stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
+ stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
+ stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
+ stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
+ stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
+ stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
+ stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
+ stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
+ stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
+ stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
+ stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
+ stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
+ stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
+ stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
+ stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
+ stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
+ stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
+ stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
+ stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
+ stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
+ stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
+ stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
+ stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
+ stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
+ stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
+ stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
+ stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
+ stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
+ stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
+ stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
+ stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
+ stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
+ stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
+ stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
+ stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
+ stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
+ stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
+ stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
+ stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
+ stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
+ stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
+ stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
+ stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
+ stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
+ stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
+ stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
+ stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
+ stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
+ stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
+ stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
+ stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
+ stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
+ stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
+ stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
+ stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
+ stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
+ stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
+ stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
+ stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
+ stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
+ stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
+ stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
+ stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
+ stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
+ stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
+ stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
+ stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
+ stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
+ stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
+ stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
+ stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
+ stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
+ stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
+ stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
+ stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
+ stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
+ stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
+ stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
+ stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
+ stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
+ stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
+ stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
+ stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
+ stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
+ stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
+ stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
+ stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
+ stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
+ stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
+ stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
+ stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
+ stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
+ stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
+ stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
+ stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
+ stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
+ stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
+ stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
+ stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
+ stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
+ stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
+ stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
+ stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
+ stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
+ stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
+ stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
+ stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
+ stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
+ stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
+ stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
+ stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
+ stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
+ stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
+ stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
+ stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
+ stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
+ stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
+ stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
+ stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
+ stack4988, stack4992, stack4996, stack5000,
+}
+
+// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
+func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() }
+func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() }
+func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() }
+func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() }
+func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() }
+func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() }
+func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() }
+func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() }
+func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() }
+func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() }
+func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() }
+func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() }
+func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() }
+func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() }
+func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() }
+func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() }
+func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() }
+func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() }
+func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() }
+func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() }
+func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() }
+func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() }
+func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() }
+func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() }
+func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() }
+func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() }
+func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() }
+func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() }
+func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() }
+func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() }
+func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() }
+func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() }
+func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() }
+func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() }
+func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() }
+func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() }
+func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() }
+func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() }
+func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() }
+func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() }
+func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() }
+func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() }
+func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() }
+func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() }
+func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() }
+func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() }
+func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() }
+func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() }
+func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() }
+func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() }
+func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() }
+func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() }
+func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() }
+func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() }
+func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() }
+func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() }
+func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() }
+func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() }
+func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() }
+func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() }
+func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() }
+func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() }
+func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() }
+func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() }
+func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() }
+func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() }
+func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() }
+func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() }
+func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() }
+func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() }
+func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() }
+func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() }
+func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() }
+func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() }
+func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() }
+func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() }
+func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() }
+func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() }
+func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() }
+func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() }
+func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() }
+func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() }
+func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() }
+func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() }
+func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() }
+func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() }
+func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() }
+func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() }
+func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() }
+func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() }
+func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() }
+func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() }
+func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() }
+func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() }
+func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() }
+func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() }
+func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() }
+func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() }
+func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() }
+func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() }
+func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() }
+func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() }
+func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() }
+func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() }
+func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() }
+func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() }
+func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() }
+func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() }
+func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() }
+func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() }
+func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() }
+func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() }
+func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() }
+func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() }
+func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() }
+func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() }
+func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() }
+func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() }
+func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() }
+func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() }
+func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() }
+func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() }
+func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() }
+func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() }
+func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() }
+func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() }
+func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() }
+func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() }
+func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() }
+func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() }
+func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() }
+func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() }
+func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() }
+func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() }
+func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() }
+func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() }
+func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() }
+func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() }
+func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() }
+func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() }
+func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() }
+func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() }
+func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() }
+func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() }
+func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() }
+func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() }
+func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() }
+func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() }
+func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() }
+func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() }
+func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() }
+func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() }
+func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() }
+func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() }
+func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() }
+func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() }
+func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() }
+func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() }
+func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() }
+func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() }
+func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() }
+func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() }
+func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() }
+func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() }
+func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() }
+func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() }
+func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() }
+func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() }
+func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() }
+func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() }
+func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() }
+func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() }
+func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() }
+func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() }
+func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() }
+func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() }
+func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() }
+func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() }
+func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() }
+func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() }
+func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() }
+func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() }
+func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() }
+func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() }
+func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() }
+func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() }
+func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() }
+func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() }
+func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() }
+func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() }
+func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() }
+func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() }
+func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() }
+func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() }
+func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() }
+func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() }
+func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() }
+func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() }
+func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() }
+func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() }
+func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() }
+func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() }
+func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() }
+func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() }
+func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() }
+func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() }
+func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() }
+func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() }
+func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() }
+func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() }
+func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() }
+func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() }
+func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() }
+func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() }
+func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() }
+func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() }
+func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() }
+func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() }
+func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() }
+func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() }
+func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() }
+func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() }
+func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() }
+func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() }
+func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() }
+func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() }
+func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() }
+func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() }
+func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() }
+func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() }
+func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() }
+func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() }
+func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() }
+func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() }
+func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() }
+func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() }
+func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() }
+func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() }
+func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() }
+func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() }
+func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() }
+func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() }
+func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() }
+func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() }
+func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() }
+func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() }
+func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() }
+func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() }
+func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() }
+func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
+func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
+func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
+func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
+func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
+func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
+func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
+func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
+func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
+func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
+func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
+func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
+func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
+func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
+func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
+func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
+func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
+func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
+func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
+func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
+func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
+func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
+func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
+func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
+func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
+func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
+func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
+func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
+func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
+func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
+func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
+func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
+func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
+func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
+func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
+func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
+func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
+func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
+func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
+func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
+func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
+func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
+func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
+func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
+func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
+func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
+func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
+func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
+func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
+func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
+func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
+func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
+func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
+func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
+func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
+func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
+func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
+func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
+func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
+func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
+func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
+func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
+func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
+func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
+func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
+func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
+func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
+func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
+func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
+func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
+func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
+func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
+func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
+func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
+func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
+func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
+func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
+func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
+func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
+func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
+func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
+func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
+func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
+func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
+func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
+func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
+func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
+func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
+func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
+func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
+func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
+func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
+func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
+func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
+func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
+func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
+func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
+func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
+func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
+func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
+func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
+func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
+func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
+func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
+func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
+func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
+func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
+func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
+func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
+func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
+func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
+func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
+func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
+func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
+func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
+func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
+func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
+func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
+func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
+func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
+func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
+func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
+func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
+func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
+func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
+func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
+func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
+func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
+func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
+func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
+func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
+func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
+func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
+func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
+func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
+func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
+func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
+func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
+func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
+func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
+func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
+func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
+func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
+func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
+func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
+func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
+func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
+func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
+func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
+func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
+func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
+func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
+func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
+func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
+func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
+func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
+func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
+func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
+func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
+func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
+func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
+func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
+func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
+func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
+func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
+func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
+func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
+func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
+func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
+func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
+func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
+func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
+func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
+func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
+func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
+func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
+func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
+func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
+func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
+func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
+func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
+func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
+func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
+func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
+func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
+func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
+func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
+func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
+func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
+func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
+func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
+func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
+func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
+func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
+func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
+func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
+func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
+func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
+func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
+func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
+func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
+func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
+func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
+func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
+func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
+func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
+func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
+func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
+func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
+func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
+func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
+func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
+func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
+func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
+func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
+func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
+func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
+func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
+func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
+func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
+func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
+func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
+func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
+func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
+func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
+func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
+func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
+func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
+func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
+func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
+func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
+func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
+func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
+func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
+func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
+func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
+func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
+func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
+func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
+func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
+func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
+func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
+func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
+func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
+func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
+func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
+func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
+func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
+func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
+func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
+func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
+func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
+func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
+func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
+func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
+func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
+func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
+func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
+func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
+func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
+func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
+func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
+func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
+func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
+func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
+func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
+func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
+func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
+func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
+func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
+func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
+func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
+func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
+func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
+func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
+func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
+func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
+func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
+func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
+func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
+func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
+func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
+func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
+func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
+func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
+func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
+func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
+func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
+func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
+func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
+func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
+func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
+func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
+func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
+func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
+func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
+func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
+func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
+func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
+func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
+func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
+func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
+func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
+func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
+func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
+func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
+func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
+func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
+func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
+func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
+func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
+func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
+func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
+func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
+func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
+func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
+func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
+func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
+func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
+func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
+func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
+func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
+func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
+func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
+func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
+func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
+func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
+func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
+func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
+func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
+func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
+func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
+func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
+func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
+func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
+func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
+func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
+func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
+func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
+func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
+func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
+func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
+func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
+func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
+func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
+func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
+func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
+func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
+func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
+func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
+func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
+func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
+func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
+func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
+func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
+func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
+func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
+func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
+func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
+func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
+func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
+func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
+func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
+func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
+func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
+func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
+func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
+func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
+func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
+func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
+func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
+func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
+func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
+func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
+func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
+func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
+func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
+func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
+func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
+func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
+func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
+func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
+func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
+func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
+func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
+func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
+func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
+func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
+func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
+func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
+func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
+func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
+func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
+func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
+func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
+func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
+func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
+func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
+func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
+func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
+func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
+func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
+func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
+func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
+func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
+func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
+func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
+func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
+func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
+func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
+func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
+func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
+func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
+func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
+func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
+func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
+func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
+func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
+func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
+func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
+func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
+func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
+func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
+func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
+func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
+func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
+func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
+func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
+func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
+func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
+func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
+func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
+func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
+func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
+func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
+func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
+func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
+func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
+func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
+func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
+func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
+func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
+func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
+func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
+func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
+func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
+func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
+func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
+func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
+func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
+func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
+func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
+func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
+func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
+func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
+func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
+func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
+func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
+func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
+func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
+func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
+func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
+func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
+func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
+func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
+func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
+func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
+func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
+func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
+func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
+func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
+func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
+func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
+func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
+func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
+func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
+func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
+func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
+func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
+func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
+func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
+func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
+func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
+func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
+func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
+func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
+func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
+func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
+func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
+func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
+func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
+func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
+func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
+func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
+func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
+func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
+func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
+func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
+func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
+func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
+func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
+func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
+func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
+func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
+func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
+func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
+func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
+func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
+func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
+func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
+func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
+func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
+func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
+func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
+func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
+func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
+func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
+func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
+func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
+func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
+func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
+func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
+func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
+func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
+func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
+func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
+func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
+func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
+func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
+func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
+func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
+func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
+func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
+func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
+func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
+func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
+func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
+func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
+func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
+func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
+func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
+func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
+func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
+func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
+func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
+func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
+func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
+func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
+func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
+func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
+func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
+func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
+func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
+func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
+func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
+func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
+func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
+func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
+func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
+func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
+func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
+func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
+func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
+func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
+func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
+func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
+func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
+func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
+func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
+func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
+func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
+func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
+func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
+func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
+func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
+func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
+func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
+func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
+func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
+func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
+func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
+func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
+func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
+func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
+func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
+func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
+func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
+func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
+func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
+func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
+func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
+func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
+func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
+func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
+func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
+func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
+func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
+func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
+func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
+func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
+func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
+func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
+func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
+func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
+func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
+func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
+func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
+func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
+func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
+func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
+func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
+func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
+func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
+func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
+func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
+func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
+func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
+func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
+func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
+func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
+func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
+func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
+func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
+func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
+func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
+func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
+func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
+func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
+func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
+func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
+func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
+func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
+func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
+func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
+func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
+func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
+func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
+func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
+func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
+func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
+func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
+func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
+func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
+func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
+func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
+func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
+func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
+func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
+func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
+func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
+func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
+func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
+func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
+func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
+func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
+func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
+func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
+func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
+func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
+func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
+func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
+func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
+func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
+func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
+func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
+func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
+func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
+func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
+func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
+func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
+func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
+func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
+func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
+func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
+func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
+func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
+func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
+func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
+func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
+func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
+func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
+func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
+func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
+func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
+func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
+func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
+func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
+func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
+func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
+func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
+func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
+func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
+func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
+func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
+func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
+func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
+func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
+func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
+func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
+func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
+func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
+func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
+func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
+func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
+func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
+func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
+func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
+func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
+func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
+func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
+func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
+func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
+func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
+func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
+func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
+func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
+func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
+func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
+func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
+func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
+func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
+func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
+func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
+func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
+func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
+func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
+func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
+func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
+func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
+func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
+func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
+func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
+func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
+func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
+func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
+func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
+func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
+func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
+func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
+func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
+func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
+func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
+func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
+func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
+func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
+func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
+func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
+func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
+func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
+func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
+func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
+func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
+func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
+func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
+func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
+func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
+func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
+func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
+func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
+func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
+func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
+func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
+func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
+func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
+func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
+func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
+func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
+func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
+func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
+func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
+func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
+func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
+func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
+func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
+func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
+func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
+func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
+func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
+func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
+func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
+func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
+func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
+func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
+func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
+func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
+func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
+func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
+func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
+func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
+func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
+func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
+func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
+func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
+func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
+func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
+func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
+func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
+func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
+func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
+func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
+func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
+func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
+func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
+func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
+func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
+func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
+func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
+func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
+func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
+func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
+func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
+func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
+func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
+func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
+func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
+func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
+func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
+func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
+func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
+func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
+func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
+func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
+func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
+func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
+func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
+func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
+func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
+func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
+func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
+func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
+func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
+func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
+func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
+func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
+func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
+func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
+func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
+func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
+func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
+func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
+func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
+func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
+func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
+func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
+func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
+func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
+func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
+func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
+func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
+func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
+func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
+func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
+func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
+func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
+func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
+func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
+func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
+func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
+func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
+func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
+func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
+func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
+func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
+func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
+func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
+func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
+func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
+func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
+func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
+func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
+func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
+func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
+func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
+func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
+func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
+func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
+func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
+func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
+func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
+func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
+func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
+func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
+func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
+func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
+func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
+func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
+func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
+func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
+func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
+func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
+func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
+func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
+func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
+func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
+func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
+func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
+func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
+func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
+func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
+func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
+func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
+func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
+func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
+func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
+func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
+func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
+func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
+func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
+func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
+func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
+func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
+func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
+func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
+func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
+func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
+func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
+func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
+func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
+func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
+func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
+func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
+func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
+func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
+func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
+func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
+func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
+func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
+func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
+func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
+func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
+func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
+func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
+func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
+func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
+func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
+func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
+func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
+func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
+func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
+func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
+func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
+func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
+func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
+func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
+func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
+func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
+func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
+func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
+func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
+func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
+func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
+func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
+func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
+func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
+func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
+func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
+func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
+func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
+func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
+func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
+func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
+func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
+func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
+func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
+func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
+func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
+func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
+func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
+func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
+func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
+func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
+func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
+func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
+func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
+func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
+func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
+func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
+func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
+func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
+func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
+func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
+func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
+func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
+func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
+func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
+func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
+func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
+func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
+func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
+func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
+func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
+func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
+func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
+func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
+func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
+func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
+func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
+func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
+func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
+func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
+func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
index 00c2d0e06..f0c599ac5 100644
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -2,6 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package runtime_test
+
+import (
+ . "runtime"
+ "sync"
+ "testing"
+ "time"
+ "unsafe"
+)
+
+// See stack.h.
+const (
+ StackGuard = 256
+ StackLimit = 128
+)
+
// Test stack split logic by calling functions of every frame size
// from near 0 up to and beyond the default segment size (4k).
// Each of those functions reports its SP + stack limit, and then
@@ -28,22 +44,6 @@
// stack_test.go:22: after runtime_test.stack3860: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
// stack_test.go:22: after runtime_test.stack3864: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
// FAIL
-
-package runtime_test
-
-import (
- . "runtime"
- "testing"
- "time"
- "unsafe"
-)
-
-// See stack.h.
-const (
- StackGuard = 256
- StackLimit = 128
-)
-
func TestStackSplit(t *testing.T) {
for _, f := range splitTests {
sp, guard := f()
@@ -56,218 +56,6 @@ func TestStackSplit(t *testing.T) {
}
}
-var splitTests = []func() (uintptr, uintptr){
- // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt
- stack4, stack8, stack12, stack16, stack20, stack24, stack28,
- stack32, stack36, stack40, stack44, stack48, stack52, stack56,
- stack60, stack64, stack68, stack72, stack76, stack80, stack84,
- stack88, stack92, stack96, stack100, stack104, stack108, stack112,
- stack116, stack120, stack124, stack128, stack132, stack136,
- stack140, stack144, stack148, stack152, stack156, stack160,
- stack164, stack168, stack172, stack176, stack180, stack184,
- stack188, stack192, stack196, stack200, stack204, stack208,
- stack212, stack216, stack220, stack224, stack228, stack232,
- stack236, stack240, stack244, stack248, stack252, stack256,
- stack260, stack264, stack268, stack272, stack276, stack280,
- stack284, stack288, stack292, stack296, stack300, stack304,
- stack308, stack312, stack316, stack320, stack324, stack328,
- stack332, stack336, stack340, stack344, stack348, stack352,
- stack356, stack360, stack364, stack368, stack372, stack376,
- stack380, stack384, stack388, stack392, stack396, stack400,
- stack404, stack408, stack412, stack416, stack420, stack424,
- stack428, stack432, stack436, stack440, stack444, stack448,
- stack452, stack456, stack460, stack464, stack468, stack472,
- stack476, stack480, stack484, stack488, stack492, stack496,
- stack500, stack504, stack508, stack512, stack516, stack520,
- stack524, stack528, stack532, stack536, stack540, stack544,
- stack548, stack552, stack556, stack560, stack564, stack568,
- stack572, stack576, stack580, stack584, stack588, stack592,
- stack596, stack600, stack604, stack608, stack612, stack616,
- stack620, stack624, stack628, stack632, stack636, stack640,
- stack644, stack648, stack652, stack656, stack660, stack664,
- stack668, stack672, stack676, stack680, stack684, stack688,
- stack692, stack696, stack700, stack704, stack708, stack712,
- stack716, stack720, stack724, stack728, stack732, stack736,
- stack740, stack744, stack748, stack752, stack756, stack760,
- stack764, stack768, stack772, stack776, stack780, stack784,
- stack788, stack792, stack796, stack800, stack804, stack808,
- stack812, stack816, stack820, stack824, stack828, stack832,
- stack836, stack840, stack844, stack848, stack852, stack856,
- stack860, stack864, stack868, stack872, stack876, stack880,
- stack884, stack888, stack892, stack896, stack900, stack904,
- stack908, stack912, stack916, stack920, stack924, stack928,
- stack932, stack936, stack940, stack944, stack948, stack952,
- stack956, stack960, stack964, stack968, stack972, stack976,
- stack980, stack984, stack988, stack992, stack996, stack1000,
- stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
- stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
- stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
- stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
- stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
- stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
- stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
- stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
- stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
- stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
- stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
- stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
- stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
- stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
- stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
- stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
- stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
- stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
- stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
- stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
- stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
- stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
- stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
- stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
- stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
- stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
- stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
- stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
- stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
- stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
- stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
- stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
- stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
- stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
- stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
- stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
- stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
- stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
- stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
- stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
- stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
- stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
- stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
- stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
- stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
- stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
- stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
- stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
- stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
- stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
- stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
- stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
- stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
- stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
- stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
- stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
- stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
- stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
- stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
- stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
- stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
- stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
- stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
- stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
- stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
- stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
- stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
- stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
- stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
- stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
- stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
- stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
- stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
- stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
- stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
- stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
- stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
- stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
- stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
- stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
- stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
- stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
- stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
- stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
- stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
- stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
- stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
- stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
- stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
- stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
- stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
- stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
- stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
- stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
- stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
- stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
- stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
- stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
- stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
- stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
- stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
- stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
- stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
- stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
- stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
- stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
- stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
- stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
- stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
- stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
- stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
- stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
- stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
- stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
- stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
- stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
- stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
- stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
- stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
- stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
- stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
- stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
- stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
- stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
- stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
- stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
- stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
- stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
- stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
- stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
- stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
- stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
- stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
- stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
- stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
- stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
- stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
- stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
- stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
- stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
- stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
- stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
- stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
- stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
- stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
- stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
- stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
- stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
- stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
- stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
- stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
- stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
- stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
- stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
- stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
- stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
- stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
- stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
- stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
- stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
- stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
- stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
- stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
- stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
- stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
- stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
- stack4988, stack4992, stack4996, stack5000,
-}
-
var Used byte
func use(buf []byte) {
@@ -276,1258 +64,6 @@ func use(buf []byte) {
}
}
-// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
-func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() }
-func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() }
-func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() }
-func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() }
-func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() }
-func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() }
-func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() }
-func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() }
-func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() }
-func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() }
-func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() }
-func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() }
-func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() }
-func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() }
-func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() }
-func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() }
-func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() }
-func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() }
-func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() }
-func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() }
-func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() }
-func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() }
-func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() }
-func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() }
-func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() }
-func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() }
-func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() }
-func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() }
-func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() }
-func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() }
-func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() }
-func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() }
-func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() }
-func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() }
-func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() }
-func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() }
-func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() }
-func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() }
-func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() }
-func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() }
-func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() }
-func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() }
-func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() }
-func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() }
-func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() }
-func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() }
-func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() }
-func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() }
-func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() }
-func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() }
-func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() }
-func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() }
-func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() }
-func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() }
-func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() }
-func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() }
-func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() }
-func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() }
-func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() }
-func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() }
-func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() }
-func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() }
-func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() }
-func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() }
-func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() }
-func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() }
-func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() }
-func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() }
-func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() }
-func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() }
-func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() }
-func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() }
-func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() }
-func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() }
-func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() }
-func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() }
-func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() }
-func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() }
-func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() }
-func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() }
-func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() }
-func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() }
-func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() }
-func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() }
-func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() }
-func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() }
-func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() }
-func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() }
-func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() }
-func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() }
-func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() }
-func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() }
-func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() }
-func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() }
-func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() }
-func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() }
-func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() }
-func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() }
-func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() }
-func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() }
-func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() }
-func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() }
-func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() }
-func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() }
-func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() }
-func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() }
-func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() }
-func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() }
-func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() }
-func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() }
-func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() }
-func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() }
-func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() }
-func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() }
-func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() }
-func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() }
-func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() }
-func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() }
-func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() }
-func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() }
-func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() }
-func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() }
-func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() }
-func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() }
-func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() }
-func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() }
-func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() }
-func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() }
-func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() }
-func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() }
-func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() }
-func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() }
-func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() }
-func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() }
-func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() }
-func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() }
-func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() }
-func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() }
-func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() }
-func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() }
-func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() }
-func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() }
-func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() }
-func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() }
-func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() }
-func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() }
-func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() }
-func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() }
-func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() }
-func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() }
-func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() }
-func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() }
-func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() }
-func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() }
-func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() }
-func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() }
-func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() }
-func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() }
-func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() }
-func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() }
-func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() }
-func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() }
-func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() }
-func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() }
-func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() }
-func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() }
-func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() }
-func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() }
-func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() }
-func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() }
-func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() }
-func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() }
-func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() }
-func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() }
-func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() }
-func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() }
-func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() }
-func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() }
-func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() }
-func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() }
-func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() }
-func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() }
-func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() }
-func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() }
-func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() }
-func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() }
-func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() }
-func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() }
-func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() }
-func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() }
-func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() }
-func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() }
-func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() }
-func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() }
-func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() }
-func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() }
-func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() }
-func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() }
-func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() }
-func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() }
-func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() }
-func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() }
-func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() }
-func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() }
-func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() }
-func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() }
-func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() }
-func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() }
-func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() }
-func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() }
-func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() }
-func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() }
-func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() }
-func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() }
-func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() }
-func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() }
-func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() }
-func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() }
-func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() }
-func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() }
-func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() }
-func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() }
-func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() }
-func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() }
-func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() }
-func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() }
-func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() }
-func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() }
-func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() }
-func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() }
-func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() }
-func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() }
-func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() }
-func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() }
-func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() }
-func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() }
-func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() }
-func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() }
-func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() }
-func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() }
-func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() }
-func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() }
-func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() }
-func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() }
-func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() }
-func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() }
-func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() }
-func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() }
-func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() }
-func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
-func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
-func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
-func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
-func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
-func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
-func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
-func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
-func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
-func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
-func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
-func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
-func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
-func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
-func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
-func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
-func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
-func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
-func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
-func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
-func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
-func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
-func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
-func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
-func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
-func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
-func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
-func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
-func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
-func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
-func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
-func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
-func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
-func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
-func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
-func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
-func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
-func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
-func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
-func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
-func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
-func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
-func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
-func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
-func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
-func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
-func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
-func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
-func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
-func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
-func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
-func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
-func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
-func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
-func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
-func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
-func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
-func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
-func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
-func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
-func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
-func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
-func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
-func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
-func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
-func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
-func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
-func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
-func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
-func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
-func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
-func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
-func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
-func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
-func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
-func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
-func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
-func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
-func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
-func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
-func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
-func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
-func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
-func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
-func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
-func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
-func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
-func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
-func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
-func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
-func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
-func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
-func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
-func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
-func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
-func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
-func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
-func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
-func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
-func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
-func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
-func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
-func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
-func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
-func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
-func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
-func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
-func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
-func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
-func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
-func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
-func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
-func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
-func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
-func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
-func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
-func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
-func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
-func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
-func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
-func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
-func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
-func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
-func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
-func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
-func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
-func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
-func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
-func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
-func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
-func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
-func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
-func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
-func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
-func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
-func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
-func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
-func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
-func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
-func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
-func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
-func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
-func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
-func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
-func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
-func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
-func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
-func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
-func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
-func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
-func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
-func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
-func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
-func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
-func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
-func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
-func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
-func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
-func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
-func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
-func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
-func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
-func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
-func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
-func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
-func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
-func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
-func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
-func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
-func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
-func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
-func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
-func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
-func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
-func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
-func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
-func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
-func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
-func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
-func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
-func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
-func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
-func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
-func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
-func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
-func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
-func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
-func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
-func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
-func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
-func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
-func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
-func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
-func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
-func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
-func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
-func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
-func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
-func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
-func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
-func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
-func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
-func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
-func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
-func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
-func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
-func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
-func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
-func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
-func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
-func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
-func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
-func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
-func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
-func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
-func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
-func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
-func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
-func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
-func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
-func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
-func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
-func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
-func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
-func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
-func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
-func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
-func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
-func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
-func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
-func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
-func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
-func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
-func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
-func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
-func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
-func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
-func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
-func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
-func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
-func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
-func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
-func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
-func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
-func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
-func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
-func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
-func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
-func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
-func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
-func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
-func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
-func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
-func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
-func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
-func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
-func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
-func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
-func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
-func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
-func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
-func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
-func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
-func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
-func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
-func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
-func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
-func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
-func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
-func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
-func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
-func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
-func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
-func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
-func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
-func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
-func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
-func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
-func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
-func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
-func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
-func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
-func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
-func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
-func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
-func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
-func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
-func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
-func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
-func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
-func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
-func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
-func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
-func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
-func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
-func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
-func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
-func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
-func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
-func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
-func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
-func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
-func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
-func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
-func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
-func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
-func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
-func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
-func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
-func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
-func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
-func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
-func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
-func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
-func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
-func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
-func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
-func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
-func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
-func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
-func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
-func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
-func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
-func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
-func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
-func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
-func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
-func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
-func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
-func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
-func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
-func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
-func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
-func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
-func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
-func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
-func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
-func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
-func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
-func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
-func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
-func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
-func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
-func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
-func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
-func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
-func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
-func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
-func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
-func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
-func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
-func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
-func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
-func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
-func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
-func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
-func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
-func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
-func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
-func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
-func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
-func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
-func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
-func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
-func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
-func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
-func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
-func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
-func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
-func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
-func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
-func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
-func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
-func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
-func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
-func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
-func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
-func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
-func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
-func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
-func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
-func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
-func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
-func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
-func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
-func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
-func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
-func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
-func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
-func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
-func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
-func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
-func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
-func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
-func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
-func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
-func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
-func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
-func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
-func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
-func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
-func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
-func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
-func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
-func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
-func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
-func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
-func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
-func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
-func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
-func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
-func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
-func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
-func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
-func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
-func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
-func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
-func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
-func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
-func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
-func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
-func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
-func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
-func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
-func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
-func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
-func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
-func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
-func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
-func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
-func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
-func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
-func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
-func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
-func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
-func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
-func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
-func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
-func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
-func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
-func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
-func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
-func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
-func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
-func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
-func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
-func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
-func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
-func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
-func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
-func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
-func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
-func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
-func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
-func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
-func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
-func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
-func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
-func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
-func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
-func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
-func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
-func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
-func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
-func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
-func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
-func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
-func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
-func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
-func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
-func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
-func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
-func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
-func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
-func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
-func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
-func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
-func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
-func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
-func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
-func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
-func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
-func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
-func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
-func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
-func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
-func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
-func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
-func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
-func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
-func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
-func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
-func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
-func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
-func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
-func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
-func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
-func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
-func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
-func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
-func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
-func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
-func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
-func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
-func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
-func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
-func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
-func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
-func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
-func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
-func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
-func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
-func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
-func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
-func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
-func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
-func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
-func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
-func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
-func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
-func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
-func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
-func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
-func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
-func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
-func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
-func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
-func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
-func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
-func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
-func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
-func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
-func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
-func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
-func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
-func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
-func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
-func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
-func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
-func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
-func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
-func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
-func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
-func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
-func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
-func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
-func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
-func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
-func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
-func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
-func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
-func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
-func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
-func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
-func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
-func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
-func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
-func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
-func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
-func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
-func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
-func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
-func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
-func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
-func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
-func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
-func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
-func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
-func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
-func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
-func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
-func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
-func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
-func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
-func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
-func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
-func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
-func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
-func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
-func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
-func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
-func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
-func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
-func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
-func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
-func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
-func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
-func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
-func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
-func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
-func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
-func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
-func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
-func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
-func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
-func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
-func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
-func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
-func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
-func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
-func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
-func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
-func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
-func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
-func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
-func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
-func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
-func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
-func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
-func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
-func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
-func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
-func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
-func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
-func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
-func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
-func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
-func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
-func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
-func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
-func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
-func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
-func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
-func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
-func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
-func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
-func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
-func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
-func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
-func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
-func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
-func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
-func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
-func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
-func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
-func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
-func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
-func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
-func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
-func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
-func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
-func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
-func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
-func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
-func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
-func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
-func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
-func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
-func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
-func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
-func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
-func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
-func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
-func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
-func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
-func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
-func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
-func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
-func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
-func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
-func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
-func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
-func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
-func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
-func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
-func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
-func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
-func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
-func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
-func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
-func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
-func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
-func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
-func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
-func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
-func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
-func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
-func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
-func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
-func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
-func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
-func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
-func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
-func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
-func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
-func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
-func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
-func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
-func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
-func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
-func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
-func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
-func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
-func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
-func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
-func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
-func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
-func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
-func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
-func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
-func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
-func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
-func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
-func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
-func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
-func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
-func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
-func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
-func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
-func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
-func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
-func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
-func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
-func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
-func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
-func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
-func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
-func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
-func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
-func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
-func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
-func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
-func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
-func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
-func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
-func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
-func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
-func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
-func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
-func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
-func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
-func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
-func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
-func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
-func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
-func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
-func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
-func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
-func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
-func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
-func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
-func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
-func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
-func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
-func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
-func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
-func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
-func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
-func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
-func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
-func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
-func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
-func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
-func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
-func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
-func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
-func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
-func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
-func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
-func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
-func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
-func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
-func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
-func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
-func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
-func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
-func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
-func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
-func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
-func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
-func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
-func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
-func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
-func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
-func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
-func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
-func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
-func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
-func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
-func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
-func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
-func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
-func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
-func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
-func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
-func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
-func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
-func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
-func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
-func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
-func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
-func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
-func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
-func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
-func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
-func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
-func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
-func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
-func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
-func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
-func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
-func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
-func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
-func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
-func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
-func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
-func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
-func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
-func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
-func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
-func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
-func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
-func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
-func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
-func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
-func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
-func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
-func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
-func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
-func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
-func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
-func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
-func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
-func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
-func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
-func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
-func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
-func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
-func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
-func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
-func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
-func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
-func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
-func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
-func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
-func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
-func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
-func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
-func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
-func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
-func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
-func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
-func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
-func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
-func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
-func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
-func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
-func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
-func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
-func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
-func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
-func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
-func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
-func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
-func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
-func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
-func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
-func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
-func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
-func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
-func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
-func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
-func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
-func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
-func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
-func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
-func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
-func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
-func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
-func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
-func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
-func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
-func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
-func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
-func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
-func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
-func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
-func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
-func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
-func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
-func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
-func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
-func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
-func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
-func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
-func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
-func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
-func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
-func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
-func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
-func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
-func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
-func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
-func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
-func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
-func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
-func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
-func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
-func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
-func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
-func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
-func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
-func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
-func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
-func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
-func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
-func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
-func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
-func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
-func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
-func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
-func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
-func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
-func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
-func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
-func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
-func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
-func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
-func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
-func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
-func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
-func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
-func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
-func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
-func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
-func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
-func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
-func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
-func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
-func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
-func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
-func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
-func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
-func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
-func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
-func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
-func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
-func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
-func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
-func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
-func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
-func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
-func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
-func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
-func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
-func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
-func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
-func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
-func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
-func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
-func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
-func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
-func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
-func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
-func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
-func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
-func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
-func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
-func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
-func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
-func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
-func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
-func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
-func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
-func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
-func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
-func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
-func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
-func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
-func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
-func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
-func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
-func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
-func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
-func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
-func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
-func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
-func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
-func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
-func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
-func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
-func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
-func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
-func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
-func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
-func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
-func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
-func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
-func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
-func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
-func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
-func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
-func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
-func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
-func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
-func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
-func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
-func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
-func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
-func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
-func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
-
// TestStackMem measures per-thread stack segment cache behavior.
// The test consumed up to 500MB in the past.
func TestStackMem(t *testing.T) {
@@ -1576,9 +112,172 @@ func TestStackMem(t *testing.T) {
if consumed > estimate {
t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
}
- inuse := s1.StackInuse - s0.StackInuse
+ // Due to broken stack memory accounting (http://golang.org/issue/7468),
+ // StackInuse can decrease during function execution, so we cast the values to int64.
+ inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
t.Logf("Inuse %vMB for stack mem", inuse>>20)
if inuse > 4<<20 {
t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
}
}
+
+// Test stack growing in different contexts.
+func TestStackGrowth(t *testing.T) {
+ switch GOARCH {
+ case "386", "arm":
+ t.Skipf("skipping test on %q; see issue 8083", GOARCH)
+ }
+ t.Parallel()
+ var wg sync.WaitGroup
+
+ // in a normal goroutine
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ growStack()
+ }()
+ wg.Wait()
+
+ // in locked goroutine
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ LockOSThread()
+ growStack()
+ UnlockOSThread()
+ }()
+ wg.Wait()
+
+ // in finalizer
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ done := make(chan bool)
+ go func() {
+ s := new(string)
+ SetFinalizer(s, func(ss *string) {
+ growStack()
+ done <- true
+ })
+ s = nil
+ done <- true
+ }()
+ <-done
+ GC()
+ select {
+ case <-done:
+ case <-time.After(20 * time.Second):
+ t.Fatal("finalizer did not run")
+ }
+ }()
+ wg.Wait()
+}
+
+// ... and in init
+//func init() {
+// growStack()
+//}
+
+func growStack() {
+ n := 1 << 10
+ if testing.Short() {
+ n = 1 << 8
+ }
+ for i := 0; i < n; i++ {
+ x := 0
+ growStackIter(&x, i)
+ if x != i+1 {
+ panic("stack is corrupted")
+ }
+ }
+ GC()
+}
+
+// This function is not an anonimous func, so that the compiler can do escape
+// analysis and place x on stack (and subsequently stack growth update the pointer).
+func growStackIter(p *int, n int) {
+ if n == 0 {
+ *p = n + 1
+ GC()
+ return
+ }
+ *p = n + 1
+ x := 0
+ growStackIter(&x, n-1)
+ if x != n {
+ panic("stack is corrupted")
+ }
+}
+
+func TestStackGrowthCallback(t *testing.T) {
+ t.Parallel()
+ var wg sync.WaitGroup
+
+ // test stack growth at chan op
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ c := make(chan int, 1)
+ growStackWithCallback(func() {
+ c <- 1
+ <-c
+ })
+ }()
+
+ // test stack growth at map op
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ m := make(map[int]int)
+ growStackWithCallback(func() {
+ _, _ = m[1]
+ m[1] = 1
+ })
+ }()
+
+ // test stack growth at goroutine creation
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ growStackWithCallback(func() {
+ done := make(chan bool)
+ go func() {
+ done <- true
+ }()
+ <-done
+ })
+ }()
+
+ wg.Wait()
+}
+
+func growStackWithCallback(cb func()) {
+ var f func(n int)
+ f = func(n int) {
+ if n == 0 {
+ cb()
+ return
+ }
+ f(n - 1)
+ }
+ for i := 0; i < 1<<10; i++ {
+ f(i)
+ }
+}
+
+// TestDeferPtrs tests the adjustment of Defer's argument pointers (p aka &y)
+// during a stack copy.
+func set(p *int, x int) {
+ *p = x
+}
+func TestDeferPtrs(t *testing.T) {
+ var y int
+
+ defer func() {
+ if y != 42 {
+ t.Errorf("defer's stack references were not adjusted appropriately")
+ }
+ }()
+ defer set(&y, 42)
+ growStack()
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index b79acbe1c..97a69d07b 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -46,10 +46,8 @@ gostringsize(intgo l)
if(l == 0)
return runtime·emptystring;
- // leave room for NUL for C runtime (e.g., callers of getenv)
- s.str = runtime·mallocgc(l+1, 0, FlagNoScan|FlagNoZero);
+ s.str = runtime·mallocgc(l, 0, FlagNoScan|FlagNoZero);
s.len = l;
- s.str[l] = 0;
for(;;) {
ms = runtime·maxstring;
if((uintptr)l <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)l))
@@ -80,6 +78,7 @@ runtime·gostringn(byte *str, intgo l)
return s;
}
+// used by cmd/cgo
Slice
runtime·gobytes(byte *p, intgo n)
{
@@ -102,11 +101,8 @@ runtime·gostringnocopy(byte *str)
return s;
}
-void
-runtime·cstringToGo(byte *str, String s)
-{
+func cstringToGo(str *byte) (s String) {
s = runtime·gostringnocopy(str);
- FLUSH(&s);
}
String
@@ -179,14 +175,35 @@ concatstring(intgo n, String *s)
return out;
}
-// NOTE: Cannot use func syntax, because we need the ...,
-// to signal to the garbage collector that this function does
-// not have a fixed size argument count.
#pragma textflag NOSPLIT
-void
-runtime·concatstring(intgo n, String s1, ...)
-{
- (&s1)[n] = concatstring(n, &s1);
+func concatstring2(s1 String, s2 String) (res String) {
+ USED(&s2);
+ res = concatstring(2, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring3(s1 String, s2 String, s3 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ res = concatstring(3, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring4(s1 String, s2 String, s3 String, s4 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ USED(&s4);
+ res = concatstring(4, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring5(s1 String, s2 String, s3 String, s4 String, s5 String) (res String) {
+ USED(&s2);
+ USED(&s3);
+ USED(&s4);
+ USED(&s5);
+ res = concatstring(5, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstrings(s Slice) (res String) {
+ res = concatstring(s.len, (String*)s.array);
}
func eqstring(s1 String, s2 String) (v bool) {
@@ -219,6 +236,25 @@ runtime·strcmp(byte *s1, byte *s2)
}
}
+int32
+runtime·strncmp(byte *s1, byte *s2, uintptr n)
+{
+ uintptr i;
+ byte c1, c2;
+
+ for(i=0; i<n; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ break;
+ }
+ return 0;
+}
+
byte*
runtime·strstr(byte *s1, byte *s2)
{
@@ -258,11 +294,35 @@ func slicebytetostring(b Slice) (s String) {
runtime·memmove(s.str, b.array, s.len);
}
+func slicebytetostringtmp(b Slice) (s String) {
+ void *pc;
+
+ if(raceenabled) {
+ pc = runtime·getcallerpc(&b);
+ runtime·racereadrangepc(b.array, b.len, pc, runtime·slicebytetostringtmp);
+ }
+
+ // Return a "string" referring to the actual []byte bytes.
+ // This is only for use by internal compiler optimizations
+ // that know that the string form will be discarded before
+ // the calling goroutine could possibly modify the original
+ // slice or synchronize with another goroutine.
+ // Today, the only such case is a m[string(k)] lookup where
+ // m is a string-keyed map and k is a []byte.
+ s.str = b.array;
+ s.len = b.len;
+}
+
func stringtoslicebyte(s String) (b Slice) {
- b.array = runtime·mallocgc(s.len, 0, FlagNoScan|FlagNoZero);
+ uintptr cap;
+
+ cap = runtime·roundupsize(s.len);
+ b.array = runtime·mallocgc(cap, 0, FlagNoScan|FlagNoZero);
b.len = s.len;
- b.cap = s.len;
+ b.cap = cap;
runtime·memmove(b.array, s.str, s.len);
+ if(cap != b.len)
+ runtime·memclr(b.array+b.len, cap-b.len);
}
func slicerunetostring(b Slice) (s String) {
@@ -297,6 +357,7 @@ func stringtoslicerune(s String) (b Slice) {
intgo n;
int32 dum, *r;
uint8 *p, *ep;
+ uintptr mem;
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
@@ -308,13 +369,18 @@ func stringtoslicerune(s String) (b Slice) {
n++;
}
- b.array = runtime·mallocgc(n*sizeof(r[0]), 0, FlagNoScan|FlagNoZero);
+ if(n > MaxMem/sizeof(r[0]))
+ runtime·throw("out of memory");
+ mem = runtime·roundupsize(n*sizeof(r[0]));
+ b.array = runtime·mallocgc(mem, 0, FlagNoScan|FlagNoZero);
b.len = n;
- b.cap = n;
+ b.cap = mem/sizeof(r[0]);
p = s.str;
r = (int32*)b.array;
while(p < ep)
p += runtime·charntorune(r++, p, ep-p);
+ if(b.cap > b.len)
+ runtime·memclr(b.array+b.len*sizeof(r[0]), (b.cap-b.len)*sizeof(r[0]));
}
enum
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.goc
index dd0015aee..15e1d28fa 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.goc
@@ -5,6 +5,7 @@
// Runtime symbol table parsing.
// See http://golang.org/s/go12symtab for an overview.
+package runtime
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
@@ -38,7 +39,7 @@ runtime·symtabinit(void)
// two zero bytes, a byte giving the PC quantum,
// and a byte giving the pointer width in bytes.
if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
- runtime·printf("runtime: function symbol table header: 0x%x 0x%x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
+ runtime·printf("runtime: function symbol table header: %x %x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
runtime·throw("invalid function symbol table\n");
}
@@ -86,8 +87,11 @@ runtime·funcdata(Func *f, int32 i)
if(i < 0 || i >= f->nfuncdata)
return nil;
p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
- if(sizeof(void*) == 8 && ((uintptr)p & 4))
+ if(sizeof(void*) == 8 && ((uintptr)p & 4)) {
+ if(((uintptr)f & 4))
+ runtime·printf("misaligned func %p\n", f);
p += 4;
+ }
return ((void**)p)[i];
}
@@ -224,27 +228,18 @@ runtime·funcarglen(Func *f, uintptr targetpc)
return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
}
-void
-runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline)
-{
+func funcline_go(f *Func, targetpc uintptr) (retfile String, retline int) {
// Pass strict=false here, because anyone can call this function,
// and they might just be wrong about targetpc belonging to f.
retline = funcline(f, targetpc, &retfile, false);
- FLUSH(&retline);
}
-void
-runtime·funcname_go(Func *f, String ret)
-{
+func funcname_go(f *Func) (ret String) {
ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
- FLUSH(&ret);
}
-void
-runtime·funcentry_go(Func *f, uintptr ret)
-{
+func funcentry_go(f *Func) (ret uintptr) {
ret = f->entry;
- FLUSH(&ret);
}
Func*
@@ -281,6 +276,10 @@ runtime·findfunc(uintptr addr)
return nil;
}
+func FuncForPC(pc uintptr) (ret *Func) {
+ ret = runtime·findfunc(pc);
+}
+
static bool
hasprefix(String s, int8 *p)
{
diff --git a/src/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index c2a259e5b..bfaaa00a7 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -457,8 +457,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
* we use its pthread_create and let it set up %gs
* for us. When we do that, the private storage
* we get is not at 0(GS) but at 0x468(GS).
- * To insulate the rest of the tool chain from this ugliness,
- * 8l rewrites 0(GS) into 0x468(GS) for us.
+ * 8l rewrites 0(TLS) into 0x468(GS) for us.
* To accommodate that rewrite, we translate the
* address and limit here so that 0x468(GS) maps to 0(address).
*
diff --git a/src/pkg/runtime/sys_dragonfly_386.s b/src/pkg/runtime/sys_dragonfly_386.s
index 9085ded6f..20e699966 100644
--- a/src/pkg/runtime/sys_dragonfly_386.s
+++ b/src/pkg/runtime/sys_dragonfly_386.s
@@ -155,7 +155,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $0, 4(SP) // CLOCK_REALTIME
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -172,7 +172,7 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $4, 4(SP) // CLOCK_MONOTONIC
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
diff --git a/src/pkg/runtime/sys_dragonfly_amd64.s b/src/pkg/runtime/sys_dragonfly_amd64.s
index 2fa97f207..d70d2e80c 100644
--- a/src/pkg/runtime/sys_dragonfly_amd64.s
+++ b/src/pkg/runtime/sys_dragonfly_amd64.s
@@ -125,7 +125,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
@@ -138,7 +138,7 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $4, DI // CLOCK_MONOTONIC
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index 8b4d2317d..4c97eec7b 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -135,7 +135,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ MOVL $0, 4(SP) // CLOCK_REALTIME
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -152,7 +152,9 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVL $4, 4(SP) // CLOCK_MONOTONIC
MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
@@ -307,8 +309,7 @@ TEXT runtime·i386_set_ldt(SB),NOSPLIT,$16
MOVL AX, 8(SP)
MOVL $165, AX
INT $0x80
- CMPL AX, $0xfffff001
- JLS 2(PC)
+ JAE 2(PC)
INT $3
RET
@@ -324,7 +325,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$28
MOVSL // arg 6 - newlen
MOVL $202, AX // sys___sysctl
INT $0x80
- JCC 3(PC)
+ JAE 3(PC)
NEGL AX
RET
MOVL $0, AX
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 63cd3ac07..4c5b32504 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -144,7 +144,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
@@ -157,7 +157,9 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $232, AX
- MOVQ $0, DI
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVQ $4, DI // CLOCK_MONOTONIC
LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 106d72799..3ec95a651 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -162,7 +162,9 @@ TEXT time·now(SB), NOSPLIT, $32
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), NOSPLIT, $32
- MOVW $0, R0 // CLOCK_REALTIME
+ // We can use CLOCK_MONOTONIC_FAST here when we drop
+ // support for FreeBSD 8-STABLE.
+ MOVW $4, R0 // CLOCK_MONOTONIC
MOVW $8(R13), R1
MOVW $SYS_clock_gettime, R7
SWI $0
@@ -365,6 +367,7 @@ TEXT runtime·casp(SB),NOSPLIT,$0
TEXT runtime·cas(SB),NOSPLIT,$0
B runtime·armcas(SB)
+// TODO(minux): this only supports ARMv6K+.
TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
- MOVW $0xffff1000, R0
- MOVW (R0), R0
+ WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
+ RET
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index fcda739db..b7896f178 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime
- MOVL $0, BX
+ MOVL $0, BX // CLOCK_REALTIME
LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime
- MOVL $0, BX
+ MOVL $1, BX // CLOCK_MONOTONIC
LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
@@ -383,7 +383,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
* for us. When we do that, the private storage
* we get is not at 0(GS), 4(GS), but -8(GS), -4(GS).
* To insulate the rest of the tool chain from this
- * ugliness, 8l rewrites 0(GS) into -8(GS) for us.
+ * ugliness, 8l rewrites 0(TLS) into -8(GS) for us.
* To accommodate that rewrite, we translate
* the address here and bump the limit to 0xffffffff (no limit)
* so that -8(GS) maps to 0(address).
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index 481841a67..b340c4f2c 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -76,7 +76,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
SYSCALL
RET
-TEXT runtime·raise(SB),NOSPLIT,$12
+TEXT runtime·raise(SB),NOSPLIT,$0
MOVL $186, AX // syscall - gettid
SYSCALL
MOVL AX, DI // arg 1 tid
@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
CMPQ AX, $0
JEQ fallback_gtod_nt
- MOVL $0, DI // CLOCK_REALTIME
+ MOVL $1, DI // CLOCK_MONOTONIC
LEAQ 0(SP), SI
CALL AX
MOVQ 0(SP), AX // sec
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 42aef56a7..c537a8722 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -175,7 +175,7 @@ TEXT time·now(SB), NOSPLIT, $32
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),NOSPLIT,$32
- MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $1, R0 // CLOCK_MONOTONIC
MOVW $8(R13), R1 // timespec
MOVW $SYS_clock_gettime, R7
SWI $0
diff --git a/src/pkg/runtime/sys_nacl_386.s b/src/pkg/runtime/sys_nacl_386.s
new file mode 100644
index 000000000..42ba0e0ed
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_386.s
@@ -0,0 +1,243 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $12-16
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL DI, 0(SP)
+ MOVL SI, 4(SP)
+ MOVL DX, 8(SP)
+ CALL runtime·write(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_write)
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+ JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$32
+ MOVL arg1+0(FP), AX
+ MOVL AX, 0(SP)
+ MOVL arg2+4(FP), AX
+ MOVL AX, 4(SP)
+ MOVL arg3+8(FP), AX
+ MOVL AX, 8(SP)
+ MOVL arg4+12(FP), AX
+ MOVL AX, 12(SP)
+ MOVL arg5+16(FP), AX
+ MOVL AX, 16(SP)
+ MOVL arg6+20(FP), AX
+ MOVL AX, 24(SP)
+ MOVL $0, 28(SP)
+ LEAL 24(SP), AX
+ MOVL AX, 20(SP)
+ NACL_SYSCALL(SYS_mmap)
+ RET
+
+TEXT time·now(SB),NOSPLIT,$20
+ MOVL $0, 0(SP) // real time clock
+ LEAL 8(SP), AX
+ MOVL AX, 4(SP) // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 8(SP), AX // low 32 sec
+ MOVL 12(SP), CX // high 32 sec
+ MOVL 16(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ MOVL AX, sec+0(FP)
+ MOVL CX, sec+4(FP)
+ MOVL BX, nsec+8(FP)
+ RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+ JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_clock_gettime)
+
+TEXT runtime·nanotime(SB),NOSPLIT,$20
+ MOVL $0, 0(SP) // real time clock
+ LEAL 8(SP), AX
+ MOVL AX, 4(SP) // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 8(SP), AX // low 32 sec
+ MOVL 16(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·setldt(SB),NOSPLIT,$8
+ MOVL addr+4(FP), BX // aka base
+ ADDL $0x8, BX
+ MOVL BX, 0(SP)
+ NACL_SYSCALL(SYS_tls_init)
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 6(PC)
+ MOVL $11, BX
+ MOVL BX, 0(SP)
+ MOVL $runtime·badsignal(SB), AX
+ CALL AX
+ JMP sigtramp_ret
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for sighandler
+ MOVL $11, 0(SP) // signal
+ MOVL $0, 4(SP) // siginfo
+ LEAL ctxt+4(FP), AX
+ MOVL AX, 8(SP) // context
+ MOVL DI, 12(SP) // g
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+sigtramp_ret:
+ // Enable exceptions again.
+ NACL_SYSCALL(SYS_exception_clear_flag)
+
+ // NaCl has abidcated its traditional operating system responsibility
+ // and declined to implement 'sigreturn'. Instead the only way to return
+ // to the execution of our program is to restore the registers ourselves.
+ // Unfortunately, that is impossible to do with strict fidelity, because
+ // there is no way to do the final update of PC that ends the sequence
+ // without either (1) jumping to a register, in which case the register ends
+ // holding the PC value instead of its intended value or (2) storing the PC
+ // on the stack and using RET, which imposes the requirement that SP is
+ // valid and that is okay to smash the word below it. The second would
+ // normally be the lesser of the two evils, except that on NaCl, the linker
+ // must rewrite RET into "POP reg; AND $~31, reg; JMP reg", so either way
+ // we are going to lose a register as a result of the incoming signal.
+ // Similarly, there is no way to restore EFLAGS; the usual way is to use
+ // POPFL, but NaCl rejects that instruction. We could inspect the bits and
+ // execute a sequence of instructions designed to recreate those flag
+ // settings, but that's a lot of work.
+ //
+ // Thankfully, Go's signal handlers never try to return directly to the
+ // executing code, so all the registers and EFLAGS are dead and can be
+ // smashed. The only registers that matter are the ones that are setting
+ // up for the simulated call that the signal handler has created.
+ // Today those registers are just PC and SP, but in case additional registers
+ // are relevant in the future (for example DX is the Go func context register)
+ // we restore as many registers as possible.
+ //
+ // We smash BP, because that's what the linker smashes during RET.
+ //
+ LEAL ctxt+4(FP), BP
+ ADDL $64, BP
+ MOVL 0(BP), AX
+ MOVL 4(BP), CX
+ MOVL 8(BP), DX
+ MOVL 12(BP), BX
+ MOVL 16(BP), SP
+ // 20(BP) is saved BP, never to be seen again
+ MOVL 24(BP), SI
+ MOVL 28(BP), DI
+ // 36(BP) is saved EFLAGS, never to be seen again
+ MOVL 32(BP), BP // saved PC
+ JMP BP
diff --git a/src/pkg/runtime/sys_nacl_amd64p32.s b/src/pkg/runtime/sys_nacl_amd64p32.s
new file mode 100644
index 000000000..43c172372
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_amd64p32.s
@@ -0,0 +1,413 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·settls(SB),NOSPLIT,$0
+ MOVL DI, TLS // really BP
+ RET
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $16-20
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL DI, 0(SP)
+ MOVL SI, 4(SP)
+ MOVL DX, 8(SP)
+ CALL runtime·write(SB)
+ MOVL AX, ret+16(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$16-12
+ // If using fake time and writing to stdout or stderr,
+ // emit playback header before actual data.
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ write
+ MOVL arg1+0(FP), DI
+ CMPL DI, $1
+ JEQ playback
+ CMPL DI, $2
+ JEQ playback
+
+write:
+ // Ordinary write.
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSCALL(SYS_write)
+ RET
+
+ // Write with playback header.
+ // First, lock to avoid interleaving writes.
+playback:
+ MOVL $1, BX
+ XCHGL runtime·writelock(SB), BX
+ CMPL BX, $0
+ JNE playback
+
+ // Playback header: 0 0 P B <8-byte time> <4-byte data length>
+ MOVL $(('B'<<24) | ('P'<<16)), 0(SP)
+ BSWAPQ AX
+ MOVQ AX, 4(SP)
+ MOVL arg3+8(FP), DX
+ BSWAPL DX
+ MOVL DX, 12(SP)
+ MOVL $1, DI // standard output
+ MOVL SP, SI
+ MOVL $16, DX
+ NACL_SYSCALL(SYS_write)
+
+ // Write actual data.
+ MOVL $1, DI // standard output
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSCALL(SYS_write)
+
+ // Unlock.
+ MOVL $0, runtime·writelock(SB)
+
+ RET
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL arg4+12(FP), CX
+ NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+ NACL_SYSCALL(SYS_tls_get)
+ SUBL $8, AX
+ MOVL AX, TLS
+ JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+ NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$8
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ MOVL arg3+8(FP), DX
+ MOVL arg4+12(FP), CX
+ MOVL arg5+16(FP), R8
+ MOVL arg6+20(FP), AX
+ MOVQ AX, 0(SP)
+ MOVL SP, R9
+ NACL_SYSCALL(SYS_mmap)
+ CMPL AX, $-4095
+ JNA 2(PC)
+ NEGL AX
+ RET
+
+TEXT time·now(SB),NOSPLIT,$16
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ realtime
+ MOVQ $0, DX
+ MOVQ $1000000000, CX
+ DIVQ CX
+ MOVQ AX, sec+0(FP)
+ MOVL DX, nsec+8(FP)
+ RET
+realtime:
+ MOVL $0, DI // real time clock
+ LEAL 0(SP), AX
+ MOVL AX, SI // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVL 0(SP), AX // low 32 sec
+ MOVL 4(SP), CX // high 32 sec
+ MOVL 8(SP), BX // nsec
+
+ // sec is in AX, nsec in BX
+ MOVL AX, sec+0(FP)
+ MOVL CX, sec+4(FP)
+ MOVL BX, nsec+8(FP)
+ RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+ JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+ MOVL arg1+0(FP), DI
+ MOVL arg2+4(FP), SI
+ NACL_SYSJMP(SYS_clock_gettime)
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+ MOVQ runtime·timens(SB), AX
+ CMPQ AX, $0
+ JEQ 2(PC)
+ RET
+ MOVL $0, DI // real time clock
+ LEAL 0(SP), AX
+ MOVL AX, SI // timespec
+ NACL_SYSCALL(SYS_clock_gettime)
+ MOVQ 0(SP), AX // sec
+ MOVL 8(SP), DX // nsec
+
+ // sec is in AX, nsec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$80
+ // restore TLS register at time of execution,
+ // in case it's been smashed.
+ // the TLS register is really BP, but for consistency
+ // with non-NaCl systems it is referred to here as TLS.
+ // NOTE: Cannot use SYS_tls_get here (like we do in mstart_nacl),
+ // because the main thread never calls tls_set.
+ LEAL ctxt+0(FP), AX
+ MOVL (16*4+5*8)(AX), AX
+ MOVL AX, TLS
+
+ // check that m exists
+ get_tls(CX)
+ MOVL m(CX), BX
+
+ CMPL BX, $0
+ JEQ nom
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+//JMP debughandler
+
+ // copy arguments for sighandler
+ MOVL $11, 0(SP) // signal
+ MOVL $0, 4(SP) // siginfo
+ LEAL ctxt+0(FP), AX
+ MOVL AX, 8(SP) // context
+ MOVL DI, 12(SP) // g
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+sigtramp_ret:
+ // Enable exceptions again.
+ NACL_SYSCALL(SYS_exception_clear_flag)
+
+ // Restore registers as best we can. Impossible to do perfectly.
+ // See comment in sys_nacl_386.s for extended rationale.
+ LEAL ctxt+0(FP), SI
+ ADDL $64, SI
+ MOVQ 0(SI), AX
+ MOVQ 8(SI), CX
+ MOVQ 16(SI), DX
+ MOVQ 24(SI), BX
+ MOVL 32(SI), SP // MOVL for SP sandboxing
+ // 40(SI) is saved BP aka TLS, already restored above
+ // 48(SI) is saved SI, never to be seen again
+ MOVQ 56(SI), DI
+ MOVQ 64(SI), R8
+ MOVQ 72(SI), R9
+ MOVQ 80(SI), R10
+ MOVQ 88(SI), R11
+ MOVQ 96(SI), R12
+ MOVQ 104(SI), R13
+ MOVQ 112(SI), R14
+ // 120(SI) is R15, which is owned by Native Client and must not be modified
+ MOVQ 128(SI), SI // saved PC
+ // 136(SI) is saved EFLAGS, never to be seen again
+ JMP SI
+
+debughandler:
+ // print basic information
+ LEAL ctxt+0(FP), DI
+ MOVL $runtime·sigtrampf(SB), AX
+ MOVL AX, 0(SP)
+ MOVQ (16*4+16*8)(DI), BX // rip
+ MOVQ BX, 8(SP)
+ MOVQ (16*4+0*8)(DI), BX // rax
+ MOVQ BX, 16(SP)
+ MOVQ (16*4+1*8)(DI), BX // rcx
+ MOVQ BX, 24(SP)
+ MOVQ (16*4+2*8)(DI), BX // rdx
+ MOVQ BX, 32(SP)
+ MOVQ (16*4+3*8)(DI), BX // rbx
+ MOVQ BX, 40(SP)
+ MOVQ (16*4+7*8)(DI), BX // rdi
+ MOVQ BX, 48(SP)
+ MOVQ (16*4+15*8)(DI), BX // r15
+ MOVQ BX, 56(SP)
+ MOVQ (16*4+4*8)(DI), BX // rsp
+ MOVQ 0(BX), BX
+ MOVQ BX, 64(SP)
+ CALL runtime·printf(SB)
+
+ LEAL ctxt+0(FP), DI
+ MOVQ (16*4+16*8)(DI), BX // rip
+ MOVL BX, 0(SP)
+ MOVQ (16*4+4*8)(DI), BX // rsp
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP) // lr
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL BX, 12(SP) // gp
+ CALL runtime·traceback(SB)
+
+notls:
+ MOVL 0, AX
+ RET
+
+nom:
+ MOVL 0, AX
+ RET
+
+// cannot do real signal handling yet, because gsignal has not been allocated.
+MOVL $1, DI; NACL_SYSCALL(SYS_exit)
+
+TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
+/*
+ MOVL di+0(FP), DI
+ LEAL 12(DI), BX
+ MOVL 8(DI), AX
+ ADDL 4(DI), AX
+ ADDL $2, AX
+ LEAL (BX)(AX*4), BX
+ MOVL BX, runtime·nacl_irt_query(SB)
+auxloop:
+ MOVL 0(BX), DX
+ CMPL DX, $0
+ JNE 2(PC)
+ RET
+ CMPL DX, $32
+ JEQ auxfound
+ ADDL $8, BX
+ JMP auxloop
+auxfound:
+ MOVL 4(BX), BX
+ MOVL BX, runtime·nacl_irt_query(SB)
+
+ LEAL runtime·nacl_irt_basic_v0_1_str(SB), DI
+ LEAL runtime·nacl_irt_basic_v0_1(SB), SI
+ MOVL runtime·nacl_irt_basic_v0_1_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ LEAL runtime·nacl_irt_memory_v0_3_str(SB), DI
+ LEAL runtime·nacl_irt_memory_v0_3(SB), SI
+ MOVL runtime·nacl_irt_memory_v0_3_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ LEAL runtime·nacl_irt_thread_v0_1_str(SB), DI
+ LEAL runtime·nacl_irt_thread_v0_1(SB), SI
+ MOVL runtime·nacl_irt_thread_v0_1_size(SB), DX
+ MOVL runtime·nacl_irt_query(SB), BX
+ CALL BX
+
+ // TODO: Once we have a NaCl SDK with futex syscall support,
+ // try switching to futex syscalls and here load the
+ // nacl-irt-futex-0.1 table.
+*/
+ RET
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index e1ec5337a..8f0da5c0e 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -9,6 +9,8 @@
#include "zasm_GOOS_GOARCH.h"
#include "../../cmd/ld/textflag.h"
+#define CLOCK_MONOTONIC $3
+
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$-4
MOVL $1, AX
@@ -45,21 +47,22 @@ TEXT runtime·write(SB),NOSPLIT,$-4
INT $0x80
RET
-TEXT runtime·usleep(SB),NOSPLIT,$20
+TEXT runtime·usleep(SB),NOSPLIT,$24
MOVL $0, DX
MOVL usec+0(FP), AX
MOVL $1000000, CX
DIVL CX
- MOVL AX, 12(SP) // tv_sec
+ MOVL AX, 12(SP) // tv_sec - l32
+ MOVL $0, 16(SP) // tv_sec - h32
MOVL $1000, AX
MULL DX
- MOVL AX, 16(SP) // tv_nsec
+ MOVL AX, 20(SP) // tv_nsec
MOVL $0, 0(SP)
LEAL 12(SP), AX
MOVL AX, 4(SP) // arg 1 - rqtp
MOVL $0, 8(SP) // arg 2 - rmtp
- MOVL $240, AX // sys_nanosleep
+ MOVL $91, AX // sys_nanosleep
INT $0x80
RET
@@ -107,43 +110,46 @@ TEXT runtime·madvise(SB),NOSPLIT,$-4
RET
TEXT runtime·setitimer(SB),NOSPLIT,$-4
- MOVL $83, AX
+ MOVL $69, AX
INT $0x80
RET
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
- MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
- MOVL BX, 8(SP)
+ MOVL $0, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $87, AX // sys_clock_gettime
INT $0x80
- MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // nsec
- // sec is in AX, nsec in BX
+ MOVL 12(SP), AX // sec - l32
MOVL AX, sec+0(FP)
- MOVL $0, sec+4(FP)
+ MOVL 16(SP), AX // sec - h32
+ MOVL AX, sec+4(FP)
+
+ MOVL 20(SP), BX // nsec
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),NOSPLIT,$32
- MOVL $232, AX
LEAL 12(SP), BX
- MOVL $0, 4(SP)
- MOVL BX, 8(SP)
+ MOVL CLOCK_MONOTONIC, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $87, AX // sys_clock_gettime
INT $0x80
- MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // nsec
- // sec is in AX, nsec in BX
- // convert to DX:AX nsec
- MOVL $1000000000, CX
- MULL CX
+ MOVL 16(SP), CX // sec - h32
+ IMULL $1000000000, CX
+
+ MOVL 12(SP), AX // sec - l32
+ MOVL $1000000000, BX
+ MULL BX // result in dx:ax
+
+ MOVL 20(SP), BX // nsec
ADDL BX, AX
- ADCL $0, DX
+ ADCL CX, DX // add high bits with carry
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
@@ -325,7 +331,7 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
RET
TEXT runtime·thrsleep(SB),NOSPLIT,$-4
- MOVL $300, AX // sys___thrsleep
+ MOVL $94, AX // sys___thrsleep
INT $0x80
RET
@@ -362,7 +368,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL $270, AX
+ MOVL $72, AX // sys_kevent
INT $0x80
JAE 2(PC)
NEGL AX
@@ -370,7 +376,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
// int32 runtime·closeonexec(int32 fd);
TEXT runtime·closeonexec(SB),NOSPLIT,$32
- MOVL $92, AX // fcntl
+ MOVL $92, AX // sys_fcntl
// 0(SP) is where the caller PC would be; kernel skips it
MOVL fd+0(FP), BX
MOVL BX, 4(SP) // fd
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 26dc61f71..b2a61820a 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -9,6 +9,8 @@
#include "zasm_GOOS_GOARCH.h"
#include "../../cmd/ld/textflag.h"
+#define CLOCK_MONOTONIC $3
+
// int64 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
TEXT runtime·tfork(SB),NOSPLIT,$32
@@ -62,7 +64,7 @@ TEXT runtime·thrsleep(SB),NOSPLIT,$0
MOVQ 24(SP), DX // arg 3 - tp
MOVQ 32(SP), R10 // arg 4 - lock
MOVQ 40(SP), R8 // arg 5 - abort
- MOVL $300, AX // sys___thrsleep
+ MOVL $94, AX // sys___thrsleep
SYSCALL
RET
@@ -130,7 +132,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
MOVQ SP, DI // arg 1 - rqtp
MOVQ $0, SI // arg 2 - rmtp
- MOVL $240, AX // sys_nanosleep
+ MOVL $91, AX // sys_nanosleep
SYSCALL
RET
@@ -138,7 +140,7 @@ TEXT runtime·raise(SB),NOSPLIT,$16
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, DI // arg 1 - pid
- MOVL sig+0(FP), SI // arg 2 - signum
+ MOVL sig+0(FP), SI // arg 2 - signum
MOVL $37, AX // sys_kill
SYSCALL
RET
@@ -147,7 +149,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
MOVL 8(SP), DI // arg 1 - which
MOVQ 16(SP), SI // arg 2 - itv
MOVQ 24(SP), DX // arg 3 - oitv
- MOVL $83, AX // sys_setitimer
+ MOVL $69, AX // sys_setitimer
SYSCALL
RET
@@ -155,9 +157,9 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
TEXT time·now(SB), NOSPLIT, $32
MOVQ $0, DI // arg 1 - clock_id
LEAQ 8(SP), SI // arg 2 - tp
- MOVL $232, AX // sys_clock_gettime
+ MOVL $87, AX // sys_clock_gettime
SYSCALL
- MOVL 8(SP), AX // sec
+ MOVQ 8(SP), AX // sec
MOVQ 16(SP), DX // nsec
// sec is in AX, nsec in DX
@@ -166,11 +168,11 @@ TEXT time·now(SB), NOSPLIT, $32
RET
TEXT runtime·nanotime(SB),NOSPLIT,$24
- MOVQ $0, DI // arg 1 - clock_id
+ MOVQ CLOCK_MONOTONIC, DI // arg 1 - clock_id
LEAQ 8(SP), SI // arg 2 - tp
- MOVL $232, AX // sys_clock_gettime
+ MOVL $87, AX // sys_clock_gettime
SYSCALL
- MOVL 8(SP), AX // sec
+ MOVQ 8(SP), AX // sec
MOVQ 16(SP), DX // nsec
// sec is in AX, nsec in DX
@@ -318,7 +320,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
MOVQ 32(SP), R10
MOVL 40(SP), R8
MOVQ 48(SP), R9
- MOVL $270, AX
+ MOVL $72, AX
SYSCALL
JCC 2(PC)
NEGQ AX
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index bed0f7ebe..143cd2e49 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -81,6 +81,10 @@ TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0
TEXT runtime·rfork(SB),NOSPLIT,$0
MOVL $19, AX // rfork
+ MOVL stack+8(SP), CX
+ MOVL mm+12(SP), BX // m
+ MOVL gg+16(SP), DX // g
+ MOVL fn+20(SP), SI // fn
INT $64
// In parent, return.
@@ -88,13 +92,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
JEQ 2(PC)
RET
- // In child on old stack.
- MOVL mm+12(SP), BX // m
- MOVL gg+16(SP), DX // g
- MOVL fn+20(SP), SI // fn
-
// set SP to be on the new child stack
- MOVL stack+8(SP), CX
MOVL CX, SP
// Initialize m, g.
@@ -102,8 +100,9 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
MOVL DX, g(AX)
MOVL BX, m(AX)
- // Initialize AX from TOS struct.
- MOVL procid(AX), AX
+ // Initialize procid from TOS struct.
+ // TODO: Be explicit and insert a new MOVL _tos(SB), AX here.
+ MOVL 48(AX), AX // procid
MOVL AX, m_procid(BX) // save pid as m->procid
CALL runtime·stackcheck(SB) // smashes AX, CX
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index d6702e865..e60459cb8 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -136,7 +136,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
MOVQ BX, m(AX)
// Initialize AX from pid in TLS.
- MOVQ procid(AX), AX
+ MOVQ 0(FS), AX
MOVQ AX, m_procid(BX) // save pid as m->procid
CALL runtime·stackcheck(SB) // smashes AX, CX
diff --git a/src/pkg/runtime/sys_solaris_amd64.s b/src/pkg/runtime/sys_solaris_amd64.s
new file mode 100644
index 000000000..21517693b
--- /dev/null
+++ b/src/pkg/runtime/sys_solaris_amd64.s
@@ -0,0 +1,267 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for AMD64, SunOS
+// /usr/include/sys/syscall.h for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+
+// This is needed by asm_amd64.s
+TEXT runtime·settls(SB),NOSPLIT,$8
+ RET
+
+// void libc·miniterrno(void *(*___errno)(void));
+//
+// Set the TLS errno pointer in M.
+//
+// Called using runtime·asmcgocall from os_solaris.c:/minit.
+TEXT runtime·miniterrno(SB),NOSPLIT,$0
+ // asmcgocall will put first argument into DI.
+ CALL DI // SysV ABI so returns in AX
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_perrno(BX)
+ RET
+
+// int64 runtime·nanotime1(void);
+//
+// clock_gettime(3c) wrapper because Timespec is too large for
+// runtime·nanotime stack.
+//
+// Called using runtime·sysvicall6 from os_solaris.c:/nanotime.
+TEXT runtime·nanotime1(SB),NOSPLIT,$0
+ // need space for the timespec argument.
+ SUBQ $64, SP // 16 bytes will do, but who knows in the future?
+ MOVQ $3, DI // CLOCK_REALTIME from <sys/time_impl.h>
+ MOVQ SP, SI
+ MOVQ libc·clock_gettime(SB), AX
+ CALL AX
+ MOVQ (SP), AX // tv_sec from struct timespec
+ IMULQ $1000000000, AX // multiply into nanoseconds
+ ADDQ 8(SP), AX // tv_nsec, offset should be stable.
+ ADDQ $64, SP
+ RET
+
+// pipe(3c) wrapper that returns fds in AX, DX.
+TEXT runtime·pipe1(SB),NOSPLIT,$0
+ SUBQ $16, SP // 8 bytes will do, but stack has to be 16-byte alligned
+ MOVQ SP, DI
+ MOVQ libc·pipe(SB), AX
+ CALL AX
+ MOVL 0(SP), AX
+ MOVL 4(SP), DX
+ ADDQ $16, SP
+ RET
+
+// Call a library function with SysV calling conventions.
+// The called function can take a maximum of 6 INTEGER class arguments,
+// see
+// Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
+// System V Application Binary Interface
+// AMD64 Architecture Processor Supplement
+// section 3.2.3.
+//
+// Called by runtime·asmcgocall or runtime·cgocall.
+TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0
+ // asmcgocall will put first argument into DI.
+ PUSHQ DI // save for later
+ MOVQ libcall_fn(DI), AX
+ MOVQ libcall_args(DI), R11
+ MOVQ libcall_n(DI), R10
+
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ m_perrno(BX), DX
+ CMPQ DX, $0
+ JEQ skiperrno1
+ MOVL $0, 0(DX)
+
+skiperrno1:
+ CMPQ R11, $0
+ JEQ skipargs
+ // Load 6 args into correspondent registers.
+ MOVQ 0(R11), DI
+ MOVQ 8(R11), SI
+ MOVQ 16(R11), DX
+ MOVQ 24(R11), CX
+ MOVQ 32(R11), R8
+ MOVQ 40(R11), R9
+skipargs:
+
+ // Call SysV function
+ CALL AX
+
+ // Return result
+ POPQ DI
+ MOVQ AX, libcall_r1(DI)
+ MOVQ DX, libcall_r2(DI)
+
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ m_perrno(BX), AX
+ CMPQ AX, $0
+ JEQ skiperrno2
+ MOVL 0(AX), AX
+ MOVQ AX, libcall_err(DI)
+
+skiperrno2:
+ RET
+
+// uint32 tstart_sysvicall(M *newm);
+TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
+ // DI contains first arg newm
+ MOVQ m_g0(DI), DX // g
+
+ // Make TLS entries point at g and m.
+ get_tls(BX)
+ MOVQ DX, g(BX)
+ MOVQ DI, m(BX)
+
+ // Layout new m scheduler stack on os stack.
+ MOVQ SP, AX
+ MOVQ AX, g_stackbase(DX)
+ SUBQ $(0x100000), AX // stack size
+ MOVQ AX, g_stackguard(DX)
+ MOVQ AX, g_stackguard0(DX)
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+ CALL runtime·mstart(SB)
+
+ XORL AX, AX // return 0 == success
+ RET
+
+// Careful, this is called by __sighndlr, a libc function. We must preserve
+// registers as per AMD 64 ABI.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Note that we are executing on altsigstack here, so we have
+ // more stack available than NOSPLIT would have us believe.
+ // To defeat the linker, we make our own stack frame with
+ // more space:
+ SUBQ $184, SP
+
+ // save registers
+ MOVQ BX, 32(SP)
+ MOVQ BP, 40(SP)
+ MOVQ R12, 48(SP)
+ MOVQ R13, 56(SP)
+ MOVQ R14, 64(SP)
+ MOVQ R15, 72(SP)
+
+ get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE allgood
+ MOVQ DI, 0(SP)
+ MOVQ $runtime·badsignal(SB), AX
+ CALL AX
+ RET
+
+allgood:
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 80(SP)
+
+ // Save m->libcall and m->scratch. We need to do this because we
+ // might get interrupted by a signal in runtime·asmcgocall.
+
+ // save m->libcall
+ LEAQ m_libcall(BP), R11
+ MOVQ libcall_fn(R11), R10
+ MOVQ R10, 88(SP)
+ MOVQ libcall_args(R11), R10
+ MOVQ R10, 96(SP)
+ MOVQ libcall_n(R11), R10
+ MOVQ R10, 104(SP)
+ MOVQ libcall_r1(R11), R10
+ MOVQ R10, 168(SP)
+ MOVQ libcall_r2(R11), R10
+ MOVQ R10, 176(SP)
+
+ // save m->scratch
+ LEAQ m_scratch(BP), R11
+ MOVQ 0(R11), R10
+ MOVQ R10, 112(SP)
+ MOVQ 8(R11), R10
+ MOVQ R10, 120(SP)
+ MOVQ 16(R11), R10
+ MOVQ R10, 128(SP)
+ MOVQ 24(R11), R10
+ MOVQ R10, 136(SP)
+ MOVQ 32(R11), R10
+ MOVQ R10, 144(SP)
+ MOVQ 40(R11), R10
+ MOVQ R10, 152(SP)
+
+ // save errno, it might be EINTR; stuff we do here might reset it.
+ MOVQ m_perrno(BP), R10
+ MOVL 0(R10), R10
+ MOVQ R10, 160(SP)
+
+ MOVQ g(BX), R10
+ // g = m->gsignal
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ // prepare call
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+ CALL runtime·sighandler(SB)
+
+ get_tls(BX)
+ MOVQ m(BX), BP
+ // restore libcall
+ LEAQ m_libcall(BP), R11
+ MOVQ 88(SP), R10
+ MOVQ R10, libcall_fn(R11)
+ MOVQ 96(SP), R10
+ MOVQ R10, libcall_args(R11)
+ MOVQ 104(SP), R10
+ MOVQ R10, libcall_n(R11)
+ MOVQ 168(SP), R10
+ MOVQ R10, libcall_r1(R11)
+ MOVQ 176(SP), R10
+ MOVQ R10, libcall_r2(R11)
+
+ // restore scratch
+ LEAQ m_scratch(BP), R11
+ MOVQ 112(SP), R10
+ MOVQ R10, 0(R11)
+ MOVQ 120(SP), R10
+ MOVQ R10, 8(R11)
+ MOVQ 128(SP), R10
+ MOVQ R10, 16(R11)
+ MOVQ 136(SP), R10
+ MOVQ R10, 24(R11)
+ MOVQ 144(SP), R10
+ MOVQ R10, 32(R11)
+ MOVQ 152(SP), R10
+ MOVQ R10, 40(R11)
+
+ // restore errno
+ MOVQ m_perrno(BP), R11
+ MOVQ 160(SP), R10
+ MOVL R10, 0(R11)
+
+ // restore g
+ MOVQ 80(SP), R10
+ MOVQ R10, g(BX)
+
+ // restore registers
+ MOVQ 32(SP), BX
+ MOVQ 40(SP), BP
+ MOVQ 48(SP), R12
+ MOVQ 56(SP), R13
+ MOVQ 64(SP), R14
+ MOVQ 72(SP), R15
+
+ ADDQ $184, SP
+ RET
diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s
index 20753638e..e0c0631cf 100644
--- a/src/pkg/runtime/sys_windows_386.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -14,28 +14,28 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$0
// Copy args to the stack.
MOVL SP, BP
- MOVL wincall_n(BX), CX // words
+ MOVL libcall_n(BX), CX // words
MOVL CX, AX
SALL $2, AX
SUBL AX, SP // room for args
MOVL SP, DI
- MOVL wincall_args(BX), SI
+ MOVL libcall_args(BX), SI
CLD
REP; MOVSL
// Call stdcall or cdecl function.
// DI SI BP BX are preserved, SP is not
- CALL wincall_fn(BX)
+ CALL libcall_fn(BX)
MOVL BP, SP
// Return result.
MOVL c+0(FP), BX
- MOVL AX, wincall_r1(BX)
- MOVL DX, wincall_r2(BX)
+ MOVL AX, libcall_r1(BX)
+ MOVL DX, libcall_r2(BX)
// GetLastError().
MOVL 0x34(FS), AX
- MOVL AX, wincall_err(BX)
+ MOVL AX, libcall_err(BX)
RET
@@ -69,43 +69,47 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
MOVL AX, 0x34(FS)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$28
- // unwinding?
- MOVL info+0(FP), CX
- TESTL $6, 4(CX) // exception flags
- MOVL $1, AX
- JNZ sigdone
-
- // copy arguments for call to sighandler
- MOVL CX, 0(SP)
- MOVL context+8(FP), CX
- MOVL CX, 4(SP)
-
- get_tls(CX)
-
- // check that m exists
- MOVL m(CX), AX
- CMPL AX, $0
- JNE 2(PC)
- CALL runtime·badsignal2(SB)
-
- MOVL g(CX), CX
- MOVL CX, 8(SP)
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+ MOVL ptrs+0(FP), CX
+ SUBL $28, SP
+ // save callee-saved registers
MOVL BX, 12(SP)
MOVL BP, 16(SP)
MOVL SI, 20(SP)
MOVL DI, 24(SP)
+ MOVL 0(CX), BX // ExceptionRecord*
+ MOVL 4(CX), CX // Context*
+
+ // fetch g
+ get_tls(DX)
+ MOVL m(DX), AX
+ CMPL AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal2(SB)
+ MOVL g(DX), DX
+ // call sighandler(ExceptionRecord*, Context*, G*)
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
CALL runtime·sighandler(SB)
// AX is set to report result back to Windows
+ // restore callee-saved registers
MOVL 24(SP), DI
MOVL 20(SP), SI
MOVL 16(SP), BP
MOVL 12(SP), BX
-sigdone:
- RET
+
+ ADDL $28, SP
+ // RET 4 (return and pop 4 bytes parameters)
+ BYTE $0xC2; WORD $4
+ RET // unreached; make assembler happy
TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
PUSHL $runtime·ctrlhandler1(SB)
@@ -182,11 +186,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
PUSHL BP
PUSHL BX
- // set up SEH frame again
- PUSHL $runtime·sigtramp(SB)
- PUSHL 0(FS)
- MOVL SP, 0(FS)
-
// determine index into runtime·cbctxts table
SUBL $runtime·callbackasm(SB), AX
MOVL $0, DX
@@ -232,10 +231,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
MOVL BX, CX // cannot use BX anymore
- // pop SEH frame
- POPL 0(FS)
- POPL BX
-
// restore registers as required for windows callback
POPL BX
POPL BP
@@ -299,35 +294,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
MOVL CX, 0x14(FS)
RET
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
- get_tls(CX)
- MOVL m(CX), CX // m
-
- // Set up SEH frame
- MOVL m_seh(CX), DX
- MOVL $runtime·sigtramp(SB), AX
- MOVL AX, seh_handler(DX)
- MOVL 0(FS), AX
- MOVL AX, seh_prev(DX)
-
- // Install it
- MOVL DX, 0(FS)
-
- RET
-
-// void remove_exception_handler()
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
- get_tls(CX)
- MOVL m(CX), CX // m
-
- // Remove SEH frame
- MOVL m_seh(CX), DX
- MOVL seh_prev(DX), AX
- MOVL AX, 0(FS)
-
- RET
-
// Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX
@@ -343,19 +309,36 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
RET
MOVL m(CX), BP
+
+ // leave pc/sp for cpu profiler
+ MOVL (SP), SI
+ MOVL SI, m_libcallpc(BP)
+ MOVL g(CX), SI
+ MOVL SI, m_libcallg(BP)
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ LEAL 4(SP), SI
+ MOVL SI, m_libcallsp(BP)
+
MOVL m_g0(BP), SI
CMPL g(CX), SI
- JNE 3(PC)
+ JNE usleep1_switch
// executing on m->g0 already
CALL AX
- RET
+ JMP usleep1_ret
+usleep1_switch:
// Switch to m->g0 stack and back.
MOVL (g_sched+gobuf_sp)(SI), SI
MOVL SP, -4(SI)
LEAL -4(SI), SP
CALL AX
MOVL 0(SP), SP
+
+usleep1_ret:
+ get_tls(CX)
+ MOVL m(CX), BP
+ MOVL $0, m_libcallsp(BP)
RET
// Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
index 8c4caf867..94845903e 100644
--- a/src/pkg/runtime/sys_windows_amd64.s
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -13,9 +13,9 @@
TEXT runtime·asmstdcall(SB),NOSPLIT,$0
// asmcgocall will put first argument into CX.
PUSHQ CX // save for later
- MOVQ wincall_fn(CX), AX
- MOVQ wincall_args(CX), SI
- MOVQ wincall_n(CX), CX
+ MOVQ libcall_fn(CX), AX
+ MOVQ libcall_args(CX), SI
+ MOVQ libcall_n(CX), CX
// SetLastError(0).
MOVQ 0x30(GS), DI
@@ -52,12 +52,12 @@ loadregs:
// Return result.
POPQ CX
- MOVQ AX, wincall_r1(CX)
+ MOVQ AX, libcall_r1(CX)
// GetLastError().
MOVQ 0x30(GS), DI
MOVL 0x68(DI), AX
- MOVQ AX, wincall_err(CX)
+ MOVQ AX, libcall_err(CX)
RET
@@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
MOVL AX, 0x68(CX)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$0
- // CX: exception record
- // R8: context
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+ // CX: PEXCEPTION_POINTERS ExceptionInfo
- // unwinding?
- TESTL $6, 4(CX) // exception flags
- MOVL $1, AX
- JNZ sigdone
-
- // copy arguments for call to sighandler.
-
- // Stack adjustment is here to hide from 6l,
- // which doesn't understand that sigtramp
- // runs on essentially unlimited stack.
- SUBQ $56, SP
- MOVQ CX, 0(SP)
- MOVQ R8, 8(SP)
-
- get_tls(CX)
-
- // check that m exists
- MOVQ m(CX), AX
+ // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
+ // as required by windows callback convention.
+ PUSHFQ
+ SUBQ $88, SP
+ MOVQ DI, 80(SP)
+ MOVQ SI, 72(SP)
+ MOVQ BP, 64(SP)
+ MOVQ BX, 56(SP)
+ MOVQ R12, 48(SP)
+ MOVQ R13, 40(SP)
+ MOVQ R14, 32(SP)
+ MOVQ R15, 24(SP)
+
+ MOVQ 0(CX), BX // ExceptionRecord*
+ MOVQ 8(CX), CX // Context*
+
+ // fetch g
+ get_tls(DX)
+ MOVQ m(DX), AX
CMPQ AX, $0
JNE 2(PC)
CALL runtime·badsignal2(SB)
-
- MOVQ g(CX), CX
- MOVQ CX, 16(SP)
-
- MOVQ BX, 24(SP)
- MOVQ BP, 32(SP)
- MOVQ SI, 40(SP)
- MOVQ DI, 48(SP)
-
+ MOVQ g(DX), DX
+ // call sighandler(ExceptionRecord*, Context*, G*)
+ MOVQ BX, 0(SP)
+ MOVQ CX, 8(SP)
+ MOVQ DX, 16(SP)
CALL runtime·sighandler(SB)
+ // AX is set to report result back to Windows
- MOVQ 24(SP), BX
- MOVQ 32(SP), BP
- MOVQ 40(SP), SI
- MOVQ 48(SP), DI
- ADDQ $56, SP
+ // restore registers as required for windows callback
+ MOVQ 24(SP), R15
+ MOVQ 32(SP), R14
+ MOVQ 40(SP), R13
+ MOVQ 48(SP), R12
+ MOVQ 56(SP), BX
+ MOVQ 64(SP), BP
+ MOVQ 72(SP), SI
+ MOVQ 80(SP), DI
+ ADDQ $88, SP
+ POPFQ
-sigdone:
RET
TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
@@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
POPQ -8(CX)(DX*1) // restore bytes just after the args
RET
-TEXT runtime·setstacklimits(SB),NOSPLIT,$0
- MOVQ 0x30(GS), CX
- MOVQ $0, 0x10(CX)
- MOVQ $0xffffffffffff, AX
- MOVQ AX, 0x08(CX)
- RET
-
// uint32 tstart_stdcall(M *newm);
TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
// CX contains first arg newm
@@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0
MOVQ DI, 0x28(GS)
RET
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
- CALL runtime·setstacklimits(SB)
- RET
-
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
- RET
-
// Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX
@@ -337,20 +328,35 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
CALL AX
RET
- MOVQ m(R15), R14
- MOVQ m_g0(R14), R14
+ MOVQ m(R15), R13
+
+ // leave pc/sp for cpu profiler
+ MOVQ (SP), R12
+ MOVQ R12, m_libcallpc(R13)
+ MOVQ g(R15), R12
+ MOVQ R12, m_libcallg(R13)
+ // sp must be the last, because once async cpu profiler finds
+ // all three values to be non-zero, it will use them
+ LEAQ 8(SP), R12
+ MOVQ R12, m_libcallsp(R13)
+
+ MOVQ m_g0(R13), R14
CMPQ g(R15), R14
- JNE 3(PC)
+ JNE usleep1_switch
// executing on m->g0 already
CALL AX
- RET
+ JMP usleep1_ret
+usleep1_switch:
// Switch to m->g0 stack and back.
MOVQ (g_sched+gobuf_sp)(R14), R14
MOVQ SP, -8(R14)
LEAQ -8(R14), SP
CALL AX
MOVQ 0(SP), SP
+
+usleep1_ret:
+ MOVQ $0, m_libcallsp(R13)
RET
// Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_x86.c b/src/pkg/runtime/sys_x86.c
index 0df6dfbbd..a450b3e58 100644
--- a/src/pkg/runtime/sys_x86.c
+++ b/src/pkg/runtime/sys_x86.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 386
+// +build amd64 amd64p32 386
#include "runtime.h"
@@ -14,6 +14,8 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
uintptr *sp;
sp = (uintptr*)gobuf->sp;
+ if(sizeof(uintreg) > sizeof(uintptr))
+ *--sp = 0;
*--sp = (uintptr)gobuf->pc;
gobuf->sp = (uintptr)sp;
gobuf->pc = (uintptr)fn;
@@ -27,7 +29,7 @@ void
runtime·rewindmorestack(Gobuf *gobuf)
{
byte *pc;
-
+
pc = (byte*)gobuf->pc;
if(pc[0] == 0xe9) { // jmp 4-byte offset
gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
@@ -37,18 +39,18 @@ runtime·rewindmorestack(Gobuf *gobuf)
gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
return;
}
- if(pc[0] == 0xcc) {
- // This is a breakpoint inserted by gdb. We could use
- // runtime·findfunc to find the function. But if we
- // do that, then we will continue execution at the
- // function entry point, and we will not hit the gdb
- // breakpoint. So for this case we don't change
- // gobuf->pc, so that when we return we will execute
- // the jump instruction and carry on. This means that
- // stack unwinding may not work entirely correctly
- // (http://golang.org/issue/5723) but the user is
- // running under gdb anyhow.
- return;
+ if(pc[0] == 0xcc) {
+ // This is a breakpoint inserted by gdb. We could use
+ // runtime·findfunc to find the function. But if we
+ // do that, then we will continue execution at the
+ // function entry point, and we will not hit the gdb
+ // breakpoint. So for this case we don't change
+ // gobuf->pc, so that when we return we will execute
+ // the jump instruction and carry on. This means that
+ // stack unwinding may not work entirely correctly
+ // (http://golang.org/issue/5723) but the user is
+ // running under gdb anyhow.
+ return;
}
runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
runtime·throw("runtime: misuse of rewindmorestack");
diff --git a/src/pkg/runtime/syscall_nacl.h b/src/pkg/runtime/syscall_nacl.h
new file mode 100644
index 000000000..b33852ec8
--- /dev/null
+++ b/src/pkg/runtime/syscall_nacl.h
@@ -0,0 +1,71 @@
+// generated by mknacl.sh - do not edit
+#define SYS_null 1
+#define SYS_nameservice 2
+#define SYS_dup 8
+#define SYS_dup2 9
+#define SYS_open 10
+#define SYS_close 11
+#define SYS_read 12
+#define SYS_write 13
+#define SYS_lseek 14
+#define SYS_ioctl 15
+#define SYS_stat 16
+#define SYS_fstat 17
+#define SYS_chmod 18
+#define SYS_brk 20
+#define SYS_mmap 21
+#define SYS_munmap 22
+#define SYS_getdents 23
+#define SYS_mprotect 24
+#define SYS_list_mappings 25
+#define SYS_exit 30
+#define SYS_getpid 31
+#define SYS_sched_yield 32
+#define SYS_sysconf 33
+#define SYS_gettimeofday 40
+#define SYS_clock 41
+#define SYS_nanosleep 42
+#define SYS_clock_getres 43
+#define SYS_clock_gettime 44
+#define SYS_mkdir 45
+#define SYS_rmdir 46
+#define SYS_chdir 47
+#define SYS_getcwd 48
+#define SYS_unlink 49
+#define SYS_imc_makeboundsock 60
+#define SYS_imc_accept 61
+#define SYS_imc_connect 62
+#define SYS_imc_sendmsg 63
+#define SYS_imc_recvmsg 64
+#define SYS_imc_mem_obj_create 65
+#define SYS_imc_socketpair 66
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_trylock 72
+#define SYS_mutex_unlock 73
+#define SYS_cond_create 74
+#define SYS_cond_wait 75
+#define SYS_cond_signal 76
+#define SYS_cond_broadcast 77
+#define SYS_cond_timed_wait_abs 79
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_thread_nice 83
+#define SYS_tls_get 84
+#define SYS_second_tls_set 85
+#define SYS_second_tls_get 86
+#define SYS_exception_handler 87
+#define SYS_exception_stack 88
+#define SYS_exception_clear_flag 89
+#define SYS_sem_create 100
+#define SYS_sem_wait 101
+#define SYS_sem_post 102
+#define SYS_sem_get_value 103
+#define SYS_dyncode_create 104
+#define SYS_dyncode_modify 105
+#define SYS_dyncode_delete 106
+#define SYS_test_infoleak 109
+#define SYS_test_crash 110
+#define SYS_test_syscall_1 111
+#define SYS_test_syscall_2 112
diff --git a/src/pkg/runtime/syscall_solaris.goc b/src/pkg/runtime/syscall_solaris.goc
new file mode 100644
index 000000000..21bcce4d1
--- /dev/null
+++ b/src/pkg/runtime/syscall_solaris.goc
@@ -0,0 +1,374 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "cgocall.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynimport libc·chdir chdir "libc.so"
+#pragma dynimport libc·chroot chroot "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·dlclose dlclose "libc.so"
+#pragma dynimport libc·dlopen dlopen "libc.so"
+#pragma dynimport libc·dlsym dlsym "libc.so"
+#pragma dynimport libc·execve execve "libc.so"
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·gethostname gethostname "libc.so"
+#pragma dynimport libc·ioctl ioctl "libc.so"
+#pragma dynimport libc·pipe pipe "libc.so"
+#pragma dynimport libc·setgid setgid "libc.so"
+#pragma dynimport libc·setgroups setgroups "libc.so"
+#pragma dynimport libc·setsid setsid "libc.so"
+#pragma dynimport libc·setuid setuid "libc.so"
+#pragma dynimport libc·setpgid setsid "libc.so"
+#pragma dynimport libc·syscall syscall "libc.so"
+#pragma dynimport libc·forkx forkx "libc.so"
+#pragma dynimport libc·wait4 wait4 "libc.so"
+extern uintptr libc·chdir;
+extern uintptr libc·chroot;
+extern uintptr libc·close;
+extern uintptr libc·dlclose;
+extern uintptr libc·dlopen;
+extern uintptr libc·dlsym;
+extern uintptr libc·execve;
+extern uintptr libc·exit;
+extern uintptr libc·fcntl;
+extern uintptr libc·gethostname;
+extern uintptr libc·ioctl;
+extern uintptr libc·pipe;
+extern uintptr libc·setgid;
+extern uintptr libc·setgroups;
+extern uintptr libc·setsid;
+extern uintptr libc·setuid;
+extern uintptr libc·setpgid;
+extern uintptr libc·syscall;
+extern uintptr libc·forkx;
+extern uintptr libc·wait4;
+extern uintptr libc·write;
+
+func sysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+ LibCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ c.fn = (void*)func;
+ c.n = nargs;
+ c.args = (void*)&a1;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func rawSysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+ LibCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ c.fn = (void*)func;
+ c.n = nargs;
+ c.args = (void*)&a1;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func chdir(path uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·chdir;
+ c.n = 1;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func chroot1(path uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·chroot;
+ c.n = 1;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func close(fd uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·close;
+ c.n = 1;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+func dlclose(handle uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(handle);
+ c.fn = (void*)libc·dlclose;
+ c.n = 1;
+ c.args = (void*)&handle;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.r1;
+}
+
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err uintptr) {
+ LibCall c;
+
+ USED(mode);
+ c.fn = (void*)libc·dlopen;
+ c.n = 2;
+ c.args = (void*)&name;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ handle = c.r1;
+ if(handle == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err uintptr) {
+ LibCall c;
+
+ USED(name);
+ c.fn = (void*)libc·dlsym;
+ c.n = 2;
+ c.args = &handle;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ proc = c.r1;
+ if(proc == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+#pragma textflag NOSPLIT
+func execve(path uintptr, argv uintptr, envp uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(argv);
+ USED(envp);
+ c.fn = (void*)libc·execve;
+ c.n = 3;
+ c.args = (void*)&path;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func exit(code uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·exit;
+ c.n = 1;
+ c.args = (void*)&code;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+}
+
+#pragma textflag NOSPLIT
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err uintptr) {
+ LibCall c;
+
+ USED(cmd);
+ USED(arg);
+ c.fn = (void*)libc·fcntl;
+ c.n = 3;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ val = c.r1;
+}
+
+func gethostname() (name String, err uintptr) {
+ struct { uintptr v[2]; } args;
+ uint8 cname[MAXHOSTNAMELEN];
+ LibCall c;
+
+ c.fn = (void*)libc·gethostname;
+ c.n = 2;
+ args.v[0] = (uintptr)&cname[0];
+ args.v[1] = MAXHOSTNAMELEN;
+ c.args = (void*)&args;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ if(c.r1) {
+ name = runtime·emptystring;
+ return;
+ }
+ cname[MAXHOSTNAMELEN - 1] = 0;
+ name = runtime·gostring(cname);
+}
+
+#pragma textflag NOSPLIT
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(req);
+ USED(arg);
+ c.fn = (void*)libc·ioctl;
+ c.n = 3;
+ c.args = (void*)&fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+func wait4(pid uintptr, wstatus *uint32, options uintptr, rusage *void) (wpid int, err uintptr) {
+ LibCall c;
+
+ USED(wstatus);
+ USED(options);
+ USED(rusage);
+ c.fn = (void*)libc·wait4;
+ c.n = 4;
+ c.args = (void*)&pid;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ wpid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setgid(gid uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setgid;
+ c.n = 1;
+ c.args = (void*)&gid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setgroups1(ngid uintptr, gid uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(gid);
+ c.fn = (void*)libc·setgroups;
+ c.n = 2;
+ c.args = (void*)&ngid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setsid() (pid uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setsid;
+ c.n = 0;
+ c.args = (void*)0;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ pid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setuid(uid uintptr) (err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·setuid;
+ c.n = 1;
+ c.args = (void*)&uid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setpgid(pid uintptr, pgid uintptr) (err uintptr) {
+ LibCall c;
+
+ USED(pgid);
+ c.fn = (void*)libc·setpgid;
+ c.n = 2;
+ c.args = (void*)&pid;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func forkx(flags uintptr) (pid uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)libc·forkx;
+ c.n = 1;
+ c.args = (void*)&flags;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ pid = c.r1;
+}
+
+void runtime·pipe1(void);
+
+func pipe() (r uintptr, w uintptr, err uintptr) {
+ LibCall c;
+
+ c.fn = (void*)runtime·pipe1;
+ c.n = 0;
+ c.args = (void*)0;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r = c.r1;
+ w = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err uintptr) {
+ LibCall c;
+
+ USED(buf);
+ USED(nbyte);
+ c.fn = (void*)libc·write;
+ c.n = 3;
+ c.args = (void*)fd;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ n = c.r1;
+}
+
+func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ LibCall c;
+
+ USED(a1);
+ USED(a2);
+ USED(a3);
+ c.fn = (void*)libc·syscall;
+ c.n = 4;
+ c.args = &trap;
+ runtime·cgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ LibCall c;
+
+ USED(a1);
+ USED(a2);
+ USED(a3);
+ c.fn = (void*)libc·syscall;
+ c.n = 4;
+ c.args = &trap;
+ runtime·asmcgocall(runtime·asmsysvicall6, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
diff --git a/src/pkg/runtime/syscall_windows.goc b/src/pkg/runtime/syscall_windows.goc
index 173d3ed6a..528245363 100644
--- a/src/pkg/runtime/syscall_windows.goc
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -8,7 +8,7 @@ package syscall
#include "cgocall.h"
func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
c.fn = runtime·LoadLibrary;
c.n = 1;
@@ -22,7 +22,7 @@ func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
}
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(procname);
c.fn = runtime·GetProcAddress;
@@ -40,17 +40,12 @@ func NewCallback(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, true);
}
-/*
- * If this is needed, uncomment here and add a declaration in package syscall
- * next to the NewCallback declaration.
- *
func NewCallbackCDecl(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, false);
}
- */
func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -64,7 +59,7 @@ func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1
}
func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -81,7 +76,7 @@ func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -101,7 +96,7 @@ func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
@@ -124,7 +119,7 @@ func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
}
func Syscall15(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr, a13 uintptr, a14 uintptr, a15 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- WinCall c;
+ LibCall c;
USED(a2);
USED(a3);
diff --git a/src/pkg/runtime/syscall_windows_test.go b/src/pkg/runtime/syscall_windows_test.go
index f04d2cd54..fabf935d8 100644
--- a/src/pkg/runtime/syscall_windows_test.go
+++ b/src/pkg/runtime/syscall_windows_test.go
@@ -5,7 +5,13 @@
package runtime_test
import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
"runtime"
+ "strings"
"syscall"
"testing"
"unsafe"
@@ -171,10 +177,12 @@ func TestCallbackGC(t *testing.T) {
nestedCall(t, runtime.GC)
}
-func TestCallbackPanic(t *testing.T) {
- // Make sure panic during callback unwinds properly.
- if runtime.LockedOSThread() {
- t.Fatal("locked OS thread on entry to TestCallbackPanic")
+func TestCallbackPanicLocked(t *testing.T) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if !runtime.LockedOSThread() {
+ t.Fatal("runtime.LockOSThread didn't")
}
defer func() {
s := recover()
@@ -184,27 +192,18 @@ func TestCallbackPanic(t *testing.T) {
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
- if runtime.LockedOSThread() {
- t.Fatal("locked OS thread on exit from TestCallbackPanic")
+ if !runtime.LockedOSThread() {
+ t.Fatal("lost lock on OS thread after panic")
}
}()
nestedCall(t, func() { panic("callback panic") })
panic("nestedCall returned")
}
-func TestCallbackPanicLoop(t *testing.T) {
- // Make sure we don't blow out m->g0 stack.
- for i := 0; i < 100000; i++ {
- TestCallbackPanic(t)
- }
-}
-
-func TestCallbackPanicLocked(t *testing.T) {
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
-
- if !runtime.LockedOSThread() {
- t.Fatal("runtime.LockOSThread didn't")
+func TestCallbackPanic(t *testing.T) {
+ // Make sure panic during callback unwinds properly.
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on entry to TestCallbackPanic")
}
defer func() {
s := recover()
@@ -214,14 +213,21 @@ func TestCallbackPanicLocked(t *testing.T) {
if s.(string) != "callback panic" {
t.Fatal("wrong panic:", s)
}
- if !runtime.LockedOSThread() {
- t.Fatal("lost lock on OS thread after panic")
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on exit from TestCallbackPanic")
}
}()
nestedCall(t, func() { panic("callback panic") })
panic("nestedCall returned")
}
+func TestCallbackPanicLoop(t *testing.T) {
+ // Make sure we don't blow out m->g0 stack.
+ for i := 0; i < 100000; i++ {
+ TestCallbackPanic(t)
+ }
+}
+
func TestBlockingCallback(t *testing.T) {
c := make(chan int)
go func() {
@@ -242,3 +248,204 @@ func TestBlockingCallback(t *testing.T) {
func TestCallbackInAnotherThread(t *testing.T) {
// TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread()
}
+
+type cbDLLFunc int // int determines number of callback parameters
+
+func (f cbDLLFunc) stdcallName() string {
+ return fmt.Sprintf("stdcall%d", f)
+}
+
+func (f cbDLLFunc) cdeclName() string {
+ return fmt.Sprintf("cdecl%d", f)
+}
+
+func (f cbDLLFunc) buildOne(stdcall bool) string {
+ var funcname, attr string
+ if stdcall {
+ funcname = f.stdcallName()
+ attr = "__stdcall"
+ } else {
+ funcname = f.cdeclName()
+ attr = "__cdecl"
+ }
+ typename := "t" + funcname
+ p := make([]string, f)
+ for i := range p {
+ p[i] = "void*"
+ }
+ params := strings.Join(p, ",")
+ for i := range p {
+ p[i] = fmt.Sprintf("%d", i+1)
+ }
+ args := strings.Join(p, ",")
+ return fmt.Sprintf(`
+typedef void %s (*%s)(%s);
+void %s(%s f, void *n) {
+ int i;
+ for(i=0;i<(int)n;i++){
+ f(%s);
+ }
+}
+ `, attr, typename, params, funcname, typename, args)
+}
+
+func (f cbDLLFunc) build() string {
+ return f.buildOne(false) + f.buildOne(true)
+}
+
+var cbFuncs = [...]interface{}{
+ 2: func(i1, i2 uintptr) uintptr {
+ if i1+i2 != 3 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 3: func(i1, i2, i3 uintptr) uintptr {
+ if i1+i2+i3 != 6 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 4: func(i1, i2, i3, i4 uintptr) uintptr {
+ if i1+i2+i3+i4 != 10 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 5: func(i1, i2, i3, i4, i5 uintptr) uintptr {
+ if i1+i2+i3+i4+i5 != 15 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 6: func(i1, i2, i3, i4, i5, i6 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6 != 21 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 7: func(i1, i2, i3, i4, i5, i6, i7 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7 != 28 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 8: func(i1, i2, i3, i4, i5, i6, i7, i8 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7+i8 != 36 {
+ panic("bad input")
+ }
+ return 0
+ },
+ 9: func(i1, i2, i3, i4, i5, i6, i7, i8, i9 uintptr) uintptr {
+ if i1+i2+i3+i4+i5+i6+i7+i8+i9 != 45 {
+ panic("bad input")
+ }
+ return 0
+ },
+}
+
+type cbDLL struct {
+ name string
+ buildArgs func(out, src string) []string
+}
+
+func (d *cbDLL) buildSrc(t *testing.T, path string) {
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatalf("failed to create source file: %v", err)
+ }
+ defer f.Close()
+
+ for i := 2; i < 10; i++ {
+ fmt.Fprint(f, cbDLLFunc(i).build())
+ }
+}
+
+func (d *cbDLL) build(t *testing.T, dir string) string {
+ srcname := d.name + ".c"
+ d.buildSrc(t, filepath.Join(dir, srcname))
+ outname := d.name + ".dll"
+ args := d.buildArgs(outname, srcname)
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build dll: %v - %v", err, string(out))
+ }
+ return filepath.Join(dir, outname)
+}
+
+var cbDLLs = []cbDLL{
+ {
+ "test",
+ func(out, src string) []string {
+ return []string{"gcc", "-shared", "-s", "-o", out, src}
+ },
+ },
+ {
+ "testO2",
+ func(out, src string) []string {
+ return []string{"gcc", "-shared", "-s", "-o", out, "-O2", src}
+ },
+ },
+}
+
+type cbTest struct {
+ n int // number of callback parameters
+ param uintptr // dll function parameter
+}
+
+func (test *cbTest) run(t *testing.T, dllpath string) {
+ dll := syscall.MustLoadDLL(dllpath)
+ defer dll.Release()
+ cb := cbFuncs[test.n]
+ stdcall := syscall.NewCallback(cb)
+ f := cbDLLFunc(test.n)
+ test.runOne(t, dll, f.stdcallName(), stdcall)
+ cdecl := syscall.NewCallbackCDecl(cb)
+ test.runOne(t, dll, f.cdeclName(), cdecl)
+}
+
+func (test *cbTest) runOne(t *testing.T, dll *syscall.DLL, proc string, cb uintptr) {
+ defer func() {
+ if r := recover(); r != nil {
+ t.Errorf("dll call %v(..., %d) failed: %v", proc, test.param, r)
+ }
+ }()
+ dll.MustFindProc(proc).Call(cb, test.param)
+}
+
+var cbTests = []cbTest{
+ {2, 1},
+ {2, 10000},
+ {3, 3},
+ {4, 5},
+ {4, 6},
+ {5, 2},
+ {6, 7},
+ {6, 8},
+ {7, 6},
+ {8, 1},
+ {9, 8},
+ {9, 10000},
+ {3, 4},
+ {5, 3},
+ {7, 7},
+ {8, 2},
+ {9, 9},
+}
+
+func TestStdcallAndCDeclCallbacks(t *testing.T) {
+ tmp, err := ioutil.TempDir("", "TestCDeclCallback")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ for _, dll := range cbDLLs {
+ dllPath := dll.build(t, tmp)
+ for _, test := range cbTests {
+ test.run(t, dllPath)
+ }
+ }
+}
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
index b575696f7..712e03e83 100644
--- a/src/pkg/runtime/time.goc
+++ b/src/pkg/runtime/time.goc
@@ -21,11 +21,19 @@ static Timers timers;
static void addtimer(Timer*);
static void dumptimers(int8*);
+// nacl fake time support.
+int64 runtime·timens;
+
// Package time APIs.
// Godoc uses the comments in package time, not these.
// time.now is implemented in assembly.
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+ ns = runtime·nanotime();
+}
+
// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
func Sleep(ns int64) {
runtime·tsleep(ns, "sleep");
@@ -46,6 +54,16 @@ func stopTimer(t *Timer) (stopped bool) {
// C runtime.
+void runtime·gc_unixnanotime(int64 *now);
+
+int64 runtime·unixnanotime(void)
+{
+ int64 now;
+
+ runtime·gc_unixnanotime(&now);
+ return now;
+}
+
static void timerproc(void);
static void siftup(int32);
static void siftdown(int32);
@@ -76,7 +94,7 @@ runtime·tsleep(int64 ns, int8 *reason)
t.arg.data = g;
runtime·lock(&timers);
addtimer(&t);
- runtime·park(runtime·unlock, &timers, reason);
+ runtime·parkunlock(&timers, reason);
}
static FuncVal timerprocv = {timerproc};
@@ -217,12 +235,22 @@ timerproc(void)
if(raceenabled)
runtime·raceacquire(t);
f(now, arg);
+
+ // clear f and arg to avoid leak while sleeping for next timer
+ f = nil;
+ USED(f);
+ arg.type = nil;
+ arg.data = nil;
+ USED(&arg);
+
runtime·lock(&timers);
}
if(delta < 0) {
// No timers left - put goroutine to sleep.
timers.rescheduling = true;
- runtime·park(runtime·unlock, &timers, "timer goroutine (idle)");
+ g->isbackground = true;
+ runtime·parkunlock(&timers, "timer goroutine (idle)");
+ g->isbackground = false;
continue;
}
// At least one timer pending. Sleep until then.
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c
index 8a3685e76..d15244c2a 100644
--- a/src/pkg/runtime/traceback_arm.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -8,17 +8,23 @@
#include "funcdata.h"
void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
{
- int32 i, n, nprint, line;
- uintptr x, tracepc;
- bool waspanic, printing;
+ int32 i, n, nprint, line, gotraceback;
+ uintptr x, tracepc, sparg;
+ bool waspanic, wasnewproc, printing;
Func *f, *flr;
Stkframe frame;
Stktop *stk;
String file;
+ Panic *panic;
+ Defer *defer;
+
+ gotraceback = runtime·gotraceback(nil);
if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
if(gp->syscallstack != (uintptr)nil) {
@@ -38,8 +44,17 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.lr = lr0;
frame.sp = sp0;
waspanic = false;
+ wasnewproc = false;
printing = pcbuf==nil && callback==nil;
+ panic = gp->panic;
+ defer = gp->defer;
+
+ while(defer != nil && defer->argp == NoArgs)
+ defer = defer->link;
+ while(panic != nil && panic->defer == nil)
+ panic = panic->link;
+
// If the PC is zero, it's likely a nil function call.
// Start in the caller's frame.
if(frame.pc == 0) {
@@ -95,6 +110,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(runtime·topofstack(f)) {
frame.lr = 0;
flr = nil;
+ } else if(f->entry == (uintptr)runtime·jmpdefer) {
+ // jmpdefer modifies SP/LR/PC non-atomically.
+ // If a profiling interrupt arrives during jmpdefer,
+ // the stack unwind may see a mismatched register set
+ // and get confused. Stop if we see PC within jmpdefer
+ // to avoid that confusion.
+ // See golang.org/issue/8153.
+ // This check can be deleted if jmpdefer is changed
+ // to restore all three atomically using pop.
+ if(callback != nil)
+ runtime·throw("traceback_arm: found jmpdefer when tracing with callback");
+ frame.lr = 0;
+ flr = nil;
} else {
if((n == 0 && frame.sp < frame.fp) || frame.lr == 0)
frame.lr = *(uintptr*)frame.sp;
@@ -133,6 +161,47 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
}
}
+ // Determine function SP where deferproc would find its arguments.
+ // On ARM that's just the standard bottom-of-stack plus 1 word for
+ // the saved LR. If the previous frame was a direct call to newproc/deferproc,
+ // however, the SP is three words lower than normal.
+ // If the function has no frame at all - perhaps it just started, or perhaps
+ // it is a leaf with no local variables - then we cannot possibly find its
+ // SP in a defer, and we might confuse its SP for its caller's SP, so
+ // set sparg=0 in that case.
+ sparg = 0;
+ if(frame.fp != frame.sp) {
+ sparg = frame.sp + sizeof(uintreg);
+ if(wasnewproc)
+ sparg += 3*sizeof(uintreg);
+ }
+
+ // Determine frame's 'continuation PC', where it can continue.
+ // Normally this is the return address on the stack, but if sigpanic
+ // is immediately below this function on the stack, then the frame
+ // stopped executing due to a trap, and frame.pc is probably not
+ // a safe point for looking up liveness information. In this panicking case,
+ // the function either doesn't return at all (if it has no defers or if the
+ // defers do not recover) or it returns from one of the calls to
+ // deferproc a second time (if the corresponding deferred func recovers).
+ // It suffices to assume that the most recent deferproc is the one that
+ // returns; everything live at earlier deferprocs is still live at that one.
+ frame.continpc = frame.pc;
+ if(waspanic) {
+ if(panic != nil && panic->defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)panic->defer->pc;
+ else if(defer != nil && defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)defer->pc;
+ else
+ frame.continpc = 0;
+ }
+
+ // Unwind our local panic & defer stacks past this frame.
+ while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+ panic = panic->link;
+ while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+ defer = defer->link;
+
if(skip > 0) {
skip--;
goto skipped;
@@ -140,8 +209,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf != nil)
pcbuf[n] = frame.pc;
- if(callback != nil)
- callback(&frame, v);
+ if(callback != nil) {
+ if(!callback(&frame, v))
+ return n;
+ }
if(printing) {
if(printall || runtime·showframe(f, gp)) {
// Print during crash.
@@ -152,7 +223,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc -= sizeof(uintptr);
runtime·printf("%s(", runtime·funcname(f));
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
- if(i >= 5) {
+ if(i >= 10) {
runtime·prints(", ...");
break;
}
@@ -165,8 +236,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
- if(m->throwing > 0 && gp == m->curg)
- runtime·printf(" fp=%p", frame.fp);
+ if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+ runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
runtime·printf("\n");
nprint++;
}
@@ -175,6 +246,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
skipped:
waspanic = f->entry == (uintptr)runtime·sigpanic;
+ wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
// Do not unwind past the bottom of the stack.
if(flr == nil)
@@ -202,6 +274,23 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf == nil && callback == nil)
n = nprint;
+ // For rationale, see long comment in traceback_x86.c.
+ if(callback != nil && n < max && defer != nil) {
+ if(defer != nil)
+ runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+ if(panic != nil)
+ runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+ for(defer = gp->defer; defer != nil; defer = defer->link)
+ runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+ for(panic = gp->panic; panic != nil; panic = panic->link) {
+ runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+ if(panic->defer != nil)
+ runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+ runtime·printf("\n");
+ }
+ runtime·throw("traceback has leftover defers or panics");
+ }
+
return n;
}
@@ -231,6 +320,8 @@ runtime·printcreatedby(G *gp)
void
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
{
+ int32 n;
+
if(gp->status == Gsyscall) {
// Override signal registers if blocked in system call.
pc = gp->syscallpc;
@@ -240,8 +331,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
// Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed.
- if(runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, false) == 0)
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, true);
+ n = runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+ if(n == 0)
+ runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+ if(n == TracebackMaxFrames)
+ runtime·printf("...additional frames elided...\n");
runtime·printcreatedby(gp);
}
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c
index 8e3063f43..851504f52 100644
--- a/src/pkg/runtime/traceback_x86.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -2,14 +2,23 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 386
+// +build amd64 amd64p32 386
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "funcdata.h"
+#ifdef GOOS_windows
+#include "defs_GOOS_GOARCH.h"
+#endif
void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
+
+#ifdef GOOS_windows
+void runtime·sigtramp(void);
+#endif
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
@@ -19,18 +28,22 @@ void runtime·sigpanic(void);
// collector (callback != nil). A little clunky to merge these, but avoids
// duplicating the code and all its subtlety.
int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
{
- int32 i, n, nprint, line;
- uintptr tracepc;
- bool waspanic, printing;
+ int32 i, n, nprint, line, gotraceback;
+ uintptr tracepc, sparg;
+ bool waspanic, wasnewproc, printing;
Func *f, *flr;
Stkframe frame;
Stktop *stk;
String file;
+ Panic *panic;
+ Defer *defer;
USED(lr0);
+ gotraceback = runtime·gotraceback(nil);
+
if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
if(gp->syscallstack != (uintptr)nil) {
pc0 = gp->syscallpc;
@@ -46,13 +59,21 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.pc = pc0;
frame.sp = sp0;
waspanic = false;
+ wasnewproc = false;
printing = pcbuf==nil && callback==nil;
-
+ panic = gp->panic;
+ defer = gp->defer;
+
+ while(defer != nil && defer->argp == NoArgs)
+ defer = defer->link;
+ while(panic != nil && panic->defer == nil)
+ panic = panic->link;
+
// If the PC is zero, it's likely a nil function call.
// Start in the caller's frame.
if(frame.pc == 0) {
frame.pc = *(uintptr*)frame.sp;
- frame.sp += sizeof(uintptr);
+ frame.sp += sizeof(uintreg);
}
f = runtime·findfunc(frame.pc);
@@ -95,20 +116,63 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.fn = f;
continue;
}
+
f = frame.fn;
+#ifdef GOOS_windows
+ // Windows exception handlers run on the actual g stack (there is room
+ // dedicated to this below the usual "bottom of stack"), not on a separate
+ // stack. As a result, we have to be able to unwind past the exception
+ // handler when called to unwind during stack growth inside the handler.
+ // Recognize the frame at the call to sighandler in sigtramp and unwind
+ // using the context argument passed to the call. This is awful.
+ if(f != nil && f->entry == (uintptr)runtime·sigtramp && frame.pc > f->entry) {
+ Context *r;
+
+ // Invoke callback so that stack copier sees an uncopyable frame.
+ if(callback != nil) {
+ frame.continpc = frame.pc;
+ frame.argp = nil;
+ frame.arglen = 0;
+ if(!callback(&frame, v))
+ return n;
+ }
+ r = (Context*)((uintptr*)frame.sp)[1];
+#ifdef GOARCH_amd64
+ frame.pc = r->Rip;
+ frame.sp = r->Rsp;
+#else
+ frame.pc = r->Eip;
+ frame.sp = r->Esp;
+#endif
+ frame.lr = 0;
+ frame.fp = 0;
+ frame.fn = nil;
+ if(printing && runtime·showframe(nil, gp))
+ runtime·printf("----- exception handler -----\n");
+ f = runtime·findfunc(frame.pc);
+ if(f == nil) {
+ runtime·printf("runtime: unknown pc %p after exception handler\n", frame.pc);
+ if(callback != nil)
+ runtime·throw("unknown pc");
+ }
+ frame.fn = f;
+ continue;
+ }
+#endif
+
// Found an actual function.
// Derive frame pointer and link register.
if(frame.fp == 0) {
frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
- frame.fp += sizeof(uintptr); // caller PC
+ frame.fp += sizeof(uintreg); // caller PC
}
if(runtime·topofstack(f)) {
frame.lr = 0;
flr = nil;
} else {
if(frame.lr == 0)
- frame.lr = ((uintptr*)frame.fp)[-1];
+ frame.lr = ((uintreg*)frame.fp)[-1];
flr = runtime·findfunc(frame.lr);
if(flr == nil) {
runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
@@ -117,7 +181,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
}
}
- frame.varp = (byte*)frame.fp - sizeof(uintptr);
+ frame.varp = (byte*)frame.fp - sizeof(uintreg);
// Derive size of arguments.
// Most functions have a fixed-size argument block,
@@ -143,6 +207,40 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.arglen = 0;
}
}
+
+ // Determine function SP where deferproc would find its arguments.
+ // On x86 that's just the standard bottom-of-stack, so SP exactly.
+ // If the previous frame was a direct call to newproc/deferproc, however,
+ // the SP is two words lower than normal.
+ sparg = frame.sp;
+ if(wasnewproc)
+ sparg += 2*sizeof(uintreg);
+
+ // Determine frame's 'continuation PC', where it can continue.
+ // Normally this is the return address on the stack, but if sigpanic
+ // is immediately below this function on the stack, then the frame
+ // stopped executing due to a trap, and frame.pc is probably not
+ // a safe point for looking up liveness information. In this panicking case,
+ // the function either doesn't return at all (if it has no defers or if the
+ // defers do not recover) or it returns from one of the calls to
+ // deferproc a second time (if the corresponding deferred func recovers).
+ // It suffices to assume that the most recent deferproc is the one that
+ // returns; everything live at earlier deferprocs is still live at that one.
+ frame.continpc = frame.pc;
+ if(waspanic) {
+ if(panic != nil && panic->defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)panic->defer->pc;
+ else if(defer != nil && defer->argp == (byte*)sparg)
+ frame.continpc = (uintptr)defer->pc;
+ else
+ frame.continpc = 0;
+ }
+
+ // Unwind our local panic & defer stacks past this frame.
+ while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+ panic = panic->link;
+ while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+ defer = defer->link;
if(skip > 0) {
skip--;
@@ -151,8 +249,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf != nil)
pcbuf[n] = frame.pc;
- if(callback != nil)
- callback(&frame, v);
+ if(callback != nil) {
+ if(!callback(&frame, v))
+ return n;
+ }
if(printing) {
if(printall || runtime·showframe(f, gp)) {
// Print during crash.
@@ -164,7 +264,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc--;
runtime·printf("%s(", runtime·funcname(f));
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
- if(i >= 5) {
+ if(i >= 10) {
runtime·prints(", ...");
break;
}
@@ -177,8 +277,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
- if(m->throwing > 0 && gp == m->curg)
- runtime·printf(" fp=%p", frame.fp);
+ if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+ runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
runtime·printf("\n");
nprint++;
}
@@ -187,6 +287,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
skipped:
waspanic = f->entry == (uintptr)runtime·sigpanic;
+ wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
// Do not unwind past the bottom of the stack.
if(flr == nil)
@@ -202,7 +303,72 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
if(pcbuf == nil && callback == nil)
n = nprint;
-
+
+ // If callback != nil, we're being called to gather stack information during
+ // garbage collection or stack growth. In that context, require that we used
+ // up the entire defer stack. If not, then there is a bug somewhere and the
+ // garbage collection or stack growth may not have seen the correct picture
+ // of the stack. Crash now instead of silently executing the garbage collection
+ // or stack copy incorrectly and setting up for a mysterious crash later.
+ //
+ // Note that panic != nil is okay here: there can be leftover panics,
+ // because the defers on the panic stack do not nest in frame order as
+ // they do on the defer stack. If you have:
+ //
+ // frame 1 defers d1
+ // frame 2 defers d2
+ // frame 3 defers d3
+ // frame 4 panics
+ // frame 4's panic starts running defers
+ // frame 5, running d3, defers d4
+ // frame 5 panics
+ // frame 5's panic starts running defers
+ // frame 6, running d4, garbage collects
+ // frame 6, running d2, garbage collects
+ //
+ // During the execution of d4, the panic stack is d4 -> d3, which
+ // is nested properly, and we'll treat frame 3 as resumable, because we
+ // can find d3. (And in fact frame 3 is resumable. If d4 recovers
+ // and frame 5 continues running, d3, d3 can recover and we'll
+ // resume execution in (returning from) frame 3.)
+ //
+ // During the execution of d2, however, the panic stack is d2 -> d3,
+ // which is inverted. The scan will match d2 to frame 2 but having
+ // d2 on the stack until then means it will not match d3 to frame 3.
+ // This is okay: if we're running d2, then all the defers after d2 have
+ // completed and their corresponding frames are dead. Not finding d3
+ // for frame 3 means we'll set frame 3's continpc == 0, which is correct
+ // (frame 3 is dead). At the end of the walk the panic stack can thus
+ // contain defers (d3 in this case) for dead frames. The inversion here
+ // always indicates a dead frame, and the effect of the inversion on the
+ // scan is to hide those dead frames, so the scan is still okay:
+ // what's left on the panic stack are exactly (and only) the dead frames.
+ //
+ // We require callback != nil here because only when callback != nil
+ // do we know that gentraceback is being called in a "must be correct"
+ // context as opposed to a "best effort" context. The tracebacks with
+ // callbacks only happen when everything is stopped nicely.
+ // At other times, such as when gathering a stack for a profiling signal
+ // or when printing a traceback during a crash, everything may not be
+ // stopped nicely, and the stack walk may not be able to complete.
+ // It's okay in those situations not to use up the entire defer stack:
+ // incomplete information then is still better than nothing.
+ if(callback != nil && n < max && defer != nil) {
+ if(defer != nil)
+ runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+ if(panic != nil)
+ runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+ for(defer = gp->defer; defer != nil; defer = defer->link)
+ runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+ for(panic = gp->panic; panic != nil; panic = panic->link) {
+ runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+ if(panic->defer != nil)
+ runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+ runtime·printf("\n");
+ }
+ runtime·throw("traceback has leftover defers or panics");
+ }
+
return n;
}
@@ -232,6 +398,8 @@ runtime·printcreatedby(G *gp)
void
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
{
+ int32 n;
+
USED(lr);
if(gp->status == Gsyscall) {
@@ -242,8 +410,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
// Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed.
- if(runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, false) == 0)
- runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, true);
+ n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+ if(n == 0)
+ n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+ if(n == TracebackMaxFrames)
+ runtime·printf("...additional frames elided...\n");
runtime·printcreatedby(gp);
}
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 374754afa..276dbc0c9 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -26,6 +26,7 @@ type rtype struct {
string *string
*uncommonType
ptrToThis *rtype
+ zero unsafe.Pointer
}
type _method struct {
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 30936046c..1598acc18 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -15,9 +15,8 @@ typedef struct Method Method;
typedef struct IMethod IMethod;
typedef struct SliceType SliceType;
typedef struct FuncType FuncType;
-typedef struct PtrType PtrType;
-// Needs to be in sync with typekind.h/CommonSize
+// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize
struct Type
{
uintptr size;
@@ -31,6 +30,7 @@ struct Type
String *string;
UncommonType *x;
Type *ptrto;
+ byte *zero; // ptr to the zero value for this type
};
struct Method
@@ -100,7 +100,3 @@ struct PtrType
Type;
Type *elem;
};
-
-// Here instead of in runtime.h because it uses the type names.
-bool runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
-bool runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type**, PtrType**);
diff --git a/src/pkg/runtime/typekind.h b/src/pkg/runtime/typekind.h
index 9bae2a871..3f0ba9acb 100644
--- a/src/pkg/runtime/typekind.h
+++ b/src/pkg/runtime/typekind.h
@@ -34,8 +34,5 @@ enum {
KindUnsafePointer,
KindNoPointers = 1<<7,
-
- // size of Type structure.
- CommonSize = 6*PtrSize + 8,
};
diff --git a/src/pkg/runtime/vlop_arm.s b/src/pkg/runtime/vlop_arm.s
index d7c566afb..80f516ec4 100644
--- a/src/pkg/runtime/vlop_arm.s
+++ b/src/pkg/runtime/vlop_arm.s
@@ -75,10 +75,14 @@ TEXT _sfloat(SB), NOSPLIT, $64-0 // 4 arg + 14*4 saved regs + cpsr
MOVW m_locks(m), R1
ADD $1, R1
MOVW R1, m_locks(m)
+ MOVW $1, R1
+ MOVW R1, m_softfloat(m)
BL runtime·_sfloat2(SB)
MOVW m_locks(m), R1
SUB $1, R1
MOVW R1, m_locks(m)
+ MOVW $0, R1
+ MOVW R1, m_softfloat(m)
MOVW R0, 0(R13)
MOVW 64(R13), R1
WORD $0xe128f001 // msr cpsr_f, r1
@@ -255,7 +259,7 @@ TEXT _div(SB),NOSPLIT,$16
d0:
BL udiv<>(SB) /* none/both neg */
MOVW R(q), R(TMP)
- B out
+ B out1
d1:
CMP $0, R(q)
BGE d0
@@ -263,7 +267,12 @@ d1:
d2:
BL udiv<>(SB) /* one neg */
RSB $0, R(q), R(TMP)
- B out
+out1:
+ MOVW 4(R13), R(q)
+ MOVW 8(R13), R(r)
+ MOVW 12(R13), R(s)
+ MOVW 16(R13), R(M)
+ RET
TEXT _mod(SB),NOSPLIT,$16
MOVW R(q), 4(R13)
diff --git a/src/pkg/runtime/vlrt_386.c b/src/pkg/runtime/vlrt_386.c
index 8d965c086..ace1beb4c 100644
--- a/src/pkg/runtime/vlrt_386.c
+++ b/src/pkg/runtime/vlrt_386.c
@@ -32,6 +32,8 @@
* to generate the code directly now. Find and remove.
*/
+extern void runtime·panicdivide(void);
+
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
@@ -240,6 +242,8 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
}
} else {
if(num.hi >= den.lo){
+ if(den.lo == 0)
+ runtime·panicdivide();
q.hi = n = num.hi/den.lo;
num.hi -= den.lo*n;
} else {
@@ -263,6 +267,8 @@ _divvu(Vlong *q, Vlong n, Vlong d)
{
if(n.hi == 0 && d.hi == 0) {
+ if(d.lo == 0)
+ runtime·panicdivide();
q->hi = 0;
q->lo = n.lo / d.lo;
return;
@@ -281,6 +287,8 @@ _modvu(Vlong *r, Vlong n, Vlong d)
{
if(n.hi == 0 && d.hi == 0) {
+ if(d.lo == 0)
+ runtime·panicdivide();
r->hi = 0;
r->lo = n.lo % d.lo;
return;
@@ -319,6 +327,8 @@ _divv(Vlong *q, Vlong n, Vlong d)
q->hi = 0;
return;
}
+ if(d.lo == 0)
+ runtime·panicdivide();
q->lo = (long)n.lo / (long)d.lo;
q->hi = ((long)q->lo) >> 31;
return;
@@ -353,6 +363,8 @@ _modv(Vlong *r, Vlong n, Vlong d)
r->hi = 0;
return;
}
+ if(d.lo == 0)
+ runtime·panicdivide();
r->lo = (long)n.lo % (long)d.lo;
r->hi = ((long)r->lo) >> 31;
return;
diff --git a/src/pkg/runtime/vlrt_arm.c b/src/pkg/runtime/vlrt_arm.c
index 219163c60..7dd71b40e 100644
--- a/src/pkg/runtime/vlrt_arm.c
+++ b/src/pkg/runtime/vlrt_arm.c
@@ -27,6 +27,7 @@
// declared here to avoid include of runtime.h
void runtime·panicstring(char*);
+void runtime·panicdivide(void);
typedef unsigned long ulong;
typedef unsigned int uint;
@@ -36,12 +37,6 @@ typedef signed char schar;
#define SIGN(n) (1UL<<(n-1))
-void
-runtime·panicdivide(void)
-{
- runtime·panicstring("integer divide by zero");
-}
-
typedef struct Vlong Vlong;
struct Vlong
{
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index f06eb3827..e980c295c 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -287,9 +287,9 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// Notes on stable sorting:
// The used algorithms are simple and provable correct on all input and use
// only logarithmic additional stack space. They perform well if compared
-// experimentaly to other stable in-place sorting algorithms.
+// experimentally to other stable in-place sorting algorithms.
//
-// Remarks on other algoritms evaluated:
+// Remarks on other algorithms evaluated:
// - GCC's 4.6.3 stable_sort with merge_without_buffer from libstdc++:
// Not faster.
// - GCC's __rotate for block rotations: Not faster.
@@ -349,7 +349,7 @@ func Stable(data Interface) {
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
//
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm wich uses O(M+N+gcd(M+N)) assignments. The argumentation
+// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
// in the paper carries through for Swap operations, especially as the block
// swapping rotate uses only O(M+N) Swaps.
func symMerge(data Interface, a, m, b int) {
diff --git a/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
index a7c1454eb..28f469f58 100644
--- a/src/pkg/strconv/atob_test.go
+++ b/src/pkg/strconv/atob_test.go
@@ -5,6 +5,7 @@
package strconv_test
import (
+ "bytes"
. "strconv"
"testing"
)
@@ -55,3 +56,36 @@ func TestParseBool(t *testing.T) {
}
}
}
+
+var boolString = map[bool]string{
+ true: "true",
+ false: "false",
+}
+
+func TestFormatBool(t *testing.T) {
+ for b, s := range boolString {
+ if f := FormatBool(b); f != s {
+ t.Errorf(`FormatBool(%v): expected %q but got %q`, b, s, f)
+ }
+ }
+}
+
+type appendBoolTest struct {
+ b bool
+ in []byte
+ out []byte
+}
+
+var appendBoolTests = []appendBoolTest{
+ {true, []byte("foo "), []byte("foo true")},
+ {false, []byte("foo "), []byte("foo false")},
+}
+
+func TestAppendBool(t *testing.T) {
+ for _, test := range appendBoolTests {
+ b := AppendBool(test.in, test.b)
+ if !bytes.Equal(b, test.out) {
+ t.Errorf("AppendBool(%q, %v): expected %q but got %q", test.in, test.b, test.out, b)
+ }
+ }
+}
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 1b3f8fb33..286206481 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -353,17 +353,6 @@ out:
return bits, overflow
}
-func (d *decimal) atof32int() float32 {
- f := float32(0)
- for i := 0; i < d.nd; i++ {
- f = f*10 + float32(d.d[i]-'0')
- }
- if d.neg {
- f = -f
- }
- return f
-}
-
// Exact powers of 10.
var float64pow10 = []float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index 2d0db7155..cbf0380ec 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -142,9 +142,11 @@ Error:
//
// The errors that ParseInt returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
-// digits, err.Err = ErrSyntax; if the value corresponding
-// to s cannot be represented by a signed integer of the
-// given size, err.Err = ErrRange.
+// digits, err.Err = ErrSyntax and the returned value is 0;
+// if the value corresponding to s cannot be represented by a
+// signed integer of the given size, err.Err = ErrRange and the
+// returned value is the maximum magnitude integer of the
+// appropriate bitSize and sign.
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
const fnParseInt = "ParseInt"
diff --git a/src/pkg/strconv/isprint.go b/src/pkg/strconv/isprint.go
index db5f0fbae..91f179535 100644
--- a/src/pkg/strconv/isprint.go
+++ b/src/pkg/strconv/isprint.go
@@ -1,3 +1,7 @@
+// 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.
+
// DO NOT EDIT. GENERATED BY
// go run makeisprint.go >x && mv x isprint.go
diff --git a/src/pkg/strconv/makeisprint.go b/src/pkg/strconv/makeisprint.go
index 8a6699bdb..216159cc0 100644
--- a/src/pkg/strconv/makeisprint.go
+++ b/src/pkg/strconv/makeisprint.go
@@ -122,6 +122,9 @@ func main() {
}
}
+ fmt.Printf(`// 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.` + "\n\n")
fmt.Printf("// DO NOT EDIT. GENERATED BY\n")
fmt.Printf("// go run makeisprint.go >x && mv x isprint.go\n\n")
fmt.Printf("package strconv\n\n")
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 7d6cdcf0b..aded7e593 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -144,7 +144,8 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
// characters other than space and tab.
func CanBackquote(s string) bool {
for i := 0; i < len(s); i++ {
- if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+ c := s[i]
+ if (c < ' ' && c != '\t') || c == '`' || c == '\u007F' {
return false
}
}
diff --git a/src/pkg/strconv/quote_example_test.go b/src/pkg/strconv/quote_example_test.go
new file mode 100644
index 000000000..405a57eb5
--- /dev/null
+++ b/src/pkg/strconv/quote_example_test.go
@@ -0,0 +1,35 @@
+// 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 strconv_test
+
+import (
+ "fmt"
+ "strconv"
+)
+
+func ExampleUnquote() {
+ test := func(s string) {
+ t, err := strconv.Unquote(s)
+ if err != nil {
+ fmt.Printf("Unquote(%#v): %v\n", s, err)
+ } else {
+ fmt.Printf("Unquote(%#v) = %v\n", s, t)
+ }
+ }
+
+ s := `cafe\u0301`
+ // If the string doesn't have quotes, it can't be unquoted.
+ test(s) // invalid syntax
+ test("`" + s + "`")
+ test(`"` + s + `"`)
+
+ test(`'\u00e9'`)
+
+ // Output:
+ // Unquote("cafe\\u0301"): invalid syntax
+ // Unquote("`cafe\\u0301`") = cafe\u0301
+ // Unquote("\"cafe\\u0301\"") = café
+ // Unquote("'\\u00e9'") = é
+}
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 61d9bf9a5..e4b5b6b9f 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -140,6 +140,7 @@ var canbackquotetests = []canBackquoteTest{
{string(29), false},
{string(30), false},
{string(31), false},
+ {string(0x7F), false},
{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
{`0123456789`, true},
{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
diff --git a/src/pkg/strings/example_test.go b/src/pkg/strings/example_test.go
index 36e0a42fb..7243e16b1 100644
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/strings/example_test.go
@@ -7,6 +7,7 @@ package strings_test
import (
"fmt"
"strings"
+ "unicode"
)
func ExampleFields() {
@@ -14,6 +15,14 @@ func ExampleFields() {
// Output: Fields are: ["foo" "bar" "baz"]
}
+func ExampleFieldsFunc() {
+ f := func(c rune) bool {
+ return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+ }
+ fmt.Printf("Fields are: %q", strings.FieldsFunc(" foo1;bar2,baz3...", f))
+ // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
func ExampleContains() {
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
@@ -59,6 +68,25 @@ func ExampleIndex() {
// -1
}
+func ExampleIndexFunc() {
+ f := func(c rune) bool {
+ return unicode.Is(unicode.Han, c)
+ }
+ fmt.Println(strings.IndexFunc("Hello, 世界", f))
+ fmt.Println(strings.IndexFunc("Hello, world", f))
+ // Output:
+ // 7
+ // -1
+}
+
+func ExampleIndexAny() {
+ fmt.Println(strings.IndexAny("chicken", "aeiouy"))
+ fmt.Println(strings.IndexAny("crwth", "aeiouy"))
+ // Output:
+ // 2
+ // -1
+}
+
func ExampleIndexRune() {
fmt.Println(strings.IndexRune("chicken", 'k'))
fmt.Println(strings.IndexRune("chicken", 'd'))
@@ -141,8 +169,8 @@ func ExampleToTitle() {
}
func ExampleTrim() {
- fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
- // Output: ["Achtung"]
+ fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
+ // Output: ["Achtung! Achtung"]
}
func ExampleMap() {
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index 11240efc0..82df97439 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/strings/reader.go
@@ -15,40 +15,41 @@ import (
// from a string.
type Reader struct {
s string
- i int // current reading index
- prevRune int // index of previous rune; or < 0
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0
}
- return len(r.s) - r.i
+ return int(int64(len(r.s)) - r.i)
}
func (r *Reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[r.i:])
- r.i += n
r.prevRune = -1
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
return
}
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ // cannot modify state - see io.ReaderAt
if off < 0 {
- return 0, errors.New("strings: invalid offset")
+ return 0, errors.New("strings.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[int(off):])
+ n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
@@ -56,49 +57,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
}
func (r *Reader) ReadByte() (b byte, err error) {
- if r.i >= len(r.s) {
+ r.prevRune = -1
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
b = r.s[r.i]
r.i++
- r.prevRune = -1
return
}
func (r *Reader) UnreadByte() error {
+ r.prevRune = -1
if r.i <= 0 {
- return errors.New("strings.Reader: at beginning of string")
+ return errors.New("strings.Reader.UnreadByte: at beginning of string")
}
r.i--
- r.prevRune = -1
return nil
}
func (r *Reader) ReadRune() (ch rune, size int, err error) {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
+ r.prevRune = -1
return 0, 0, io.EOF
}
- r.prevRune = r.i
+ r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRuneInString(r.s[r.i:])
- r.i += size
+ r.i += int64(size)
return
}
func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return errors.New("strings.Reader: previous operation was not ReadRune")
+ return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune")
}
- r.i = r.prevRune
+ r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ r.prevRune = -1
var abs int64
switch whence {
case 0:
@@ -108,22 +111,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
case 2:
abs = int64(len(r.s)) + offset
default:
- return 0, errors.New("strings: invalid whence")
+ return 0, errors.New("strings.Reader.Seek: invalid whence")
}
if abs < 0 {
- return 0, errors.New("strings: negative position")
- }
- if abs >= 1<<31 {
- return 0, errors.New("strings: position out of range")
+ return 0, errors.New("strings.Reader.Seek: negative position")
}
- r.i = int(abs)
+ r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, nil
}
s := r.s[r.i:]
@@ -131,7 +131,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
if m > len(s) {
panic("strings.Reader.WriteTo: invalid WriteString count")
}
- r.i += m
+ r.i += int64(m)
n = int64(m)
if m != len(s) && err == nil {
err = io.ErrShortWrite
diff --git a/src/pkg/strings/reader_test.go b/src/pkg/strings/reader_test.go
index 4fdddcdb5..bee90eb25 100644
--- a/src/pkg/strings/reader_test.go
+++ b/src/pkg/strings/reader_test.go
@@ -10,6 +10,7 @@ import (
"io"
"os"
"strings"
+ "sync"
"testing"
)
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"},
- {seek: os.SEEK_SET, off: 1<<31 - 1},
- {seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"},
+ {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
{seek: os.SEEK_SET, n: 5, want: "01234"},
{seek: os.SEEK_CUR, n: 5, want: "56789"},
{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
}
}
+func TestReadAfterBigSeek(t *testing.T) {
+ r := strings.NewReader("0123456789")
+ if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ t.Fatal(err)
+ }
+ if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+ }
+}
+
func TestReaderAt(t *testing.T) {
r := strings.NewReader("0123456789")
tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
- {-1, 0, "", "strings: invalid offset"},
+ {-1, 0, "", "strings.Reader.ReadAt: negative offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
}
}
+func TestReaderAtConcurrent(t *testing.T) {
+ // Test for the race detector, to verify ReadAt doesn't mutate
+ // any state.
+ r := strings.NewReader("0123456789")
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var buf [1]byte
+ r.ReadAt(buf[:], int64(i))
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+ // Test for the race detector, to verify a Read that doesn't yield any bytes
+ // is okay to use from multiple goroutines. This was our historic behavior.
+ // See golang.org/issue/7856
+ r := strings.NewReader("")
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ var buf [1]byte
+ r.Read(buf[:])
+ }()
+ go func() {
+ defer wg.Done()
+ r.Read(nil)
+ }()
+ }
+ wg.Wait()
+}
+
func TestWriteTo(t *testing.T) {
const str = "0123456789"
for i := 0; i <= len(str); i++ {
diff --git a/src/pkg/strings/replace.go b/src/pkg/strings/replace.go
index 54c9323e0..3e05d2057 100644
--- a/src/pkg/strings/replace.go
+++ b/src/pkg/strings/replace.go
@@ -492,7 +492,7 @@ func (r *byteStringReplacer) Replace(s string) string {
for i := 0; i < len(s); i++ {
b := s[i]
if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
- n := copy(bi[:], r.new[b])
+ n := copy(bi, r.new[b])
bi = bi[n:]
} else {
bi[0] = b
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index df0dd7165..e40a18015 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -652,7 +652,7 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
e1 := Split(s1, "")
e2 := Split(s2, "")
for i, c1 := range e1 {
- if i > len(e2) {
+ if i >= len(e2) {
break
}
r1, _ := utf8.DecodeRuneInString(c1)
@@ -858,6 +858,32 @@ func TestReadRune(t *testing.T) {
}
}
+var UnreadRuneErrorTests = []struct {
+ name string
+ f func(*Reader)
+}{
+ {"Read", func(r *Reader) { r.Read([]byte{0}) }},
+ {"ReadByte", func(r *Reader) { r.ReadByte() }},
+ {"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+ {"Seek", func(r *Reader) { r.Seek(0, 1) }},
+ {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+ for _, tt := range UnreadRuneErrorTests {
+ reader := NewReader("0123456789")
+ if _, _, err := reader.ReadRune(); err != nil {
+ // should not happen
+ t.Fatal(err)
+ }
+ tt.f(reader)
+ err := reader.UnreadRune()
+ if err == nil {
+ t.Errorf("Unreading after %s: expected error", tt.name)
+ }
+ }
+}
+
var ReplaceTests = []struct {
in string
old, new string
@@ -903,6 +929,8 @@ var TitleTests = []struct {
{"123a456", "123a456"},
{"double-blind", "Double-Blind"},
{"ÿøû", "Ÿøû"},
+ {"with_underscore", "With_underscore"},
+ {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
}
func TestTitle(t *testing.T) {
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index eaa72eabb..807c2f873 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-12
MOVL addr+0(FP), BP
MOVL new+4(FP), AX
XCHGL AX, 0(BP)
- MOVL AX, new+8(FP)
+ MOVL AX, old+8(FP)
RET
TEXT ·SwapInt64(SB),NOSPLIT,$0-20
@@ -43,8 +43,8 @@ swaploop:
// success
// return DX:AX
- MOVL AX, new_lo+12(FP)
- MOVL DX, new_hi+16(FP)
+ MOVL AX, old_lo+12(FP)
+ MOVL DX, old_hi+16(FP)
RET
TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
@@ -155,10 +155,10 @@ TEXT ·LoadUint32(SB),NOSPLIT,$0-8
MOVL AX, val+4(FP)
RET
-TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+TEXT ·LoadInt64(SB),NOSPLIT,$0-12
JMP ·LoadUint64(SB)
-TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+TEXT ·LoadUint64(SB),NOSPLIT,$0-12
MOVL addr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
@@ -186,10 +186,10 @@ TEXT ·StoreUint32(SB),NOSPLIT,$0-8
XCHGL AX, 0(BP)
RET
-TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+TEXT ·StoreInt64(SB),NOSPLIT,$0-12
JMP ·StoreUint64(SB)
-TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+TEXT ·StoreUint64(SB),NOSPLIT,$0-12
MOVL addr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
index 0900492dc..77afa129e 100644
--- a/src/pkg/sync/atomic/asm_amd64.s
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-20
MOVQ addr+0(FP), BP
MOVL new+8(FP), AX
XCHGL AX, 0(BP)
- MOVL AX, new+16(FP)
+ MOVL AX, old+16(FP)
RET
TEXT ·SwapInt64(SB),NOSPLIT,$0-24
@@ -23,7 +23,7 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
MOVQ addr+0(FP), BP
MOVQ new+8(FP), AX
XCHGQ AX, 0(BP)
- MOVQ AX, new+16(FP)
+ MOVQ AX, old+16(FP)
RET
TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
diff --git a/src/pkg/sync/atomic/asm_amd64p32.s b/src/pkg/sync/atomic/asm_amd64p32.s
new file mode 100644
index 000000000..b24ae7a59
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_amd64p32.s
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), BX
+ MOVL new+4(FP), AX
+ XCHGL AX, 0(BX)
+ MOVL AX, old+8(FP)
+ RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+ JMP ·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ new+8(FP), AX
+ XCHGQ AX, 0(BX)
+ MOVQ AX, old+16(FP)
+ RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·SwapPointer(SB),NOSPLIT,$0-12
+ JMP ·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+ MOVL addr+0(FP), BX
+ MOVL old+4(FP), AX
+ MOVL new+8(FP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ SETEQ swapped+16(FP)
+ RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-17
+ JMP ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+ JMP ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ old+8(FP), AX
+ MOVQ new+16(FP), CX
+ LOCK
+ CMPXCHGQ CX, 0(BX)
+ SETEQ swapped+24(FP)
+ RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-12
+ JMP ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), BX
+ MOVL delta+4(FP), AX
+ MOVL AX, CX
+ LOCK
+ XADDL AX, 0(BX)
+ ADDL AX, CX
+ MOVL CX, new+8(FP)
+ RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-12
+ JMP ·AddUint32(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+ JMP ·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ delta+8(FP), AX
+ MOVQ AX, CX
+ LOCK
+ XADDQ AX, 0(BX)
+ ADDQ AX, CX
+ MOVQ CX, new+16(FP)
+ RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+ JMP ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, val+8(FP)
+ RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+ JMP ·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+ MOVL addr+0(FP), AX
+ TESTL $7, AX
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
+ MOVQ 0(AX), AX
+ MOVQ AX, val+8(FP)
+ RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-12
+ JMP ·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-12
+ MOVL addr+0(FP), AX
+ MOVL 0(AX), AX
+ MOVL AX, val+8(FP)
+ RET
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-8
+ JMP ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+ JMP ·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+ MOVL addr+0(FP), BX
+ TESTL $7, BX
+ JZ 2(PC)
+ MOVL 0, BX // crash with nil ptr deref
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
+ JMP ·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-8
+ MOVL addr+0(FP), BX
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BX)
+ RET
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index b85ca0a13..27be57aa1 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -42,7 +42,7 @@ casagain:
BCC cascheck
MOVW $1, R0
casret:
- MOVW R0, ret+12(FP)
+ MOVB R0, swapped+12(FP)
RET
cascheck:
// Kernel lies; double-check.
@@ -73,7 +73,7 @@ addloop1:
ADD R4, R1
BL cas<>(SB)
BCC addloop1
- MOVW R1, ret+8(FP)
+ MOVW R1, new+8(FP)
RET
TEXT ·AddUintptr(SB),NOSPLIT,$0
@@ -132,13 +132,13 @@ TEXT ·generalCAS64(SB),NOSPLIT,$20-21
BEQ 2(PC)
MOVW R1, (R1)
MOVW R0, 4(R13)
- MOVW oldlo+4(FP), R1
+ MOVW old_lo+4(FP), R1
MOVW R1, 8(R13)
- MOVW oldhi+8(FP), R1
+ MOVW old_hi+8(FP), R1
MOVW R1, 12(R13)
- MOVW newlo+12(FP), R2
+ MOVW new_lo+12(FP), R2
MOVW R2, 16(R13)
- MOVW newhi+16(FP), R3
+ MOVW new_hi+16(FP), R3
MOVW R3, 20(R13)
BL runtime·cas64(SB)
MOVB R0, ret+20(FP)
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index e10effe7e..a5f44f70d 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
old := SwapUintptr(addr, new)
if old>>16 != old<<16>>16 {
- panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+ panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old))
}
}
}
@@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) {
new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
if old>>16 != old<<16>>16 {
- panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
+ panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
}
}
}
@@ -1463,6 +1463,9 @@ func TestUnaligned64(t *testing.T) {
}
func TestNilDeref(t *testing.T) {
+ if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" {
+ t.Skipf("issue 7338: skipping test on %q", p)
+ }
funcs := [...]func(){
func() { CompareAndSwapInt32(nil, 0, 0) },
func() { CompareAndSwapInt64(nil, 0, 0) },
diff --git a/src/pkg/sync/atomic/export_linux_arm_test.go b/src/pkg/sync/atomic/export_linux_arm_test.go
index 8c0b5a75c..5cd43353e 100644
--- a/src/pkg/sync/atomic/export_linux_arm_test.go
+++ b/src/pkg/sync/atomic/export_linux_arm_test.go
@@ -4,6 +4,6 @@
package atomic
-func generalCAS64(*uint64, uint64, uint64) bool
+func generalCAS64(addr *uint64, old uint64, new uint64) bool
var GeneralCAS64 = generalCAS64
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index bf78c6f60..151b25c10 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -9,7 +9,6 @@ package sync_test
import (
"runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -90,63 +89,34 @@ func BenchmarkMutexUncontended(b *testing.B) {
Mutex
pad [128]uint8
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var mu PaddedMutex
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- mu.Lock()
- mu.Unlock()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var mu PaddedMutex
+ for pb.Next() {
+ mu.Lock()
+ mu.Unlock()
+ }
+ })
}
func benchmarkMutex(b *testing.B, slack, work bool) {
- const (
- CallsPerSched = 1000
- LocalWork = 100
- GoroutineSlack = 10
- )
- procs := runtime.GOMAXPROCS(-1)
+ var mu Mutex
if slack {
- procs *= GoroutineSlack
+ b.SetParallelism(10)
}
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- var mu Mutex
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- mu.Lock()
- mu.Unlock()
- if work {
- for i := 0; i < LocalWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ mu.Lock()
+ mu.Unlock()
+ if work {
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
}
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkMutex(b *testing.B) {
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
index 183069a1a..8afda82f3 100644
--- a/src/pkg/sync/once_test.go
+++ b/src/pkg/sync/once_test.go
@@ -5,9 +5,7 @@
package sync_test
import (
- "runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -62,24 +60,11 @@ func TestOncePanic(t *testing.T) {
}
func BenchmarkOnce(b *testing.B) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
var once Once
f := func() {}
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- once.Do(f)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ once.Do(f)
+ }
+ })
}
diff --git a/src/pkg/sync/pool.go b/src/pkg/sync/pool.go
new file mode 100644
index 000000000..1f08707cd
--- /dev/null
+++ b/src/pkg/sync/pool.go
@@ -0,0 +1,223 @@
+// 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 sync
+
+import (
+ "runtime"
+ "sync/atomic"
+ "unsafe"
+)
+
+// A Pool is a set of temporary objects that may be individually saved and
+// retrieved.
+//
+// Any item stored in the Pool may be removed automatically at any time without
+// notification. If the Pool holds the only reference when this happens, the
+// item might be deallocated.
+//
+// A Pool is safe for use by multiple goroutines simultaneously.
+//
+// Pool's purpose is to cache allocated but unused items for later reuse,
+// relieving pressure on the garbage collector. That is, it makes it easy to
+// build efficient, thread-safe free lists. However, it is not suitable for all
+// free lists.
+//
+// An appropriate use of a Pool is to manage a group of temporary items
+// silently shared among and potentially reused by concurrent independent
+// clients of a package. Pool provides a way to amortize allocation overhead
+// across many clients.
+//
+// An example of good use of a Pool is in the fmt package, which maintains a
+// dynamically-sized store of temporary output buffers. The store scales under
+// load (when many goroutines are actively printing) and shrinks when
+// quiescent.
+//
+// On the other hand, a free list maintained as part of a short-lived object is
+// not a suitable use for a Pool, since the overhead does not amortize well in
+// that scenario. It is more efficient to have such objects implement their own
+// free list.
+//
+type Pool struct {
+ local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
+ localSize uintptr // size of the local array
+
+ // New optionally specifies a function to generate
+ // a value when Get would otherwise return nil.
+ // It may not be changed concurrently with calls to Get.
+ New func() interface{}
+}
+
+// Local per-P Pool appendix.
+type poolLocal struct {
+ private interface{} // Can be used only by the respective P.
+ shared []interface{} // Can be used by any P.
+ Mutex // Protects shared.
+ pad [128]byte // Prevents false sharing.
+}
+
+// Put adds x to the pool.
+func (p *Pool) Put(x interface{}) {
+ if raceenabled {
+ // Under race detector the Pool degenerates into no-op.
+ // It's conforming, simple and does not introduce excessive
+ // happens-before edges between unrelated goroutines.
+ return
+ }
+ if x == nil {
+ return
+ }
+ l := p.pin()
+ if l.private == nil {
+ l.private = x
+ x = nil
+ }
+ runtime_procUnpin()
+ if x == nil {
+ return
+ }
+ l.Lock()
+ l.shared = append(l.shared, x)
+ l.Unlock()
+}
+
+// Get selects an arbitrary item from the Pool, removes it from the
+// Pool, and returns it to the caller.
+// Get may choose to ignore the pool and treat it as empty.
+// Callers should not assume any relation between values passed to Put and
+// the values returned by Get.
+//
+// If Get would otherwise return nil and p.New is non-nil, Get returns
+// the result of calling p.New.
+func (p *Pool) Get() interface{} {
+ if raceenabled {
+ if p.New != nil {
+ return p.New()
+ }
+ return nil
+ }
+ l := p.pin()
+ x := l.private
+ l.private = nil
+ runtime_procUnpin()
+ if x != nil {
+ return x
+ }
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ }
+ l.Unlock()
+ if x != nil {
+ return x
+ }
+ return p.getSlow()
+}
+
+func (p *Pool) getSlow() (x interface{}) {
+ // See the comment in pin regarding ordering of the loads.
+ size := atomic.LoadUintptr(&p.localSize) // load-acquire
+ local := p.local // load-consume
+ // Try to steal one element from other procs.
+ pid := runtime_procPin()
+ runtime_procUnpin()
+ for i := 0; i < int(size); i++ {
+ l := indexLocal(local, (pid+i+1)%int(size))
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ l.Unlock()
+ break
+ }
+ l.Unlock()
+ }
+
+ if x == nil && p.New != nil {
+ x = p.New()
+ }
+ return x
+}
+
+// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P.
+// Caller must call runtime_procUnpin() when done with the pool.
+func (p *Pool) pin() *poolLocal {
+ pid := runtime_procPin()
+ // In pinSlow we store to localSize and then to local, here we load in opposite order.
+ // Since we've disabled preemption, GC can not happen in between.
+ // Thus here we must observe local at least as large localSize.
+ // We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
+ s := atomic.LoadUintptr(&p.localSize) // load-acquire
+ l := p.local // load-consume
+ if uintptr(pid) < s {
+ return indexLocal(l, pid)
+ }
+ return p.pinSlow()
+}
+
+func (p *Pool) pinSlow() *poolLocal {
+ // Retry under the mutex.
+ // Can not lock the mutex while pinned.
+ runtime_procUnpin()
+ allPoolsMu.Lock()
+ defer allPoolsMu.Unlock()
+ pid := runtime_procPin()
+ // poolCleanup won't be called while we are pinned.
+ s := p.localSize
+ l := p.local
+ if uintptr(pid) < s {
+ return indexLocal(l, pid)
+ }
+ if p.local == nil {
+ allPools = append(allPools, p)
+ }
+ // If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
+ size := runtime.GOMAXPROCS(0)
+ local := make([]poolLocal, size)
+ atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release
+ atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release
+ return &local[pid]
+}
+
+func poolCleanup() {
+ // This function is called with the world stopped, at the beginning of a garbage collection.
+ // It must not allocate and probably should not call any runtime functions.
+ // Defensively zero out everything, 2 reasons:
+ // 1. To prevent false retention of whole Pools.
+ // 2. If GC happens while a goroutine works with l.shared in Put/Get,
+ // it will retain whole Pool. So next cycle memory consumption would be doubled.
+ for i, p := range allPools {
+ allPools[i] = nil
+ for i := 0; i < int(p.localSize); i++ {
+ l := indexLocal(p.local, i)
+ l.private = nil
+ for j := range l.shared {
+ l.shared[j] = nil
+ }
+ l.shared = nil
+ }
+ }
+ allPools = []*Pool{}
+}
+
+var (
+ allPoolsMu Mutex
+ allPools []*Pool
+)
+
+func init() {
+ runtime_registerPoolCleanup(poolCleanup)
+}
+
+func indexLocal(l unsafe.Pointer, i int) *poolLocal {
+ return &(*[1000000]poolLocal)(l)[i]
+}
+
+// Implemented in runtime.
+func runtime_registerPoolCleanup(cleanup func())
+func runtime_procPin() int
+func runtime_procUnpin()
diff --git a/src/pkg/sync/pool_test.go b/src/pkg/sync/pool_test.go
new file mode 100644
index 000000000..509448b62
--- /dev/null
+++ b/src/pkg/sync/pool_test.go
@@ -0,0 +1,151 @@
+// 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.
+
+// Pool is no-op under race detector, so all these tests do not work.
+// +build !race
+
+package sync_test
+
+import (
+ "runtime"
+ "runtime/debug"
+ . "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+func TestPool(t *testing.T) {
+ // disable GC so we can control when it happens.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+ var p Pool
+ if p.Get() != nil {
+ t.Fatal("expected empty")
+ }
+ p.Put("a")
+ p.Put("b")
+ if g := p.Get(); g != "a" {
+ t.Fatalf("got %#v; want a", g)
+ }
+ if g := p.Get(); g != "b" {
+ t.Fatalf("got %#v; want b", g)
+ }
+ if g := p.Get(); g != nil {
+ t.Fatalf("got %#v; want nil", g)
+ }
+
+ p.Put("c")
+ debug.SetGCPercent(100) // to allow following GC to actually run
+ runtime.GC()
+ if g := p.Get(); g != nil {
+ t.Fatalf("got %#v; want nil after GC", g)
+ }
+}
+
+func TestPoolNew(t *testing.T) {
+ // disable GC so we can control when it happens.
+ defer debug.SetGCPercent(debug.SetGCPercent(-1))
+
+ i := 0
+ p := Pool{
+ New: func() interface{} {
+ i++
+ return i
+ },
+ }
+ if v := p.Get(); v != 1 {
+ t.Fatalf("got %v; want 1", v)
+ }
+ if v := p.Get(); v != 2 {
+ t.Fatalf("got %v; want 2", v)
+ }
+ p.Put(42)
+ if v := p.Get(); v != 42 {
+ t.Fatalf("got %v; want 42", v)
+ }
+ if v := p.Get(); v != 3 {
+ t.Fatalf("got %v; want 3", v)
+ }
+}
+
+// Test that Pool does not hold pointers to previously cached
+// resources
+func TestPoolGC(t *testing.T) {
+ var p Pool
+ var fin uint32
+ const N = 100
+ for i := 0; i < N; i++ {
+ v := new(string)
+ runtime.SetFinalizer(v, func(vv *string) {
+ atomic.AddUint32(&fin, 1)
+ })
+ p.Put(v)
+ }
+ for i := 0; i < N; i++ {
+ p.Get()
+ }
+ for i := 0; i < 5; i++ {
+ runtime.GC()
+ time.Sleep(time.Duration(i*100+10) * time.Millisecond)
+ // 1 pointer can remain on stack or elsewhere
+ if atomic.LoadUint32(&fin) >= N-1 {
+ return
+ }
+ }
+ t.Fatalf("only %v out of %v resources are finalized",
+ atomic.LoadUint32(&fin), N)
+}
+
+func TestPoolStress(t *testing.T) {
+ const P = 10
+ N := int(1e6)
+ if testing.Short() {
+ N /= 100
+ }
+ var p Pool
+ done := make(chan bool)
+ for i := 0; i < P; i++ {
+ go func() {
+ var v interface{} = 0
+ for j := 0; j < N; j++ {
+ if v == nil {
+ v = 0
+ }
+ p.Put(v)
+ v = p.Get()
+ if v != nil && v.(int) != 0 {
+ t.Fatalf("expect 0, got %v", v)
+ }
+ }
+ done <- true
+ }()
+ }
+ for i := 0; i < P; i++ {
+ <-done
+ }
+}
+
+func BenchmarkPool(b *testing.B) {
+ var p Pool
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ p.Put(1)
+ p.Get()
+ }
+ })
+}
+
+func BenchmarkPoolOverlflow(b *testing.B) {
+ var p Pool
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ for b := 0; b < 100; b++ {
+ p.Put(1)
+ }
+ for b := 0; b < 100; b++ {
+ p.Get()
+ }
+ }
+ })
+}
diff --git a/src/pkg/sync/runtime_sema_test.go b/src/pkg/sync/runtime_sema_test.go
index 57a8dbee7..5b7dd3df3 100644
--- a/src/pkg/sync/runtime_sema_test.go
+++ b/src/pkg/sync/runtime_sema_test.go
@@ -7,7 +7,6 @@ package sync_test
import (
"runtime"
. "sync"
- "sync/atomic"
"testing"
)
@@ -16,72 +15,44 @@ func BenchmarkSemaUncontended(b *testing.B) {
sem uint32
pad [32]uint32
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- sem := new(PaddedSem)
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- Runtime_Semrelease(&sem.sem)
- Runtime_Semacquire(&sem.sem)
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ sem := new(PaddedSem)
+ for pb.Next() {
+ Runtime_Semrelease(&sem.sem)
+ Runtime_Semacquire(&sem.sem)
+ }
+ })
}
func benchmarkSema(b *testing.B, block, work bool) {
- const CallsPerSched = 1000
- const LocalWork = 100
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- c2 := make(chan bool, procs/2)
sem := uint32(0)
if block {
- for p := 0; p < procs/2; p++ {
- go func() {
- Runtime_Semacquire(&sem)
- c2 <- true
- }()
- }
- }
- for p := 0; p < procs; p++ {
+ done := make(chan bool)
go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- Runtime_Semrelease(&sem)
- if work {
- for i := 0; i < LocalWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
- Runtime_Semacquire(&sem)
- }
+ for p := 0; p < runtime.GOMAXPROCS(0)/2; p++ {
+ Runtime_Semacquire(&sem)
}
- c <- foo == 42
- Runtime_Semrelease(&sem)
+ done <- true
+ }()
+ defer func() {
+ <-done
}()
}
- if block {
- for p := 0; p < procs/2; p++ {
- <-c2
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ Runtime_Semrelease(&sem)
+ if work {
+ for i := 0; i < 100; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ Runtime_Semacquire(&sem)
}
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ _ = foo
+ Runtime_Semrelease(&sem)
+ })
}
func BenchmarkSemaSyntNonblock(b *testing.B) {
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index 39d5d6540..0436f9723 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_test.go
@@ -160,64 +160,39 @@ func BenchmarkRWMutexUncontended(b *testing.B) {
RWMutex
pad [32]uint32
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var rwm PaddedRWMutex
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- rwm.RLock()
- rwm.RLock()
- rwm.RUnlock()
- rwm.RUnlock()
- rwm.Lock()
- rwm.Unlock()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var rwm PaddedRWMutex
+ for pb.Next() {
+ rwm.RLock()
+ rwm.RLock()
+ rwm.RUnlock()
+ rwm.RUnlock()
+ rwm.Lock()
+ rwm.Unlock()
+ }
+ })
}
func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var rwm RWMutex
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- foo++
- if foo%writeRatio == 0 {
- rwm.Lock()
- rwm.Unlock()
- } else {
- rwm.RLock()
- for i := 0; i != localWork; i += 1 {
- foo *= 2
- foo /= 2
- }
- rwm.RUnlock()
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ foo++
+ if foo%writeRatio == 0 {
+ rwm.Lock()
+ rwm.Unlock()
+ } else {
+ rwm.RLock()
+ for i := 0; i != localWork; i += 1 {
+ foo *= 2
+ foo /= 2
}
+ rwm.RUnlock()
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkRWMutexWrite100(b *testing.B) {
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index 22681115c..4c64dca39 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -67,11 +67,13 @@ func (wg *WaitGroup) Add(delta int) {
return
}
wg.m.Lock()
- for i := int32(0); i < wg.waiters; i++ {
- runtime_Semrelease(wg.sema)
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ for i := int32(0); i < wg.waiters; i++ {
+ runtime_Semrelease(wg.sema)
+ }
+ wg.waiters = 0
+ wg.sema = nil
}
- wg.waiters = 0
- wg.sema = nil
wg.m.Unlock()
}
diff --git a/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
index 84c4cfc37..4c0a043c0 100644
--- a/src/pkg/sync/waitgroup_test.go
+++ b/src/pkg/sync/waitgroup_test.go
@@ -5,7 +5,6 @@
package sync_test
import (
- "runtime"
. "sync"
"sync/atomic"
"testing"
@@ -61,60 +60,60 @@ func TestWaitGroupMisuse(t *testing.T) {
t.Fatal("Should panic")
}
+func TestWaitGroupRace(t *testing.T) {
+ // Run this test for about 1ms.
+ for i := 0; i < 1000; i++ {
+ wg := &WaitGroup{}
+ n := new(int32)
+ // spawn goroutine 1
+ wg.Add(1)
+ go func() {
+ atomic.AddInt32(n, 1)
+ wg.Done()
+ }()
+ // spawn goroutine 2
+ wg.Add(1)
+ go func() {
+ atomic.AddInt32(n, 1)
+ wg.Done()
+ }()
+ // Wait for goroutine 1 and 2
+ wg.Wait()
+ if atomic.LoadInt32(n) != 2 {
+ t.Fatal("Spurious wakeup from Wait")
+ }
+ }
+}
+
func BenchmarkWaitGroupUncontended(b *testing.B) {
type PaddedWaitGroup struct {
WaitGroup
pad [128]uint8
}
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
- for p := 0; p < procs; p++ {
- go func() {
- var wg PaddedWaitGroup
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Add(1)
- wg.Done()
- wg.Wait()
- }
- }
- c <- true
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ b.RunParallel(func(pb *testing.PB) {
+ var wg PaddedWaitGroup
+ for pb.Next() {
+ wg.Add(1)
+ wg.Done()
+ wg.Wait()
+ }
+ })
}
func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var wg WaitGroup
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Add(1)
- for i := 0; i < localWork; i++ {
- foo *= 2
- foo /= 2
- }
- wg.Done()
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ wg.Add(1)
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ wg.Done()
+ }
+ _ = foo
+ })
}
func BenchmarkWaitGroupAddDone(b *testing.B) {
@@ -126,34 +125,18 @@ func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
}
func benchmarkWaitGroupWait(b *testing.B, localWork int) {
- const CallsPerSched = 1000
- procs := runtime.GOMAXPROCS(-1)
- N := int32(b.N / CallsPerSched)
- c := make(chan bool, procs)
var wg WaitGroup
- wg.Add(procs)
- for p := 0; p < procs; p++ {
- go wg.Done()
- }
- for p := 0; p < procs; p++ {
- go func() {
- foo := 0
- for atomic.AddInt32(&N, -1) >= 0 {
- runtime.Gosched()
- for g := 0; g < CallsPerSched; g++ {
- wg.Wait()
- for i := 0; i < localWork; i++ {
- foo *= 2
- foo /= 2
- }
- }
+ b.RunParallel(func(pb *testing.PB) {
+ foo := 0
+ for pb.Next() {
+ wg.Wait()
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
}
- c <- foo == 42
- }()
- }
- for p := 0; p < procs; p++ {
- <-c
- }
+ }
+ _ = foo
+ })
}
func BenchmarkWaitGroupWait(b *testing.B) {
diff --git a/src/pkg/syscall/asm_darwin_386.s b/src/pkg/syscall/asm_darwin_386.s
index 2ddfb3bbd..9b4dfa81d 100644
--- a/src/pkg/syscall/asm_darwin_386.s
+++ b/src/pkg/syscall/asm_darwin_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_darwin_amd64.s b/src/pkg/syscall/asm_darwin_amd64.s
index c1970b71d..19ea05be7 100644
--- a/src/pkg/syscall/asm_darwin_amd64.s
+++ b/src/pkg/syscall/asm_darwin_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -60,7 +63,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -81,7 +84,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_386.s b/src/pkg/syscall/asm_freebsd_386.s
index d24216fdd..91a46b106 100644
--- a/src/pkg/syscall/asm_freebsd_386.s
+++ b/src/pkg/syscall/asm_freebsd_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_freebsd_amd64.s b/src/pkg/syscall/asm_freebsd_amd64.s
index fca7f371e..7abb36828 100644
--- a/src/pkg/syscall/asm_freebsd_amd64.s
+++ b/src/pkg/syscall/asm_freebsd_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -18,7 +21,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -41,7 +44,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -64,7 +67,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX
MOVQ 16(SP), DI
@@ -97,7 +100,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -117,7 +120,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_arm.s b/src/pkg/syscall/asm_freebsd_arm.s
index 9283d079b..c01ce6feb 100644
--- a/src/pkg/syscall/asm_freebsd_arm.s
+++ b/src/pkg/syscall/asm_freebsd_arm.s
@@ -8,13 +8,13 @@
// System call support for ARM, FreeBSD
//
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32)
+// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, errno uintptr);
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr);
+// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr)
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
@@ -23,69 +23,71 @@ TEXT ·Syscall(SB),NOSPLIT,$0-28
BCS error
MOVW R0, 16(FP) // r1
MOVW R1, 20(FP) // r2
- MOVW R2, 24(FP) // err
+ MOVW R2, 24(FP) // errno
BL runtime·exitsyscall(SB)
RET
error:
MOVW $-1, R3
MOVW R3, 16(FP) // r1
MOVW R2, 20(FP) // r2
- MOVW R0, 24(FP) // err
+ MOVW R0, 24(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·Syscall6(SB),NOSPLIT,$0-40
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a6 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS error6
MOVW R0, 28(FP) // r1
MOVW R1, 32(FP) // r2
- MOVW R2, 36(FP) // err
+ MOVW R2, 36(FP) // errno
BL runtime·exitsyscall(SB)
RET
error6:
MOVW $-1, R3
MOVW R3, 28(FP) // r1
MOVW R2, 32(FP) // r2
- MOVW R0, 36(FP) // err
+ MOVW R0, 36(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·Syscall9(SB),NOSPLIT,$0-52
BL runtime·entersyscall(SB)
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a9 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a9 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS error9
MOVW R0, 40(FP) // r1
MOVW R1, 44(FP) // r2
- MOVW R2, 48(FP) // err
+ MOVW R2, 48(FP) // errno
BL runtime·exitsyscall(SB)
RET
error9:
MOVW $-1, R3
MOVW R3, 40(FP) // r1
MOVW R2, 44(FP) // r2
- MOVW R0, 48(FP) // err
+ MOVW R0, 48(FP) // errno
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
@@ -94,33 +96,34 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28
BCS errorr
MOVW R0, 16(FP) // r1
MOVW R1, 20(FP) // r2
- MOVW R2, 24(FP) // err
+ MOVW R2, 24(FP) // errno
RET
errorr:
MOVW $-1, R3
MOVW R3, 16(FP) // r1
MOVW R2, 20(FP) // r2
- MOVW R0, 24(FP) // err
+ MOVW R0, 24(FP) // errno
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVW 0(FP), R7 // sigcall num
+ MOVW 0(FP), R7 // syscall number
MOVW 4(FP), R0 // a1
MOVW 8(FP), R1 // a2
MOVW 12(FP), R2 // a3
MOVW 16(FP), R3 // a4
- ADD $24, R13 // a5 to a6 are passed on stack
+ MOVW R13, R4
+ MOVW $20(FP), R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- SUB $24, R13
+ MOVW R4, R13
MOVW $0, R2
BCS errorr6
MOVW R0, 28(FP) // r1
MOVW R1, 32(FP) // r2
- MOVW R2, 36(FP) // err
+ MOVW R2, 36(FP) // errno
RET
errorr6:
MOVW $-1, R3
MOVW R3, 28(FP) // r1
MOVW R2, 32(FP) // r2
- MOVW R0, 36(FP) // err
+ MOVW R0, 36(FP) // errno
RET
diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s
index cf2ab02ab..30b22073d 100644
--- a/src/pkg/syscall/asm_linux_386.s
+++ b/src/pkg/syscall/asm_linux_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -11,7 +14,7 @@
// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
// Trap # in AX, args in BX CX DX SI DI, return in AX
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
@@ -36,7 +39,7 @@ ok:
RET
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
@@ -62,7 +65,7 @@ ok6:
RET
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
MOVL 12(SP), CX
@@ -84,7 +87,7 @@ ok1:
RET
// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
MOVL 8(SP), BX
MOVL 12(SP), CX
@@ -110,7 +113,7 @@ ok2:
// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
// Kernel interface gets call sub-number and pointer to a0.
-TEXT ·socketcall(SB),NOSPLIT,$0-40
+TEXT ·socketcall(SB),NOSPLIT,$0-36
CALL runtime·entersyscall(SB)
MOVL $SYS_SOCKETCALL, AX // syscall entry
MOVL 4(SP), BX // socket call number
@@ -134,7 +137,7 @@ oksock:
// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
// Kernel interface gets call sub-number and pointer to a0.
-TEXT ·rawsocketcall(SB),NOSPLIT,$0-40
+TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
MOVL $SYS_SOCKETCALL, AX // syscall entry
MOVL 4(SP), BX // socket call number
LEAL 8(SP), CX // pointer to call arguments
@@ -159,7 +162,7 @@ oksock1:
// taking the address of the return value newoffset.
// Underlying system call is
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL $SYS__LLSEEK, AX // syscall entry
MOVL 4(SP), BX // fd
diff --git a/src/pkg/syscall/asm_linux_amd64.s b/src/pkg/syscall/asm_linux_amd64.s
index 28a2a5809..995b60ecd 100644
--- a/src/pkg/syscall/asm_linux_amd64.s
+++ b/src/pkg/syscall/asm_linux_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// Note that this differs from "standard" ABI convention, which
// would pass 4th arg in CX, not R10.
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -38,7 +41,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 16(SP), DI
MOVQ 24(SP), SI
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -85,7 +88,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -107,7 +110,7 @@ ok2:
MOVQ $0, 80(SP) // errno
RET
-TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
+TEXT ·gettimeofday(SB),NOSPLIT,$0-16
MOVQ 8(SP), DI
MOVQ $0, SI
MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
@@ -121,11 +124,3 @@ TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
ok7:
MOVQ $0, 16(SP) // errno
RET
-
-TEXT ·Time(SB),NOSPLIT,$0-32
- MOVQ 8(SP), DI
- MOVQ runtime·__vdso_time_sym(SB), AX
- CALL AX
- MOVQ AX, 16(SP) // tt
- MOVQ $0, 24(SP) // errno
- RET
diff --git a/src/pkg/syscall/asm_linux_arm.s b/src/pkg/syscall/asm_linux_arm.s
index bf54b4fe6..a28bc6cfc 100644
--- a/src/pkg/syscall/asm_linux_arm.s
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -98,12 +98,12 @@ ok2:
RET
#define SYS__LLSEEK 140 /* from zsysnum_linux_arm.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// func seek(fd int, offset int64, whence int) (newoffset int64, errno int)
// Implemented in assembly to avoid allocation when
// taking the address of the return value newoffset.
// Underlying system call is
// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-32
BL runtime·entersyscall(SB)
MOVW $SYS__LLSEEK, R7 // syscall entry
MOVW 4(SP), R0 // fd
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
new file mode 100644
index 000000000..de7c3cc5d
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_386.s
@@ -0,0 +1,43 @@
+// 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for 386, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$12-28
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX
+ MOVL a1+4(FP), BX
+ MOVL BX, 0(SP)
+ MOVL a2+8(FP), BX
+ MOVL BX, 4(SP)
+ MOVL a3+12(FP), BX
+ MOVL BX, 8(SP)
+ SHLL $5, AX
+ ADDL $0x10000, AX
+ CALL AX
+ CMPL AX, $0
+ JGE ok
+ MOVL $-1, r1+16(FP)
+ MOVL $-1, r2+20(FP)
+ NEGL AX
+ MOVL AX, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ MOVL $0, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/pkg/syscall/asm_nacl_amd64p32.s b/src/pkg/syscall/asm_nacl_amd64p32.s
new file mode 100644
index 000000000..de030ec80
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_amd64p32.s
@@ -0,0 +1,41 @@
+// 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for amd64, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX
+ MOVL a1+4(FP), DI
+ MOVL a2+8(FP), SI
+ MOVL a3+12(FP), DX
+ // more args would use CX, R8, R9
+ SHLL $5, AX
+ ADDL $0x10000, AX
+ CALL AX
+ CMPL AX, $0
+ JGE ok
+ MOVL $-1, r1+16(FP)
+ MOVL $-1, r2+20(FP)
+ NEGL AX
+ MOVL AX, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ MOVL $0, err+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/pkg/syscall/asm_netbsd_386.s b/src/pkg/syscall/asm_netbsd_386.s
index 8caade255..40b30b405 100644
--- a/src/pkg/syscall/asm_netbsd_386.s
+++ b/src/pkg/syscall/asm_netbsd_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_netbsd_amd64.s b/src/pkg/syscall/asm_netbsd_amd64.s
index e0b8b3cb8..94ad0284a 100644
--- a/src/pkg/syscall/asm_netbsd_amd64.s
+++ b/src/pkg/syscall/asm_netbsd_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -59,7 +62,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -91,7 +94,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -111,7 +114,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_openbsd_386.s b/src/pkg/syscall/asm_openbsd_386.s
index a38349661..7dd2e373f 100644
--- a/src/pkg/syscall/asm_openbsd_386.s
+++ b/src/pkg/syscall/asm_openbsd_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -12,7 +15,7 @@
// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
// Trap # in AX, args on stack above caller pc.
-TEXT ·Syscall(SB),NOSPLIT,$0-32
+TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-44
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
CALL runtime·entersyscall(SB)
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -114,7 +117,7 @@ ok1:
MOVL $0, 28(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
diff --git a/src/pkg/syscall/asm_openbsd_amd64.s b/src/pkg/syscall/asm_openbsd_amd64.s
index 1bf25f1db..e127bf220 100644
--- a/src/pkg/syscall/asm_openbsd_amd64.s
+++ b/src/pkg/syscall/asm_openbsd_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -13,7 +16,7 @@
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
// Trap # in AX, args in DI SI DX, return in AX DX
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -36,7 +39,7 @@ ok:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -59,7 +62,7 @@ ok6:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
CALL runtime·entersyscall(SB)
MOVQ 8(SP), AX // syscall entry
MOVQ 16(SP), DI
@@ -91,7 +94,7 @@ ok9:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
@@ -111,7 +114,7 @@ ok1:
MOVQ $0, 56(SP) // errno
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ 16(SP), DI
MOVQ 24(SP), SI
MOVQ 32(SP), DX
diff --git a/src/pkg/syscall/asm_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s
index 7ebd20690..f8c07c407 100644
--- a/src/pkg/syscall/asm_plan9_386.s
+++ b/src/pkg/syscall/asm_plan9_386.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -87,7 +90,7 @@ copyresult4:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -102,7 +105,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-32
MOVL AX, err+28(SP)
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVL 4(SP), AX // syscall entry
// slide args down on top of system call number
LEAL 8(SP), SI
@@ -123,7 +126,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-40
+TEXT ·seek(SB),NOSPLIT,$0-36
LEAL newoffset+24(SP), AX
MOVL AX, placeholder+4(SP)
diff --git a/src/pkg/syscall/asm_plan9_amd64.s b/src/pkg/syscall/asm_plan9_amd64.s
index 880bf7c6f..2154a87d5 100644
--- a/src/pkg/syscall/asm_plan9_amd64.s
+++ b/src/pkg/syscall/asm_plan9_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
#include "../../cmd/ld/textflag.h"
//
@@ -91,7 +94,7 @@ copyresult4:
CALL runtime·exitsyscall(SB)
RET
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVQ $0x8000, AX // for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
@@ -107,7 +110,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-64
MOVQ AX, err+56(SP)
RET
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ $0x8000, AX // for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
@@ -129,7 +132,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
#define SYS_SEEK 39 /* from zsysnum_plan9_amd64.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-64
+TEXT ·seek(SB),NOSPLIT,$0-56
LEAQ newoffset+40(SP), AX
MOVQ AX, placeholder+8(SP)
@@ -160,7 +163,7 @@ copyresult6:
//func exit(code int)
// Import runtime·exit for cleanly exiting.
-TEXT ·exit(SB),NOSPLIT,$8-4
+TEXT ·exit(SB),NOSPLIT,$8-8
MOVQ code+0(FP), AX
MOVQ AX, 0(SP)
CALL runtime·exit(SB)
diff --git a/src/pkg/syscall/asm_solaris_amd64.s b/src/pkg/syscall/asm_solaris_amd64.s
new file mode 100644
index 000000000..3735890fa
--- /dev/null
+++ b/src/pkg/syscall/asm_solaris_amd64.s
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for amd64, Solaris are implemented in ../runtime/syscall_solaris.goc
+//
diff --git a/src/pkg/syscall/consistency_unix_test.go b/src/pkg/syscall/consistency_unix_test.go
deleted file mode 100644
index 73630bc61..000000000
--- a/src/pkg/syscall/consistency_unix_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build freebsd dragonfly darwin linux netbsd openbsd
-
-// This file tests that some basic syscalls are consistent across
-// all Unixes.
-
-package syscall_test
-
-import "syscall"
-
-// {Set,Get}priority and needed constants for them
-func _() {
- var (
- _ func(int, int, int) error = syscall.Setpriority
- _ func(int, int) (int, error) = syscall.Getpriority
- )
- const (
- _ int = syscall.PRIO_USER
- _ int = syscall.PRIO_PROCESS
- _ int = syscall.PRIO_PGRP
- )
-}
-
-// termios functions and constants
-func _() {
- const (
- _ int = syscall.TCIFLUSH
- _ int = syscall.TCIOFLUSH
- _ int = syscall.TCOFLUSH
- )
-}
diff --git a/src/pkg/syscall/dir_plan9.go b/src/pkg/syscall/dir_plan9.go
index b7ab4cd10..697bf5499 100644
--- a/src/pkg/syscall/dir_plan9.go
+++ b/src/pkg/syscall/dir_plan9.go
@@ -11,6 +11,7 @@ import "errors"
var (
ErrShortStat = errors.New("stat buffer too short")
ErrBadStat = errors.New("malformed stat buffer")
+ ErrBadName = errors.New("bad character in file name")
)
// A Qid represents a 9P server's unique identification for a file.
@@ -53,7 +54,7 @@ var nullDir = Dir{
}
// Null assigns special "don't touch" values to members of d to
-// avoid modifiying them during syscall.Wstat.
+// avoid modifying them during syscall.Wstat.
func (d *Dir) Null() { *d = nullDir }
// Marshal encodes a 9P stat message corresponding to d into b
@@ -65,6 +66,12 @@ func (d *Dir) Marshal(b []byte) (n int, err error) {
return n, ErrShortStat
}
+ for _, c := range d.Name {
+ if c == '/' {
+ return n, ErrBadName
+ }
+ }
+
b = pbit16(b, uint16(n)-2)
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
diff --git a/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
index 5970df8fc..ad354ed05 100644
--- a/src/pkg/syscall/env_unix.go
+++ b/src/pkg/syscall/env_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Unix environment variables.
diff --git a/src/pkg/syscall/exec_linux.go b/src/pkg/syscall/exec_linux.go
index a1656e8dc..f27950f73 100644
--- a/src/pkg/syscall/exec_linux.go
+++ b/src/pkg/syscall/exec_linux.go
@@ -131,11 +131,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := uintptr(len(cred.Groups))
- groups := uintptr(0)
+ var groups unsafe.Pointer
if ngroups > 0 {
- groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ groups = unsafe.Pointer(&cred.Groups[0])
}
- _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
if err1 != 0 {
goto childerror
}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index 99ad2f158..45ee542bb 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -486,7 +486,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
if err != nil || n != 0 {
if n != 0 {
- err = NewError(string(errbuf[:]))
+ err = NewError(string(errbuf[:n]))
}
// Child failed; wait for it to exit, to make sure
diff --git a/src/pkg/syscall/exec_solaris.go b/src/pkg/syscall/exec_solaris.go
new file mode 100644
index 000000000..97de6ca00
--- /dev/null
+++ b/src/pkg/syscall/exec_solaris.go
@@ -0,0 +1,243 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+type SysProcAttr struct {
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd 0
+ Noctty bool // Detach fd 0 from controlling terminal
+}
+
+// Implemented in runtime package.
+func runtime_BeforeFork()
+func runtime_AfterFork()
+
+func chdir(path uintptr) (err Errno)
+func chroot1(path uintptr) (err Errno)
+func close(fd uintptr) (err Errno)
+func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
+func exit(code uintptr)
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
+func forkx(flags uintptr) (pid uintptr, err Errno)
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
+func setgid(gid uintptr) (err Errno)
+func setgroups1(ngid uintptr, gid uintptr) (err Errno)
+func setsid() (pid uintptr, err Errno)
+func setuid(uid uintptr) (err Errno)
+func setpgid(pid uintptr, pgid uintptr) (err Errno)
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+//
+// We call hand-crafted syscalls, implemented in
+// ../runtime/syscall_solaris.goc, rather than generated libc wrappers
+// because we need to avoid lazy-loading the functions (might malloc,
+// split the stack, or acquire mutexes). We can't call RawSyscall
+// because it's not safe even for BSD-subsystem calls.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., err1).
+ var (
+ r1 uintptr
+ err1 Errno
+ nextfd int
+ i int
+ )
+
+ // guard against side effects of shuffling fds below.
+ // Make sure that nextfd is beyond any currently open files so
+ // that we can't run the risk of overwriting any of them.
+ fd := make([]int, len(attr.Files))
+ nextfd = len(attr.Files)
+ for i, ufd := range attr.Files {
+ if nextfd < int(ufd) {
+ nextfd = int(ufd)
+ }
+ fd[i] = int(ufd)
+ }
+ nextfd++
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ runtime_BeforeFork()
+ r1, err1 = forkx(0x1) // FORK_NOSIGCHLD
+ if err1 != 0 {
+ runtime_AfterFork()
+ return 0, err1
+ }
+
+ if r1 != 0 {
+ // parent; return PID
+ runtime_AfterFork()
+ return int(r1), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Session ID
+ if sys.Setsid {
+ _, err1 = setsid()
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Set process group
+ if sys.Setpgid {
+ err1 = setpgid(0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ err1 = chroot1(uintptr(unsafe.Pointer(chroot)))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ groups := uintptr(0)
+ if ngroups > 0 {
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ }
+ err1 = setgroups1(ngroups, groups)
+ if err1 != 0 {
+ goto childerror
+ }
+ err1 = setgid(uintptr(cred.Gid))
+ if err1 != 0 {
+ goto childerror
+ }
+ err1 = setuid(uintptr(cred.Uid))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ err1 = chdir(uintptr(unsafe.Pointer(dir)))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ if pipe < nextfd {
+ _, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
+ if err1 != 0 {
+ goto childerror
+ }
+ fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
+ if err1 != 0 {
+ goto childerror
+ }
+ fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ close(uintptr(i))
+ continue
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ _, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ continue
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ close(uintptr(i))
+ }
+
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ err1 = ioctl(0, uintptr(TIOCNOTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Time to exec.
+ err1 = execve(
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])),
+ uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+ // send error code on pipe
+ write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ for {
+ exit(253)
+ }
+}
+
+// Try to open a pipe with O_CLOEXEC set on both file descriptors.
+func forkExecPipe(p []int) error {
+ err := Pipe(p)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+ return err
+}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index b82e39701..890bfdc22 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Fork, exec, wait, etc.
@@ -158,7 +158,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
return 0, err
}
- if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
+ if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
}
diff --git a/src/pkg/syscall/fd_nacl.go b/src/pkg/syscall/fd_nacl.go
new file mode 100644
index 000000000..74324142a
--- /dev/null
+++ b/src/pkg/syscall/fd_nacl.go
@@ -0,0 +1,326 @@
+// 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.
+
+// File descriptor support for Native Client.
+// We want to provide access to a broader range of (simulated) files than
+// Native Client allows, so we maintain our own file descriptor table exposed
+// to higher-level packages.
+
+package syscall
+
+import (
+ "sync"
+)
+
+// files is the table indexed by a file descriptor.
+var files struct {
+ sync.RWMutex
+ tab []*file
+}
+
+// A file is an open file, something with a file descriptor.
+// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
+type file struct {
+ fdref int // uses in files.tab
+ impl fileImpl // underlying implementation
+}
+
+// A fileImpl is the implementation of something that can be a file.
+type fileImpl interface {
+ // Standard operations.
+ // These can be called concurrently from multiple goroutines.
+ stat(*Stat_t) error
+ read([]byte) (int, error)
+ write([]byte) (int, error)
+ seek(int64, int) (int64, error)
+ pread([]byte, int64) (int, error)
+ pwrite([]byte, int64) (int, error)
+
+ // Close is called when the last reference to a *file is removed
+ // from the file descriptor table. It may be called concurrently
+ // with active operations such as blocked read or write calls.
+ close() error
+}
+
+// newFD adds impl to the file descriptor table,
+// returning the new file descriptor.
+// Like Unix, it uses the lowest available descriptor.
+func newFD(impl fileImpl) int {
+ files.Lock()
+ defer files.Unlock()
+ f := &file{impl: impl, fdref: 1}
+ for fd, oldf := range files.tab {
+ if oldf == nil {
+ files.tab[fd] = f
+ return fd
+ }
+ }
+ fd := len(files.tab)
+ files.tab = append(files.tab, f)
+ return fd
+}
+
+// Install Native Client stdin, stdout, stderr.
+func init() {
+ newFD(&naclFile{naclFD: 0})
+ newFD(&naclFile{naclFD: 1})
+ newFD(&naclFile{naclFD: 2})
+}
+
+// fdToFile retrieves the *file corresponding to a file descriptor.
+func fdToFile(fd int) (*file, error) {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ return nil, EBADF
+ }
+ return files.tab[fd], nil
+}
+
+func Close(fd int) error {
+ files.Lock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ files.Unlock()
+ return EBADF
+ }
+ f := files.tab[fd]
+ files.tab[fd] = nil
+ f.fdref--
+ fdref := f.fdref
+ files.Unlock()
+ if fdref > 0 {
+ return nil
+ }
+ return f.impl.close()
+}
+
+func CloseOnExec(fd int) {
+ // nothing to do - no exec
+}
+
+func Dup(fd int) (int, error) {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+ return -1, EBADF
+ }
+ f := files.tab[fd]
+ f.fdref++
+ for newfd, oldf := range files.tab {
+ if oldf == nil {
+ files.tab[newfd] = f
+ return newfd, nil
+ }
+ }
+ newfd := len(files.tab)
+ files.tab = append(files.tab, f)
+ return newfd, nil
+}
+
+func Dup2(fd, newfd int) error {
+ files.Lock()
+ defer files.Unlock()
+ if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
+ files.Unlock()
+ return EBADF
+ }
+ f := files.tab[fd]
+ f.fdref++
+ for cap(files.tab) <= newfd {
+ files.tab = append(files.tab[:cap(files.tab)], nil)
+ }
+ oldf := files.tab[newfd]
+ var oldfdref int
+ if oldf != nil {
+ oldf.fdref--
+ oldfdref = oldf.fdref
+ }
+ files.tab[newfd] = f
+ files.Unlock()
+ if oldf != nil {
+ if oldfdref == 0 {
+ oldf.impl.close()
+ }
+ }
+ return nil
+}
+
+func Fstat(fd int, st *Stat_t) error {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.impl.stat(st)
+}
+
+func Read(fd int, b []byte) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.read(b)
+}
+
+var zerobuf [0]byte
+
+func Write(fd int, b []byte) (int, error) {
+ if b == nil {
+ // avoid nil in syscalls; nacl doesn't like that.
+ b = zerobuf[:]
+ }
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.write(b)
+}
+
+func Pread(fd int, b []byte, offset int64) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.pread(b, offset)
+}
+
+func Pwrite(fd int, b []byte, offset int64) (int, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.pwrite(b, offset)
+}
+
+func Seek(fd int, offset int64, whence int) (int64, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ return f.impl.seek(offset, whence)
+}
+
+// defaulFileImpl implements fileImpl.
+// It can be embedded to complete a partial fileImpl implementation.
+type defaultFileImpl struct{}
+
+func (*defaultFileImpl) close() error { return nil }
+func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS }
+func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS }
+func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS }
+func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
+
+// naclFile is the fileImpl implementation for a Native Client file descriptor.
+type naclFile struct {
+ defaultFileImpl
+ naclFD int
+}
+
+func (f *naclFile) stat(st *Stat_t) error {
+ return naclFstat(f.naclFD, st)
+}
+
+func (f *naclFile) read(b []byte) (int, error) {
+ n, err := naclRead(f.naclFD, b)
+ if err != nil {
+ n = 0
+ }
+ return n, err
+}
+
+// implemented in package runtime, to add time header on playground
+func naclWrite(fd int, b []byte) int
+
+func (f *naclFile) write(b []byte) (int, error) {
+ n := naclWrite(f.naclFD, b)
+ if n < 0 {
+ return 0, Errno(-n)
+ }
+ return n, nil
+}
+
+func (f *naclFile) seek(off int64, whence int) (int64, error) {
+ old := off
+ err := naclSeek(f.naclFD, &off, whence)
+ if err != nil {
+ return old, err
+ }
+ return off, nil
+}
+
+func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
+ // NaCl has no pread; simulate with seek and hope for no races.
+ old, err := f.seek(0, 1)
+ if err != nil {
+ return 0, err
+ }
+ if _, err := f.seek(offset, 0); err != nil {
+ return 0, err
+ }
+ n, err := rw(b)
+ f.seek(old, 0)
+ return n, err
+}
+
+func (f *naclFile) pread(b []byte, offset int64) (int, error) {
+ return f.prw(b, offset, f.read)
+}
+
+func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
+ return f.prw(b, offset, f.write)
+}
+
+func (f *naclFile) close() error {
+ err := naclClose(f.naclFD)
+ f.naclFD = -1
+ return err
+}
+
+// A pipeFile is an in-memory implementation of a pipe.
+// The byteq implementation is in net_nacl.go.
+type pipeFile struct {
+ defaultFileImpl
+ rd *byteq
+ wr *byteq
+}
+
+func (f *pipeFile) close() error {
+ if f.rd != nil {
+ f.rd.close()
+ }
+ if f.wr != nil {
+ f.wr.close()
+ }
+ return nil
+}
+
+func (f *pipeFile) read(b []byte) (int, error) {
+ if f.rd == nil {
+ return 0, EINVAL
+ }
+ n, err := f.rd.read(b, 0)
+ if err == EAGAIN {
+ err = nil
+ }
+ return n, err
+}
+
+func (f *pipeFile) write(b []byte) (int, error) {
+ if f.wr == nil {
+ return 0, EINVAL
+ }
+ n, err := f.wr.write(b, 0)
+ if err == EAGAIN {
+ err = EPIPE
+ }
+ return n, err
+}
+
+func Pipe(fd []int) error {
+ q := newByteq()
+ fd[0] = newFD(&pipeFile{rd: q})
+ fd[1] = newFD(&pipeFile{wr: q})
+ return nil
+}
diff --git a/src/pkg/syscall/flock.go b/src/pkg/syscall/flock.go
new file mode 100644
index 000000000..62736ae9d
--- /dev/null
+++ b/src/pkg/syscall/flock.go
@@ -0,0 +1,22 @@
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
+// systems by flock_linux_32bit.go to be SYS_FCNTL64.
+var fcntl64Syscall uintptr = SYS_FCNTL
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
+ if errno == 0 {
+ return nil
+ }
+ return errno
+}
diff --git a/src/pkg/syscall/flock_linux_32bit.go b/src/pkg/syscall/flock_linux_32bit.go
new file mode 100644
index 000000000..500a97344
--- /dev/null
+++ b/src/pkg/syscall/flock_linux_32bit.go
@@ -0,0 +1,13 @@
+// +build linux,386 linux,arm
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func init() {
+ // On 32-bit Linux systems, the fcntl syscall that matches Go's
+ // Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
+ fcntl64Syscall = SYS_FCNTL64
+}
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go
new file mode 100644
index 000000000..ac9239483
--- /dev/null
+++ b/src/pkg/syscall/fs_nacl.go
@@ -0,0 +1,815 @@
+// 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.
+
+// A simulated Unix-like file system for use within NaCl.
+//
+// The simulation is not particularly tied to NaCl other than the reuse
+// of NaCl's definition for the Stat_t structure.
+//
+// The file system need never be written to disk, so it is represented as
+// in-memory Go data structures, never in a serialized form.
+//
+// TODO: Perhaps support symlinks, although they muck everything up.
+
+package syscall
+
+import (
+ "sync"
+ "unsafe"
+)
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// An fsys is a file system.
+// Since there is no I/O (everything is in memory),
+// the global lock mu protects the whole file system state,
+// and that's okay.
+type fsys struct {
+ mu sync.Mutex
+ root *inode // root directory
+ cwd *inode // process current directory
+ inum uint64 // number of inodes created
+ dev []func() (devFile, error) // table for opening devices
+}
+
+// A devFile is the implementation required of device files
+// like /dev/null or /dev/random.
+type devFile interface {
+ pread([]byte, int64) (int, error)
+ pwrite([]byte, int64) (int, error)
+}
+
+// An inode is a (possibly special) file in the file system.
+type inode struct {
+ Stat_t
+ data []byte
+ dir []dirent
+}
+
+// A dirent describes a single directory entry.
+type dirent struct {
+ name string
+ inode *inode
+}
+
+// An fsysFile is the fileImpl implementation backed by the file system.
+type fsysFile struct {
+ defaultFileImpl
+ fsys *fsys
+ inode *inode
+ openmode int
+ offset int64
+ dev devFile
+}
+
+// newFsys creates a new file system.
+func newFsys() *fsys {
+ fs := &fsys{}
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip := fs.newInode()
+ ip.Mode = 0555 | S_IFDIR
+ fs.dirlink(ip, ".", ip)
+ fs.dirlink(ip, "..", ip)
+ fs.cwd = ip
+ fs.root = ip
+ return fs
+}
+
+var fs = newFsys()
+
+func init() {
+ Mkdir("/dev", 0555)
+ Mkdir("/tmp", 0777)
+ mkdev("/dev/null", 0666, openNull)
+ mkdev("/dev/random", 0444, openRandom)
+ mkdev("/dev/urandom", 0444, openRandom)
+ mkdev("/dev/zero", 0666, openZero)
+ chdirEnv()
+}
+
+func chdirEnv() {
+ pwd, ok := Getenv("NACLPWD")
+ if ok {
+ Chdir(pwd)
+ }
+}
+
+// Except where indicated otherwise, unexported methods on fsys
+// expect fs.mu to have been locked by the caller.
+
+// newInode creates a new inode.
+func (fs *fsys) newInode() *inode {
+ fs.inum++
+ ip := &inode{
+ Stat_t: Stat_t{
+ Ino: fs.inum,
+ Blksize: 512,
+ },
+ }
+ return ip
+}
+
+// atime sets ip.Atime to the current time.
+func (fs *fsys) atime(ip *inode) {
+ sec, nsec := now()
+ ip.Atime, ip.AtimeNsec = sec, int64(nsec)
+}
+
+// mtime sets ip.Mtime to the current time.
+func (fs *fsys) mtime(ip *inode) {
+ sec, nsec := now()
+ ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
+}
+
+// dirlookup looks for an entry in the directory dp with the given name.
+// It returns the directory entry and its index within the directory.
+func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
+ fs.atime(dp)
+ for i := range dp.dir {
+ de := &dp.dir[i]
+ if de.name == name {
+ fs.atime(de.inode)
+ return de, i, nil
+ }
+ }
+ return nil, 0, ENOENT
+}
+
+// dirlink adds to the directory dp an entry for name pointing at the inode ip.
+// If dp already contains an entry for name, that entry is overwritten.
+func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
+ fs.mtime(dp)
+ fs.atime(ip)
+ ip.Nlink++
+ for i := range dp.dir {
+ if dp.dir[i].name == name {
+ dp.dir[i] = dirent{name, ip}
+ return
+ }
+ }
+ dp.dir = append(dp.dir, dirent{name, ip})
+ dp.dirSize()
+}
+
+func (dp *inode) dirSize() {
+ dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
+}
+
+// skipelem splits path into the first element and the remainder.
+// the returned first element contains no slashes, and the returned
+// remainder does not begin with a slash.
+func skipelem(path string) (elem, rest string) {
+ for len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+ if len(path) == 0 {
+ return "", ""
+ }
+ i := 0
+ for i < len(path) && path[i] != '/' {
+ i++
+ }
+ elem, path = path[:i], path[i:]
+ for len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+ return elem, path
+}
+
+// namei translates a file system path name into an inode.
+// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
+// If parent is false, the walk stops at the next-to-last element in the name,
+// so that ip is the parent directory and elem is the final element in the path.
+func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
+ // Reject NUL in name.
+ for i := 0; i < len(path); i++ {
+ if path[i] == '\x00' {
+ return nil, "", EINVAL
+ }
+ }
+
+ // Reject empty name.
+ if path == "" {
+ return nil, "", EINVAL
+ }
+
+ if path[0] == '/' {
+ ip = fs.root
+ } else {
+ ip = fs.cwd
+ }
+
+ for len(path) > 0 && path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+
+ for {
+ elem, rest := skipelem(path)
+ if elem == "" {
+ if parent && ip.Mode&S_IFMT == S_IFDIR {
+ return ip, ".", nil
+ }
+ break
+ }
+ if ip.Mode&S_IFMT != S_IFDIR {
+ return nil, "", ENOTDIR
+ }
+ if len(elem) >= 256 {
+ return nil, "", ENAMETOOLONG
+ }
+ if parent && rest == "" {
+ // Stop one level early.
+ return ip, elem, nil
+ }
+ de, _, err := fs.dirlookup(ip, elem)
+ if err != nil {
+ return nil, "", err
+ }
+ ip = de.inode
+ path = rest
+ }
+ if parent {
+ return nil, "", ENOTDIR
+ }
+ return ip, "", nil
+}
+
+// open opens or creates a file with the given name, open mode,
+// and permission mode bits.
+func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
+ dp, elem, err := fs.namei(name, true)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ ip *inode
+ dev devFile
+ )
+ de, _, err := fs.dirlookup(dp, elem)
+ if err != nil {
+ if openmode&O_CREATE == 0 {
+ return nil, err
+ }
+ ip = fs.newInode()
+ ip.Mode = mode
+ fs.dirlink(dp, elem, ip)
+ if ip.Mode&S_IFMT == S_IFDIR {
+ fs.dirlink(ip, ".", ip)
+ fs.dirlink(ip, "..", dp)
+ }
+ } else {
+ ip = de.inode
+ if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
+ return nil, EEXIST
+ }
+ if openmode&O_TRUNC != 0 {
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return nil, EISDIR
+ }
+ ip.data = nil
+ }
+ if ip.Mode&S_IFMT == S_IFCHR {
+ if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
+ return nil, ENODEV
+ }
+ dev, err = fs.dev[ip.Rdev]()
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ switch openmode & O_ACCMODE {
+ case O_WRONLY, O_RDWR:
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return nil, EISDIR
+ }
+ }
+
+ switch ip.Mode & S_IFMT {
+ case S_IFDIR:
+ if openmode&O_ACCMODE != O_RDONLY {
+ return nil, EISDIR
+ }
+
+ case S_IFREG:
+ // ok
+
+ case S_IFCHR:
+ // handled above
+
+ default:
+ // TODO: some kind of special file
+ return nil, EPERM
+ }
+
+ f := &fsysFile{
+ fsys: fs,
+ inode: ip,
+ openmode: openmode,
+ dev: dev,
+ }
+ if openmode&O_APPEND != 0 {
+ f.offset = ip.Size
+ }
+ return f, nil
+}
+
+// fsysFile methods to implement fileImpl.
+
+func (f *fsysFile) stat(st *Stat_t) error {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ *st = f.inode.Stat_t
+ return nil
+}
+
+func (f *fsysFile) read(b []byte) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ n, err := f.preadLocked(b, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func ReadDirent(fd int, buf []byte) (int, error) {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ if f.inode.Mode&S_IFMT != S_IFDIR {
+ return 0, EINVAL
+ }
+ n, err := f.preadLocked(buf, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func (f *fsysFile) write(b []byte) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ n, err := f.pwriteLocked(b, f.offset)
+ f.offset += int64(n)
+ return n, err
+}
+
+func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ switch whence {
+ case 1:
+ offset += f.offset
+ case 2:
+ offset += f.inode.Size
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if offset > f.inode.Size {
+ return 0, EINVAL
+ }
+ f.offset = offset
+ return offset, nil
+}
+
+func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.preadLocked(b, offset)
+}
+
+func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.pwriteLocked(b, offset)
+}
+
+func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
+ if f.openmode&O_ACCMODE == O_WRONLY {
+ return 0, EINVAL
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if f.dev != nil {
+ f.fsys.atime(f.inode)
+ f.fsys.mu.Unlock()
+ defer f.fsys.mu.Lock()
+ return f.dev.pread(b, offset)
+ }
+ if offset > f.inode.Size {
+ return 0, nil
+ }
+ if int64(len(b)) > f.inode.Size-offset {
+ b = b[:f.inode.Size-offset]
+ }
+
+ if f.inode.Mode&S_IFMT == S_IFDIR {
+ if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
+ return 0, EINVAL
+ }
+ fs.atime(f.inode)
+ n := 0
+ for len(b) >= direntSize {
+ src := f.inode.dir[int(offset/direntSize)]
+ dst := (*Dirent)(unsafe.Pointer(&b[0]))
+ dst.Ino = int64(src.inode.Ino)
+ dst.Off = offset
+ dst.Reclen = direntSize
+ for i := range dst.Name {
+ dst.Name[i] = 0
+ }
+ copy(dst.Name[:], src.name)
+ n += direntSize
+ offset += direntSize
+ b = b[direntSize:]
+ }
+ return n, nil
+ }
+
+ fs.atime(f.inode)
+ n := copy(b, f.inode.data[offset:])
+ return n, nil
+}
+
+func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
+ if f.openmode&O_ACCMODE == O_RDONLY {
+ return 0, EINVAL
+ }
+ if offset < 0 {
+ return 0, EINVAL
+ }
+ if f.dev != nil {
+ f.fsys.atime(f.inode)
+ f.fsys.mu.Unlock()
+ defer f.fsys.mu.Lock()
+ return f.dev.pwrite(b, offset)
+ }
+ if offset > f.inode.Size {
+ return 0, EINVAL
+ }
+ f.fsys.mtime(f.inode)
+ n := copy(f.inode.data[offset:], b)
+ if n < len(b) {
+ f.inode.data = append(f.inode.data, b[n:]...)
+ f.inode.Size = int64(len(f.inode.data))
+ }
+ return len(b), nil
+}
+
+// Standard Unix system calls.
+
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+ if err != nil {
+ return -1, err
+ }
+ return newFD(f), nil
+}
+
+func Mkdir(path string, perm uint32) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ _, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
+ return err
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+ // Force package os to default to the old algorithm using .. and directory reads.
+ return 0, ENOSYS
+}
+
+func Stat(path string, st *Stat_t) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ *st = ip.Stat_t
+ return nil
+}
+
+func Lstat(path string, st *Stat_t) error {
+ return Stat(path, st)
+}
+
+func unlink(path string, isdir bool) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ dp, elem, err := fs.namei(path, true)
+ if err != nil {
+ return err
+ }
+ if elem == "." || elem == ".." {
+ return EINVAL
+ }
+ de, _, err := fs.dirlookup(dp, elem)
+ if err != nil {
+ return err
+ }
+ if isdir {
+ if de.inode.Mode&S_IFMT != S_IFDIR {
+ return ENOTDIR
+ }
+ if len(de.inode.dir) != 2 {
+ return ENOTEMPTY
+ }
+ } else {
+ if de.inode.Mode&S_IFMT == S_IFDIR {
+ return EISDIR
+ }
+ }
+ de.inode.Nlink--
+ *de = dp.dir[len(dp.dir)-1]
+ dp.dir = dp.dir[:len(dp.dir)-1]
+ dp.dirSize()
+ return nil
+}
+
+func Unlink(path string) error {
+ return unlink(path, false)
+}
+
+func Rmdir(path string) error {
+ return unlink(path, true)
+}
+
+func Chmod(path string, mode uint32) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Mode = ip.Mode&^0777 | mode&0777
+ return nil
+}
+
+func Fchmod(fd int, mode uint32) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ f.inode.Mode = f.inode.Mode&^0777 | mode&0777
+ return nil
+}
+
+func Chown(path string, uid, gid int) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Uid = uint32(uid)
+ ip.Gid = uint32(gid)
+ return nil
+}
+
+func Fchown(fd int, uid, gid int) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ f.inode.Uid = uint32(uid)
+ f.inode.Gid = uint32(gid)
+ return nil
+}
+
+func Lchown(path string, uid, gid int) error {
+ return Chown(path, uid, gid)
+}
+
+func UtimesNano(path string, ts []Timespec) error {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ ip.Atime = ts[0].Sec
+ ip.AtimeNsec = int64(ts[0].Nsec)
+ ip.Mtime = ts[1].Sec
+ ip.MtimeNsec = int64(ts[1].Nsec)
+ return nil
+}
+
+func Link(path, link string) error {
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ dp, elem, err := fs.namei(link, true)
+ if err != nil {
+ return err
+ }
+ if ip.Mode&S_IFMT == S_IFDIR {
+ return EPERM
+ }
+ fs.dirlink(dp, elem, ip)
+ return nil
+}
+
+func Rename(from, to string) error {
+ fdp, felem, err := fs.namei(from, true)
+ if err != nil {
+ return err
+ }
+ fde, _, err := fs.dirlookup(fdp, felem)
+ if err != nil {
+ return err
+ }
+ tdp, telem, err := fs.namei(to, true)
+ if err != nil {
+ return err
+ }
+ fs.dirlink(tdp, telem, fde.inode)
+ fde.inode.Nlink--
+ *fde = fdp.dir[len(fdp.dir)-1]
+ fdp.dir = fdp.dir[:len(fdp.dir)-1]
+ fdp.dirSize()
+ return nil
+}
+
+func (fs *fsys) truncate(ip *inode, length int64) error {
+ if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
+ return EINVAL
+ }
+ if length < int64(len(ip.data)) {
+ ip.data = ip.data[:length]
+ } else {
+ data := make([]byte, length)
+ copy(data, ip.data)
+ ip.data = data
+ }
+ ip.Size = int64(len(ip.data))
+ return nil
+}
+
+func Truncate(path string, length int64) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ return fs.truncate(ip, length)
+}
+
+func Ftruncate(fd int, length int64) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ return f.fsys.truncate(f.inode, length)
+}
+
+func Chdir(path string) error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ ip, _, err := fs.namei(path, false)
+ if err != nil {
+ return err
+ }
+ fs.cwd = ip
+ return nil
+}
+
+func Fchdir(fd int) error {
+ f, err := fdToFsysFile(fd)
+ if err != nil {
+ return err
+ }
+ f.fsys.mu.Lock()
+ defer f.fsys.mu.Unlock()
+ if f.inode.Mode&S_IFMT != S_IFDIR {
+ return ENOTDIR
+ }
+ fs.cwd = f.inode
+ return nil
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ return 0, ENOSYS
+}
+
+func Symlink(path, link string) error {
+ return ENOSYS
+}
+
+func Fsync(fd int) error {
+ return nil
+}
+
+// Special devices.
+
+func mkdev(path string, mode uint32, open func() (devFile, error)) error {
+ fs.mu.Lock()
+ fs.mu.Unlock()
+ f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
+ if err != nil {
+ return err
+ }
+ ip := f.(*fsysFile).inode
+ ip.Rdev = int64(len(fs.dev))
+ fs.dev = append(fs.dev, open)
+ return nil
+}
+
+type nullFile struct{}
+
+func openNull() (devFile, error) { return &nullFile{}, nil }
+func (f *nullFile) close() error { return nil }
+func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil }
+func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+type zeroFile struct{}
+
+func openZero() (devFile, error) { return &zeroFile{}, nil }
+func (f *zeroFile) close() error { return nil }
+func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
+ for i := range b {
+ b[i] = 0
+ }
+ return len(b), nil
+}
+
+type randomFile struct {
+ naclFD int
+}
+
+func openRandom() (devFile, error) {
+ fd, err := openNamedService("SecureRandom", O_RDONLY)
+ if err != nil {
+ return nil, err
+ }
+ return &randomFile{naclFD: fd}, nil
+}
+
+func (f *randomFile) close() error {
+ naclClose(f.naclFD)
+ f.naclFD = -1
+ return nil
+}
+
+func (f *randomFile) pread(b []byte, offset int64) (int, error) {
+ return naclRead(f.naclFD, b)
+}
+
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+ return 0, EPERM
+}
+
+func fdToFsysFile(fd int) (*fsysFile, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ impl := f.impl
+ fsysf, ok := impl.(*fsysFile)
+ if !ok {
+ return nil, EINVAL
+ }
+ return fsysf, nil
+}
+
+// create creates a file in the file system with the given name, mode, time, and data.
+// It is meant to be called when initializing the file system image.
+func create(name string, mode uint32, sec int64, data []byte) error {
+ fs.mu.Lock()
+ fs.mu.Unlock()
+ f, err := fs.open(name, O_CREATE|O_EXCL, mode)
+ if err != nil {
+ return err
+ }
+ ip := f.(*fsysFile).inode
+ ip.Atime = sec
+ ip.Mtime = sec
+ ip.Ctime = sec
+ if len(data) > 0 {
+ ip.Size = int64(len(data))
+ ip.data = data
+ }
+ return nil
+}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
index 05d653b4a..ee07fea3f 100644
--- a/src/pkg/syscall/lsf_linux.go
+++ b/src/pkg/syscall/lsf_linux.go
@@ -69,10 +69,10 @@ func AttachLsf(fd int, i []SockFilter) error {
var p SockFprog
p.Len = uint16(len(i))
p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
- return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
+ return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
}
func DetachLsf(fd int) error {
var dummy int
- return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
+ return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index a3139d603..886db133c 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -81,6 +81,8 @@ mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
run="sh"
case "$1" in
@@ -136,19 +138,21 @@ dragonfly_amd64)
freebsd_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
mksyscall="./mksyscall.pl -l32 -arm"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
- mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ # Let the type of C char be singed for making the bare syscall
+ # API consistent across over platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
linux_386)
mkerrors="$mkerrors -m32"
@@ -172,6 +176,18 @@ linux_arm)
mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
+nacl_386)
+ mkerrors=""
+ mksyscall="./mksyscall.pl -l32 -nacl"
+ mksysnum=""
+ mktypes=""
+ ;;
+nacl_amd64p32)
+ mkerrors=""
+ mksyscall="./mksyscall.pl -nacl"
+ mksysnum=""
+ mktypes=""
+ ;;
netbsd_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32 -netbsd"
@@ -206,19 +222,16 @@ plan9_386)
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
mktypes="XXX"
;;
-windows_386)
- mksyscall="./mksyscall_windows.pl -l32"
+solaris_amd64)
+ mksyscall="./mksyscall_solaris.pl"
+ mkerrors="$mkerrors -m64"
mksysnum=
- mktypes=
- mkerrors="./mkerrors_windows.sh -m32"
- zerrors="zerrors_windows.go"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
-windows_amd64)
- mksyscall="./mksyscall_windows.pl"
- mksysnum=
- mktypes=
- mkerrors="./mkerrors_windows.sh -m32"
- zerrors="zerrors_windows.go"
+windows_*)
+ mksyscall=
+ mkerrors=
+ zerrors=
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
@@ -228,17 +241,23 @@ esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
- syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
- darwin | dragonfly | freebsd | netbsd | openbsd)
- syscall_goos="syscall_bsd.go $syscall_goos"
- ;;
windows)
- syscall_goos="$syscall_goos security_windows.go"
+ echo "GOOS= GOARCH= go build mksyscall_windows.go"
+ echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
+ echo "rm -f ./mksyscall_windows"
+ ;;
+ *)
+ syscall_goos="syscall_$GOOS.go"
+ case "$GOOS" in
+ darwin | dragonfly | freebsd | netbsd | openbsd)
+ syscall_goos="syscall_bsd.go $syscall_goos"
+ ;;
+ esac
+ if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
;;
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
- if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run
diff --git a/src/pkg/syscall/mkall_windows.bat b/src/pkg/syscall/mkall_windows.bat
new file mode 100644
index 000000000..a4a3f1674
--- /dev/null
+++ b/src/pkg/syscall/mkall_windows.bat
@@ -0,0 +1,21 @@
+:: 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.
+@echo off
+
+if exist mkall.sh goto dirok
+echo mkall_windows.bat must be run from src\pkg\syscall directory
+goto :end
+:dirok
+
+if "%1"=="386" goto :paramok
+if "%1"=="amd64" goto :paramok
+echo parameters must be 386 or amd64
+goto :end
+:paramok
+
+go build mksyscall_windows.go
+.\mksyscall_windows syscall_windows.go security_windows.go syscall_windows_%1.go |gofmt >zsyscall_windows_%1.go
+del mksyscall_windows.exe
+
+:end \ No newline at end of file
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 20b2b9875..cf0afe0bd 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -11,7 +11,7 @@ unset LANG
export LC_ALL=C
export LC_CTYPE=C
-GCC=gcc
+CC=${CC:-gcc}
uname=$(uname)
@@ -57,6 +57,7 @@ includes_DragonFly='
'
includes_FreeBSD='
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
@@ -73,6 +74,14 @@ includes_FreeBSD='
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
+
+#if __FreeBSD__ >= 10
+#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
+#undef SIOCAIFADDR
+#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
+#undef SIOCSIFPHYADDR
+#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
+#endif
'
includes_Linux='
@@ -92,9 +101,12 @@ includes_Linux='
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
-#include <linux/if_addr.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
+#include <linux/if_packet.h>
+#include <linux/if_addr.h>
#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/reboot.h>
@@ -103,10 +115,7 @@ includes_Linux='
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/icmpv6.h>
-#include <net/if.h>
-#include <net/if_arp.h>
#include <net/route.h>
-#include <netpacket/packet.h>
#include <termios.h>
#ifndef MSG_FASTOPEN
@@ -118,6 +127,7 @@ includes_NetBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -142,6 +152,7 @@ includes_OpenBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -151,6 +162,7 @@ includes_OpenBSD='
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
+#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -158,6 +170,36 @@ includes_OpenBSD='
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>
#include <net/if_bridge.h>
+
+// We keep some constants not supported in OpenBSD 5.5 and beyond for
+// the promise of compatibility.
+#define EMUL_ENABLED 0x1
+#define EMUL_NATIVE 0x2
+#define IPV6_FAITH 0x1d
+#define IPV6_OPTIONS 0x1
+#define IPV6_RTHDR_STRICT 0x1
+#define IPV6_SOCKOPT_RESERVED1 0x3
+#define SIOCGIFGENERIC 0xc020693a
+#define SIOCSIFGENERIC 0x80206939
+#define WALTSIG 0x4
+'
+
+includes_SunOS='
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <termios.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
'
includes='
@@ -192,7 +234,7 @@ ccflags="$@"
# The gcc command line prints all the #defines
# it encounters while processing the input
- echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
+ echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
@@ -240,6 +282,7 @@ ccflags="$@"
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
+ $2 !~ "RTF_BITS" &&
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
@@ -261,24 +304,24 @@ ccflags="$@"
# Pull out the error names for later.
errors=$(
- echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
sort
)
# Pull out the signal names for later.
signals=$(
- echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+ echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
sort
)
# Again, writing regexps to a file.
-echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
sort >_error.grep
-echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
sort >_signal.grep
@@ -302,8 +345,9 @@ echo ')'
# Run C program to print error and syscall strings.
(
- /bin/echo "
+ echo -E "
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
@@ -317,22 +361,21 @@ int errors[] = {
"
for i in $errors
do
- /bin/echo ' '$i,
+ echo -E ' '$i,
done
- /bin/echo "
+ echo -E "
};
int signals[] = {
"
for i in $signals
do
- /bin/echo ' '$i,
+ echo -E ' '$i,
done
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
+ # Use -E because on some systems bash builtin interprets \n itself.
+ echo -E '
};
static int
@@ -387,4 +430,4 @@ main(void)
'
) >_errors.c
-$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
+$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
deleted file mode 100755
index 13badcd92..000000000
--- a/src/pkg/syscall/mkerrors_windows.sh
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Generate Go code listing errors and other #defined constant
-# values (ENAMETOOLONG etc.), by asking the preprocessor
-# about the definitions.
-
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
-
-case "$GOARCH" in
-arm)
- GCC=arm-gcc
- ;;
-*)
- GCC=gcc
- ;;
-esac
-
-uname=$(uname)
-
-includes_Linux='
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/epoll.h>
-#include <linux/ptrace.h>
-#include <linux/wait.h>
-'
-
-includes_Darwin='
-#define __DARWIN_UNIX03 0
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes_FreeBSD='
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes='
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp.h>
-#include <errno.h>
-#include <sys/signal.h>
-#include <signal.h>
-'
-
-ccflags=""
-next=false
-for i
-do
- if $next; then
- ccflags="$ccflags $i"
- next=false
- elif [ "$i" = "-f" ]; then
- next=true
- fi
-done
-
-# These are go errors that will be mapped directly to windows errors
-goerrors='
-ENOENT:ERROR_FILE_NOT_FOUND
-ENOTDIR:ERROR_PATH_NOT_FOUND
-'
-
-# Pull out just the error names for later.
-i=$(
- for j in "$goerrors"
- do
- echo "$j"
- done |
- awk -F: '
- { if (NR > 1) printf("|") }
- { printf("%s", $1) }
- '
-)
-errors=$(
- echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
- awk '
- $1 != "#define" || $2 ~ /\(/ {next}
- $2 ~ /^('$i')$/ {next}
- $2 ~ /^E[A-Z0-9_]+$/ { print $2 }
- {next}
- ' | sort
-)
-
-echo '// mkerrors_windows.sh' "$@"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
-echo
-echo 'package syscall'
-
-# Run C program to print error strings.
-(
- /bin/echo "
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-
-enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
-
-struct {
- char *goname;
- char *winname;
-} goerrors[] = {
-"
- for i in $goerrors
- do
- j=`echo $i | cut -d: -f1`
- k=`echo $i | cut -d: -f2`
- echo ' {"'$j'", "'$k'"},'
- done
-
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
-};
-
-struct {
- char *name;
- int value;
-} errors[] = {
-'
- for i in $errors
- do
- echo ' {"'$i'",' $i'},'
- done
-
- # Use /bin/echo to avoid builtin echo,
- # which interprets \n itself
- /bin/echo '
-};
-
-int
-main(void)
-{
- int i, e, iota = 1;
- char buf[1024];
-
- printf("\n// Go names for Windows errors.\n");
- printf("const (\n");
- for(i=0; i<nelem(goerrors); i++) {
- printf("\t%s Errno = %s\n", goerrors[i].goname, goerrors[i].winname);
-
- }
- printf(")\n");
-
- printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
- printf("const APPLICATION_ERROR = 1 << 29\n");
-
- printf("\n// Invented values to support what package os and others expects.\n");
- printf("const (\n");
- for(i=0; i<nelem(errors); i++) {
- printf("\t%s", errors[i].name);
- if(iota) {
- printf(" Errno = APPLICATION_ERROR + iota");
- iota = !iota;
- }
- printf("\n");
-
- }
- printf("\tEWINDOWS\n");
- printf(")\n");
-
- printf("\n// Error strings for invented errors\n");
- printf("var errors = [...]string {\n");
- for(i=0; i<nelem(errors); i++) {
- e = errors[i].value;
- strcpy(buf, strerror(e));
- // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
- if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
- buf[0] += a - A;
- printf("\t%s - APPLICATION_ERROR: \"%s\",\n", errors[i].name, buf);
- next:;
- }
- printf("\tEWINDOWS - APPLICATION_ERROR: \"not supported by windows\",\n");
- printf("}\n\n");
- return 0;
-}
-
-'
-) >_errors.c
-
-$GCC $ccflags -static -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index b4ece9a54..6d35fa689 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -28,6 +28,7 @@ my $plan9 = 0;
my $openbsd = 0;
my $netbsd = 0;
my $dragonfly = 0;
+my $nacl = 0;
my $arm = 0; # 64-bit value should use (even, odd)-pair
if($ARGV[0] eq "-b32") {
@@ -53,6 +54,10 @@ if($ARGV[0] eq "-dragonfly") {
$dragonfly = 1;
shift;
}
+if($ARGV[0] eq "-nacl") {
+ $nacl = 1;
+ shift;
+}
if($ARGV[0] eq "-arm") {
$arm = 1;
shift;
@@ -95,7 +100,7 @@ while(<>) {
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, errno error)
# Split into name, in params, out params.
- if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+ if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
@@ -219,6 +224,9 @@ while(<>) {
$sysname = "SYS_$func";
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
$sysname =~ y/a-z/A-Z/;
+ if($nacl) {
+ $sysname =~ y/A-Z/a-z/;
+ }
}
# Actual call.
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_solaris.pl
index 65d6efc20..130d043d9 100755
--- a/src/pkg/syscall/mksyscall_windows.pl
+++ b/src/pkg/syscall/mksyscall_solaris.pl
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
# This program reads a file containing function prototypes
-# (like syscall_darwin.go) and generates system call bodies.
+# (like syscall_solaris.go) and generates system call bodies.
# The prototypes are marked by lines beginning with "//sys"
# and read like func declarations if //sys is replaced by func, but:
# * The parameter lists must give a name for each argument.
@@ -12,20 +12,14 @@
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
# * If the return parameter is an error number, it must be named err.
-# * If go func name needs to be different from it's winapi dll name,
-# the winapi name could be specified at the end, after "=" sign, like
-# //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
-# * Each function that returns err needs to supply a condition,
-# that return value of winapi will be tested against to
-# detect failure. This would set err to windows "last-error",
-# otherwise it will be nil. The value can be provided
-# at end of //sys declaration, like
-# //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
-# and is [failretval==0] by default.
+# * If go func name needs to be different than its libc name,
+# * or the function is not in libc, name could be specified
+# * at the end, after "=" sign, like
+# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
use strict;
-my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
+my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
my $errors = 0;
my $_32bit = "";
@@ -40,7 +34,7 @@ if($ARGV[0] eq "-b32") {
}
if($ARGV[0] =~ /^-/) {
- print STDERR "usage: mksyscall_windows.pl [-b32 | -l32] [file ...]\n";
+ print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [file ...]\n";
exit 1;
}
@@ -75,7 +69,8 @@ while(<>) {
s/^\s+//;
s/\s+$//;
$package = $1 if !$package && /^package (\S+)$/;
- next if !/^\/\/sys /;
+ my $nonblock = /^\/\/sysnb /;
+ next if !/^\/\/sys / && !$nonblock;
my $syscalldot = "";
$syscalldot = "syscall." if $package ne "syscall";
@@ -83,25 +78,25 @@ while(<>) {
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, err error)
# Split into name, in params, out params.
- if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
+ if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
}
- my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
+ my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
# Split argument lists on comma.
my @in = parseparamlist($in);
my @out = parseparamlist($out);
- # Dll file name.
+ # So file name.
if($modname eq "") {
- $modname = "kernel32";
+ $modname = "libc";
}
my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
- $mods .= "\t$modvname = ${syscalldot}NewLazyDLL(\"$modname.dll\")\n";
+ $mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
}
# System call name.
@@ -112,16 +107,11 @@ while(<>) {
# System call pointer variable name.
my $sysvarname = "proc$sysname";
- # Returned value when failed
- if($failcond eq "") {
- $failcond = "== 0";
- }
-
- # Decide which version of api is used: ascii or unicode.
- my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
- my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
+ my $strconvfunc = "BytePtrFromString";
+ my $strconvtype = "*byte";
- # Winapi proc address variable.
+ # Library proc address variable.
+ $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
# Go function header.
@@ -191,31 +181,14 @@ while(<>) {
my $nargs = @args;
# Determine which form to use; pad args with zeros.
- my $asm = "${syscalldot}Syscall";
- if(@args <= 3) {
- while(@args < 3) {
- push @args, "0";
- }
- } elsif(@args <= 6) {
- $asm = "${syscalldot}Syscall6";
+ my $asm = "${syscalldot}sysvicall6";
+ if ($nonblock) {
+ $asm = "${syscalldot}rawSysvicall6";
+ }
+ if(@args <= 6) {
while(@args < 6) {
push @args, "0";
}
- } elsif(@args <= 9) {
- $asm = "${syscalldot}Syscall9";
- while(@args < 9) {
- push @args, "0";
- }
- } elsif(@args <= 12) {
- $asm = "${syscalldot}Syscall12";
- while(@args < 12) {
- push @args, "0";
- }
- } elsif(@args <= 15) {
- $asm = "${syscalldot}Syscall15";
- while(@args < 15) {
- push @args, "0";
- }
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
@@ -229,6 +202,7 @@ while(<>) {
my $failexpr = "";
my @ret = ("_", "_", "_");
my @pout= ();
+ my $do_errno = 0;
for(my $i=0; $i<@out; $i++) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
@@ -236,6 +210,7 @@ while(<>) {
if($name eq "err") {
$reg = "e1";
$ret[2] = $reg;
+ $do_errno = 1;
} else {
$reg = sprintf("r%d", $i);
$ret[$i] = $reg;
@@ -256,40 +231,9 @@ while(<>) {
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
- my $rettype = $type;
- if($type =~ /^\*/) {
- $reg = "unsafe.Pointer($reg)";
- $rettype = "($rettype)";
- }
- if($i == 0) {
- if($type eq "bool") {
- $failexpr = "!$name";
- } elsif($name eq "err") {
- $ret[$i] = "r1";
- $failexpr = "r1 $failcond";
- } else {
- $failexpr = "$name $failcond";
- }
- }
- $failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
- if($name eq "err") {
- # Set err to "last error" only if returned value indicate failure
- $body .= "\tif $failexpr {\n";
- $body .= "\t\tif $reg != 0 {\n";
- $body .= "\t\t\t$name = $type($reg)\n";
- $body .= "\t\t} else {\n";
- $body .= "\t\t\t$name = ${syscalldot}EINVAL\n";
- $body .= "\t\t}\n";
- $body .= "\t}\n";
- } elsif($rettype eq "error") {
- # Set $reg to "error" only if returned value indicate failure
- $body .= "\tif $reg != 0 {\n";
- $body .= "\t\t$name = ${syscalldot}Errno($reg)\n";
- $body .= "\t}\n";
- } else {
- $body .= "\t$name = $rettype($reg)\n";
+ if($reg ne "e1") {
+ $body .= "\t$name = $type($reg)\n";
}
- push @pout, sprintf "\"%s=\", %s, ", $name, $name;
}
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
$text .= "\t$call\n";
@@ -297,10 +241,12 @@ while(<>) {
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
}
$text .= $body;
- if(0) {
- $text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n";
- }
+ if ($do_errno) {
+ $text .= "\tif e1 != 0 {\n";
+ $text .= "\t\terr = e1\n";
+ $text .= "\t}\n";
+ }
$text .= "\treturn\n";
$text .= "}\n";
}
diff --git a/src/pkg/syscall/mksyscall_windows.go b/src/pkg/syscall/mksyscall_windows.go
new file mode 100644
index 000000000..4225588de
--- /dev/null
+++ b/src/pkg/syscall/mksyscall_windows.go
@@ -0,0 +1,662 @@
+// 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.
+
+// +build ignore
+
+/*
+mksyscall_windows generates windows system call bodies
+
+It parses all files specified on command line containing function
+prototypes (like syscall_windows.go) and prints system call bodies
+to standard output.
+
+The prototypes are marked by lines beginning with "//sys" and read
+like func declarations if //sys is replaced by func, but:
+
+* The parameter lists must give a name for each argument. This
+ includes return parameters.
+
+* The parameter lists must give a type for each argument:
+ the (x, y, z int) shorthand is not allowed.
+
+* If the return parameter is an error number, it must be named err.
+
+* If go func name needs to be different from it's winapi dll name,
+ the winapi name could be specified at the end, after "=" sign, like
+ //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+
+* Each function that returns err needs to supply a condition, that
+ return value of winapi will be tested against to detect failure.
+ This would set err to windows "last-error", otherwise it will be nil.
+ The value can be provided at end of //sys declaration, like
+ //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
+ and is [failretval==0] by default.
+
+Usage:
+ mksyscall_windows [flags] [path ...]
+
+The flags are:
+ -trace
+ Generate print statement after every syscall.
+*/
+package main
+
+import (
+ "bufio"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+ "text/template"
+)
+
+var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+
+func trim(s string) string {
+ return strings.Trim(s, " \t")
+}
+
+// Param is function parameter
+type Param struct {
+ Name string
+ Type string
+ fn *Fn
+ tmpVarIdx int
+}
+
+// tmpVar returns temp variable name that will be used to represent p during syscall.
+func (p *Param) tmpVar() string {
+ if p.tmpVarIdx < 0 {
+ p.tmpVarIdx = p.fn.curTmpVarIdx
+ p.fn.curTmpVarIdx++
+ }
+ return fmt.Sprintf("_p%d", p.tmpVarIdx)
+}
+
+// BoolTmpVarCode returns source code for bool temp variable.
+func (p *Param) BoolTmpVarCode() string {
+ const code = `var %s uint32
+ if %s {
+ %s = 1
+ } else {
+ %s = 0
+ }`
+ tmp := p.tmpVar()
+ return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
+}
+
+// SliceTmpVarCode returns source code for slice temp variable.
+func (p *Param) SliceTmpVarCode() string {
+ const code = `var %s *%s
+ if len(%s) > 0 {
+ %s = &%s[0]
+ }`
+ tmp := p.tmpVar()
+ return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
+}
+
+// StringTmpVarCode returns source code for string temp variable.
+func (p *Param) StringTmpVarCode() string {
+ errvar := p.fn.Rets.ErrorVarName()
+ if errvar == "" {
+ errvar = "_"
+ }
+ tmp := p.tmpVar()
+ const code = `var %s %s
+ %s, %s = %s(%s)`
+ s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
+ if errvar == "-" {
+ return s
+ }
+ const morecode = `
+ if %s != nil {
+ return
+ }`
+ return s + fmt.Sprintf(morecode, errvar)
+}
+
+// TmpVarCode returns source code for temp variable.
+func (p *Param) TmpVarCode() string {
+ switch {
+ case p.Type == "string":
+ return p.StringTmpVarCode()
+ case p.Type == "bool":
+ return p.BoolTmpVarCode()
+ case strings.HasPrefix(p.Type, "[]"):
+ return p.SliceTmpVarCode()
+ default:
+ return ""
+ }
+}
+
+// SyscallArgList returns source code fragments representing p parameter
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
+// the first element and length.
+func (p *Param) SyscallArgList() []string {
+ var s string
+ switch {
+ case p.Type[0] == '*':
+ s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
+ case p.Type == "string":
+ s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar())
+ case p.Type == "bool":
+ s = p.tmpVar()
+ case strings.HasPrefix(p.Type, "[]"):
+ return []string{
+ fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
+ fmt.Sprintf("uintptr(len(%s))", p.Name),
+ }
+ default:
+ s = p.Name
+ }
+ return []string{fmt.Sprintf("uintptr(%s)", s)}
+}
+
+// IsError determines if p parameter is used to return error.
+func (p *Param) IsError() bool {
+ return p.Name == "err" && p.Type == "error"
+}
+
+// join concatenates parameters ps into a string with sep separator.
+// Each parameter is converted into string by applying fn to it
+// before conversion.
+func join(ps []*Param, fn func(*Param) string, sep string) string {
+ if len(ps) == 0 {
+ return ""
+ }
+ a := make([]string, 0)
+ for _, p := range ps {
+ a = append(a, fn(p))
+ }
+ return strings.Join(a, sep)
+}
+
+// Rets describes function return parameters.
+type Rets struct {
+ Name string
+ Type string
+ ReturnsError bool
+ FailCond string
+}
+
+// ErrorVarName returns error variable name for r.
+func (r *Rets) ErrorVarName() string {
+ if r.ReturnsError {
+ return "err"
+ }
+ if r.Type == "error" {
+ return r.Name
+ }
+ return ""
+}
+
+// ToParams converts r into slice of *Param.
+func (r *Rets) ToParams() []*Param {
+ ps := make([]*Param, 0)
+ if len(r.Name) > 0 {
+ ps = append(ps, &Param{Name: r.Name, Type: r.Type})
+ }
+ if r.ReturnsError {
+ ps = append(ps, &Param{Name: "err", Type: "error"})
+ }
+ return ps
+}
+
+// List returns source code of syscall return parameters.
+func (r *Rets) List() string {
+ s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+ if len(s) > 0 {
+ s = "(" + s + ")"
+ }
+ return s
+}
+
+// PrintList returns source code of trace printing part correspondent
+// to syscall return values.
+func (r *Rets) PrintList() string {
+ return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// SetReturnValuesCode returns source code that accepts syscall return values.
+func (r *Rets) SetReturnValuesCode() string {
+ if r.Name == "" && !r.ReturnsError {
+ return ""
+ }
+ retvar := "r0"
+ if r.Name == "" {
+ retvar = "r1"
+ }
+ errvar := "_"
+ if r.ReturnsError {
+ errvar = "e1"
+ }
+ return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
+}
+
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
+ const code = `if %s {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }`
+ cond := retvar + " == 0"
+ if r.FailCond != "" {
+ cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
+ }
+ return fmt.Sprintf(code, cond)
+}
+
+// SetErrorCode returns source code that sets return parameters.
+func (r *Rets) SetErrorCode() string {
+ const code = `if r0 != 0 {
+ %s = Errno(r0)
+ }`
+ if r.Name == "" && !r.ReturnsError {
+ return ""
+ }
+ if r.Name == "" {
+ return r.useLongHandleErrorCode("r1")
+ }
+ if r.Type == "error" {
+ return fmt.Sprintf(code, r.Name)
+ }
+ s := ""
+ if r.Type[0] == '*' {
+ s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
+ } else {
+ s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
+ }
+ if !r.ReturnsError {
+ return s
+ }
+ return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
+}
+
+// Fn describes syscall function.
+type Fn struct {
+ Name string
+ Params []*Param
+ Rets *Rets
+ PrintTrace bool
+ dllname string
+ dllfuncname string
+ src string
+ // TODO: get rid of this field and just use parameter index instead
+ curTmpVarIdx int // insure tmp variables have uniq names
+}
+
+// extractParams parses s to extract function parameters.
+func extractParams(s string, f *Fn) ([]*Param, error) {
+ s = trim(s)
+ if s == "" {
+ return nil, nil
+ }
+ a := strings.Split(s, ",")
+ ps := make([]*Param, len(a))
+ for i := range ps {
+ s2 := trim(a[i])
+ b := strings.Split(s2, " ")
+ if len(b) != 2 {
+ b = strings.Split(s2, "\t")
+ if len(b) != 2 {
+ return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
+ }
+ }
+ ps[i] = &Param{
+ Name: trim(b[0]),
+ Type: trim(b[1]),
+ fn: f,
+ tmpVarIdx: -1,
+ }
+ }
+ return ps, nil
+}
+
+// extractSection extracts text out of string s starting after start
+// and ending just before end. found return value will indicate success,
+// and prefix, body and suffix will contain correspondent parts of string s.
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
+ s = trim(s)
+ if strings.HasPrefix(s, string(start)) {
+ // no prefix
+ body = s[1:]
+ } else {
+ a := strings.SplitN(s, string(start), 2)
+ if len(a) != 2 {
+ return "", "", s, false
+ }
+ prefix = a[0]
+ body = a[1]
+ }
+ a := strings.SplitN(body, string(end), 2)
+ if len(a) != 2 {
+ return "", "", "", false
+ }
+ return prefix, a[0], a[1], true
+}
+
+// newFn parses string s and return created function Fn.
+func newFn(s string) (*Fn, error) {
+ s = trim(s)
+ f := &Fn{
+ Rets: &Rets{},
+ src: s,
+ PrintTrace: *PrintTraceFlag,
+ }
+ // function name and args
+ prefix, body, s, found := extractSection(s, '(', ')')
+ if !found || prefix == "" {
+ return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
+ }
+ f.Name = prefix
+ var err error
+ f.Params, err = extractParams(body, f)
+ if err != nil {
+ return nil, err
+ }
+ // return values
+ _, body, s, found = extractSection(s, '(', ')')
+ if found {
+ r, err := extractParams(body, f)
+ if err != nil {
+ return nil, err
+ }
+ switch len(r) {
+ case 0:
+ case 1:
+ if r[0].IsError() {
+ f.Rets.ReturnsError = true
+ } else {
+ f.Rets.Name = r[0].Name
+ f.Rets.Type = r[0].Type
+ }
+ case 2:
+ if !r[1].IsError() {
+ return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
+ }
+ f.Rets.ReturnsError = true
+ f.Rets.Name = r[0].Name
+ f.Rets.Type = r[0].Type
+ default:
+ return nil, errors.New("Too many return values in \"" + f.src + "\"")
+ }
+ }
+ // fail condition
+ _, body, s, found = extractSection(s, '[', ']')
+ if found {
+ f.Rets.FailCond = body
+ }
+ // dll and dll function names
+ s = trim(s)
+ if s == "" {
+ return f, nil
+ }
+ if !strings.HasPrefix(s, "=") {
+ return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+ }
+ s = trim(s[1:])
+ a := strings.Split(s, ".")
+ switch len(a) {
+ case 1:
+ f.dllfuncname = a[0]
+ case 2:
+ f.dllname = a[0]
+ f.dllfuncname = a[1]
+ default:
+ return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+ }
+ return f, nil
+}
+
+// DLLName returns DLL name for function f.
+func (f *Fn) DLLName() string {
+ if f.dllname == "" {
+ return "kernel32"
+ }
+ return f.dllname
+}
+
+// DLLName returns DLL function name for function f.
+func (f *Fn) DLLFuncName() string {
+ if f.dllfuncname == "" {
+ return f.Name
+ }
+ return f.dllfuncname
+}
+
+// ParamList returns source code for function f parameters.
+func (f *Fn) ParamList() string {
+ return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+}
+
+// ParamPrintList returns source code of trace printing part correspondent
+// to syscall input parameters.
+func (f *Fn) ParamPrintList() string {
+ return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// ParamCount return number of syscall parameters for function f.
+func (f *Fn) ParamCount() int {
+ n := 0
+ for _, p := range f.Params {
+ n += len(p.SyscallArgList())
+ }
+ return n
+}
+
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
+// to use. It returns parameter count for correspondent SyscallX function.
+func (f *Fn) SyscallParamCount() int {
+ n := f.ParamCount()
+ switch {
+ case n <= 3:
+ return 3
+ case n <= 6:
+ return 6
+ case n <= 9:
+ return 9
+ case n <= 12:
+ return 12
+ case n <= 15:
+ return 15
+ default:
+ panic("too many arguments to system call")
+ }
+}
+
+// Syscall determines which SyscallX function to use for function f.
+func (f *Fn) Syscall() string {
+ c := f.SyscallParamCount()
+ if c == 3 {
+ return "Syscall"
+ }
+ return "Syscall" + strconv.Itoa(c)
+}
+
+// SyscallParamList returns source code for SyscallX parameters for function f.
+func (f *Fn) SyscallParamList() string {
+ a := make([]string, 0)
+ for _, p := range f.Params {
+ a = append(a, p.SyscallArgList()...)
+ }
+ for len(a) < f.SyscallParamCount() {
+ a = append(a, "0")
+ }
+ return strings.Join(a, ", ")
+}
+
+// IsUTF16 is true, if f is W (utf16) function. It is false
+// for all A (ascii) functions.
+func (f *Fn) IsUTF16() bool {
+ s := f.DLLFuncName()
+ return s[len(s)-1] == 'W'
+}
+
+// StrconvFunc returns name of Go string to OS string function for f.
+func (f *Fn) StrconvFunc() string {
+ if f.IsUTF16() {
+ return "UTF16PtrFromString"
+ }
+ return "BytePtrFromString"
+}
+
+// StrconvType returns Go type name used for OS string for f.
+func (f *Fn) StrconvType() string {
+ if f.IsUTF16() {
+ return "*uint16"
+ }
+ return "*byte"
+}
+
+// Source files and functions.
+type Source struct {
+ Funcs []*Fn
+ Files []string
+}
+
+// ParseFiles parses files listed in fs and extracts all syscall
+// functions listed in sys comments. It returns source files
+// and functions collection *Source if successful.
+func ParseFiles(fs []string) (*Source, error) {
+ src := &Source{
+ Funcs: make([]*Fn, 0),
+ Files: make([]string, 0),
+ }
+ for _, file := range fs {
+ if err := src.ParseFile(file); err != nil {
+ return nil, err
+ }
+ }
+ return src, nil
+}
+
+// DLLs return dll names for a source set src.
+func (src *Source) DLLs() []string {
+ uniq := make(map[string]bool)
+ r := make([]string, 0)
+ for _, f := range src.Funcs {
+ name := f.DLLName()
+ if _, found := uniq[name]; !found {
+ uniq[name] = true
+ r = append(r, name)
+ }
+ }
+ return r
+}
+
+// ParseFile adds adition file path to a source set src.
+func (src *Source) ParseFile(path string) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ s := bufio.NewScanner(file)
+ for s.Scan() {
+ t := trim(s.Text())
+ if len(t) < 7 {
+ continue
+ }
+ if !strings.HasPrefix(t, "//sys") {
+ continue
+ }
+ t = t[5:]
+ if !(t[0] == ' ' || t[0] == '\t') {
+ continue
+ }
+ f, err := newFn(t[1:])
+ if err != nil {
+ return err
+ }
+ src.Funcs = append(src.Funcs, f)
+ }
+ if err := s.Err(); err != nil {
+ return err
+ }
+ src.Files = append(src.Files, path)
+ return nil
+}
+
+// Generate output source file from a source set src.
+func (src *Source) Generate(w io.Writer) error {
+ t := template.Must(template.New("main").Parse(srcTemplate))
+ err := t.Execute(w, src)
+ if err != nil {
+ return errors.New("Failed to execute template: " + err.Error())
+ }
+ return nil
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
+ flag.PrintDefaults()
+ os.Exit(1)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if len(os.Args) <= 1 {
+ fmt.Fprintf(os.Stderr, "no files to parse provided\n")
+ usage()
+ }
+ src, err := ParseFiles(os.Args[1:])
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := src.Generate(os.Stdout); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// TODO: use println instead to print in the following template
+const srcTemplate = `
+
+{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+{{template "dlls" .}}
+{{template "funcnames" .}})
+{{range .Funcs}}{{template "funcbody" .}}{{end}}
+{{end}}
+
+{{/* help functions */}}
+
+{{define "dlls"}}{{range .DLLs}} mod{{.}} = NewLazyDLL("{{.}}.dll")
+{{end}}{{end}}
+
+{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
+{{end}}{{end}}
+
+{{define "funcbody"}}
+func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{
+{{template "tmpvars" .}} {{template "syscall" .}}
+{{template "seterror" .}}{{template "printtrace" .}} return
+}
+{{end}}
+
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
+{{end}}{{end}}{{end}}
+
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+
+{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
+{{end}}{{end}}
+
+{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
+{{end}}{{end}}
+
+`
diff --git a/src/pkg/syscall/mksysnum_dragonfly.pl b/src/pkg/syscall/mksysnum_dragonfly.pl
index 769c29ea7..3eba3ab3d 100755
--- a/src/pkg/syscall/mksysnum_dragonfly.pl
+++ b/src/pkg/syscall/mksysnum_dragonfly.pl
@@ -20,7 +20,7 @@ const (
EOF
while(<>){
- if(/^([0-9]+)\s+STD\s+\S+\s+({ \S+\s+(\w+).*)$/){
+ if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){
my $num = $1;
my $proto = $2;
my $name = "SYS_$3";
diff --git a/src/pkg/syscall/mksysnum_freebsd.pl b/src/pkg/syscall/mksysnum_freebsd.pl
index 5c156338e..cd675780b 100755
--- a/src/pkg/syscall/mksysnum_freebsd.pl
+++ b/src/pkg/syscall/mksysnum_freebsd.pl
@@ -33,8 +33,21 @@ while(<>){
if($name eq 'SYS_SYS_EXIT'){
$name = 'SYS_EXIT';
}
+ if($name =~ /^SYS_CAP_+/ || $name =~ /^SYS___CAP_+/){
+ next
+ }
print " $name = $num; // $proto\n";
+
+ # We keep Capsicum syscall numbers for FreeBSD
+ # 9-STABLE here because we are not sure whether they
+ # are mature and stable.
+ if($num == 513){
+ print " SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }\n";
+ print " SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \\\n";
+ print " SYS_CAP_ENTER = 516 // { int cap_enter(void); }\n";
+ print " SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }\n";
+ }
}
}
diff --git a/src/pkg/syscall/mmap_unix_test.go b/src/pkg/syscall/mmap_unix_test.go
new file mode 100644
index 000000000..01f778302
--- /dev/null
+++ b/src/pkg/syscall/mmap_unix_test.go
@@ -0,0 +1,22 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestMmap(t *testing.T) {
+ b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("Mmap: %v", err)
+ }
+ if err := syscall.Munmap(b); err != nil {
+ t.Fatalf("Munmap: %v", err)
+ }
+}
diff --git a/src/pkg/syscall/net_nacl.go b/src/pkg/syscall/net_nacl.go
new file mode 100644
index 000000000..b9488f48d
--- /dev/null
+++ b/src/pkg/syscall/net_nacl.go
@@ -0,0 +1,912 @@
+// 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.
+
+// A simulated network for use within NaCl.
+// The simulation is not particularly tied to NaCl,
+// but other systems have real networks.
+
+package syscall
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Really for use by package time, but we cannot import time here.
+
+type runtimeTimer struct {
+ i int32
+ when int64
+ period int64
+ f func(int64, interface{}) // NOTE: must not be closure
+ arg interface{}
+}
+
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
+
+type timer struct {
+ expired bool
+ q *queue
+ r runtimeTimer
+}
+
+func (t *timer) start(q *queue, deadline int64) {
+ if deadline == 0 {
+ return
+ }
+ t.q = q
+ t.r.when = deadline
+ t.r.f = timerExpired
+ t.r.arg = t
+ startTimer(&t.r)
+}
+
+func (t *timer) stop() {
+ stopTimer(&t.r)
+}
+
+func timerExpired(now int64, i interface{}) {
+ t := i.(*timer)
+ go func() {
+ t.q.Lock()
+ defer t.q.Unlock()
+ t.expired = true
+ t.q.canRead.Broadcast()
+ t.q.canWrite.Broadcast()
+ }()
+}
+
+// Network constants and data structures. These match the traditional values.
+
+const (
+ AF_UNSPEC = iota
+ AF_UNIX
+ AF_INET
+ AF_INET6
+)
+
+const (
+ SHUT_RD = iota
+ SHUT_WR
+ SHUT_RDWR
+)
+
+const (
+ SOCK_STREAM = 1 + iota
+ SOCK_DGRAM
+ SOCK_RAW
+ SOCK_SEQPACKET
+)
+
+const (
+ IPPROTO_IP = 0
+ IPPROTO_IPV4 = 4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 0x11
+)
+
+// Misc constants expected by package net but not supported.
+const (
+ _ = iota
+ SOL_SOCKET
+ SO_TYPE
+ NET_RT_IFLIST
+ IFNAMSIZ
+ IFF_UP
+ IFF_BROADCAST
+ IFF_LOOPBACK
+ IFF_POINTOPOINT
+ IFF_MULTICAST
+ IPV6_V6ONLY
+ SOMAXCONN
+ F_DUPFD_CLOEXEC
+ SO_BROADCAST
+ SO_REUSEADDR
+ SO_REUSEPORT
+ SO_RCVBUF
+ SO_SNDBUF
+ SO_KEEPALIVE
+ SO_LINGER
+ SO_ERROR
+ IP_PORTRANGE
+ IP_PORTRANGE_DEFAULT
+ IP_PORTRANGE_LOW
+ IP_PORTRANGE_HIGH
+ IP_MULTICAST_IF
+ IP_MULTICAST_LOOP
+ IP_ADD_MEMBERSHIP
+ IPV6_PORTRANGE
+ IPV6_PORTRANGE_DEFAULT
+ IPV6_PORTRANGE_LOW
+ IPV6_PORTRANGE_HIGH
+ IPV6_MULTICAST_IF
+ IPV6_MULTICAST_LOOP
+ IPV6_JOIN_GROUP
+ TCP_NODELAY
+ TCP_KEEPINTVL
+ TCP_KEEPIDLE
+
+ SYS_FCNTL = 500 // unsupported
+)
+
+var SocketDisableIPv6 bool
+
+// A Sockaddr is one of the SockaddrXxx structs.
+type Sockaddr interface {
+ // copy returns a copy of the underlying data.
+ copy() Sockaddr
+
+ // key returns the value of the underlying data,
+ // for comparison as a map key.
+ key() interface{}
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+}
+
+func (sa *SockaddrInet4) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrInet4) key() interface{} { return *sa }
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+}
+
+func (sa *SockaddrInet6) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrInet6) key() interface{} { return *sa }
+
+type SockaddrUnix struct {
+ Name string
+}
+
+func (sa *SockaddrUnix) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrUnix) key() interface{} { return *sa }
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+}
+
+func (sa *SockaddrDatalink) copy() Sockaddr {
+ sa1 := *sa
+ return &sa1
+}
+
+func (sa *SockaddrDatalink) key() interface{} { return *sa }
+
+// RoutingMessage represents a routing message.
+type RoutingMessage interface {
+ unimplemented()
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type ICMPv6Filter struct {
+ Filt [8]uint32
+}
+
+// A queue is the bookkeeping for a synchronized buffered queue.
+// We do not use channels because we need to be able to handle
+// writes after and during close, and because a chan byte would
+// require too many send and receive operations in real use.
+type queue struct {
+ sync.Mutex
+ canRead sync.Cond
+ canWrite sync.Cond
+ r int // total read index
+ w int // total write index
+ m int // index mask
+ closed bool
+}
+
+func (q *queue) init(size int) {
+ if size&(size-1) != 0 {
+ panic("invalid queue size - must be power of two")
+ }
+ q.canRead.L = &q.Mutex
+ q.canWrite.L = &q.Mutex
+ q.m = size - 1
+}
+
+func past(deadline int64) bool {
+ sec, nsec := now()
+ return deadline > 0 && deadline < sec*1e9+int64(nsec)
+}
+
+func (q *queue) waitRead(n int, deadline int64) (int, error) {
+ if past(deadline) {
+ return 0, EAGAIN
+ }
+ var t timer
+ t.start(q, deadline)
+ for q.w-q.r == 0 && !q.closed && !t.expired {
+ q.canRead.Wait()
+ }
+ t.stop()
+ m := q.w - q.r
+ if m == 0 && t.expired {
+ return 0, EAGAIN
+ }
+ if m > n {
+ m = n
+ q.canRead.Signal() // wake up next reader too
+ }
+ q.canWrite.Signal()
+ return m, nil
+}
+
+func (q *queue) waitWrite(n int, deadline int64) (int, error) {
+ if past(deadline) {
+ return 0, EAGAIN
+ }
+ var t timer
+ t.start(q, deadline)
+ for q.w-q.r > q.m && !q.closed && !t.expired {
+ q.canWrite.Wait()
+ }
+ t.stop()
+ m := q.m + 1 - (q.w - q.r)
+ if m == 0 && t.expired {
+ return 0, EAGAIN
+ }
+ if m == 0 {
+ return 0, EAGAIN
+ }
+ if m > n {
+ m = n
+ q.canWrite.Signal() // wake up next writer too
+ }
+ q.canRead.Signal()
+ return m, nil
+}
+
+func (q *queue) close() {
+ q.Lock()
+ defer q.Unlock()
+ q.closed = true
+ q.canRead.Broadcast()
+ q.canWrite.Broadcast()
+}
+
+// A byteq is a byte queue.
+type byteq struct {
+ queue
+ data []byte
+}
+
+func newByteq() *byteq {
+ q := &byteq{
+ data: make([]byte, 4096),
+ }
+ q.init(len(q.data))
+ return q
+}
+
+func (q *byteq) read(b []byte, deadline int64) (int, error) {
+ q.Lock()
+ defer q.Unlock()
+ n, err := q.waitRead(len(b), deadline)
+ if err != nil {
+ return 0, err
+ }
+ b = b[:n]
+ for len(b) > 0 {
+ m := copy(b, q.data[q.r&q.m:])
+ q.r += m
+ b = b[m:]
+ }
+ return n, nil
+}
+
+func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
+ q.Lock()
+ defer q.Unlock()
+ for n < len(b) {
+ nn, err := q.waitWrite(len(b[n:]), deadline)
+ if err != nil {
+ return n, err
+ }
+ bb := b[n : n+nn]
+ n += nn
+ for len(bb) > 0 {
+ m := copy(q.data[q.w&q.m:], bb)
+ q.w += m
+ bb = bb[m:]
+ }
+ }
+ return n, nil
+}
+
+// A msgq is a queue of messages.
+type msgq struct {
+ queue
+ data []interface{}
+}
+
+func newMsgq() *msgq {
+ q := &msgq{
+ data: make([]interface{}, 32),
+ }
+ q.init(len(q.data))
+ return q
+}
+
+func (q *msgq) read(deadline int64) (interface{}, error) {
+ q.Lock()
+ defer q.Unlock()
+ n, err := q.waitRead(1, deadline)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ m := q.data[q.r&q.m]
+ q.r++
+ return m, nil
+}
+
+func (q *msgq) write(m interface{}, deadline int64) error {
+ q.Lock()
+ defer q.Unlock()
+ _, err := q.waitWrite(1, deadline)
+ if err != nil {
+ return err
+ }
+ q.data[q.w&q.m] = m
+ q.w++
+ return nil
+}
+
+// An addr is a sequence of bytes uniquely identifying a network address.
+// It is not human-readable.
+type addr string
+
+// A conn is one side of a stream-based network connection.
+// That is, a stream-based network connection is a pair of cross-connected conns.
+type conn struct {
+ rd *byteq
+ wr *byteq
+ local addr
+ remote addr
+}
+
+// A pktconn is one side of a packet-based network connection.
+// That is, a packet-based network connection is a pair of cross-connected pktconns.
+type pktconn struct {
+ rd *msgq
+ wr *msgq
+ local addr
+ remote addr
+}
+
+// A listener accepts incoming stream-based network connections.
+type listener struct {
+ rd *msgq
+ local addr
+}
+
+// A netFile is an open network file.
+type netFile struct {
+ defaultFileImpl
+ proto *netproto
+ sotype int
+ listener *msgq
+ packet *msgq
+ rd *byteq
+ wr *byteq
+ rddeadline int64
+ wrdeadline int64
+ addr Sockaddr
+ raddr Sockaddr
+}
+
+// A netAddr is a network address in the global listener map.
+// All the fields must have defined == operations.
+type netAddr struct {
+ proto *netproto
+ sotype int
+ addr interface{}
+}
+
+// net records the state of the network.
+// It maps a network address to the listener on that address.
+var net = struct {
+ sync.Mutex
+ listener map[netAddr]*netFile
+}{
+ listener: make(map[netAddr]*netFile),
+}
+
+// TODO(rsc): Some day, do a better job with port allocation.
+// For playground programs, incrementing is fine.
+var nextport = 2
+
+// A netproto contains protocol-specific functionality
+// (one for AF_INET, one for AF_INET6 and so on).
+// It is a struct instead of an interface because the
+// implementation needs no state, and I expect to
+// add some data fields at some point.
+type netproto struct {
+ bind func(*netFile, Sockaddr) error
+}
+
+var netprotoAF_INET = &netproto{
+ bind: func(f *netFile, sa Sockaddr) error {
+ if sa == nil {
+ f.addr = &SockaddrInet4{
+ Port: nextport,
+ Addr: [4]byte{127, 0, 0, 1},
+ }
+ nextport++
+ return nil
+ }
+ addr, ok := sa.(*SockaddrInet4)
+ if !ok {
+ return EINVAL
+ }
+ addr = addr.copy().(*SockaddrInet4)
+ if addr.Port == 0 {
+ addr.Port = nextport
+ nextport++
+ }
+ f.addr = addr
+ return nil
+ },
+}
+
+var netprotos = map[int]*netproto{
+ AF_INET: netprotoAF_INET,
+}
+
+// These functions implement the usual BSD socket operations.
+
+func (f *netFile) bind(sa Sockaddr) error {
+ if f.addr != nil {
+ return EISCONN
+ }
+ if err := f.proto.bind(f, sa); err != nil {
+ return err
+ }
+ if f.sotype == SOCK_DGRAM {
+ _, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+ if ok {
+ f.addr = nil
+ return EADDRINUSE
+ }
+ net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+ f.packet = newMsgq()
+ }
+ return nil
+}
+
+func (f *netFile) listen(backlog int) error {
+ net.Lock()
+ defer net.Unlock()
+ if f.listener != nil {
+ return EINVAL
+ }
+ _, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+ if ok {
+ return EADDRINUSE
+ }
+ net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+ f.listener = newMsgq()
+ return nil
+}
+
+func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
+ msg, err := f.listener.read(f.readDeadline())
+ if err != nil {
+ return -1, nil, err
+ }
+ newf, ok := msg.(*netFile)
+ if !ok {
+ // must be eof
+ return -1, nil, EAGAIN
+ }
+ return newFD(newf), newf.raddr.copy(), nil
+}
+
+func (f *netFile) connect(sa Sockaddr) error {
+ if past(f.writeDeadline()) {
+ return EAGAIN
+ }
+ if f.addr == nil {
+ if err := f.bind(nil); err != nil {
+ return err
+ }
+ }
+ net.Lock()
+ if sa == nil {
+ net.Unlock()
+ return EINVAL
+ }
+ sa = sa.copy()
+ if f.raddr != nil {
+ net.Unlock()
+ return EISCONN
+ }
+ if f.sotype == SOCK_DGRAM {
+ net.Unlock()
+ f.raddr = sa
+ return nil
+ }
+ if f.listener != nil {
+ net.Unlock()
+ return EISCONN
+ }
+ l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
+ if !ok {
+ net.Unlock()
+ return ECONNREFUSED
+ }
+ f.raddr = sa
+ f.rd = newByteq()
+ f.wr = newByteq()
+ newf := &netFile{
+ proto: f.proto,
+ sotype: f.sotype,
+ addr: f.raddr,
+ raddr: f.addr,
+ rd: f.wr,
+ wr: f.rd,
+ }
+ net.Unlock()
+ l.listener.write(newf, f.writeDeadline())
+ return nil
+}
+
+func (f *netFile) read(b []byte) (int, error) {
+ if f.rd == nil {
+ if f.raddr != nil {
+ n, _, err := f.recvfrom(b, 0)
+ return n, err
+ }
+ return 0, ENOTCONN
+ }
+ return f.rd.read(b, f.readDeadline())
+}
+
+func (f *netFile) write(b []byte) (int, error) {
+ if f.wr == nil {
+ if f.raddr != nil {
+ err := f.sendto(b, 0, f.raddr)
+ var n int
+ if err == nil {
+ n = len(b)
+ }
+ return n, err
+ }
+ return 0, ENOTCONN
+ }
+ return f.wr.write(b, f.writeDeadline())
+}
+
+type pktmsg struct {
+ buf []byte
+ addr Sockaddr
+}
+
+func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
+ if f.sotype != SOCK_DGRAM {
+ return 0, nil, EINVAL
+ }
+ if f.packet == nil {
+ return 0, nil, ENOTCONN
+ }
+ msg1, err := f.packet.read(f.readDeadline())
+ if err != nil {
+ return 0, nil, err
+ }
+ msg, ok := msg1.(*pktmsg)
+ if !ok {
+ return 0, nil, EAGAIN
+ }
+ return copy(p, msg.buf), msg.addr, nil
+}
+
+func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
+ if f.sotype != SOCK_DGRAM {
+ return EINVAL
+ }
+ if f.packet == nil {
+ if err := f.bind(nil); err != nil {
+ return err
+ }
+ }
+ net.Lock()
+ if to == nil {
+ net.Unlock()
+ return EINVAL
+ }
+ to = to.copy()
+ l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
+ if !ok || l.packet == nil {
+ net.Unlock()
+ return ECONNREFUSED
+ }
+ net.Unlock()
+ msg := &pktmsg{
+ buf: make([]byte, len(p)),
+ addr: f.addr,
+ }
+ copy(msg.buf, p)
+ l.packet.write(msg, f.writeDeadline())
+ return nil
+}
+
+func (f *netFile) close() error {
+ if f.listener != nil {
+ f.listener.close()
+ }
+ if f.packet != nil {
+ f.packet.close()
+ }
+ if f.rd != nil {
+ f.rd.close()
+ }
+ if f.wr != nil {
+ f.wr.close()
+ }
+ return nil
+}
+
+func fdToNetFile(fd int) (*netFile, error) {
+ f, err := fdToFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ impl := f.impl
+ netf, ok := impl.(*netFile)
+ if !ok {
+ return nil, EINVAL
+ }
+ return netf, nil
+}
+
+func Socket(proto, sotype, unused int) (fd int, err error) {
+ p := netprotos[proto]
+ if p == nil {
+ return -1, EPROTONOSUPPORT
+ }
+ if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
+ return -1, ESOCKTNOSUPPORT
+ }
+ f := &netFile{
+ proto: p,
+ sotype: sotype,
+ }
+ return newFD(f), nil
+}
+
+func Bind(fd int, sa Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.bind(sa)
+}
+
+func StopIO(fd int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ f.close()
+ return nil
+}
+
+func Listen(fd int, backlog int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.listen(backlog)
+}
+
+func Accept(fd int) (newfd int, sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, nil, err
+ }
+ return f.accept()
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ if f.addr == nil {
+ return nil, ENOTCONN
+ }
+ return f.addr.copy(), nil
+}
+
+func Getpeername(fd int) (sa Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return nil, err
+ }
+ if f.raddr == nil {
+ return nil, ENOTCONN
+ }
+ return f.raddr.copy(), nil
+}
+
+func Connect(fd int, sa Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.connect(sa)
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, nil, err
+ }
+ return f.recvfrom(p, flags)
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return f.sendto(p, flags, to)
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return
+ }
+ n, from, err = f.recvfrom(p, flags)
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
+ _, err := SendmsgN(fd, p, oob, to, flags)
+ return err
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ switch f.sotype {
+ case SOCK_STREAM:
+ n, err = f.write(p)
+ case SOCK_DGRAM:
+ n = len(p)
+ err = f.sendto(p, flags, to)
+ }
+ if err != nil {
+ return 0, err
+ }
+ return n, nil
+}
+
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return 0, err
+ }
+ switch {
+ case level == SOL_SOCKET && opt == SO_TYPE:
+ return f.sotype, nil
+ }
+ return 0, ENOTSUP
+}
+
+func SetsockoptInt(fd, level, opt int, value int) error {
+ return nil
+}
+
+func SetsockoptByte(fd, level, opt int, value byte) error {
+ _, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ return ENOTSUP
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) error {
+ return nil
+}
+
+func SetReadDeadline(fd int, t int64) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ atomic.StoreInt64(&f.rddeadline, t)
+ return nil
+}
+
+func (f *netFile) readDeadline() int64 {
+ return atomic.LoadInt64(&f.rddeadline)
+}
+
+func SetWriteDeadline(fd int, t int64) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ atomic.StoreInt64(&f.wrdeadline, t)
+ return nil
+}
+
+func (f *netFile) writeDeadline() int64 {
+ return atomic.LoadInt64(&f.wrdeadline)
+}
+
+func Shutdown(fd int, how int) error {
+ f, err := fdToNetFile(fd)
+ if err != nil {
+ return err
+ }
+ switch how {
+ case SHUT_RD:
+ f.rd.close()
+ case SHUT_WR:
+ f.wr.close()
+ case SHUT_RDWR:
+ f.rd.close()
+ f.wr.close()
+ }
+ return nil
+}
+
+func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error { panic("SetsockoptIPMreq") }
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error { panic("SetsockoptIPv") }
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error { panic("SetsockoptInet") }
+func SetsockoptString(fd, level, opt int, s string) error { panic("SetsockoptString") }
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error { panic("SetsockoptTimeval") }
+func Socketpair(domain, typ, proto int) (fd [2]int, err error) { panic("Socketpair") }
+
+func SetNonblock(fd int, nonblocking bool) error { return nil }
diff --git a/src/pkg/syscall/rlimit_linux_test.go b/src/pkg/syscall/rlimit_linux_test.go
deleted file mode 100644
index 4ec720e93..000000000
--- a/src/pkg/syscall/rlimit_linux_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package syscall_test
-
-import (
- "syscall"
- "testing"
-)
-
-func TestRlimit(t *testing.T) {
- var rlimit, zero syscall.Rlimit
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
- if err != nil {
- t.Fatalf("Getrlimit: save failed: %v", err)
- }
- if zero == rlimit {
- t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
- }
- set := rlimit
- set.Cur = set.Max - 1
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
- if err != nil {
- t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
- }
- var get syscall.Rlimit
- err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
- if err != nil {
- t.Fatalf("Getrlimit: get failed: %v", err)
- }
- set = rlimit
- set.Cur = set.Max - 1
- if set != get {
- t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
- }
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
- if err != nil {
- t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
- }
-}
diff --git a/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
index 638073592..48af58745 100644
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -199,14 +199,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
+ msgCount := 0
for len(b) >= anyMessageLen {
+ msgCount++
any := (*anyMessage)(unsafe.Pointer(&b[0]))
if any.Version != RTM_VERSION {
- return nil, EINVAL
+ b = b[any.Msglen:]
+ continue
}
msgs = append(msgs, any.toRoutingMessage(b))
b = b[any.Msglen:]
}
+ // We failed to parse any of the messages - version mismatch?
+ if msgCount > 0 && len(msgs) == 0 {
+ return nil, EINVAL
+ }
return msgs, nil
}
diff --git a/src/pkg/syscall/route_dragonfly.go b/src/pkg/syscall/route_dragonfly.go
index acad7a2be..79190d2b0 100644
--- a/src/pkg/syscall/route_dragonfly.go
+++ b/src/pkg/syscall/route_dragonfly.go
@@ -30,7 +30,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/src/pkg/syscall/route_freebsd.go b/src/pkg/syscall/route_freebsd.go
index d8f80316b..15897b1ac 100644
--- a/src/pkg/syscall/route_freebsd.go
+++ b/src/pkg/syscall/route_freebsd.go
@@ -8,14 +8,20 @@ package syscall
import "unsafe"
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
+func init() {
+ freebsdVersion, _ = SysctlUint32("kern.osreldate")
+}
+
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
switch any.Type {
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
p := (*RouteMessage)(unsafe.Pointer(any))
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
case RTM_IFINFO:
- p := (*InterfaceMessage)(unsafe.Pointer(any))
- return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+ return any.parseInterfaceMessage(b)
case RTM_IFANNOUNCE:
p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
return &InterfaceAnnounceMessage{Header: p.Header}
@@ -30,7 +36,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/src/pkg/syscall/route_freebsd_32bit.go b/src/pkg/syscall/route_freebsd_32bit.go
new file mode 100644
index 000000000..93efdddb3
--- /dev/null
+++ b/src/pkg/syscall/route_freebsd_32bit.go
@@ -0,0 +1,24 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd,386 freebsd,arm
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ // FreeBSD 10 and beyond have a restructured mbuf
+ // packet header view.
+ // See http://svnweb.freebsd.org/base?view=revision&revision=254804.
+ if freebsdVersion >= 1000000 {
+ m := (*ifMsghdr)(unsafe.Pointer(any))
+ p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
+ p.Header.Data.Epoch = m.Data.Epoch
+ p.Header.Data.Lastchange = m.Data.Lastchange
+ return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
+ }
+ return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/src/pkg/syscall/route_freebsd_64bit.go b/src/pkg/syscall/route_freebsd_64bit.go
new file mode 100644
index 000000000..9377f2fed
--- /dev/null
+++ b/src/pkg/syscall/route_freebsd_64bit.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd,amd64
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/src/pkg/syscall/route_netbsd.go b/src/pkg/syscall/route_netbsd.go
index a6baa02f8..9883aebaf 100644
--- a/src/pkg/syscall/route_netbsd.go
+++ b/src/pkg/syscall/route_netbsd.go
@@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/src/pkg/syscall/route_openbsd.go b/src/pkg/syscall/route_openbsd.go
index 223c15779..19f902db7 100644
--- a/src/pkg/syscall/route_openbsd.go
+++ b/src/pkg/syscall/route_openbsd.go
@@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
}
// InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
diff --git a/src/pkg/syscall/so_solaris.go b/src/pkg/syscall/so_solaris.go
new file mode 100644
index 000000000..659cd67c1
--- /dev/null
+++ b/src/pkg/syscall/so_solaris.go
@@ -0,0 +1,260 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "sync"
+ "sync/atomic"
+ "unsafe"
+)
+
+// soError describes reasons for shared library load failures.
+type soError struct {
+ Err error
+ ObjName string
+ Msg string
+}
+
+func (e *soError) Error() string { return e.Msg }
+
+// Implemented in ../runtime/syscall_solaris.goc.
+func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func dlclose(handle uintptr) (err Errno)
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
+
+// A so implements access to a single shared library object.
+type so struct {
+ Name string
+ Handle uintptr
+}
+
+// loadSO loads shared library file into memory.
+func loadSO(name string) (*so, error) {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ h, e := dlopen(namep, 1) // RTLD_LAZY
+ if e != 0 {
+ return nil, &soError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to load " + name + ": " + e.Error(),
+ }
+ }
+ d := &so{
+ Name: name,
+ Handle: uintptr(h),
+ }
+ return d, nil
+}
+
+// mustLoadSO is like loadSO but panics if load operation fails.
+func mustLoadSO(name string) *so {
+ d, e := loadSO(name)
+ if e != nil {
+ panic(e)
+ }
+ return d
+}
+
+// FindProc searches shared library d for procedure named name and returns
+// *proc if found. It returns an error if the search fails.
+func (d *so) FindProc(name string) (*proc, error) {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := dlsym(uintptr(d.Handle), namep)
+ if a == 0 {
+ return nil, &soError{
+ Err: ENOSYS,
+ ObjName: name,
+ Msg: "Failed to find " + name + " procedure in " + d.Name,
+ }
+ }
+ p := &proc{
+ SO: d,
+ Name: name,
+ addr: a,
+ }
+ return p, nil
+}
+
+// MustFindProc is like FindProc but panics if search fails.
+func (d *so) MustFindProc(name string) *proc {
+ p, e := d.FindProc(name)
+ if e != nil {
+ panic(e)
+ }
+ return p
+}
+
+// Release unloads shared library d from memory.
+func (d *so) Release() (err error) {
+ return dlclose(d.Handle)
+}
+
+// A proc implements access to a procedure inside a shared library.
+type proc struct {
+ SO *so
+ Name string
+ addr uintptr
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *proc) Addr() uintptr {
+ return p.addr
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError. Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ switch len(a) {
+ case 0:
+ return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
+ case 1:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
+ case 2:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
+ case 3:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
+ case 4:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
+ case 5:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
+ case 6:
+ return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
+ default:
+ panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
+ }
+ return
+}
+
+// A lazySO implements access to a single shared library. It will delay
+// the load of the shared library until the first call to its Handle method
+// or to one of its lazyProc's Addr method.
+type lazySO struct {
+ mu sync.Mutex
+ so *so // non nil once SO is loaded
+ Name string
+}
+
+// Load loads single shared file d.Name into memory. It returns an error if
+// fails. Load will not try to load SO, if it is already loaded into memory.
+func (d *lazySO) Load() error {
+ // Non-racy version of:
+ // if d.so == nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.so == nil {
+ so, e := loadSO(d.Name)
+ if e != nil {
+ return e
+ }
+ // Non-racy version of:
+ // d.so = so
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
+ }
+ }
+ return nil
+}
+
+// mustLoad is like Load but panics if search fails.
+func (d *lazySO) mustLoad() {
+ e := d.Load()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Handle returns d's module handle.
+func (d *lazySO) Handle() uintptr {
+ d.mustLoad()
+ return uintptr(d.so.Handle)
+}
+
+// NewProc returns a lazyProc for accessing the named procedure in the SO d.
+func (d *lazySO) NewProc(name string) *lazyProc {
+ return &lazyProc{l: d, Name: name}
+}
+
+// newLazySO creates new lazySO associated with SO file.
+func newLazySO(name string) *lazySO {
+ return &lazySO{Name: name}
+}
+
+// A lazyProc implements access to a procedure inside a lazySO.
+// It delays the lookup until the Addr method is called.
+type lazyProc struct {
+ mu sync.Mutex
+ Name string
+ l *lazySO
+ proc *proc
+}
+
+// Find searches the shared library for procedure named p.Name. It returns an
+// error if search fails. Find will not search procedure, if it is already
+// found and loaded into memory.
+func (p *lazyProc) Find() error {
+ // Non-racy version of:
+ // if p.proc == nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.proc == nil {
+ e := p.l.Load()
+ if e != nil {
+ return e
+ }
+ proc, e := p.l.so.FindProc(p.Name)
+ if e != nil {
+ return e
+ }
+ // Non-racy version of:
+ // p.proc = proc
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
+ }
+ }
+ return nil
+}
+
+// mustFind is like Find but panics if search fails.
+func (p *lazyProc) mustFind() {
+ e := p.Find()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *lazyProc) Addr() uintptr {
+ p.mustFind()
+ return p.proc.Addr()
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError. Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ p.mustFind()
+ return p.proc.Call(a...)
+}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index a2d234f21..045a012c0 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// Socket control messages
@@ -13,9 +13,9 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/pkg/syscall/srpc_nacl.go b/src/pkg/syscall/srpc_nacl.go
new file mode 100644
index 000000000..dd07373d1
--- /dev/null
+++ b/src/pkg/syscall/srpc_nacl.go
@@ -0,0 +1,822 @@
+// 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.
+
+// Native Client SRPC message passing.
+// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
+
+package syscall
+
+import (
+ "errors"
+ "sync"
+ "unsafe"
+)
+
+// An srpcClient represents the client side of an SRPC connection.
+type srpcClient struct {
+ fd int // to server
+ r msgReceiver
+ s msgSender
+ service map[string]srpcService // services by name
+
+ outMu sync.Mutex // protects writing to connection
+
+ mu sync.Mutex // protects following fields
+ muxer bool // is someone reading and muxing responses
+ pending map[uint32]*srpc
+ idGen uint32 // generator for request IDs
+}
+
+// An srpcService is a single method that the server offers.
+type srpcService struct {
+ num uint32 // method number
+ fmt string // argument format; see "parsing of RPC messages" below
+}
+
+// An srpc represents a single srpc issued by a client.
+type srpc struct {
+ Ret []interface{}
+ Done chan *srpc
+ Err error
+ c *srpcClient
+ id uint32
+}
+
+// newClient allocates a new SRPC client using the file descriptor fd.
+func newClient(fd int) (*srpcClient, error) {
+ c := new(srpcClient)
+ c.fd = fd
+ c.r.fd = fd
+ c.s.fd = fd
+ c.service = make(map[string]srpcService)
+ c.pending = make(map[uint32]*srpc)
+
+ // service discovery request
+ m := &msg{
+ isRequest: 1,
+ template: []interface{}{[]byte(nil)},
+ size: []int{4000}, // max size to accept for returned byte slice
+ }
+ if err := m.pack(); err != nil {
+ return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
+ }
+ c.s.send(m)
+ m, err := c.r.recv()
+ if err != nil {
+ return nil, err
+ }
+ m.unpack()
+ if m.status != uint32(srpcOK) {
+ return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
+ }
+ list := m.value[0].([]byte)
+ var n uint32
+ for len(list) > 0 {
+ var line []byte
+ i := byteIndex(list, '\n')
+ if i < 0 {
+ line, list = list, nil
+ } else {
+ line, list = list[:i], list[i+1:]
+ }
+ i = byteIndex(line, ':')
+ if i >= 0 {
+ c.service[string(line)] = srpcService{n, string(line[i+1:])}
+ }
+ n++
+ }
+
+ return c, nil
+}
+
+func byteIndex(b []byte, c byte) int {
+ for i, bi := range b {
+ if bi == c {
+ return i
+ }
+ }
+ return -1
+}
+
+var yourTurn srpc
+
+func (c *srpcClient) wait(r *srpc) {
+ var rx *srpc
+ for rx = range r.Done {
+ if rx != &yourTurn {
+ break
+ }
+ c.input()
+ }
+ return
+}
+
+func (c *srpcClient) input() {
+ // read message
+ m, err := c.r.recv()
+ if err != nil {
+ println("Native Client SRPC receive error:", err.Error())
+ return
+ }
+ if m.unpack(); m.status != uint32(srpcOK) {
+ println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
+ return
+ }
+
+ // deliver to intended recipient
+ c.mu.Lock()
+ rpc, ok := c.pending[m.id]
+ if ok {
+ delete(c.pending, m.id)
+ }
+
+ // wake a new muxer if there are more RPCs to read
+ c.muxer = false
+ for _, rpc := range c.pending {
+ c.muxer = true
+ rpc.Done <- &yourTurn
+ break
+ }
+ c.mu.Unlock()
+ if !ok {
+ println("Native Client: unexpected response for ID", m.id)
+ return
+ }
+ rpc.Ret = m.value
+ rpc.Done <- rpc
+}
+
+// Wait blocks until the RPC has finished.
+func (r *srpc) Wait() {
+ r.c.wait(r)
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *srpc) Start(name string, arg []interface{}) {
+ r.Err = nil
+ r.c.mu.Lock()
+ srv, ok := r.c.service[name]
+ if !ok {
+ r.c.mu.Unlock()
+ r.Err = srpcErrBadRPCNumber
+ r.Done <- r
+ return
+ }
+ r.c.pending[r.id] = r
+ if !r.c.muxer {
+ r.c.muxer = true
+ r.Done <- &yourTurn
+ }
+ r.c.mu.Unlock()
+
+ var m msg
+ m.id = r.id
+ m.isRequest = 1
+ m.rpc = srv.num
+ m.value = arg
+
+ // Fill in the return values and sizes to generate
+ // the right type chars. We'll take most any size.
+
+ // Skip over input arguments.
+ // We could check them against arg, but the server
+ // will do that anyway.
+ i := 0
+ for srv.fmt[i] != ':' {
+ i++
+ }
+ format := srv.fmt[i+1:]
+
+ // Now the return prototypes.
+ m.template = make([]interface{}, len(format))
+ m.size = make([]int, len(format))
+ for i := 0; i < len(format); i++ {
+ switch format[i] {
+ default:
+ println("Native Client SRPC: unexpected service type " + string(format[i]))
+ r.Err = srpcErrBadRPCNumber
+ r.Done <- r
+ return
+ case 'b':
+ m.template[i] = false
+ case 'C':
+ m.template[i] = []byte(nil)
+ m.size[i] = 1 << 30
+ case 'd':
+ m.template[i] = float64(0)
+ case 'D':
+ m.template[i] = []float64(nil)
+ m.size[i] = 1 << 30
+ case 'h':
+ m.template[i] = int(-1)
+ case 'i':
+ m.template[i] = int32(0)
+ case 'I':
+ m.template[i] = []int32(nil)
+ m.size[i] = 1 << 30
+ case 's':
+ m.template[i] = ""
+ m.size[i] = 1 << 30
+ }
+ }
+
+ if err := m.pack(); err != nil {
+ r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
+ r.Done <- r
+ return
+ }
+
+ r.c.outMu.Lock()
+ r.c.s.send(&m)
+ r.c.outMu.Unlock()
+}
+
+// Call is a convenience wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+// r.Start(name, arg)
+// r.Wait()
+// return r.Ret, r.Errno
+//
+func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
+ r := c.NewRPC(nil)
+ r.Start(name, arg)
+ r.Wait()
+ return r.Ret, r.Err
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
+ if done == nil {
+ done = make(chan *srpc, 1)
+ }
+ c.mu.Lock()
+ id := c.idGen
+ c.idGen++
+ c.mu.Unlock()
+ return &srpc{Done: done, c: c, id: id}
+}
+
+// The current protocol number.
+// Kind of useless, since there have been backwards-incompatible changes
+// to the wire protocol that did not update the protocol number.
+// At this point it's really just a sanity check.
+const protocol = 0xc0da0002
+
+// An srpcErrno is an SRPC status code.
+type srpcErrno uint32
+
+const (
+ srpcOK srpcErrno = 256 + iota
+ srpcErrBreak
+ srpcErrMessageTruncated
+ srpcErrNoMemory
+ srpcErrProtocolMismatch
+ srpcErrBadRPCNumber
+ srpcErrBadArgType
+ srpcErrTooFewArgs
+ srpcErrTooManyArgs
+ srpcErrInArgTypeMismatch
+ srpcErrOutArgTypeMismatch
+ srpcErrInternalError
+ srpcErrAppError
+)
+
+var srpcErrstr = [...]string{
+ srpcOK - srpcOK: "ok",
+ srpcErrBreak - srpcOK: "break",
+ srpcErrMessageTruncated - srpcOK: "message truncated",
+ srpcErrNoMemory - srpcOK: "out of memory",
+ srpcErrProtocolMismatch - srpcOK: "protocol mismatch",
+ srpcErrBadRPCNumber - srpcOK: "invalid RPC method number",
+ srpcErrBadArgType - srpcOK: "unexpected argument type",
+ srpcErrTooFewArgs - srpcOK: "too few arguments",
+ srpcErrTooManyArgs - srpcOK: "too many arguments",
+ srpcErrInArgTypeMismatch - srpcOK: "input argument type mismatch",
+ srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
+ srpcErrInternalError - srpcOK: "internal error",
+ srpcErrAppError - srpcOK: "application error",
+}
+
+func (e srpcErrno) Error() string {
+ if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
+ return "srpcErrno(" + itoa(int(e)) + ")"
+ }
+ return srpcErrstr[e-srpcOK]
+}
+
+// A msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.
+type msgHdr struct {
+ iov *iov
+ niov int32
+ desc *int32
+ ndesc int32
+ flags uint32
+}
+
+// A single region for I/O.
+type iov struct {
+ base *byte
+ len int32
+}
+
+const maxMsgSize = 1<<16 - 4*4
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+ fd int
+ data [maxMsgSize]byte
+ desc [8]int32
+ hdr msgHdr
+ iov iov
+}
+
+func (r *msgReceiver) recv() (*msg, error) {
+ // Init pointers to buffers where syscall recvmsg can write.
+ r.iov.base = &r.data[0]
+ r.iov.len = int32(len(r.data))
+ r.hdr.iov = &r.iov
+ r.hdr.niov = 1
+ r.hdr.desc = &r.desc[0]
+ r.hdr.ndesc = int32(len(r.desc))
+ n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+ if e != 0 {
+ println("Native Client imc_recvmsg: ", e.Error())
+ return nil, e
+ }
+
+ // Make a copy of the data so that the next recvmsg doesn't
+ // smash it. The system call did not update r.iov.len. Instead it
+ // returned the total byte count as n.
+ m := new(msg)
+ m.data = make([]byte, n)
+ copy(m.data, r.data[0:])
+
+ // Make a copy of the desc too.
+ // The system call *did* update r.hdr.ndesc.
+ if r.hdr.ndesc > 0 {
+ m.desc = make([]int32, r.hdr.ndesc)
+ copy(m.desc, r.desc[:])
+ }
+
+ return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+ fd int
+ hdr msgHdr
+ iov iov
+}
+
+func (s *msgSender) send(m *msg) error {
+ if len(m.data) > 0 {
+ s.iov.base = &m.data[0]
+ }
+ s.iov.len = int32(len(m.data))
+ s.hdr.iov = &s.iov
+ s.hdr.niov = 1
+ s.hdr.desc = nil
+ s.hdr.ndesc = 0
+ _, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+ if e != 0 {
+ println("Native Client imc_sendmsg: ", e.Error())
+ return e
+ }
+ return nil
+}
+
+// A msg is the Go representation of an SRPC message.
+type msg struct {
+ data []byte // message data
+ desc []int32 // message file descriptors
+
+ // parsed version of message
+ id uint32
+ isRequest uint32
+ rpc uint32
+ status uint32
+ value []interface{}
+ template []interface{}
+ size []int
+ format string
+ broken bool
+}
+
+// reading from a msg
+
+func (m *msg) uint32() uint32 {
+ if m.broken {
+ return 0
+ }
+ if len(m.data) < 4 {
+ m.broken = true
+ return 0
+ }
+ b := m.data[:4]
+ x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ m.data = m.data[4:]
+ return x
+}
+
+func (m *msg) uint64() uint64 {
+ x := uint64(m.uint32()) | uint64(m.uint32())<<32
+ if m.broken {
+ return 0
+ }
+ return x
+}
+
+func (m *msg) bytes(n int) []byte {
+ if m.broken {
+ return nil
+ }
+ if len(m.data) < n {
+ m.broken = true
+ return nil
+ }
+ x := m.data[0:n]
+ m.data = m.data[n:]
+ return x
+}
+
+// writing to a msg
+
+func (m *msg) wuint32(x uint32) {
+ m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
+}
+
+func (m *msg) wuint64(x uint64) {
+ lo := uint32(x)
+ hi := uint32(x >> 32)
+ m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
+}
+
+func (m *msg) wbytes(p []byte) {
+ m.data = append(m.data, p...)
+}
+
+func (m *msg) wstring(s string) {
+ m.data = append(m.data, s...)
+}
+
+// Parsing of RPC messages.
+//
+// Each message begins with
+// total_size uint32
+// total_descs uint32
+// fragment_size uint32
+// fragment_descs uint32
+//
+// If fragment_size < total_size or fragment_descs < total_descs, the actual
+// message is broken up in multiple messages; follow-up messages omit
+// the "total" fields and begin with the "fragment" fields.
+// We do not support putting fragmented messages back together.
+// To do this we would need to change the message receiver.
+//
+// After that size information, the message header follows:
+// protocol uint32
+// requestID uint32
+// isRequest uint32
+// rpcNumber uint32
+// status uint32
+// numValue uint32
+// numTemplate uint32
+//
+// After the header come numTemplate fixed-size arguments,
+// numValue fixed-size arguments, and then the variable-sized
+// part of the values. The templates describe the expected results
+// and have no associated variable sized data in the request.
+//
+// Each fixed-size argument has the form:
+// tag uint32 // really a char, like 'b' or 'C'
+// pad uint32 // unused
+// val1 uint32
+// val2 uint32
+//
+// The tags are:
+// 'b': bool; val1 == 0 or 1
+// 'C': []byte; val1 == len, data in variable-sized section
+// 'd': float64; (val1, val2) is data
+// 'D': []float64; val1 == len, data in variable-sized section
+// 'h': int; val1 == file descriptor
+// 'i': int32; descriptor in next entry in m.desc
+// 'I': []int; val1 == len, data in variable-sized section
+// 's': string; val1 == len, data in variable-sized section
+//
+
+func (m *msg) pack() error {
+ m.data = m.data[:0]
+ m.desc = m.desc[:0]
+
+ // sizes, to fill in later
+ m.wuint32(0)
+ m.wuint32(0)
+ m.wuint32(0)
+ m.wuint32(0)
+
+ // message header
+ m.wuint32(protocol)
+ m.wuint32(m.id)
+ m.wuint32(m.isRequest)
+ m.wuint32(m.rpc)
+ m.wuint32(m.status)
+ m.wuint32(uint32(len(m.value)))
+ m.wuint32(uint32(len(m.template)))
+
+ // fixed-size templates
+ for i, x := range m.template {
+ var tag, val1, val2 uint32
+ switch x.(type) {
+ default:
+ return errors.New("unexpected template type")
+ case bool:
+ tag = 'b'
+ case []byte:
+ tag = 'C'
+ val1 = uint32(m.size[i])
+ case float64:
+ tag = 'd'
+ case []float64:
+ tag = 'D'
+ val1 = uint32(m.size[i])
+ case int:
+ tag = 'h'
+ case int32:
+ tag = 'i'
+ case []int32:
+ tag = 'I'
+ val1 = uint32(m.size[i])
+ case string:
+ tag = 's'
+ val1 = uint32(m.size[i])
+ }
+ m.wuint32(tag)
+ m.wuint32(0)
+ m.wuint32(val1)
+ m.wuint32(val2)
+ }
+
+ // fixed-size values
+ for _, x := range m.value {
+ var tag, val1, val2 uint32
+ switch x := x.(type) {
+ default:
+ return errors.New("unexpected value type")
+ case bool:
+ tag = 'b'
+ if x {
+ val1 = 1
+ }
+ case []byte:
+ tag = 'C'
+ val1 = uint32(len(x))
+ case float64:
+ tag = 'd'
+ v := float64bits(x)
+ val1 = uint32(v)
+ val2 = uint32(v >> 32)
+ case []float64:
+ tag = 'D'
+ val1 = uint32(len(x))
+ case int32:
+ tag = 'i'
+ m.desc = append(m.desc, x)
+ case []int32:
+ tag = 'I'
+ val1 = uint32(len(x))
+ case string:
+ tag = 's'
+ val1 = uint32(len(x) + 1)
+ }
+ m.wuint32(tag)
+ m.wuint32(0)
+ m.wuint32(val1)
+ m.wuint32(val2)
+ }
+
+ // variable-length data for values
+ for _, x := range m.value {
+ switch x := x.(type) {
+ case []byte:
+ m.wbytes(x)
+ case []float64:
+ for _, f := range x {
+ m.wuint64(float64bits(f))
+ }
+ case []int32:
+ for _, j := range x {
+ m.wuint32(uint32(j))
+ }
+ case string:
+ m.wstring(x)
+ m.wstring("\x00")
+ }
+ }
+
+ // fill in sizes
+ data := m.data
+ m.data = m.data[:0]
+ m.wuint32(uint32(len(data)))
+ m.wuint32(uint32(len(m.desc)))
+ m.wuint32(uint32(len(data)))
+ m.wuint32(uint32(len(m.desc)))
+ m.data = data
+
+ return nil
+}
+
+func (m *msg) unpack() error {
+ totalSize := m.uint32()
+ totalDesc := m.uint32()
+ fragSize := m.uint32()
+ fragDesc := m.uint32()
+ if totalSize != fragSize || totalDesc != fragDesc {
+ return errors.New("Native Client: fragmented RPC messages not supported")
+ }
+ if m.uint32() != protocol {
+ return errors.New("Native Client: RPC protocol mismatch")
+ }
+
+ // message header
+ m.id = m.uint32()
+ m.isRequest = m.uint32()
+ m.rpc = m.uint32()
+ m.status = m.uint32()
+ m.value = make([]interface{}, m.uint32())
+ m.template = make([]interface{}, m.uint32())
+ m.size = make([]int, len(m.template))
+ if m.broken {
+ return errors.New("Native Client: malformed message")
+ }
+
+ // fixed-size templates
+ for i := range m.template {
+ tag := m.uint32()
+ m.uint32() // padding
+ val1 := m.uint32()
+ m.uint32() // val2
+ switch tag {
+ default:
+ return errors.New("Native Client: unexpected template type " + string(rune(tag)))
+ case 'b':
+ m.template[i] = false
+ case 'C':
+ m.template[i] = []byte(nil)
+ m.size[i] = int(val1)
+ case 'd':
+ m.template[i] = float64(0)
+ case 'D':
+ m.template[i] = []float64(nil)
+ m.size[i] = int(val1)
+ case 'i':
+ m.template[i] = int32(0)
+ case 'I':
+ m.template[i] = []int32(nil)
+ m.size[i] = int(val1)
+ case 'h':
+ m.template[i] = int(0)
+ case 's':
+ m.template[i] = ""
+ m.size[i] = int(val1)
+ }
+ }
+
+ // fixed-size values
+ var (
+ strsize []uint32
+ d int
+ )
+ for i := range m.value {
+ tag := m.uint32()
+ m.uint32() // padding
+ val1 := m.uint32()
+ val2 := m.uint32()
+ switch tag {
+ default:
+ return errors.New("Native Client: unexpected value type " + string(rune(tag)))
+ case 'b':
+ m.value[i] = val1 > 0
+ case 'C':
+ m.value[i] = []byte(nil)
+ strsize = append(strsize, val1)
+ case 'd':
+ m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
+ case 'D':
+ m.value[i] = make([]float64, val1)
+ case 'i':
+ m.value[i] = int32(val1)
+ case 'I':
+ m.value[i] = make([]int32, val1)
+ case 'h':
+ m.value[i] = int(m.desc[d])
+ d++
+ case 's':
+ m.value[i] = ""
+ strsize = append(strsize, val1)
+ }
+ }
+
+ // variable-sized parts of values
+ for i, x := range m.value {
+ switch x := x.(type) {
+ case []byte:
+ m.value[i] = m.bytes(int(strsize[0]))
+ strsize = strsize[1:]
+ case []float64:
+ for i := range x {
+ x[i] = float64frombits(m.uint64())
+ }
+ case []int32:
+ for i := range x {
+ x[i] = int32(m.uint32())
+ }
+ case string:
+ m.value[i] = string(m.bytes(int(strsize[0])))
+ strsize = strsize[1:]
+ }
+ }
+
+ if len(m.data) > 0 {
+ return errors.New("Native Client: junk at end of message")
+ }
+ return nil
+}
+
+func float64bits(x float64) uint64 {
+ return *(*uint64)(unsafe.Pointer(&x))
+}
+
+func float64frombits(x uint64) float64 {
+ return *(*float64)(unsafe.Pointer(&x))
+}
+
+// At startup, connect to the name service.
+var nsClient = nsConnect()
+
+func nsConnect() *srpcClient {
+ var ns int32 = -1
+ _, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
+ if errno != 0 {
+ println("Native Client nameservice:", errno.Error())
+ return nil
+ }
+
+ sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
+ if errno != 0 {
+ println("Native Client nameservice connect:", errno.Error())
+ return nil
+ }
+
+ c, err := newClient(int(sock))
+ if err != nil {
+ println("Native Client nameservice init:", err.Error())
+ return nil
+ }
+
+ return c
+}
+
+const (
+ nsSuccess = 0
+ nsNameNotFound = 1
+ nsDuplicateName = 2
+ nsInsufficientResources = 3
+ nsPermissionDenied = 4
+ nsInvalidArgument = 5
+)
+
+func openNamedService(name string, mode int32) (fd int, err error) {
+ if nsClient == nil {
+ return 0, errors.New("no name service")
+ }
+ ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
+ if err != nil {
+ return 0, err
+ }
+ status := ret[0].(int32)
+ fd = ret[1].(int)
+ switch status {
+ case nsSuccess:
+ // ok
+ case nsNameNotFound:
+ return -1, ENOENT
+ case nsDuplicateName:
+ return -1, EEXIST
+ case nsInsufficientResources:
+ return -1, EWOULDBLOCK
+ case nsPermissionDenied:
+ return -1, EPERM
+ case nsInvalidArgument:
+ return -1, EINVAL
+ default:
+ return -1, EINVAL
+ }
+ return fd, nil
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 76b1f41b4..b042841a5 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -64,8 +64,11 @@ func Setgroups(gids []int) (err error) {
func ReadDirent(fd int, buf []byte) (n int, err error) {
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // 64 bits should be enough. (32 bits isn't even on 386). Since the
+ // actual system call is getdirentries64, 64 is a good guess.
// TODO(rsc): Can we use a single global basep for all calls?
- return Getdirentries(fd, buf, new(uintptr))
+ var base = (*uintptr)(unsafe.Pointer(new(uint64)))
+ return Getdirentries(fd, buf, base)
}
// Wait status is 7 bits at bottom, either 0 (exited),
@@ -131,18 +134,18 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
}
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys Shutdown(s int, how int) (err error)
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = SizeofSockaddrInet4
sa.raw.Family = AF_INET
@@ -152,12 +155,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = SizeofSockaddrInet6
sa.raw.Family = AF_INET6
@@ -168,26 +171,26 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) || n == 0 {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ {
sa.raw.Path[i] = int8(name[i])
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+ return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Index == 0 {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Len = sa.Len
sa.raw.Family = AF_LINK
@@ -199,7 +202,7 @@ func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.raw.Data); i++ {
sa.raw.Data[i] = sa.Data[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -221,14 +224,20 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
- if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
+ if pp.Len < 2 || pp.Len > SizeofSockaddrUnix {
return nil, EINVAL
}
sa := new(SockaddrUnix)
- n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL
+
+ // Some BSDs include the trailing NUL in the length, whereas
+ // others do not. Work around this by subtracting the leading
+ // family and len. The path is then scanned to see if a NUL
+ // terminator still exists within the length.
+ n := int(pp.Len) - 2 // subtract leading Family, Len
for i := 0; i < n; i++ {
if pp.Path[i] == 0 {
- // found early NUL; assume Len is overestimating
+ // found early NUL; assume Len included the NUL
+ // or was overestimating.
n = i
break
}
@@ -290,10 +299,9 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- // TODO(jsing): Remove after OpenBSD 5.4 is released (see issue 3349).
- // TODO(jsing): Apparently dragonfly has the same "bug", which should
- // be reported upstream.
- if (runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd") && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
+ // TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
+ // reported upstream.
+ if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
@@ -305,46 +313,46 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
var n byte
vallen := _Socklen(1)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return n, err
}
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
return value, err
}
func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
var value IPMreq
vallen := _Socklen(SizeofIPMreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
var value IPv6Mreq
vallen := _Socklen(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
var value IPv6MTUInfo
vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
var value ICMPv6Filter
vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -381,15 +389,20 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
return
}
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
- var ptr uintptr
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
ptr, salen, err = to.sockaddr()
if err != nil {
- return
+ return 0, err
}
}
var msg Msghdr
@@ -412,21 +425,24 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if err = sendmsg(fd, &msg, flags); err != nil {
- return
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
}
- return
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
}
-//sys kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error)
+//sys kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error)
func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) {
- var change, event uintptr
+ var change, event unsafe.Pointer
if len(changes) > 0 {
- change = uintptr(unsafe.Pointer(&changes[0]))
+ change = unsafe.Pointer(&changes[0])
}
if len(events) > 0 {
- event = uintptr(unsafe.Pointer(&events[0]))
+ event = unsafe.Pointer(&events[0])
}
return kevent(kq, change, len(changes), event, len(events), timeout)
}
diff --git a/src/pkg/syscall/syscall_bsd_test.go b/src/pkg/syscall/syscall_bsd_test.go
new file mode 100644
index 000000000..c2ea089d5
--- /dev/null
+++ b/src/pkg/syscall/syscall_bsd_test.go
@@ -0,0 +1,34 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd openbsd
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+const MNT_WAIT = 1
+
+func TestGetfsstat(t *testing.T) {
+ n, err := syscall.Getfsstat(nil, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ data := make([]syscall.Statfs_t, n)
+ n, err = syscall.Getfsstat(data, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ empty := syscall.Statfs_t{}
+ for _, stat := range data {
+ if stat == empty {
+ t.Fatal("an empty Statfs_t struct was returned")
+ }
+ }
+}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index bd929ff99..97414dcda 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -187,6 +187,21 @@ func Pipe(p []int) (err error) {
return
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Wrapped
*/
@@ -224,7 +239,6 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error) = SYS_GETFSSTAT64
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
@@ -244,6 +258,11 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mlock(b []byte) (err error)
+//sys Mlockall(flags int) (err error)
+//sys Mprotect(b []byte, prot int) (err error)
+//sys Munlock(b []byte) (err error)
+//sys Munlockall() (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
diff --git a/src/pkg/syscall/syscall_dragonfly.go b/src/pkg/syscall/syscall_dragonfly.go
index e19a9cee3..39c51df7e 100644
--- a/src/pkg/syscall/syscall_dragonfly.go
+++ b/src/pkg/syscall/syscall_dragonfly.go
@@ -101,6 +101,21 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
return extpwrite(fd, p, 0, offset)
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Exposed directly
*/
@@ -129,7 +144,6 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index 9fbcc48c6..3d834f52b 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -95,12 +95,45 @@ func Pipe(p []int) (err error) {
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
var value IPMreqn
vallen := _Socklen(SizeofIPMreqn)
- errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, errno
}
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
+}
+
+func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept4(fd, &rsa, &len, flags)
+ if err != nil {
+ return
+ }
+ if len > SizeofSockaddrAny {
+ panic("RawSockaddrAny too small")
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
}
/*
@@ -131,7 +164,6 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
@@ -191,6 +223,7 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
//sys munmap(addr uintptr, length uintptr) (err error)
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
+//sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
/*
* Unimplemented
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 79c1fda68..fa0d7ea3c 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -230,9 +230,9 @@ func Mkfifo(path string, mode uint32) (err error) {
return Mknod(path, mode|S_IFIFO, 0)
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -241,12 +241,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET6
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -256,14 +256,14 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ {
@@ -280,7 +280,7 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
sl--
}
- return uintptr(unsafe.Pointer(&sa.raw)), sl, nil
+ return unsafe.Pointer(&sa.raw), sl, nil
}
type SockaddrLinklayer struct {
@@ -293,9 +293,9 @@ type SockaddrLinklayer struct {
raw RawSockaddrLinklayer
}
-func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_PACKET
sa.raw.Protocol = sa.Protocol
@@ -306,7 +306,7 @@ func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil
}
type SockaddrNetlink struct {
@@ -317,12 +317,12 @@ type SockaddrNetlink struct {
raw RawSockaddrNetlink
}
-func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_NETLINK
sa.raw.Pad = sa.Pad
sa.raw.Pid = sa.Pid
sa.raw.Groups = sa.Groups
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, nil
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil
}
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -420,6 +420,9 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
if err != nil {
return
}
+ if len > SizeofSockaddrAny {
+ panic("RawSockaddrAny too small")
+ }
sa, err = anyToSockaddr(&rsa)
if err != nil {
Close(nfd)
@@ -439,54 +442,54 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
return value, err
}
func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
var value IPMreq
vallen := _Socklen(SizeofIPMreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
var value IPMreqn
vallen := _Socklen(SizeofIPMreqn)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
var value IPv6Mreq
vallen := _Socklen(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
var value IPv6MTUInfo
vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
var value ICMPv6Filter
vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func GetsockoptUcred(fd, level, opt int) (*Ucred, error) {
var value Ucred
vallen := _Socklen(SizeofUcred)
- err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
return &value, err
}
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -524,13 +527,18 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
- var ptr uintptr
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ var ptr unsafe.Pointer
var salen _Socklen
if to != nil {
var err error
ptr, salen, err = to.sockaddr()
if err != nil {
- return err
+ return 0, err
}
}
var msg Msghdr
@@ -553,10 +561,13 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if err = sendmsg(fd, &msg, flags); err != nil {
- return
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
}
- return
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
}
// BindToDevice binds the socket associated with fd to device.
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index a61695676..c491a286c 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
package syscall
import "unsafe"
@@ -132,7 +135,15 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ newoffset, errno := seek(fd, offset, whence)
+ if errno != 0 {
+ return 0, errno
+ }
+ return newoffset, nil
+}
// Vsyscalls on amd64.
//sysnb Gettimeofday(tv *Timeval) (err error)
@@ -212,7 +223,7 @@ func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
return
}
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e != 0 {
err = e
@@ -220,7 +231,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
return
}
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e != 0 {
err = e
@@ -236,7 +247,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
return
}
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e != 0 {
err = e
@@ -244,8 +255,8 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
return
}
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
- _, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
if e != 0 {
err = e
}
@@ -264,12 +275,12 @@ func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockle
return
}
-func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var base uintptr
if len(p) > 0 {
base = uintptr(unsafe.Pointer(&p[0]))
}
- _, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+ _, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
if e != 0 {
err = e
}
@@ -284,8 +295,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
if e != 0 {
err = e
}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index f4b73b20e..8915ed83b 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -40,26 +40,46 @@ package syscall
//sys Truncate(path string, length int64) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb setgroups(n int, list *_Gid_t) (err error)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
func Getpagesize() int { return 4096 }
-func Gettimeofday(tv *Timeval) (err error)
-func Time(t *Time_t) (tt Time_t, err error)
+//go:noescape
+func gettimeofday(tv *Timeval) (err Errno)
+
+func Gettimeofday(tv *Timeval) (err error) {
+ errno := gettimeofday(tv)
+ if errno != 0 {
+ return errno
+ }
+ return nil
+}
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ var tv Timeval
+ errno := gettimeofday(&tv)
+ if errno != 0 {
+ return 0, errno
+ }
+ if t != nil {
+ *t = Time_t(tv.Sec)
+ }
+ return Time_t(tv.Sec), nil
+}
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 4aadf9e4c..9fe80232a 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -23,26 +23,34 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-// Seek is defined in assembly.
-
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ newoffset, errno := seek(fd, offset, whence)
+ if errno != 0 {
+ return 0, errno
+ }
+ return newoffset, nil
+}
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb socketpair(domain int, typ int, flags int, fd *[2]int32) (err error)
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
// 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels)
diff --git a/src/pkg/syscall/syscall_nacl.go b/src/pkg/syscall/syscall_nacl.go
new file mode 100644
index 000000000..c2788b20a
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl.go
@@ -0,0 +1,311 @@
+// 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 syscall
+
+import (
+ "sync"
+ "unsafe"
+)
+
+//sys naclClose(fd int) (err error) = sys_close
+//sys Exit(code int) (err error)
+//sys naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
+//sys naclRead(fd int, b []byte) (n int, err error) = sys_read
+//sys naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+
+const direntSize = 8 + 8 + 2 + 256
+
+// native_client/src/trusted/service_runtime/include/sys/dirent.h
+type Dirent struct {
+ Ino int64
+ Off int64
+ Reclen uint16
+ Name [256]byte
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+const PathMax = 256
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface. The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+// err = nil
+// if errno != 0 {
+// err = errno
+// }
+type Errno uintptr
+
+func (e Errno) Error() string {
+ if 0 <= int(e) && int(e) < len(errorstr) {
+ s := errorstr[e]
+ if s != "" {
+ return s
+ }
+ }
+ return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+ return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+const (
+ _ Signal = iota
+ SIGCHLD
+ SIGINT
+ SIGKILL
+ SIGTRAP
+ SIGQUIT
+)
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ if 0 <= s && int(s) < len(signals) {
+ str := signals[s]
+ if str != "" {
+ return str
+ }
+ }
+ return "signal " + itoa(int(s))
+}
+
+var signals = [...]string{}
+
+// File system
+
+const (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+ O_RDONLY = 0
+ O_WRONLY = 1
+ O_RDWR = 2
+ O_ACCMODE = 3
+
+ O_CREAT = 0100
+ O_CREATE = O_CREAT // for ken
+ O_TRUNC = 01000
+ O_APPEND = 02000
+ O_EXCL = 0200
+ O_NONBLOCK = 04000
+ O_NDELAY = O_NONBLOCK
+ O_SYNC = 010000
+ O_FSYNC = O_SYNC
+ O_ASYNC = 020000
+
+ O_CLOEXEC = 0
+
+ FD_CLOEXEC = 1
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+ F_DUPFD = 0
+ F_GETFD = 1
+ F_SETFD = 2
+ F_GETFL = 3
+ F_SETFL = 4
+ F_GETOWN = 5
+ F_SETOWN = 6
+ F_GETLK = 7
+ F_SETLK = 8
+ F_SETLKW = 9
+ F_RGETLK = 10
+ F_RSETLK = 11
+ F_CNVT = 12
+ F_RSETLKW = 13
+
+ F_RDLCK = 1
+ F_WRLCK = 2
+ F_UNLCK = 3
+ F_UNLKSYS = 4
+)
+
+// native_client/src/trusted/service_runtime/include/bits/stat.h
+const (
+ S_IFMT = 0000370000
+ S_IFSHM_SYSV = 0000300000
+ S_IFSEMA = 0000270000
+ S_IFCOND = 0000260000
+ S_IFMUTEX = 0000250000
+ S_IFSHM = 0000240000
+ S_IFBOUNDSOCK = 0000230000
+ S_IFSOCKADDR = 0000220000
+ S_IFDSOCK = 0000210000
+
+ S_IFSOCK = 0000140000
+ S_IFLNK = 0000120000
+ S_IFREG = 0000100000
+ S_IFBLK = 0000060000
+ S_IFDIR = 0000040000
+ S_IFCHR = 0000020000
+ S_IFIFO = 0000010000
+
+ S_UNSUP = 0000370000
+
+ S_ISUID = 0004000
+ S_ISGID = 0002000
+ S_ISVTX = 0001000
+
+ S_IREAD = 0400
+ S_IWRITE = 0200
+ S_IEXEC = 0100
+
+ S_IRWXU = 0700
+ S_IRUSR = 0400
+ S_IWUSR = 0200
+ S_IXUSR = 0100
+
+ S_IRWXG = 070
+ S_IRGRP = 040
+ S_IWGRP = 020
+ S_IXGRP = 010
+
+ S_IRWXO = 07
+ S_IROTH = 04
+ S_IWOTH = 02
+ S_IXOTH = 01
+)
+
+// native_client/src/trusted/service_runtime/include/sys/stat.h
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+type Stat_t struct {
+ Dev int64
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int64
+ Size int64
+ Blksize int32
+ Blocks int32
+ Atime int64
+ AtimeNsec int64
+ Mtime int64
+ MtimeNsec int64
+ Ctime int64
+ CtimeNsec int64
+}
+
+// Processes
+// Not supported on NaCl - just enough for package os.
+
+var ForkLock sync.RWMutex
+
+type WaitStatus uint32
+
+func (w WaitStatus) Exited() bool { return false }
+func (w WaitStatus) ExitStatus() int { return 0 }
+func (w WaitStatus) Signaled() bool { return false }
+func (w WaitStatus) Signal() Signal { return 0 }
+func (w WaitStatus) CoreDump() bool { return false }
+func (w WaitStatus) Stopped() bool { return false }
+func (w WaitStatus) Continued() bool { return false }
+func (w WaitStatus) StopSignal() Signal { return 0 }
+func (w WaitStatus) TrapCause() int { return 0 }
+
+// XXX made up
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+}
+
+// XXX made up
+type ProcAttr struct {
+ Dir string
+ Env []string
+ Files []uintptr
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
+}
+
+// System
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+ return 0, 0, ENOSYS
+}
+
+func Sysctl(key string) (string, error) {
+ if key == "kern.hostname" {
+ return "naclbox", nil
+ }
+ return "", ENOSYS
+}
+
+// Unimplemented Unix midden heap.
+
+const ImplementsGetwd = false
+
+func Getwd() (wd string, err error) { return "", ENOSYS }
+func Getegid() int { return 1 }
+func Geteuid() int { return 1 }
+func Getgid() int { return 1 }
+func Getgroups() ([]int, error) { return []int{1}, nil }
+func Getpagesize() int { return 65536 }
+func Getppid() int { return 2 }
+func Getpid() int { return 3 }
+func Getuid() int { return 1 }
+func Kill(pid int, signum Signal) error { return ENOSYS }
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return 0, ENOSYS
+}
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
+ return 0, 0, ENOSYS
+}
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ return 0, ENOSYS
+}
+func RouteRIB(facility, param int) ([]byte, error) { return nil, ENOSYS }
+func ParseRoutingMessage(b []byte) ([]RoutingMessage, error) { return nil, ENOSYS }
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
+func SysctlUint32(name string) (value uint32, err error) { return 0, ENOSYS }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
new file mode 100644
index 000000000..d12f8e2d6
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_386.go
@@ -0,0 +1,32 @@
+// 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 syscall
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int64(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
diff --git a/src/pkg/syscall/syscall_nacl_amd64p32.go b/src/pkg/syscall/syscall_nacl_amd64p32.go
new file mode 100644
index 000000000..d12f8e2d6
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_amd64p32.go
@@ -0,0 +1,32 @@
+// 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 syscall
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int64(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
diff --git a/src/pkg/syscall/syscall_openbsd.go b/src/pkg/syscall/syscall_openbsd.go
index 89c73215a..8d3f825f8 100644
--- a/src/pkg/syscall/syscall_openbsd.go
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -90,11 +90,31 @@ func Pipe(p []int) (err error) {
return
}
+//sys getdents(fd int, buf []byte) (n int, err error)
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return getdents(fd, buf)
+}
+
// TODO
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ var bufsize uintptr
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
/*
* Exposed directly
*/
@@ -119,10 +139,8 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_openbsd_386.go b/src/pkg/syscall/syscall_openbsd_386.go
index 3c4c693c9..ad5ae14bf 100644
--- a/src/pkg/syscall/syscall_openbsd_386.go
+++ b/src/pkg/syscall/syscall_openbsd_386.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
+ ts.Sec = int64(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
@@ -19,7 +19,7 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
+ tv.Sec = int64(nsec / 1e9)
return
}
diff --git a/src/pkg/syscall/syscall_openbsd_amd64.go b/src/pkg/syscall/syscall_openbsd_amd64.go
index c356ad4fa..6181344cd 100644
--- a/src/pkg/syscall/syscall_openbsd_amd64.go
+++ b/src/pkg/syscall/syscall_openbsd_amd64.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
+ ts.Sec = nsec / 1e9
ts.Nsec = nsec % 1e9
return
}
@@ -19,12 +19,12 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
+ tv.Sec = nsec / 1e9
return
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
- k.Ident = uint32(fd)
+ k.Ident = uint64(fd)
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 2e1c064c4..a8c340541 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -83,7 +83,7 @@ func errstr() string {
}
// Implemented in assembly to import from runtime.
-func exit(int)
+func exit(code int)
func Exit(code int) { exit(code) }
diff --git a/src/pkg/syscall/syscall_solaris.go b/src/pkg/syscall/syscall_solaris.go
new file mode 100644
index 000000000..adc52b1f7
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris.go
@@ -0,0 +1,523 @@
+// 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.
+
+// Solaris system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_solaris.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+type SockaddrDatalink struct {
+ Family uint16
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [244]int8
+ raw RawSockaddrDatalink
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Ino == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:clen(bytes[:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+func pipe() (r uintptr, w uintptr, err uintptr)
+
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ r0, w0, e1 := pipe()
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ p[0], p[1] = int(r0), int(w0)
+ return
+}
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ name := sa.Name
+ n := len(name)
+ if n >= len(sa.raw.Path) {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := _Socklen(2)
+ if n > 0 {
+ sl += _Socklen(n) + 1
+ }
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0
+ // Don't count trailing NUL for abstract address.
+ sl--
+ }
+
+ return unsafe.Pointer(&sa.raw), sl, nil
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if err = getsockname(fd, &rsa, &len); err != nil {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+// The const provides a compile-time constant so clients
+// can adjust to whether there is a working Getwd and avoid
+// even linking this function into the binary. See ../os/getwd.go.
+const ImplementsGetwd = false
+
+func Getwd() (string, error) { return "", ENOTSUP }
+
+/*
+ * Wrapped
+ */
+
+//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
+//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
+
+func Getgroups() (gids []int, err error) {
+ n, err := getgroups(0, nil)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != nil {
+ return nil, err
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (err error) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ // Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // TODO(rsc): Can we use a single global basep for all calls?
+ return Getdents(fd, buf, new(uintptr))
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits.
+
+type WaitStatus uint32
+
+const (
+ mask = 0x7F
+ core = 0x80
+ shift = 8
+
+ exited = 0
+ stopped = 0x7F
+)
+
+func (w WaitStatus) Exited() bool { return w&mask == exited }
+
+func (w WaitStatus) ExitStatus() int {
+ if w&mask != exited {
+ return -1
+ }
+ return int(w >> shift)
+}
+
+func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
+
+func (w WaitStatus) Signal() Signal {
+ sig := Signal(w & mask)
+ if sig == stopped || sig == 0 {
+ return -1
+ }
+ return sig
+}
+
+func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
+
+func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
+
+func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
+
+func (w WaitStatus) StopSignal() Signal {
+ if !w.Stopped() {
+ return -1
+ }
+ return Signal(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+func wait4(pid uintptr, wstatus *WaitStatus, options uintptr, rusage *Rusage) (wpid uintptr, err uintptr)
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ r0, e1 := wait4(uintptr(pid), wstatus, uintptr(options), rusage)
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ return int(r0), err
+}
+
+func gethostname() (name string, err uintptr)
+
+func Gethostname() (name string, err error) {
+ name, e1 := gethostname()
+ if e1 != 0 {
+ err = Errno(e1)
+ }
+ return name, err
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ var tv [2]Timeval
+ for i := 0; i < 2; i++ {
+ tv[i].Sec = ts[i].Sec
+ tv[i].Usec = ts[i].Nsec / 1000
+ }
+ return Utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+ if e1 != 0 {
+ return e1
+ }
+ return nil
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ // Assume path ends at NUL.
+ // This is not technically the Solaris semantics for
+ // abstract Unix domain sockets -- they are supposed
+ // to be uninterpreted fixed-size binary blobs -- but
+ // everyone uses this convention.
+ n := 0
+ for n < len(pp.Path) && pp.Path[n] != 0 {
+ n++
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, nil
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+ }
+ return nil, EAFNOSUPPORT
+}
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = libsocket.accept
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
+ return
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy int8
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
+ return
+ }
+ oobn = int(msg.Accrightslen)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, err = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.sendmsg
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ var ptr unsafe.Pointer
+ var salen _Socklen
+ if to != nil {
+ ptr, salen, err = to.sockaddr()
+ if err != nil {
+ return 0, err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy int8
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
+ }
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
+}
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sys Dup(fd int) (nfd int, err error)
+//sys Exit(code int)
+//sys Fchdir(fd int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sysnb Getgid() (gid int)
+//sysnb Getpid() (pid int)
+//sys Geteuid() (euid int)
+//sys Getegid() (egid int)
+//sys Getppid() (ppid int)
+//sys Getpriority(which int, who int) (n int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Getuid() (uid int)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error) = libsocket.listen
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Setuid(uid int) (err error)
+//sys Shutdown(s int, how int) (err error) = libsocket.shutdown
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Umask(newmask int) (oldmask int)
+//sys Unlink(path string) (err error)
+//sys Utimes(path string, times *[2]Timeval) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.bind
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.connect
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.sendto
+//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.socket
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.socketpair
+//sys write(fd int, p []byte) (n int, err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.getsockopt
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
+//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/syscall_solaris_amd64.go b/src/pkg/syscall/syscall_solaris_amd64.go
new file mode 100644
index 000000000..37cf06d70
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris_amd64.go
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = nsec % 1e9 / 1e3
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ // TODO(aram): implement this, see issue 5847.
+ panic("unimplemented")
+}
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index 6455dc29c..b28891568 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall
@@ -19,8 +19,9 @@ var (
)
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
@@ -55,7 +56,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
cap int
}{addr, length, length}
- // Use unsafe to turn sl into a []byte.
+ // Use unsafeto turn sl into a []byte.
b := *(*[]byte)(unsafe.Pointer(&sl))
// Register mapping in m and return it.
@@ -160,7 +161,7 @@ func Write(fd int, p []byte) (n int, err error) {
var SocketDisableIPv6 bool
type Sockaddr interface {
- sockaddr() (ptr uintptr, len _Socklen, err error) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -209,7 +210,7 @@ func Getpeername(fd int) (sa Sockaddr, err error) {
func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
return int(n), err
}
@@ -234,40 +235,40 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
}
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), 1)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}
func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
}
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), 4)
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
}
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPMreq)
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
}
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPv6Mreq)
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
}
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(filter)), SizeofICMPv6Filter)
+ return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
}
func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), SizeofLinger)
+ return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
}
func SetsockoptString(fd, level, opt int, s string) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
+ return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
}
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
+ return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
}
func Socket(domain, typ, proto int) (fd int, err error) {
diff --git a/src/pkg/syscall/passfd_test.go b/src/pkg/syscall/syscall_unix_test.go
index 53c7a1ffa..a0afb91fc 100644
--- a/src/pkg/syscall/passfd_test.go
+++ b/src/pkg/syscall/syscall_unix_test.go
@@ -1,8 +1,8 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// 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.
-// +build linux dragonfly darwin freebsd netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall_test
@@ -13,12 +13,70 @@ import (
"net"
"os"
"os/exec"
+ "path/filepath"
"runtime"
"syscall"
"testing"
"time"
)
+// Tests that below functions, structures and constants are consistent
+// on all Unix-like systems.
+func _() {
+ // program scheduling priority functions and constants
+ var (
+ _ func(int, int, int) error = syscall.Setpriority
+ _ func(int, int) (int, error) = syscall.Getpriority
+ )
+ const (
+ _ int = syscall.PRIO_USER
+ _ int = syscall.PRIO_PROCESS
+ _ int = syscall.PRIO_PGRP
+ )
+
+ // termios constants
+ const (
+ _ int = syscall.TCIFLUSH
+ _ int = syscall.TCIOFLUSH
+ _ int = syscall.TCOFLUSH
+ )
+
+ // fcntl file locking structure and constants
+ var (
+ _ = syscall.Flock_t{
+ Type: int16(0),
+ Whence: int16(0),
+ Start: int64(0),
+ Len: int64(0),
+ Pid: int32(0),
+ }
+ )
+ const (
+ _ = syscall.F_GETLK
+ _ = syscall.F_SETLK
+ _ = syscall.F_SETLKW
+ )
+}
+
+// TestFcntlFlock tests whether the file locking structure matches
+// the calling convention of each kernel.
+func TestFcntlFlock(t *testing.T) {
+ name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+ fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+ if err != nil {
+ t.Fatalf("Open failed: %v", err)
+ }
+ defer syscall.Unlink(name)
+ defer syscall.Close(fd)
+ flock := syscall.Flock_t{
+ Type: syscall.F_RDLCK,
+ Start: 0, Len: 0, Whence: 1,
+ }
+ if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
+ t.Fatalf("FcntlFlock failed: %v", err)
+ }
+}
+
// TestPassFD tests passing a file descriptor over a Unix socket.
//
// This test involved both a parent and child process. The parent
@@ -27,9 +85,13 @@ import (
// "-test.run=^TestPassFD$" and an environment variable used to signal
// that the test should become the child process instead.
func TestPassFD(t *testing.T) {
- if runtime.GOOS == "dragonfly" {
+ switch runtime.GOOS {
+ case "dragonfly":
// TODO(jsing): Figure out why sendmsg is returning EINVAL.
- t.Skip("Skipping test on dragonfly")
+ t.Skip("skipping test on dragonfly")
+ case "solaris":
+ // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
+ t.Skip("skipping test on solaris, see issue 7402")
}
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
passFDChild()
@@ -200,3 +262,53 @@ func TestUnixRightsRoundtrip(t *testing.T) {
}
}
}
+
+func TestRlimit(t *testing.T) {
+ var rlimit, zero syscall.Rlimit
+ err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Getrlimit: save failed: %v", err)
+ }
+ if zero == rlimit {
+ t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
+ }
+ set := rlimit
+ set.Cur = set.Max - 1
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
+ if err != nil {
+ t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
+ }
+ var get syscall.Rlimit
+ err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
+ if err != nil {
+ t.Fatalf("Getrlimit: get failed: %v", err)
+ }
+ set = rlimit
+ set.Cur = set.Max - 1
+ if set != get {
+ // Seems like Darwin requires some privilege to
+ // increase the soft limit of rlimit sandbox, though
+ // Setrlimit never reports an error.
+ switch runtime.GOOS {
+ case "darwin":
+ default:
+ t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
+ }
+ }
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
+ }
+}
+
+func TestSeekFailure(t *testing.T) {
+ _, err := syscall.Seek(-1, 0, 0)
+ if err == nil {
+ t.Fatalf("Seek(-1, 0, 0) did not fail")
+ }
+ str := err.Error() // used to crash on Linux
+ t.Logf("Seek: %v", str)
+ if str == "" {
+ t.Fatalf("Seek(-1, 0, 0) return error with empty message")
+ }
+}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 3d78b6823..f9733f6ce 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -106,10 +106,11 @@ func (e Errno) Timeout() bool {
}
// Converts a Go function to a function pointer conforming
-// to the stdcall calling convention. This is useful when
+// to the stdcall or cdecl calling convention. This is useful when
// interoperating with Windows code requiring callbacks.
// Implemented in ../runtime/syscall_windows.goc
func NewCallback(fn interface{}) uintptr
+func NewCallbackCDecl(fn interface{}) uintptr
// windows api calls
@@ -522,8 +523,8 @@ const socket_error = uintptr(^uint32(0))
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
-//sys bind(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
-//sys connect(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
+//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
+//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
@@ -578,7 +579,7 @@ type RawSockaddrAny struct {
}
type Sockaddr interface {
- sockaddr() (ptr uintptr, len int32, err error) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -587,9 +588,9 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -598,7 +599,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
}
type SockaddrInet6 struct {
@@ -608,9 +609,9 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
- return 0, 0, EINVAL
+ return nil, 0, EINVAL
}
sa.raw.Family = AF_INET6
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -620,16 +621,16 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
}
type SockaddrUnix struct {
Name string
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
// TODO(brainman): implement SockaddrUnix.sockaddr()
- return 0, 0, EWINDOWS
+ return nil, 0, EWINDOWS
}
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
@@ -753,7 +754,7 @@ func LoadConnectEx() error {
return connectExFunc.err
}
-func connectEx(s Handle, name uintptr, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
+func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
if r1 == 0 {
if e1 != 0 {
diff --git a/src/pkg/syscall/tables_nacl.go b/src/pkg/syscall/tables_nacl.go
new file mode 100644
index 000000000..08f4ced53
--- /dev/null
+++ b/src/pkg/syscall/tables_nacl.go
@@ -0,0 +1,324 @@
+// 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 syscall
+
+// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+const (
+ sys_null = 1
+ sys_nameservice = 2
+ sys_dup = 8
+ sys_dup2 = 9
+ sys_open = 10
+ sys_close = 11
+ sys_read = 12
+ sys_write = 13
+ sys_lseek = 14
+ sys_ioctl = 15
+ sys_stat = 16
+ sys_fstat = 17
+ sys_chmod = 18
+ sys_brk = 20
+ sys_mmap = 21
+ sys_munmap = 22
+ sys_getdents = 23
+ sys_mprotect = 24
+ sys_list_mappings = 25
+ sys_exit = 30
+ sys_getpid = 31
+ sys_sched_yield = 32
+ sys_sysconf = 33
+ sys_gettimeofday = 40
+ sys_clock = 41
+ sys_nanosleep = 42
+ sys_clock_getres = 43
+ sys_clock_gettime = 44
+ sys_mkdir = 45
+ sys_rmdir = 46
+ sys_chdir = 47
+ sys_getcwd = 48
+ sys_unlink = 49
+ sys_imc_makeboundsock = 60
+ sys_imc_accept = 61
+ sys_imc_connect = 62
+ sys_imc_sendmsg = 63
+ sys_imc_recvmsg = 64
+ sys_imc_mem_obj_create = 65
+ sys_imc_socketpair = 66
+ sys_mutex_create = 70
+ sys_mutex_lock = 71
+ sys_mutex_trylock = 72
+ sys_mutex_unlock = 73
+ sys_cond_create = 74
+ sys_cond_wait = 75
+ sys_cond_signal = 76
+ sys_cond_broadcast = 77
+ sys_cond_timed_wait_abs = 79
+ sys_thread_create = 80
+ sys_thread_exit = 81
+ sys_tls_init = 82
+ sys_thread_nice = 83
+ sys_tls_get = 84
+ sys_second_tls_set = 85
+ sys_second_tls_get = 86
+ sys_exception_handler = 87
+ sys_exception_stack = 88
+ sys_exception_clear_flag = 89
+ sys_sem_create = 100
+ sys_sem_wait = 101
+ sys_sem_post = 102
+ sys_sem_get_value = 103
+ sys_dyncode_create = 104
+ sys_dyncode_modify = 105
+ sys_dyncode_delete = 106
+ sys_test_infoleak = 109
+ sys_test_crash = 110
+ sys_test_syscall_1 = 111
+ sys_test_syscall_2 = 112
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+const (
+ // native_client/src/trusted/service_runtime/include/sys/errno.h
+ // The errors are mainly copied from Linux.
+ EPERM Errno = 1 /* Operation not permitted */
+ ENOENT Errno = 2 /* No such file or directory */
+ ESRCH Errno = 3 /* No such process */
+ EINTR Errno = 4 /* Interrupted system call */
+ EIO Errno = 5 /* I/O error */
+ ENXIO Errno = 6 /* No such device or address */
+ E2BIG Errno = 7 /* Argument list too long */
+ ENOEXEC Errno = 8 /* Exec format error */
+ EBADF Errno = 9 /* Bad file number */
+ ECHILD Errno = 10 /* No child processes */
+ EAGAIN Errno = 11 /* Try again */
+ ENOMEM Errno = 12 /* Out of memory */
+ EACCES Errno = 13 /* Permission denied */
+ EFAULT Errno = 14 /* Bad address */
+ EBUSY Errno = 16 /* Device or resource busy */
+ EEXIST Errno = 17 /* File exists */
+ EXDEV Errno = 18 /* Cross-device link */
+ ENODEV Errno = 19 /* No such device */
+ ENOTDIR Errno = 20 /* Not a directory */
+ EISDIR Errno = 21 /* Is a directory */
+ EINVAL Errno = 22 /* Invalid argument */
+ ENFILE Errno = 23 /* File table overflow */
+ EMFILE Errno = 24 /* Too many open files */
+ ENOTTY Errno = 25 /* Not a typewriter */
+ EFBIG Errno = 27 /* File too large */
+ ENOSPC Errno = 28 /* No space left on device */
+ ESPIPE Errno = 29 /* Illegal seek */
+ EROFS Errno = 30 /* Read-only file system */
+ EMLINK Errno = 31 /* Too many links */
+ EPIPE Errno = 32 /* Broken pipe */
+ ENAMETOOLONG Errno = 36 /* File name too long */
+ ENOSYS Errno = 38 /* Function not implemented */
+ EDQUOT Errno = 122 /* Quota exceeded */
+ EDOM Errno = 33 /* Math arg out of domain of func */
+ ERANGE Errno = 34 /* Math result not representable */
+ EDEADLK Errno = 35 /* Deadlock condition */
+ ENOLCK Errno = 37 /* No record locks available */
+ ENOTEMPTY Errno = 39 /* Directory not empty */
+ ELOOP Errno = 40 /* Too many symbolic links */
+ ENOMSG Errno = 42 /* No message of desired type */
+ EIDRM Errno = 43 /* Identifier removed */
+ ECHRNG Errno = 44 /* Channel number out of range */
+ EL2NSYNC Errno = 45 /* Level 2 not synchronized */
+ EL3HLT Errno = 46 /* Level 3 halted */
+ EL3RST Errno = 47 /* Level 3 reset */
+ ELNRNG Errno = 48 /* Link number out of range */
+ EUNATCH Errno = 49 /* Protocol driver not attached */
+ ENOCSI Errno = 50 /* No CSI structure available */
+ EL2HLT Errno = 51 /* Level 2 halted */
+ EBADE Errno = 52 /* Invalid exchange */
+ EBADR Errno = 53 /* Invalid request descriptor */
+ EXFULL Errno = 54 /* Exchange full */
+ ENOANO Errno = 55 /* No anode */
+ EBADRQC Errno = 56 /* Invalid request code */
+ EBADSLT Errno = 57 /* Invalid slot */
+ EDEADLOCK Errno = EDEADLK /* File locking deadlock error */
+ EBFONT Errno = 59 /* Bad font file fmt */
+ ENOSTR Errno = 60 /* Device not a stream */
+ ENODATA Errno = 61 /* No data (for no delay io) */
+ ETIME Errno = 62 /* Timer expired */
+ ENOSR Errno = 63 /* Out of streams resources */
+ ENONET Errno = 64 /* Machine is not on the network */
+ ENOPKG Errno = 65 /* Package not installed */
+ EREMOTE Errno = 66 /* The object is remote */
+ ENOLINK Errno = 67 /* The link has been severed */
+ EADV Errno = 68 /* Advertise error */
+ ESRMNT Errno = 69 /* Srmount error */
+ ECOMM Errno = 70 /* Communication error on send */
+ EPROTO Errno = 71 /* Protocol error */
+ EMULTIHOP Errno = 72 /* Multihop attempted */
+ EDOTDOT Errno = 73 /* Cross mount point (not really error) */
+ EBADMSG Errno = 74 /* Trying to read unreadable message */
+ EOVERFLOW Errno = 75 /* Value too large for defined data type */
+ ENOTUNIQ Errno = 76 /* Given log. name not unique */
+ EBADFD Errno = 77 /* f.d. invalid for this operation */
+ EREMCHG Errno = 78 /* Remote address changed */
+ ELIBACC Errno = 79 /* Can't access a needed shared lib */
+ ELIBBAD Errno = 80 /* Accessing a corrupted shared lib */
+ ELIBSCN Errno = 81 /* .lib section in a.out corrupted */
+ ELIBMAX Errno = 82 /* Attempting to link in too many libs */
+ ELIBEXEC Errno = 83 /* Attempting to exec a shared library */
+ EILSEQ Errno = 84
+ EUSERS Errno = 87
+ ENOTSOCK Errno = 88 /* Socket operation on non-socket */
+ EDESTADDRREQ Errno = 89 /* Destination address required */
+ EMSGSIZE Errno = 90 /* Message too long */
+ EPROTOTYPE Errno = 91 /* Protocol wrong type for socket */
+ ENOPROTOOPT Errno = 92 /* Protocol not available */
+ EPROTONOSUPPORT Errno = 93 /* Unknown protocol */
+ ESOCKTNOSUPPORT Errno = 94 /* Socket type not supported */
+ EOPNOTSUPP Errno = 95 /* Operation not supported on transport endpoint */
+ EPFNOSUPPORT Errno = 96 /* Protocol family not supported */
+ EAFNOSUPPORT Errno = 97 /* Address family not supported by protocol family */
+ EADDRINUSE Errno = 98 /* Address already in use */
+ EADDRNOTAVAIL Errno = 99 /* Address not available */
+ ENETDOWN Errno = 100 /* Network interface is not configured */
+ ENETUNREACH Errno = 101 /* Network is unreachable */
+ ENETRESET Errno = 102
+ ECONNABORTED Errno = 103 /* Connection aborted */
+ ECONNRESET Errno = 104 /* Connection reset by peer */
+ ENOBUFS Errno = 105 /* No buffer space available */
+ EISCONN Errno = 106 /* Socket is already connected */
+ ENOTCONN Errno = 107 /* Socket is not connected */
+ ESHUTDOWN Errno = 108 /* Can't send after socket shutdown */
+ ETOOMANYREFS Errno = 109
+ ETIMEDOUT Errno = 110 /* Connection timed out */
+ ECONNREFUSED Errno = 111 /* Connection refused */
+ EHOSTDOWN Errno = 112 /* Host is down */
+ EHOSTUNREACH Errno = 113 /* Host is unreachable */
+ EALREADY Errno = 114 /* Socket already connected */
+ EINPROGRESS Errno = 115 /* Connection already in progress */
+ ESTALE Errno = 116
+ ENOTSUP Errno = EOPNOTSUPP /* Not supported */
+ ENOMEDIUM Errno = 123 /* No medium (in tape drive) */
+ ECANCELED Errno = 125 /* Operation canceled. */
+ ELBIN Errno = 2048 /* Inode is remote (not really error) */
+ EFTYPE Errno = 2049 /* Inappropriate file type or format */
+ ENMFILE Errno = 2050 /* No more files */
+ EPROCLIM Errno = 2051
+ ENOSHARE Errno = 2052 /* No such host or network path */
+ ECASECLASH Errno = 2053 /* Filename exists with different case */
+ EWOULDBLOCK Errno = EAGAIN /* Operation would block */
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+var errorstr = [...]string{
+ EPERM: "Operation not permitted",
+ ENOENT: "No such file or directory",
+ ESRCH: "No such process",
+ EINTR: "Interrupted system call",
+ EIO: "I/O error",
+ ENXIO: "No such device or address",
+ E2BIG: "Argument list too long",
+ ENOEXEC: "Exec format error",
+ EBADF: "Bad file number",
+ ECHILD: "No child processes",
+ EAGAIN: "Try again",
+ ENOMEM: "Out of memory",
+ EACCES: "Permission denied",
+ EFAULT: "Bad address",
+ EBUSY: "Device or resource busy",
+ EEXIST: "File exists",
+ EXDEV: "Cross-device link",
+ ENODEV: "No such device",
+ ENOTDIR: "Not a directory",
+ EISDIR: "Is a directory",
+ EINVAL: "Invalid argument",
+ ENFILE: "File table overflow",
+ EMFILE: "Too many open files",
+ ENOTTY: "Not a typewriter",
+ EFBIG: "File too large",
+ ENOSPC: "No space left on device",
+ ESPIPE: "Illegal seek",
+ EROFS: "Read-only file system",
+ EMLINK: "Too many links",
+ EPIPE: "Broken pipe",
+ ENAMETOOLONG: "File name too long",
+ ENOSYS: "not implemented on Native Client",
+ EDQUOT: "Quota exceeded",
+ EDOM: "Math arg out of domain of func",
+ ERANGE: "Math result not representable",
+ EDEADLK: "Deadlock condition",
+ ENOLCK: "No record locks available",
+ ENOTEMPTY: "Directory not empty",
+ ELOOP: "Too many symbolic links",
+ ENOMSG: "No message of desired type",
+ EIDRM: "Identifier removed",
+ ECHRNG: "Channel number out of range",
+ EL2NSYNC: "Level 2 not synchronized",
+ EL3HLT: "Level 3 halted",
+ EL3RST: "Level 3 reset",
+ ELNRNG: "Link number out of range",
+ EUNATCH: "Protocol driver not attached",
+ ENOCSI: "No CSI structure available",
+ EL2HLT: "Level 2 halted",
+ EBADE: "Invalid exchange",
+ EBADR: "Invalid request descriptor",
+ EXFULL: "Exchange full",
+ ENOANO: "No anode",
+ EBADRQC: "Invalid request code",
+ EBADSLT: "Invalid slot",
+ EBFONT: "Bad font file fmt",
+ ENOSTR: "Device not a stream",
+ ENODATA: "No data (for no delay io)",
+ ETIME: "Timer expired",
+ ENOSR: "Out of streams resources",
+ ENONET: "Machine is not on the network",
+ ENOPKG: "Package not installed",
+ EREMOTE: "The object is remote",
+ ENOLINK: "The link has been severed",
+ EADV: "Advertise error",
+ ESRMNT: "Srmount error",
+ ECOMM: "Communication error on send",
+ EPROTO: "Protocol error",
+ EMULTIHOP: "Multihop attempted",
+ EDOTDOT: "Cross mount point (not really error)",
+ EBADMSG: "Trying to read unreadable message",
+ EOVERFLOW: "Value too large for defined data type",
+ ENOTUNIQ: "Given log. name not unique",
+ EBADFD: "f.d. invalid for this operation",
+ EREMCHG: "Remote address changed",
+ ELIBACC: "Can't access a needed shared lib",
+ ELIBBAD: "Accessing a corrupted shared lib",
+ ELIBSCN: ".lib section in a.out corrupted",
+ ELIBMAX: "Attempting to link in too many libs",
+ ELIBEXEC: "Attempting to exec a shared library",
+ ENOTSOCK: "Socket operation on non-socket",
+ EDESTADDRREQ: "Destination address required",
+ EMSGSIZE: "Message too long",
+ EPROTOTYPE: "Protocol wrong type for socket",
+ ENOPROTOOPT: "Protocol not available",
+ EPROTONOSUPPORT: "Unknown protocol",
+ ESOCKTNOSUPPORT: "Socket type not supported",
+ EOPNOTSUPP: "Operation not supported on transport endpoint",
+ EPFNOSUPPORT: "Protocol family not supported",
+ EAFNOSUPPORT: "Address family not supported by protocol family",
+ EADDRINUSE: "Address already in use",
+ EADDRNOTAVAIL: "Address not available",
+ ENETDOWN: "Network interface is not configured",
+ ENETUNREACH: "Network is unreachable",
+ ECONNABORTED: "Connection aborted",
+ ECONNRESET: "Connection reset by peer",
+ ENOBUFS: "No buffer space available",
+ EISCONN: "Socket is already connected",
+ ENOTCONN: "Socket is not connected",
+ ESHUTDOWN: "Can't send after socket shutdown",
+ ETIMEDOUT: "Connection timed out",
+ ECONNREFUSED: "Connection refused",
+ EHOSTDOWN: "Host is down",
+ EHOSTUNREACH: "Host is unreachable",
+ EALREADY: "Socket already connected",
+ EINPROGRESS: "Connection already in progress",
+ ENOMEDIUM: "No medium (in tape drive)",
+ ECANCELED: "Operation canceled.",
+ ELBIN: "Inode is remote (not really error)",
+ EFTYPE: "Inappropriate file type or format",
+ ENMFILE: "No more files",
+ ENOSHARE: "No such host or network path",
+ ECASECLASH: "Filename exists with different case",
+}
diff --git a/src/pkg/syscall/time_nacl_386.s b/src/pkg/syscall/time_nacl_386.s
new file mode 100644
index 000000000..b5a22d31b
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_386.s
@@ -0,0 +1,11 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+ JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+ JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/time_nacl_amd64p32.s b/src/pkg/syscall/time_nacl_amd64p32.s
new file mode 100644
index 000000000..b5a22d31b
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_amd64p32.s
@@ -0,0 +1,11 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+ JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+ JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/types_dragonfly.go b/src/pkg/syscall/types_dragonfly.go
index 009b8f045..fb7fd1bb4 100644
--- a/src/pkg/syscall/types_dragonfly.go
+++ b/src/pkg/syscall/types_dragonfly.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
@@ -97,10 +98,6 @@ type _Gid_t C.gid_t
// Files
-const (
- F_DUPFD_CLOEXEC = 0 // not supported
-)
-
const ( // Directory mode bits
S_IFMT = C.S_IFMT
S_IFIFO = C.S_IFIFO
@@ -239,3 +236,7 @@ type BpfProgram C.struct_bpf_program
type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_freebsd.go b/src/pkg/syscall/types_freebsd.go
index ccf53d0ad..68a69312b 100644
--- a/src/pkg/syscall/types_freebsd.go
+++ b/src/pkg/syscall/types_freebsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
@@ -59,6 +60,91 @@ struct sockaddr_any {
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
+// This structure is a duplicate of stat on FreeBSD 8-STABLE.
+// See /usr/include/sys/stat.h.
+struct stat8 {
+#undef st_atimespec st_atim
+#undef st_mtimespec st_mtim
+#undef st_ctimespec st_ctim
+#undef st_birthtimespec st_birthtim
+ __dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ __dev_t st_rdev;
+#if __BSD_VISIBLE
+ struct timespec st_atimespec;
+ struct timespec st_mtimespec;
+ struct timespec st_ctimespec;
+#else
+ time_t st_atime;
+ long __st_atimensec;
+ time_t st_mtime;
+ long __st_mtimensec;
+ time_t st_ctime;
+ long __st_ctimensec;
+#endif
+ off_t st_size;
+ blkcnt_t st_blocks;
+ blksize_t st_blksize;
+ fflags_t st_flags;
+ __uint32_t st_gen;
+ __int32_t st_lspare;
+#if __BSD_VISIBLE
+ struct timespec st_birthtimespec;
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+#else
+ time_t st_birthtime;
+ long st_birthtimensec;
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+ unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+#endif
+};
+
+// This structure is a duplicate of if_data on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_data8 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_spare_char1;
+ u_char ifi_spare_char2;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ u_long ifi_hwassist;
+ time_t ifi_epoch;
+ struct timeval ifi_lastchange;
+};
+
+// This structure is a duplicate of if_msghdr on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_msghdr8 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data8 ifm_data;
+};
*/
import "C"
@@ -97,10 +183,6 @@ type _Gid_t C.gid_t
// Files
-const (
- O_CLOEXEC = 0 // not supported
-)
-
const ( // Directory mode bits
S_IFMT = C.S_IFMT
S_IFIFO = C.S_IFIFO
@@ -118,7 +200,7 @@ const ( // Directory mode bits
S_IXUSR = C.S_IXUSR
)
-type Stat_t C.struct_stat
+type Stat_t C.struct_stat8
type Statfs_t C.struct_statfs
@@ -200,8 +282,10 @@ type FdSet C.fd_set
// Routing and interface messages
const (
- SizeofIfMsghdr = C.sizeof_struct_if_msghdr
- SizeofIfData = C.sizeof_struct_if_data
+ sizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr8
+ sizeofIfData = C.sizeof_struct_if_data
+ SizeofIfData = C.sizeof_struct_if_data8
SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
SizeofIfmaMsghdr = C.sizeof_struct_ifma_msghdr
SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr
@@ -209,9 +293,13 @@ const (
SizeofRtMetrics = C.sizeof_struct_rt_metrics
)
-type IfMsghdr C.struct_if_msghdr
+type ifMsghdr C.struct_if_msghdr
+
+type IfMsghdr C.struct_if_msghdr8
-type IfData C.struct_if_data
+type ifData C.struct_if_data
+
+type IfData C.struct_if_data8
type IfaMsghdr C.struct_ifa_msghdr
@@ -248,3 +336,7 @@ type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
type BpfZbufHeader C.struct_bpf_zbuf_header
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_linux.go b/src/pkg/syscall/types_linux.go
index fea09d1d7..e8396a41f 100644
--- a/src/pkg/syscall/types_linux.go
+++ b/src/pkg/syscall/types_linux.go
@@ -158,6 +158,8 @@ type Dirent C.struct_dirent
type Fsid C.fsid_t
+type Flock_t C.struct_flock
+
// Sockets
type RawSockaddrInet4 C.struct_sockaddr_in
diff --git a/src/pkg/syscall/types_netbsd.go b/src/pkg/syscall/types_netbsd.go
index badaa1049..04354a32a 100644
--- a/src/pkg/syscall/types_netbsd.go
+++ b/src/pkg/syscall/types_netbsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/param.h>
@@ -222,6 +223,10 @@ type BpfHdr C.struct_bpf_hdr
type BpfTimeval C.struct_bpf_timeval
+// Terminal handling
+
+type Termios C.struct_termios
+
// Sysctl
type Sysctlnode C.struct_sysctlnode
diff --git a/src/pkg/syscall/types_openbsd.go b/src/pkg/syscall/types_openbsd.go
index 6fe2af6e0..e6d1ea704 100644
--- a/src/pkg/syscall/types_openbsd.go
+++ b/src/pkg/syscall/types_openbsd.go
@@ -18,6 +18,7 @@ package syscall
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/param.h>
@@ -237,3 +238,7 @@ type BpfInsn C.struct_bpf_insn
type BpfHdr C.struct_bpf_hdr
type BpfTimeval C.struct_bpf_timeval
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_solaris.go b/src/pkg/syscall/types_solaris.go
new file mode 100644
index 000000000..53fa35068
--- /dev/null
+++ b/src/pkg/syscall/types_solaris.go
@@ -0,0 +1,222 @@
+// 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
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timeval32 C.struct_timeval32
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const ( // Directory mode bits
+ S_IFMT = C.S_IFMT
+ S_IFIFO = C.S_IFIFO
+ S_IFCHR = C.S_IFCHR
+ S_IFDIR = C.S_IFDIR
+ S_IFBLK = C.S_IFBLK
+ S_IFREG = C.S_IFREG
+ S_IFLNK = C.S_IFLNK
+ S_IFSOCK = C.S_IFSOCK
+ S_ISUID = C.S_ISUID
+ S_ISGID = C.S_ISGID
+ S_ISVTX = C.S_ISVTX
+ S_IRUSR = C.S_IRUSR
+ S_IWUSR = C.S_IWUSR
+ S_IXUSR = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+type IPv6MTUInfo C.struct_ip6_mtuinfo
+
+type ICMPv6Filter C.struct_icmp6_filter
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ SizeofIPv6MTUInfo = C.sizeof_struct_ip6_mtuinfo
+ SizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+)
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfTimeval C.struct_bpf_timeval
+
+type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/unzip_nacl.go b/src/pkg/syscall/unzip_nacl.go
new file mode 100644
index 000000000..5845e44f0
--- /dev/null
+++ b/src/pkg/syscall/unzip_nacl.go
@@ -0,0 +1,685 @@
+// 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.
+
+// Small in-memory unzip implementation.
+// A simplified copy of the pre-Go 1 compress/flate/inflate.go
+// and a modified copy of the zip reader in package time.
+// (The one in package time does not support decompression; this one does.)
+
+package syscall
+
+const (
+ maxCodeLen = 16 // max length of Huffman code
+ maxHist = 32768 // max history required
+ maxLit = 286
+ maxDist = 32
+ numCodes = 19 // number of codes in Huffman meta-code
+)
+
+type decompressor struct {
+ in string // compressed input
+ out []byte // uncompressed output
+ b uint32 // input bits, at top of b
+ nb uint
+ err bool // invalid input
+ eof bool // reached EOF
+
+ h1, h2 huffmanDecoder // decoders for literal/length, distance
+ bits [maxLit + maxDist]int // lengths defining Huffman codes
+ codebits [numCodes]int
+}
+
+func (f *decompressor) nextBlock() {
+ for f.nb < 1+2 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ f.eof = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ f.dataBlock()
+ case 1:
+ // compressed, fixed Huffman tables
+ f.huffmanBlock(&fixedHuffmanDecoder, nil)
+ case 2:
+ // compressed, dynamic Huffman tables
+ if f.readHuffman(); f.err {
+ break
+ }
+ f.huffmanBlock(&f.h1, &f.h2)
+ default:
+ // 3 is reserved.
+ f.err = true
+ }
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() {
+ // HLIT[5], HDIST[5], HCLEN[4].
+ for f.nb < 5+5+4 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ nlit := int(f.b&0x1F) + 257
+ f.b >>= 5
+ ndist := int(f.b&0x1F) + 1
+ f.b >>= 5
+ nclen := int(f.b&0xF) + 4
+ f.b >>= 4
+ f.nb -= 5 + 5 + 4
+
+ // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+ for i := 0; i < nclen; i++ {
+ for f.nb < 3 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ f.codebits[codeOrder[i]] = int(f.b & 0x7)
+ f.b >>= 3
+ f.nb -= 3
+ }
+ for i := nclen; i < len(codeOrder); i++ {
+ f.codebits[codeOrder[i]] = 0
+ }
+ if !f.h1.init(f.codebits[0:]) {
+ f.err = true
+ return
+ }
+
+ // HLIT + 257 code lengths, HDIST + 1 code lengths,
+ // using the code length Huffman code.
+ for i, n := 0, nlit+ndist; i < n; {
+ x := f.huffSym(&f.h1)
+ if f.err {
+ return
+ }
+ if x < 16 {
+ // Actual length.
+ f.bits[i] = x
+ i++
+ continue
+ }
+ // Repeat previous length or zero.
+ var rep int
+ var nb uint
+ var b int
+ switch x {
+ default:
+ f.err = true
+ return
+ case 16:
+ rep = 3
+ nb = 2
+ if i == 0 {
+ f.err = true
+ return
+ }
+ b = f.bits[i-1]
+ case 17:
+ rep = 3
+ nb = 3
+ b = 0
+ case 18:
+ rep = 11
+ nb = 7
+ b = 0
+ }
+ for f.nb < nb {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ rep += int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ if i+rep > n {
+ f.err = true
+ return
+ }
+ for j := 0; j < rep; j++ {
+ f.bits[i] = b
+ i++
+ }
+ }
+
+ if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+ f.err = true
+ return
+ }
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
+ for {
+ v := f.huffSym(hl)
+ if f.err {
+ return
+ }
+ var n uint // number of bits extra
+ var length int
+ switch {
+ case v < 256:
+ f.out = append(f.out, byte(v))
+ continue
+ case v == 256:
+ // Done with huffman block; read next block.
+ return
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ n = 0
+ case v < 269:
+ length = v*2 - (265*2 - 11)
+ n = 1
+ case v < 273:
+ length = v*4 - (269*4 - 19)
+ n = 2
+ case v < 277:
+ length = v*8 - (273*8 - 35)
+ n = 3
+ case v < 281:
+ length = v*16 - (277*16 - 67)
+ n = 4
+ case v < 285:
+ length = v*32 - (281*32 - 131)
+ n = 5
+ default:
+ length = 258
+ n = 0
+ }
+ if n > 0 {
+ for f.nb < n {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ length += int(f.b & uint32(1<<n-1))
+ f.b >>= n
+ f.nb -= n
+ }
+
+ var dist int
+ if hd == nil {
+ for f.nb < 5 {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ dist = int(reverseByte[(f.b&0x1F)<<3])
+ f.b >>= 5
+ f.nb -= 5
+ } else {
+ if dist = f.huffSym(hd); f.err {
+ return
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist >= 30:
+ f.err = true
+ return
+ default:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << nb
+ for f.nb < nb {
+ if f.moreBits(); f.err {
+ return
+ }
+ }
+ extra |= int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ dist = 1<<(nb+1) + 1 + extra
+ }
+
+ // Copy [-dist:-dist+length] into output.
+ // Encoding can be prescient, so no check on length.
+ if dist > len(f.out) {
+ f.err = true
+ return
+ }
+
+ p := len(f.out) - dist
+ for i := 0; i < length; i++ {
+ f.out = append(f.out, f.out[p])
+ p++
+ }
+ }
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+ // Uncompressed.
+ // Discard current half-byte.
+ f.nb = 0
+ f.b = 0
+
+ if len(f.in) < 4 {
+ f.err = true
+ return
+ }
+
+ buf := f.in[:4]
+ f.in = f.in[4:]
+ n := int(buf[0]) | int(buf[1])<<8
+ nn := int(buf[2]) | int(buf[3])<<8
+ if uint16(nn) != uint16(^n) {
+ f.err = true
+ return
+ }
+
+ if len(f.in) < n {
+ f.err = true
+ return
+ }
+ f.out = append(f.out, f.in[:n]...)
+ f.in = f.in[n:]
+}
+
+func (f *decompressor) moreBits() {
+ if len(f.in) == 0 {
+ f.err = true
+ return
+ }
+ c := f.in[0]
+ f.in = f.in[1:]
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) int {
+ for n := uint(h.min); n <= uint(h.max); n++ {
+ lim := h.limit[n]
+ if lim == -1 {
+ continue
+ }
+ for f.nb < n {
+ if f.moreBits(); f.err {
+ return 0
+ }
+ }
+ v := int(f.b & uint32(1<<n-1))
+ v <<= 16 - n
+ v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+ if v <= lim {
+ f.b >>= n
+ f.nb -= n
+ return h.codes[v-h.base[n]]
+ }
+ }
+ f.err = true
+ return 0
+}
+
+var reverseByte = [256]byte{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+ 7, 9,
+ [maxCodeLen + 1]int{7: 23, 199, 511},
+ [maxCodeLen + 1]int{7: 0, 24, 224},
+ []int{
+ // length 7: 256-279
+ 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279,
+
+ // length 8: 0-143
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143,
+
+ // length 8: 280-287
+ 280, 281, 282, 283, 284, 285, 286, 287,
+
+ // length 9: 144-255
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255,
+ },
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+ // min, max code length
+ min, max int
+
+ // limit[i] = largest code word of length i
+ // Given code v of length n,
+ // need more bits if v > limit[n].
+ limit [maxCodeLen + 1]int
+
+ // base[i] = smallest code word of length i - seq number
+ base [maxCodeLen + 1]int
+
+ // codes[seq number] = output code.
+ // Given code v of length n, value is
+ // codes[v - base[n]].
+ codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+ // Count number of codes of each length,
+ // compute min and max length.
+ var count [maxCodeLen + 1]int
+ var min, max int
+ for _, n := range bits {
+ if n == 0 {
+ continue
+ }
+ if min == 0 || n < min {
+ min = n
+ }
+ if n > max {
+ max = n
+ }
+ count[n]++
+ }
+ if max == 0 {
+ return false
+ }
+
+ h.min = min
+ h.max = max
+
+ // For each code range, compute
+ // nextcode (first code of that length),
+ // limit (last code of that length), and
+ // base (offset from first code to sequence number).
+ code := 0
+ seq := 0
+ var nextcode [maxCodeLen]int
+ for i := min; i <= max; i++ {
+ n := count[i]
+ nextcode[i] = code
+ h.base[i] = code - seq
+ code += n
+ seq += n
+ h.limit[i] = code - 1
+ code <<= 1
+ }
+
+ // Make array mapping sequence numbers to codes.
+ if len(h.codes) < len(bits) {
+ h.codes = make([]int, len(bits))
+ }
+ for i, n := range bits {
+ if n == 0 {
+ continue
+ }
+ code := nextcode[n]
+ nextcode[n]++
+ seq := code - h.base[n]
+ h.codes[seq] = i
+ }
+ return true
+}
+
+func inflate(in string) (out []byte) {
+ var d decompressor
+ d.in = in
+ for !d.err && !d.eof {
+ d.nextBlock()
+ }
+ if len(d.in) != 0 {
+ println("fs unzip: junk at end of compressed data")
+ return nil
+ }
+ return d.out
+}
+
+// get4 returns the little-endian 32-bit value in b.
+func zget4(b string) int {
+ if len(b) < 4 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func zget2(b string) int {
+ if len(b) < 2 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8
+}
+
+func unzip(data string) {
+ const (
+ zecheader = 0x06054b50
+ zcheader = 0x02014b50
+ ztailsize = 22
+ zheadersize = 30
+ zheader = 0x04034b50
+ )
+
+ buf := data[len(data)-ztailsize:]
+ n := zget2(buf[10:])
+ size := zget4(buf[12:])
+ off := zget4(buf[16:])
+
+ hdr := data[off : off+size]
+ for i := 0; i < n; i++ {
+ // zip entry layout:
+ // 0 magic[4]
+ // 4 madevers[1]
+ // 5 madeos[1]
+ // 6 extvers[1]
+ // 7 extos[1]
+ // 8 flags[2]
+ // 10 meth[2]
+ // 12 modtime[2]
+ // 14 moddate[2]
+ // 16 crc[4]
+ // 20 csize[4]
+ // 24 uncsize[4]
+ // 28 namelen[2]
+ // 30 xlen[2]
+ // 32 fclen[2]
+ // 34 disknum[2]
+ // 36 iattr[2]
+ // 38 eattr[4]
+ // 42 off[4]
+ // 46 name[namelen]
+ // 46+namelen+xlen+fclen - next header
+ //
+ if zget4(hdr) != zcheader {
+ println("fs unzip: bad magic")
+ break
+ }
+ meth := zget2(hdr[10:])
+ mtime := zget2(hdr[12:])
+ mdate := zget2(hdr[14:])
+ csize := zget4(hdr[20:])
+ size := zget4(hdr[24:])
+ namelen := zget2(hdr[28:])
+ xlen := zget2(hdr[30:])
+ fclen := zget2(hdr[32:])
+ xattr := uint32(zget4(hdr[38:])) >> 16
+ off := zget4(hdr[42:])
+ name := hdr[46 : 46+namelen]
+ hdr = hdr[46+namelen+xlen+fclen:]
+
+ // zip per-file header layout:
+ // 0 magic[4]
+ // 4 extvers[1]
+ // 5 extos[1]
+ // 6 flags[2]
+ // 8 meth[2]
+ // 10 modtime[2]
+ // 12 moddate[2]
+ // 14 crc[4]
+ // 18 csize[4]
+ // 22 uncsize[4]
+ // 26 namelen[2]
+ // 28 xlen[2]
+ // 30 name[namelen]
+ // 30+namelen+xlen - file data
+ //
+ buf := data[off : off+zheadersize+namelen]
+ if zget4(buf) != zheader ||
+ zget2(buf[8:]) != meth ||
+ zget2(buf[26:]) != namelen ||
+ buf[30:30+namelen] != name {
+ println("fs unzip: inconsistent zip file")
+ return
+ }
+ xlen = zget2(buf[28:])
+
+ off += zheadersize + namelen + xlen
+
+ var fdata []byte
+ switch meth {
+ case 0:
+ // buf is uncompressed
+ buf = data[off : off+size]
+ fdata = []byte(buf)
+ case 8:
+ // buf is deflate-compressed
+ buf = data[off : off+csize]
+ fdata = inflate(buf)
+ if len(fdata) != size {
+ println("fs unzip: inconsistent size in zip file")
+ return
+ }
+ }
+
+ if xattr&S_IFMT == 0 {
+ if xattr&0777 == 0 {
+ xattr |= 0666
+ }
+ if len(name) > 0 && name[len(name)-1] == '/' {
+ xattr |= S_IFDIR
+ xattr |= 0111
+ } else {
+ xattr |= S_IFREG
+ }
+ }
+
+ if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
+ print("fs unzip: create ", name, ": ", err.Error(), "\n")
+ }
+ }
+
+ chdirEnv()
+}
+
+func zipToTime(date, time int) int64 {
+ dd := date & 0x1f
+ mm := date >> 5 & 0xf
+ yy := date >> 9 // since 1980
+
+ sec := int64(315532800) // jan 1 1980
+ sec += int64(yy) * 365 * 86400
+ sec += int64(yy) / 4 * 86400
+ if yy%4 > 0 || mm >= 3 {
+ sec += 86400
+ }
+ sec += int64(daysBeforeMonth[mm]) * 86400
+ sec += int64(dd-1) * 86400
+
+ h := time >> 11
+ m := time >> 5 & 0x3F
+ s := time & 0x1f * 2
+ sec += int64(h*3600 + m*60 + s)
+
+ return sec
+}
+
+var daysBeforeMonth = [...]int32{
+ 0,
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
diff --git a/src/pkg/syscall/zerrors_dragonfly_386.go b/src/pkg/syscall/zerrors_dragonfly_386.go
index a2eb926ee..701a1c381 100644
--- a/src/pkg/syscall/zerrors_dragonfly_386.go
+++ b/src/pkg/syscall/zerrors_dragonfly_386.go
@@ -311,7 +311,10 @@ const (
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
FLUSHO = 0x800000
+ F_DUP2FD = 0xa
+ F_DUP2FD_CLOEXEC = 0x12
F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x11
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
90: "multihop attempted",
91: "link has been severed",
92: "protocol error",
- 93: "unknown error: 93",
+ 93: "no medium found",
94: "unknown error: 94",
95: "unknown error: 95",
96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_dragonfly_amd64.go b/src/pkg/syscall/zerrors_dragonfly_amd64.go
index d2fe97c68..59bff751c 100644
--- a/src/pkg/syscall/zerrors_dragonfly_amd64.go
+++ b/src/pkg/syscall/zerrors_dragonfly_amd64.go
@@ -311,7 +311,10 @@ const (
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
FLUSHO = 0x800000
+ F_DUP2FD = 0xa
+ F_DUP2FD_CLOEXEC = 0x12
F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x11
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
90: "multihop attempted",
91: "link has been severed",
92: "protocol error",
- 93: "unknown error: 93",
+ 93: "no medium found",
94: "unknown error: 94",
95: "unknown error: 95",
96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 43d7c5969..cd3aa80a9 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -332,10 +334,11 @@ const (
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
- DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MAX = 0xf6
DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPEG_2_TS = 0xf3
DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
@@ -343,7 +346,9 @@ const (
DLT_MUX27010 = 0xec
DLT_NETANALYZER = 0xf0
DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFC_LLCP = 0xf5
DLT_NFLOG = 0xef
+ DLT_NG40 = 0xf4
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -423,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -789,6 +795,7 @@ const (
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
IPPROTO_MTP = 0x5c
IPPROTO_MUX = 0x12
IPPROTO_ND = 0x4d
@@ -996,6 +1003,9 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1014,6 +1024,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1030,6 +1041,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1069,6 +1081,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1129,6 +1142,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1177,6 +1191,7 @@ const (
RTV_WEIGHT = 0x100
RT_CACHING_CONTEXT = 0x1
RT_DEFAULT_FIB = 0x0
+ RT_NORTREF = 0x2
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1258,8 +1273,10 @@ const (
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1299,6 +1316,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1322,6 +1340,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1407,10 +1426,12 @@ const (
VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
+ WEXITED = 0x10
WLINUXCLONE = 0x80000000
WNOHANG = 0x1
WNOWAIT = 0x8
WSTOPPED = 0x2
+ WTRAPPED = 0x20
WUNTRACED = 0x2
)
@@ -1453,7 +1474,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1482,12 +1503,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1531,6 +1554,7 @@ const (
SIGIO = Signal(0x17)
SIGIOT = Signal(0x6)
SIGKILL = Signal(0x9)
+ SIGLIBRT = Signal(0x21)
SIGLWP = Signal(0x20)
SIGPIPE = Signal(0xd)
SIGPROF = Signal(0x1b)
@@ -1649,6 +1673,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
@@ -1685,4 +1711,5 @@ var signals = [...]string{
30: "user defined signal 1",
31: "user defined signal 2",
32: "unknown signal",
+ 33: "unknown signal",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 8e03f45e2..9edce6e2f 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -332,10 +334,11 @@ const (
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
- DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MAX = 0xf6
DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPEG_2_TS = 0xf3
DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
@@ -343,7 +346,9 @@ const (
DLT_MUX27010 = 0xec
DLT_NETANALYZER = 0xf0
DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFC_LLCP = 0xf5
DLT_NFLOG = 0xef
+ DLT_NG40 = 0xf4
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -423,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -789,6 +795,7 @@ const (
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
IPPROTO_MTP = 0x5c
IPPROTO_MUX = 0x12
IPPROTO_ND = 0x4d
@@ -996,6 +1003,10 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_32BIT = 0x80000
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1014,6 +1025,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1030,6 +1042,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1069,6 +1082,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1129,6 +1143,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1177,6 +1192,7 @@ const (
RTV_WEIGHT = 0x100
RT_CACHING_CONTEXT = 0x1
RT_DEFAULT_FIB = 0x0
+ RT_NORTREF = 0x2
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1258,8 +1274,10 @@ const (
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1299,6 +1317,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1322,6 +1341,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1407,10 +1427,12 @@ const (
VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
+ WEXITED = 0x10
WLINUXCLONE = 0x80000000
WNOHANG = 0x1
WNOWAIT = 0x8
WSTOPPED = 0x2
+ WTRAPPED = 0x20
WUNTRACED = 0x2
)
@@ -1453,7 +1475,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1482,12 +1504,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1531,6 +1555,7 @@ const (
SIGIO = Signal(0x17)
SIGIOT = Signal(0x6)
SIGKILL = Signal(0x9)
+ SIGLIBRT = Signal(0x21)
SIGLWP = Signal(0x20)
SIGPIPE = Signal(0xd)
SIGPROF = Signal(0x1b)
@@ -1649,6 +1674,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
@@ -1685,4 +1712,5 @@ var signals = [...]string{
30: "user defined signal 1",
31: "user defined signal 2",
32: "unknown signal",
+ 33: "unknown signal",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_arm.go b/src/pkg/syscall/zerrors_freebsd_arm.go
index 269f179b3..f29dd057b 100644
--- a/src/pkg/syscall/zerrors_freebsd_arm.go
+++ b/src/pkg/syscall/zerrors_freebsd_arm.go
@@ -25,13 +25,15 @@ const (
AF_IMPLINK = 0x3
AF_INET = 0x2
AF_INET6 = 0x1c
+ AF_INET6_SDP = 0x2a
+ AF_INET_SDP = 0x28
AF_IPX = 0x17
AF_ISDN = 0x1a
AF_ISO = 0x7
AF_LAT = 0xe
AF_LINK = 0x12
AF_LOCAL = 0x1
- AF_MAX = 0x26
+ AF_MAX = 0x2a
AF_NATM = 0x1d
AF_NETBIOS = 0x6
AF_NETGRAPH = 0x20
@@ -128,7 +130,7 @@ const (
BIOCGETZMAX = 0x4004427f
BIOCGHDRCMPLT = 0x40044274
BIOCGRSIG = 0x40044272
- BIOCGRTIMEOUT = 0x400c426e
+ BIOCGRTIMEOUT = 0x4010426e
BIOCGSEESENT = 0x40044276
BIOCGSTATS = 0x4008426f
BIOCGTSTAMP = 0x40044283
@@ -147,7 +149,7 @@ const (
BIOCSETZBUF = 0x800c4281
BIOCSHDRCMPLT = 0x80044275
BIOCSRSIG = 0x80044273
- BIOCSRTIMEOUT = 0x800c426d
+ BIOCSRTIMEOUT = 0x8010426d
BIOCSSEESENT = 0x80044277
BIOCSTSTAMP = 0x80044284
BIOCVERSION = 0x40044271
@@ -426,6 +428,7 @@ const (
EV_DELETE = 0x2
EV_DISABLE = 0x8
EV_DISPATCH = 0x80
+ EV_DROP = 0x1000
EV_ENABLE = 0x4
EV_EOF = 0x8000
EV_ERROR = 0x4000
@@ -521,6 +524,7 @@ const (
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BRIDGE = 0xd1
IFT_BSC = 0x53
+ IFT_CARP = 0xf8
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
@@ -999,6 +1003,9 @@ const (
MADV_RANDOM = 0x1
MADV_SEQUENTIAL = 0x2
MADV_WILLNEED = 0x3
+ MAP_ALIGNED_SUPER = 0x1000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
MAP_ANON = 0x1000
MAP_ANONYMOUS = 0x1000
MAP_COPY = 0x2
@@ -1017,6 +1024,7 @@ const (
MAP_STACK = 0x400
MCL_CURRENT = 0x1
MCL_FUTURE = 0x2
+ MSG_CMSG_CLOEXEC = 0x40000
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -1033,6 +1041,7 @@ const (
MS_ASYNC = 0x1
MS_INVALIDATE = 0x2
MS_SYNC = 0x0
+ NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1072,6 +1081,7 @@ const (
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
+ O_CLOEXEC = 0x100000
O_CREAT = 0x200
O_DIRECT = 0x10000
O_DIRECTORY = 0x20000
@@ -1132,6 +1142,7 @@ const (
RTF_DYNAMIC = 0x10
RTF_FMASK = 0x1004d808
RTF_GATEWAY = 0x2
+ RTF_GWFLAG_COMPAT = 0x80000000
RTF_HOST = 0x4
RTF_LLDATA = 0x400
RTF_LLINFO = 0x400
@@ -1193,7 +1204,7 @@ const (
SHUT_WR = 0x1
SIOCADDMULTI = 0x80206931
SIOCADDRT = 0x8030720a
- SIOCAIFADDR = 0x8044692b
+ SIOCAIFADDR = 0x8040691a
SIOCAIFGROUP = 0x80246987
SIOCALIFADDR = 0x8118691b
SIOCATMARK = 0x40047307
@@ -1227,7 +1238,7 @@ const (
SIOCGIFPDSTADDR = 0xc0206948
SIOCGIFPHYS = 0xc0206935
SIOCGIFPSRCADDR = 0xc0206947
- SIOCGIFSTATUS = 0xc334693b
+ SIOCGIFSTATUS = 0xc331693b
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCGLOWAT = 0x40047303
@@ -1255,15 +1266,17 @@ const (
SIOCSIFMTU = 0x80206934
SIOCSIFNAME = 0x80206928
SIOCSIFNETMASK = 0x80206916
- SIOCSIFPHYADDR = 0x80446946
+ SIOCSIFPHYADDR = 0x80406946
SIOCSIFPHYS = 0x80206936
SIOCSIFRVNET = 0xc020695b
SIOCSIFVNET = 0xc020695a
SIOCSLIFPHYADDR = 0x8118694a
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SOCK_CLOEXEC = 0x10000000
SOCK_DGRAM = 0x2
SOCK_MAXADDRLEN = 0xff
+ SOCK_NONBLOCK = 0x20000000
SOCK_RAW = 0x3
SOCK_RDM = 0x4
SOCK_SEQPACKET = 0x5
@@ -1303,6 +1316,7 @@ const (
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
SO_USER_COOKIE = 0x1015
+ SO_VENDOR = 0x80000000
TCIFLUSH = 0x1
TCIOFLUSH = 0x3
TCOFLUSH = 0x2
@@ -1326,6 +1340,7 @@ const (
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCP_VENDOR = 0x80000000
TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
@@ -1387,7 +1402,7 @@ const (
TIOCSTI = 0x80017472
TIOCSTOP = 0x2000746f
TIOCSWINSZ = 0x80087467
- TIOCTIMESTAMP = 0x400c7459
+ TIOCTIMESTAMP = 0x40107459
TIOCUCNTL = 0x80047466
TOSTOP = 0x400000
VDISCARD = 0xf
@@ -1459,7 +1474,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5e)
+ ELAST = Errno(0x60)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1488,12 +1503,14 @@ const (
ENOTCONN = Errno(0x39)
ENOTDIR = Errno(0x14)
ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x5f)
ENOTSOCK = Errno(0x26)
ENOTSUP = Errno(0x2d)
ENOTTY = Errno(0x19)
ENXIO = Errno(0x6)
EOPNOTSUPP = Errno(0x2d)
EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x60)
EPERM = Errno(0x1)
EPFNOSUPPORT = Errno(0x2e)
EPIPE = Errno(0x20)
@@ -1656,6 +1673,8 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
94: "not permitted in capability mode",
+ 95: "state not recoverable",
+ 96: "previous owner died",
}
// Signal table
diff --git a/src/pkg/syscall/zerrors_netbsd_386.go b/src/pkg/syscall/zerrors_netbsd_386.go
index 9b93f5a15..1e3dff7fa 100644
--- a/src/pkg/syscall/zerrors_netbsd_386.go
+++ b/src/pkg/syscall/zerrors_netbsd_386.go
@@ -146,6 +146,14 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CLONE_CSIGNAL = 0xff
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_PID = 0x1000
+ CLONE_PTRACE = 0x2000
+ CLONE_SIGHAND = 0x800
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -962,6 +970,40 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -980,6 +1022,9 @@ const (
MSG_TRUNC = 0x10
MSG_USERFLAGS = 0xffffff
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x4
NAME_MAX = 0x1ff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -1039,10 +1084,14 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
- PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PRI_IOFLUSH = 0x7c
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_amd64.go b/src/pkg/syscall/zerrors_netbsd_amd64.go
index 4db30fa5c..1469d00b7 100644
--- a/src/pkg/syscall/zerrors_netbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_netbsd_amd64.go
@@ -146,6 +146,14 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CLONE_CSIGNAL = 0xff
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_PID = 0x1000
+ CLONE_PTRACE = 0x2000
+ CLONE_SIGHAND = 0x800
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -952,6 +960,40 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -970,6 +1012,9 @@ const (
MSG_TRUNC = 0x10
MSG_USERFLAGS = 0xffffff
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x4
NAME_MAX = 0x1ff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -1029,10 +1074,14 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
- PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PRI_IOFLUSH = 0x7c
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_arm.go b/src/pkg/syscall/zerrors_netbsd_arm.go
index 9262d5afb..1a88c0d22 100644
--- a/src/pkg/syscall/zerrors_netbsd_arm.go
+++ b/src/pkg/syscall/zerrors_netbsd_arm.go
@@ -952,6 +952,38 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ALIGNMENT_16MB = 0x18000000
+ MAP_ALIGNMENT_1TB = 0x28000000
+ MAP_ALIGNMENT_256TB = 0x30000000
+ MAP_ALIGNMENT_4GB = 0x20000000
+ MAP_ALIGNMENT_64KB = 0x10000000
+ MAP_ALIGNMENT_64PB = 0x38000000
+ MAP_ALIGNMENT_MASK = -0x1000000
+ MAP_ALIGNMENT_SHIFT = 0x18
+ MAP_ANON = 0x1000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DEFAULT = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x2000
+ MAP_TRYFIXED = 0x400
+ MAP_WIRED = 0x800
MSG_BCAST = 0x100
MSG_CMSG_CLOEXEC = 0x800
MSG_CONTROLMBUF = 0x2000000
@@ -1029,6 +1061,10 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
PRI_IOFLUSH = 0x7c
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
diff --git a/src/pkg/syscall/zerrors_openbsd_386.go b/src/pkg/syscall/zerrors_openbsd_386.go
index e546243b0..082983494 100644
--- a/src/pkg/syscall/zerrors_openbsd_386.go
+++ b/src/pkg/syscall/zerrors_openbsd_386.go
@@ -77,7 +77,7 @@ const (
BIOCGFILDROP = 0x40044278
BIOCGHDRCMPLT = 0x40044274
BIOCGRSIG = 0x40044273
- BIOCGRTIMEOUT = 0x4008426e
+ BIOCGRTIMEOUT = 0x400c426e
BIOCGSTATS = 0x4008426f
BIOCIMMEDIATE = 0x80044270
BIOCLOCK = 0x20004276
@@ -91,7 +91,7 @@ const (
BIOCSFILDROP = 0x80044279
BIOCSHDRCMPLT = 0x80044275
BIOCSRSIG = 0x80044272
- BIOCSRTIMEOUT = 0x8008426d
+ BIOCSRTIMEOUT = 0x800c426d
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
@@ -713,6 +713,8 @@ const (
IPPROTO_AH = 0x33
IPPROTO_CARP = 0x70
IPPROTO_DIVERT = 0x102
+ IPPROTO_DIVERT_INIT = 0x2
+ IPPROTO_DIVERT_RESP = 0x1
IPPROTO_DONE = 0x101
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
@@ -783,6 +785,7 @@ const (
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVDSTPORT = 0x40
IPV6_RECVHOPLIMIT = 0x25
IPV6_RECVHOPOPTS = 0x27
IPV6_RECVPATHMTU = 0x2b
@@ -807,6 +810,7 @@ const (
IP_DEFAULT_MULTICAST_LOOP = 0x1
IP_DEFAULT_MULTICAST_TTL = 0x1
IP_DF = 0x4000
+ IP_DIVERTFL = 0x1022
IP_DROP_MEMBERSHIP = 0xd
IP_ESP_NETWORK_LEVEL = 0x16
IP_ESP_TRANS_LEVEL = 0x15
@@ -857,6 +861,32 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x4
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_FLAGMASK = 0x1ff7
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TRYFIXED = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -868,6 +898,9 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x4
+ MS_SYNC = 0x2
NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -926,10 +959,14 @@ const (
PARODD = 0x2000
PENDIN = 0x20000000
PF_FLUSH = 0x1
- PT_MASK = 0x3ff000
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_MASK = 0x3ff000
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
RLIMIT_DATA = 0x2
@@ -966,7 +1003,7 @@ const (
RTF_CLONING = 0x100
RTF_DONE = 0x40
RTF_DYNAMIC = 0x10
- RTF_FMASK = 0xf808
+ RTF_FMASK = 0x10f808
RTF_GATEWAY = 0x2
RTF_HOST = 0x4
RTF_LLINFO = 0x400
@@ -1001,7 +1038,7 @@ const (
RTM_REDIRECT = 0x6
RTM_RESOLVE = 0xb
RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x4
+ RTM_VERSION = 0x5
RTV_EXPIRE = 0x4
RTV_HOPCOUNT = 0x2
RTV_MTU = 0x1
@@ -1027,7 +1064,7 @@ const (
SIOCBRDGADD = 0x8054693c
SIOCBRDGADDS = 0x80546941
SIOCBRDGARL = 0x806e694d
- SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDADDR = 0x81286947
SIOCBRDGDEL = 0x8054693d
SIOCBRDGDELS = 0x80546942
SIOCBRDGFLUSH = 0x80546948
@@ -1037,14 +1074,14 @@ const (
SIOCBRDGGHT = 0xc0146951
SIOCBRDGGIFFLGS = 0xc054693e
SIOCBRDGGMA = 0xc0146953
- SIOCBRDGGPARAM = 0xc0386958
+ SIOCBRDGGPARAM = 0xc03c6958
SIOCBRDGGPRI = 0xc0146950
SIOCBRDGGRL = 0xc028694f
SIOCBRDGGSIFS = 0xc054693c
SIOCBRDGGTO = 0xc0146946
SIOCBRDGIFS = 0xc0546942
SIOCBRDGRTS = 0xc0186943
- SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSADDR = 0xc1286944
SIOCBRDGSCACHE = 0x80146940
SIOCBRDGSFD = 0x80146952
SIOCBRDGSHT = 0x80146951
@@ -1067,6 +1104,7 @@ const (
SIOCGETPFSYNC = 0xc02069f8
SIOCGETSGCNT = 0xc0147534
SIOCGETVIFCNT = 0xc0147533
+ SIOCGETVLAN = 0xc0206990
SIOCGHIWAT = 0x40047301
SIOCGIFADDR = 0xc0206921
SIOCGIFASYNCMAP = 0xc020697c
@@ -1080,6 +1118,7 @@ const (
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc024698a
SIOCGIFGROUP = 0xc0246988
+ SIOCGIFHARDMTU = 0xc02069a5
SIOCGIFMEDIA = 0xc0286936
SIOCGIFMETRIC = 0xc0206917
SIOCGIFMTU = 0xc020697e
@@ -1094,9 +1133,12 @@ const (
SIOCGLIFADDR = 0xc218691d
SIOCGLIFPHYADDR = 0xc218694b
SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLIFPHYTTL = 0xc02069a9
SIOCGLOWAT = 0x40047303
SIOCGPGRP = 0x40047309
+ SIOCGSPPPPARAMS = 0xc0206994
SIOCGVH = 0xc02069f6
+ SIOCGVNETID = 0xc02069a7
SIOCIFCREATE = 0x8020697a
SIOCIFDESTROY = 0x80206979
SIOCIFGCLONERS = 0xc00c6978
@@ -1104,6 +1146,7 @@ const (
SIOCSETLABEL = 0x80206999
SIOCSETPFLOW = 0x802069fd
SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLAN = 0x8020698f
SIOCSHIWAT = 0x80047300
SIOCSIFADDR = 0x8020690c
SIOCSIFASYNCMAP = 0x8020697d
@@ -1126,9 +1169,12 @@ const (
SIOCSIFXFLAGS = 0x8020699d
SIOCSLIFPHYADDR = 0x8218694a
SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLIFPHYTTL = 0x802069a8
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SIOCSSPPPPARAMS = 0x80206993
SIOCSVH = 0xc02069f5
+ SIOCSVNETID = 0x802069a6
SOCK_DGRAM = 0x2
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -1171,6 +1217,7 @@ const (
TCP_MD5SIG = 0x4
TCP_MSS = 0x200
TCP_NODELAY = 0x1
+ TCP_NOPUSH = 0x10
TCP_NSTATES = 0xb
TCP_SACK_ENABLE = 0x8
TCSAFLUSH = 0x2
@@ -1190,7 +1237,8 @@ const (
TIOCGETD = 0x4004741a
TIOCGFLAGS = 0x4004745d
TIOCGPGRP = 0x40047477
- TIOCGTSTAMP = 0x4008745b
+ TIOCGSID = 0x40047463
+ TIOCGTSTAMP = 0x400c745b
TIOCGWINSZ = 0x40087468
TIOCMBIC = 0x8004746b
TIOCMBIS = 0x8004746c
diff --git a/src/pkg/syscall/zerrors_openbsd_amd64.go b/src/pkg/syscall/zerrors_openbsd_amd64.go
index 411b51a68..e9fa37cde 100644
--- a/src/pkg/syscall/zerrors_openbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_openbsd_amd64.go
@@ -140,10 +140,8 @@ const (
BPF_W = 0x0
BPF_X = 0x8
BRKINT = 0x2
- CCR0_FLUSH = 0x10
CFLUSH = 0xf
CLOCAL = 0x8000
- CPUID_CFLUSH = 0x80000
CREAD = 0x800
CS5 = 0x0
CS6 = 0x100
@@ -198,10 +196,6 @@ const (
ECHOKE = 0x1
ECHONL = 0x10
ECHOPRT = 0x20
- EFER_LMA = 0x400
- EFER_LME = 0x100
- EFER_NXE = 0x800
- EFER_SCE = 0x1
EMT_TAGOVF = 0x1
EMUL_ENABLED = 0x1
EMUL_NATIVE = 0x2
@@ -719,6 +713,8 @@ const (
IPPROTO_AH = 0x33
IPPROTO_CARP = 0x70
IPPROTO_DIVERT = 0x102
+ IPPROTO_DIVERT_INIT = 0x2
+ IPPROTO_DIVERT_RESP = 0x1
IPPROTO_DONE = 0x101
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
@@ -789,6 +785,7 @@ const (
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVDSTPORT = 0x40
IPV6_RECVHOPLIMIT = 0x25
IPV6_RECVHOPOPTS = 0x27
IPV6_RECVPATHMTU = 0x2b
@@ -813,6 +810,7 @@ const (
IP_DEFAULT_MULTICAST_LOOP = 0x1
IP_DEFAULT_MULTICAST_TTL = 0x1
IP_DF = 0x4000
+ IP_DIVERTFL = 0x1022
IP_DROP_MEMBERSHIP = 0xd
IP_ESP_NETWORK_LEVEL = 0x16
IP_ESP_TRANS_LEVEL = 0x15
@@ -863,6 +861,32 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x6
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x4
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_FLAGMASK = 0x1ff7
+ MAP_HASSEMAPHORE = 0x200
+ MAP_INHERIT = 0x80
+ MAP_INHERIT_COPY = 0x1
+ MAP_INHERIT_DONATE_COPY = 0x3
+ MAP_INHERIT_NONE = 0x2
+ MAP_INHERIT_SHARE = 0x0
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TRYFIXED = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_BCAST = 0x100
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -874,6 +898,9 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x4
+ MS_SYNC = 0x2
NAME_MAX = 0xff
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
@@ -932,10 +959,13 @@ const (
PARODD = 0x2000
PENDIN = 0x20000000
PF_FLUSH = 0x1
- PMC5_PIPELINE_FLUSH = 0x15
PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0
PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
RLIMIT_DATA = 0x2
@@ -972,7 +1002,7 @@ const (
RTF_CLONING = 0x100
RTF_DONE = 0x40
RTF_DYNAMIC = 0x10
- RTF_FMASK = 0xf808
+ RTF_FMASK = 0x10f808
RTF_GATEWAY = 0x2
RTF_HOST = 0x4
RTF_LLINFO = 0x400
@@ -1007,7 +1037,7 @@ const (
RTM_REDIRECT = 0x6
RTM_RESOLVE = 0xb
RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x4
+ RTM_VERSION = 0x5
RTV_EXPIRE = 0x4
RTV_HOPCOUNT = 0x2
RTV_MTU = 0x1
@@ -1033,7 +1063,7 @@ const (
SIOCBRDGADD = 0x8058693c
SIOCBRDGADDS = 0x80586941
SIOCBRDGARL = 0x806e694d
- SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDADDR = 0x81286947
SIOCBRDGDEL = 0x8058693d
SIOCBRDGDELS = 0x80586942
SIOCBRDGFLUSH = 0x80586948
@@ -1050,7 +1080,7 @@ const (
SIOCBRDGGTO = 0xc0146946
SIOCBRDGIFS = 0xc0586942
SIOCBRDGRTS = 0xc0206943
- SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSADDR = 0xc1286944
SIOCBRDGSCACHE = 0x80146940
SIOCBRDGSFD = 0x80146952
SIOCBRDGSHT = 0x80146951
@@ -1073,6 +1103,7 @@ const (
SIOCGETPFSYNC = 0xc02069f8
SIOCGETSGCNT = 0xc0207534
SIOCGETVIFCNT = 0xc0287533
+ SIOCGETVLAN = 0xc0206990
SIOCGHIWAT = 0x40047301
SIOCGIFADDR = 0xc0206921
SIOCGIFASYNCMAP = 0xc020697c
@@ -1086,6 +1117,7 @@ const (
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc028698a
SIOCGIFGROUP = 0xc0286988
+ SIOCGIFHARDMTU = 0xc02069a5
SIOCGIFMEDIA = 0xc0306936
SIOCGIFMETRIC = 0xc0206917
SIOCGIFMTU = 0xc020697e
@@ -1100,9 +1132,12 @@ const (
SIOCGLIFADDR = 0xc218691d
SIOCGLIFPHYADDR = 0xc218694b
SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLIFPHYTTL = 0xc02069a9
SIOCGLOWAT = 0x40047303
SIOCGPGRP = 0x40047309
+ SIOCGSPPPPARAMS = 0xc0206994
SIOCGVH = 0xc02069f6
+ SIOCGVNETID = 0xc02069a7
SIOCIFCREATE = 0x8020697a
SIOCIFDESTROY = 0x80206979
SIOCIFGCLONERS = 0xc0106978
@@ -1110,6 +1145,7 @@ const (
SIOCSETLABEL = 0x80206999
SIOCSETPFLOW = 0x802069fd
SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLAN = 0x8020698f
SIOCSHIWAT = 0x80047300
SIOCSIFADDR = 0x8020690c
SIOCSIFASYNCMAP = 0x8020697d
@@ -1132,9 +1168,12 @@ const (
SIOCSIFXFLAGS = 0x8020699d
SIOCSLIFPHYADDR = 0x8218694a
SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLIFPHYTTL = 0x802069a8
SIOCSLOWAT = 0x80047302
SIOCSPGRP = 0x80047308
+ SIOCSSPPPPARAMS = 0x80206993
SIOCSVH = 0xc02069f5
+ SIOCSVNETID = 0x802069a6
SOCK_DGRAM = 0x2
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -1177,6 +1216,7 @@ const (
TCP_MD5SIG = 0x4
TCP_MSS = 0x200
TCP_NODELAY = 0x1
+ TCP_NOPUSH = 0x10
TCP_NSTATES = 0xb
TCP_SACK_ENABLE = 0x8
TCSAFLUSH = 0x2
@@ -1196,6 +1236,7 @@ const (
TIOCGETD = 0x4004741a
TIOCGFLAGS = 0x4004745d
TIOCGPGRP = 0x40047477
+ TIOCGSID = 0x40047463
TIOCGTSTAMP = 0x4010745b
TIOCGWINSZ = 0x40087468
TIOCMBIC = 0x8004746b
diff --git a/src/pkg/syscall/zerrors_solaris_amd64.go b/src/pkg/syscall/zerrors_solaris_amd64.go
new file mode 100644
index 000000000..3f4cbfd98
--- /dev/null
+++ b/src/pkg/syscall/zerrors_solaris_amd64.go
@@ -0,0 +1,1414 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_802 = 0x12
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_ECMA = 0x8
+ AF_FILE = 0x1
+ AF_GOSIP = 0x16
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1a
+ AF_INET_OFFLOAD = 0x1e
+ AF_IPX = 0x17
+ AF_KEY = 0x1b
+ AF_LAT = 0xe
+ AF_LINK = 0x19
+ AF_LOCAL = 0x1
+ AF_MAX = 0x20
+ AF_NBS = 0x7
+ AF_NCA = 0x1c
+ AF_NIT = 0x11
+ AF_NS = 0x6
+ AF_OSI = 0x13
+ AF_OSINET = 0x15
+ AF_PACKET = 0x20
+ AF_POLICY = 0x1d
+ AF_PUP = 0x4
+ AF_ROUTE = 0x18
+ AF_SNA = 0xb
+ AF_TRILL = 0x1f
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_X25 = 0x14
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ATM = 0x10
+ ARPHRD_AX25 = 0x3
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FC = 0x12
+ ARPHRD_FRAME = 0xf
+ ARPHRD_HDLC = 0x11
+ ARPHRD_IB = 0x20
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IPATM = 0x13
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_TUNNEL = 0x1f
+ B0 = 0x0
+ B110 = 0x3
+ B115200 = 0x12
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B153600 = 0x13
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B230400 = 0x14
+ B2400 = 0xb
+ B300 = 0x7
+ B307200 = 0x15
+ B38400 = 0xf
+ B460800 = 0x16
+ B4800 = 0xc
+ B50 = 0x1
+ B57600 = 0x10
+ B600 = 0x8
+ B75 = 0x2
+ B76800 = 0x11
+ B921600 = 0x17
+ B9600 = 0xd
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = -0x3fefbd89
+ BIOCGDLTLIST32 = -0x3ff7bd89
+ BIOCGETIF = 0x4020426b
+ BIOCGETLIF = 0x4078426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRTIMEOUT = 0x4010427b
+ BIOCGRTIMEOUT32 = 0x4008427b
+ BIOCGSEESENT = 0x40044278
+ BIOCGSTATS = 0x4080426f
+ BIOCGSTATSOLD = 0x4008426f
+ BIOCIMMEDIATE = -0x7ffbbd90
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = -0x3ffbbd9a
+ BIOCSDLT = -0x7ffbbd8a
+ BIOCSETF = -0x7fefbd99
+ BIOCSETF32 = -0x7ff7bd99
+ BIOCSETIF = -0x7fdfbd94
+ BIOCSETLIF = -0x7f87bd94
+ BIOCSHDRCMPLT = -0x7ffbbd8b
+ BIOCSRTIMEOUT = -0x7fefbd86
+ BIOCSRTIMEOUT32 = -0x7ff7bd86
+ BIOCSSEESENT = -0x7ffbbd87
+ BIOCSTCPF = -0x7fefbd8e
+ BIOCSUDPF = -0x7fefbd8d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DFLTBUFSIZE = 0x100000
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x1000000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x800
+ CREAD = 0x80
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSIZE = 0x30
+ CSTART = 0x11
+ CSTOP = 0x13
+ CSTOPB = 0x40
+ CSUSP = 0x1a
+ CSWTCH = 0x1a
+ DLT_AIRONET_HEADER = 0x78
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ARCNET_LINUX = 0x81
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AURORA = 0x7e
+ DLT_AX25 = 0x3
+ DLT_BACNET_MS_TP = 0xa5
+ DLT_CHAOS = 0x5
+ DLT_CISCO_IOS = 0x76
+ DLT_C_HDLC = 0x68
+ DLT_DOCSIS = 0x8f
+ DLT_ECONET = 0x73
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0x6d
+ DLT_ERF_ETH = 0xaf
+ DLT_ERF_POS = 0xb0
+ DLT_FDDI = 0xa
+ DLT_FRELAY = 0x6b
+ DLT_GCOM_SERIAL = 0xad
+ DLT_GCOM_T1E1 = 0xac
+ DLT_GPF_F = 0xab
+ DLT_GPF_T = 0xaa
+ DLT_GPRS_LLC = 0xa9
+ DLT_HDLC = 0x10
+ DLT_HHDLC = 0x79
+ DLT_HIPPI = 0xf
+ DLT_IBM_SN = 0x92
+ DLT_IBM_SP = 0x91
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_IPNET = 0xe2
+ DLT_IPOIB = 0xa2
+ DLT_IP_OVER_FC = 0x7a
+ DLT_JUNIPER_ATM1 = 0x89
+ DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_CHDLC = 0xb5
+ DLT_JUNIPER_ES = 0x84
+ DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FRELAY = 0xb4
+ DLT_JUNIPER_GGSN = 0x85
+ DLT_JUNIPER_MFR = 0x86
+ DLT_JUNIPER_MLFR = 0x83
+ DLT_JUNIPER_MLPPP = 0x82
+ DLT_JUNIPER_MONITOR = 0xa4
+ DLT_JUNIPER_PIC_PEER = 0xae
+ DLT_JUNIPER_PPP = 0xb3
+ DLT_JUNIPER_PPPOE = 0xa7
+ DLT_JUNIPER_PPPOE_ATM = 0xa8
+ DLT_JUNIPER_SERVICES = 0x88
+ DLT_LINUX_IRDA = 0x90
+ DLT_LINUX_LAPD = 0xb1
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_LTALK = 0x72
+ DLT_MTP2 = 0x8c
+ DLT_MTP2_WITH_PHDR = 0x8b
+ DLT_MTP3 = 0x8d
+ DLT_NULL = 0x0
+ DLT_PCI_EXP = 0x7d
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0xe
+ DLT_PPP_PPPD = 0xa6
+ DLT_PRISM_HEADER = 0x77
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_RAWAF_MASK = 0x2240000
+ DLT_RIO = 0x7c
+ DLT_SCCP = 0x8e
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xd
+ DLT_SUNATM = 0x7b
+ DLT_SYMANTEC_FIREWALL = 0x63
+ DLT_TZSP = 0x80
+ ECHO = 0x8
+ ECHOCTL = 0x200
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHOKE = 0x800
+ ECHONL = 0x40
+ ECHOPRT = 0x400
+ EMPTY_SET = 0x0
+ EMT_CPCOVF = 0x1
+ EQUALITY_CHECK = 0x0
+ EXTA = 0xe
+ EXTB = 0xf
+ FD_CLOEXEC = 0x1
+ FD_NFDBITS = 0x40
+ FD_SETSIZE = 0x10000
+ FLUSHALL = 0x1
+ FLUSHDATA = 0x0
+ FLUSHO = 0x2000
+ F_ALLOCSP = 0xa
+ F_ALLOCSP64 = 0xa
+ F_BADFD = 0x2e
+ F_BLKSIZE = 0x13
+ F_BLOCKS = 0x12
+ F_CHKFL = 0x8
+ F_COMPAT = 0x8
+ F_DUP2FD = 0x9
+ F_DUP2FD_CLOEXEC = 0x24
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x25
+ F_FREESP = 0xb
+ F_FREESP64 = 0xb
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0xe
+ F_GETLK64 = 0xe
+ F_GETOWN = 0x17
+ F_GETXFL = 0x2d
+ F_HASREMOTELOCKS = 0x1a
+ F_ISSTREAM = 0xd
+ F_MANDDNY = 0x10
+ F_MDACC = 0x20
+ F_NODNY = 0x0
+ F_NPRIV = 0x10
+ F_PRIV = 0xf
+ F_QUOTACTL = 0x11
+ F_RDACC = 0x1
+ F_RDDNY = 0x1
+ F_RDLCK = 0x1
+ F_REVOKE = 0x19
+ F_RMACC = 0x4
+ F_RMDNY = 0x4
+ F_RWACC = 0x3
+ F_RWDNY = 0x3
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x6
+ F_SETLK64 = 0x6
+ F_SETLK64_NBMAND = 0x2a
+ F_SETLKW = 0x7
+ F_SETLKW64 = 0x7
+ F_SETLK_NBMAND = 0x2a
+ F_SETOWN = 0x18
+ F_SHARE = 0x28
+ F_SHARE_NBMAND = 0x2b
+ F_UNLCK = 0x3
+ F_UNLKSYS = 0x4
+ F_UNSHARE = 0x29
+ F_WRACC = 0x2
+ F_WRDNY = 0x2
+ F_WRLCK = 0x2
+ HUPCL = 0x400
+ ICANON = 0x2
+ ICRNL = 0x100
+ IEXTEN = 0x8000
+ IFF_ADDRCONF = 0x80000
+ IFF_ALLMULTI = 0x200
+ IFF_ANYCAST = 0x400000
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x7f203003b5a
+ IFF_COS_ENABLED = 0x200000000
+ IFF_DEBUG = 0x4
+ IFF_DEPRECATED = 0x40000
+ IFF_DHCPRUNNING = 0x4000
+ IFF_DUPLICATE = 0x4000000000
+ IFF_FAILED = 0x10000000
+ IFF_FIXEDMTU = 0x1000000000
+ IFF_INACTIVE = 0x40000000
+ IFF_INTELLIGENT = 0x400
+ IFF_IPMP = 0x8000000000
+ IFF_IPMP_CANTCHANGE = 0x10000000
+ IFF_IPMP_INVALID = 0x1ec200080
+ IFF_IPV4 = 0x1000000
+ IFF_IPV6 = 0x2000000
+ IFF_L3PROTECT = 0x40000000000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x800
+ IFF_MULTI_BCAST = 0x1000
+ IFF_NOACCEPT = 0x4000000
+ IFF_NOARP = 0x80
+ IFF_NOFAILOVER = 0x8000000
+ IFF_NOLINKLOCAL = 0x20000000000
+ IFF_NOLOCAL = 0x20000
+ IFF_NONUD = 0x200000
+ IFF_NORTEXCH = 0x800000
+ IFF_NOTRAILERS = 0x20
+ IFF_NOXMIT = 0x10000
+ IFF_OFFLINE = 0x80000000
+ IFF_POINTOPOINT = 0x10
+ IFF_PREFERRED = 0x400000000
+ IFF_PRIVATE = 0x8000
+ IFF_PROMISC = 0x100
+ IFF_ROUTER = 0x100000
+ IFF_RUNNING = 0x40
+ IFF_STANDBY = 0x20000000
+ IFF_TEMPORARY = 0x800000000
+ IFF_UNNUMBERED = 0x2000
+ IFF_UP = 0x1
+ IFF_VIRTUAL = 0x2000000000
+ IFF_VRRP = 0x10000000000
+ IFF_XRESOLV = 0x100000000
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_6TO4 = 0xca
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IB = 0xc7
+ IFT_IPV4 = 0xc8
+ IFT_IPV6 = 0xc9
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_AUTOCONF_MASK = 0xffff0000
+ IN_AUTOCONF_NET = 0xa9fe0000
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_CLASSE_NET = 0xffffffff
+ IN_LOOPBACKNET = 0x7f
+ IN_PRIVATE12_MASK = 0xfff00000
+ IN_PRIVATE12_NET = 0xac100000
+ IN_PRIVATE16_MASK = 0xffff0000
+ IN_PRIVATE16_NET = 0xc0a80000
+ IN_PRIVATE8_MASK = 0xff000000
+ IN_PRIVATE8_NET = 0xa000000
+ IPPROTO_AH = 0x33
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x4
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_ND = 0x4d
+ IPPROTO_NONE = 0x3b
+ IPPROTO_OSPF = 0x59
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_UDP = 0x11
+ IPV6_ADD_MEMBERSHIP = 0x9
+ IPV6_BOUND_IF = 0x41
+ IPV6_CHECKSUM = 0x18
+ IPV6_DONTFRAG = 0x21
+ IPV6_DROP_MEMBERSHIP = 0xa
+ IPV6_DSTOPTS = 0xf
+ IPV6_FLOWINFO_FLOWLABEL = 0xffff0f00
+ IPV6_FLOWINFO_TCLASS = 0xf00f
+ IPV6_HOPLIMIT = 0xc
+ IPV6_HOPOPTS = 0xe
+ IPV6_JOIN_GROUP = 0x9
+ IPV6_LEAVE_GROUP = 0xa
+ IPV6_MULTICAST_HOPS = 0x7
+ IPV6_MULTICAST_IF = 0x6
+ IPV6_MULTICAST_LOOP = 0x8
+ IPV6_NEXTHOP = 0xd
+ IPV6_PAD1_OPT = 0x0
+ IPV6_PATHMTU = 0x25
+ IPV6_PKTINFO = 0xb
+ IPV6_PREFER_SRC_CGA = 0x20
+ IPV6_PREFER_SRC_CGADEFAULT = 0x10
+ IPV6_PREFER_SRC_CGAMASK = 0x30
+ IPV6_PREFER_SRC_COA = 0x2
+ IPV6_PREFER_SRC_DEFAULT = 0x15
+ IPV6_PREFER_SRC_HOME = 0x1
+ IPV6_PREFER_SRC_MASK = 0x3f
+ IPV6_PREFER_SRC_MIPDEFAULT = 0x1
+ IPV6_PREFER_SRC_MIPMASK = 0x3
+ IPV6_PREFER_SRC_NONCGA = 0x10
+ IPV6_PREFER_SRC_PUBLIC = 0x4
+ IPV6_PREFER_SRC_TMP = 0x8
+ IPV6_PREFER_SRC_TMPDEFAULT = 0x4
+ IPV6_PREFER_SRC_TMPMASK = 0xc
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x13
+ IPV6_RECVHOPOPTS = 0x14
+ IPV6_RECVPATHMTU = 0x24
+ IPV6_RECVPKTINFO = 0x12
+ IPV6_RECVRTHDR = 0x16
+ IPV6_RECVRTHDRDSTOPTS = 0x17
+ IPV6_RECVTCLASS = 0x19
+ IPV6_RTHDR = 0x10
+ IPV6_RTHDRDSTOPTS = 0x11
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SEC_OPT = 0x22
+ IPV6_SRC_PREFERENCES = 0x23
+ IPV6_TCLASS = 0x26
+ IPV6_UNICAST_HOPS = 0x5
+ IPV6_UNSPEC_SRC = 0x42
+ IPV6_USE_MIN_MTU = 0x20
+ IPV6_V6ONLY = 0x27
+ IP_ADD_MEMBERSHIP = 0x13
+ IP_ADD_SOURCE_MEMBERSHIP = 0x17
+ IP_BLOCK_SOURCE = 0x15
+ IP_BOUND_IF = 0x41
+ IP_BROADCAST = 0x106
+ IP_BROADCAST_TTL = 0x43
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DHCPINIT_IF = 0x45
+ IP_DONTFRAG = 0x1b
+ IP_DONTROUTE = 0x105
+ IP_DROP_MEMBERSHIP = 0x14
+ IP_DROP_SOURCE_MEMBERSHIP = 0x18
+ IP_HDRINCL = 0x2
+ IP_MAXPACKET = 0xffff
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x10
+ IP_MULTICAST_LOOP = 0x12
+ IP_MULTICAST_TTL = 0x11
+ IP_NEXTHOP = 0x19
+ IP_OPTIONS = 0x1
+ IP_PKTINFO = 0x1a
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x9
+ IP_RECVOPTS = 0x5
+ IP_RECVPKTINFO = 0x1a
+ IP_RECVRETOPTS = 0x6
+ IP_RECVSLLA = 0xa
+ IP_RECVTTL = 0xb
+ IP_RETOPTS = 0x8
+ IP_REUSEADDR = 0x104
+ IP_SEC_OPT = 0x22
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x16
+ IP_UNSPEC_SRC = 0x42
+ ISIG = 0x1
+ ISTRIP = 0x20
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IXON = 0x400
+ MADV_ACCESS_DEFAULT = 0x6
+ MADV_ACCESS_LWP = 0x7
+ MADV_ACCESS_MANY = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_32BIT = 0x80
+ MAP_ALIGN = 0x200
+ MAP_ANON = 0x100
+ MAP_ANONYMOUS = 0x100
+ MAP_FIXED = 0x10
+ MAP_INITDATA = 0x800
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_SHARED = 0x1
+ MAP_TEXT = 0x400
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x10
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_DUPCTRL = 0x800
+ MSG_EOR = 0x8
+ MSG_MAXIOVLEN = 0x10
+ MSG_NOTIFICATION = 0x100
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x20
+ MSG_WAITALL = 0x40
+ MSG_XPG4_2 = 0x8000
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_OLDSYNC = 0x0
+ MS_SYNC = 0x4
+ M_FLUSH = 0x86
+ NOFLSH = 0x80
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x4
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPENFAIL = -0x1
+ OPOST = 0x1
+ O_ACCMODE = 0x600003
+ O_APPEND = 0x8
+ O_CLOEXEC = 0x800000
+ O_CREAT = 0x100
+ O_DSYNC = 0x40
+ O_EXCL = 0x400
+ O_EXEC = 0x400000
+ O_LARGEFILE = 0x2000
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x800
+ O_NOFOLLOW = 0x20000
+ O_NOLINKS = 0x40000
+ O_NONBLOCK = 0x80
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x8000
+ O_SEARCH = 0x200000
+ O_SIOCGIFCONF = -0x3ff796ec
+ O_SIOCGLIFCONF = -0x3fef9688
+ O_SYNC = 0x10
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ O_XATTR = 0x4000
+ PARENB = 0x100
+ PAREXT = 0x100000
+ PARMRK = 0x8
+ PARODD = 0x200
+ PENDIN = 0x4000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ RLIMIT_AS = 0x6
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x5
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x3
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x9
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTA_NUMBITS = 0x9
+ RTA_SRC = 0x100
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INDIRECT = 0x40000
+ RTF_KERNEL = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MULTIRT = 0x10000
+ RTF_PRIVATE = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_REJECT = 0x8
+ RTF_SETSRC = 0x20000
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_XRESOLVE = 0x200
+ RTF_ZONE = 0x100000
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_CHGADDR = 0xf
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_FREEADDR = 0x10
+ RTM_GET = 0x4
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_VERSION = 0x3
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_AWARE = 0x1
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ SCM_RIGHTS = 0x1010
+ SCM_TIMESTAMP = 0x1013
+ SCM_UCRED = 0x1012
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIG2STR_MAX = 0x20
+ SIOCADDMULTI = -0x7fdf96cf
+ SIOCADDRT = -0x7fcf8df6
+ SIOCATMARK = 0x40047307
+ SIOCDARP = -0x7fdb96e0
+ SIOCDELMULTI = -0x7fdf96ce
+ SIOCDELRT = -0x7fcf8df5
+ SIOCDIPSECONFIG = -0x7ffb9669
+ SIOCDXARP = -0x7fff9658
+ SIOCFIPSECONFIG = -0x7ffb966b
+ SIOCGARP = -0x3fdb96e1
+ SIOCGDSTINFO = -0x3fff965c
+ SIOCGENADDR = -0x3fdf96ab
+ SIOCGENPSTATS = -0x3fdf96c7
+ SIOCGETLSGCNT = -0x3fef8deb
+ SIOCGETNAME = 0x40107334
+ SIOCGETPEER = 0x40107335
+ SIOCGETPROP = -0x3fff8f44
+ SIOCGETSGCNT = -0x3feb8deb
+ SIOCGETSYNC = -0x3fdf96d3
+ SIOCGETVIFCNT = -0x3feb8dec
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = -0x3fdf96f3
+ SIOCGIFBRDADDR = -0x3fdf96e9
+ SIOCGIFCONF = -0x3ff796a4
+ SIOCGIFDSTADDR = -0x3fdf96f1
+ SIOCGIFFLAGS = -0x3fdf96ef
+ SIOCGIFHWADDR = -0x3fdf9647
+ SIOCGIFINDEX = -0x3fdf96a6
+ SIOCGIFMEM = -0x3fdf96ed
+ SIOCGIFMETRIC = -0x3fdf96e5
+ SIOCGIFMTU = -0x3fdf96ea
+ SIOCGIFMUXID = -0x3fdf96a8
+ SIOCGIFNETMASK = -0x3fdf96e7
+ SIOCGIFNUM = 0x40046957
+ SIOCGIP6ADDRPOLICY = -0x3fff965e
+ SIOCGIPMSFILTER = -0x3ffb964c
+ SIOCGLIFADDR = -0x3f87968f
+ SIOCGLIFBINDING = -0x3f879666
+ SIOCGLIFBRDADDR = -0x3f879685
+ SIOCGLIFCONF = -0x3fef965b
+ SIOCGLIFDADSTATE = -0x3f879642
+ SIOCGLIFDSTADDR = -0x3f87968d
+ SIOCGLIFFLAGS = -0x3f87968b
+ SIOCGLIFGROUPINFO = -0x3f4b9663
+ SIOCGLIFGROUPNAME = -0x3f879664
+ SIOCGLIFHWADDR = -0x3f879640
+ SIOCGLIFINDEX = -0x3f87967b
+ SIOCGLIFLNKINFO = -0x3f879674
+ SIOCGLIFMETRIC = -0x3f879681
+ SIOCGLIFMTU = -0x3f879686
+ SIOCGLIFMUXID = -0x3f87967d
+ SIOCGLIFNETMASK = -0x3f879683
+ SIOCGLIFNUM = -0x3ff3967e
+ SIOCGLIFSRCOF = -0x3fef964f
+ SIOCGLIFSUBNET = -0x3f879676
+ SIOCGLIFTOKEN = -0x3f879678
+ SIOCGLIFUSESRC = -0x3f879651
+ SIOCGLIFZONE = -0x3f879656
+ SIOCGLOWAT = 0x40047303
+ SIOCGMSFILTER = -0x3ffb964e
+ SIOCGPGRP = 0x40047309
+ SIOCGSTAMP = -0x3fef9646
+ SIOCGXARP = -0x3fff9659
+ SIOCIFDETACH = -0x7fdf96c8
+ SIOCILB = -0x3ffb9645
+ SIOCLIFADDIF = -0x3f879691
+ SIOCLIFDELND = -0x7f879673
+ SIOCLIFGETND = -0x3f879672
+ SIOCLIFREMOVEIF = -0x7f879692
+ SIOCLIFSETND = -0x7f879671
+ SIOCLIPSECONFIG = -0x7ffb9668
+ SIOCLOWER = -0x7fdf96d7
+ SIOCSARP = -0x7fdb96e2
+ SIOCSCTPGOPT = -0x3fef9653
+ SIOCSCTPPEELOFF = -0x3ffb9652
+ SIOCSCTPSOPT = -0x7fef9654
+ SIOCSENABLESDP = -0x3ffb9649
+ SIOCSETPROP = -0x7ffb8f43
+ SIOCSETSYNC = -0x7fdf96d4
+ SIOCSHIWAT = -0x7ffb8d00
+ SIOCSIFADDR = -0x7fdf96f4
+ SIOCSIFBRDADDR = -0x7fdf96e8
+ SIOCSIFDSTADDR = -0x7fdf96f2
+ SIOCSIFFLAGS = -0x7fdf96f0
+ SIOCSIFINDEX = -0x7fdf96a5
+ SIOCSIFMEM = -0x7fdf96ee
+ SIOCSIFMETRIC = -0x7fdf96e4
+ SIOCSIFMTU = -0x7fdf96eb
+ SIOCSIFMUXID = -0x7fdf96a7
+ SIOCSIFNAME = -0x7fdf96b7
+ SIOCSIFNETMASK = -0x7fdf96e6
+ SIOCSIP6ADDRPOLICY = -0x7fff965d
+ SIOCSIPMSFILTER = -0x7ffb964b
+ SIOCSIPSECONFIG = -0x7ffb966a
+ SIOCSLGETREQ = -0x3fdf96b9
+ SIOCSLIFADDR = -0x7f879690
+ SIOCSLIFBRDADDR = -0x7f879684
+ SIOCSLIFDSTADDR = -0x7f87968e
+ SIOCSLIFFLAGS = -0x7f87968c
+ SIOCSLIFGROUPNAME = -0x7f879665
+ SIOCSLIFINDEX = -0x7f87967a
+ SIOCSLIFLNKINFO = -0x7f879675
+ SIOCSLIFMETRIC = -0x7f879680
+ SIOCSLIFMTU = -0x7f879687
+ SIOCSLIFMUXID = -0x7f87967c
+ SIOCSLIFNAME = -0x3f87967f
+ SIOCSLIFNETMASK = -0x7f879682
+ SIOCSLIFPREFIX = -0x3f879641
+ SIOCSLIFSUBNET = -0x7f879677
+ SIOCSLIFTOKEN = -0x7f879679
+ SIOCSLIFUSESRC = -0x7f879650
+ SIOCSLIFZONE = -0x7f879655
+ SIOCSLOWAT = -0x7ffb8cfe
+ SIOCSLSTAT = -0x7fdf96b8
+ SIOCSMSFILTER = -0x7ffb964d
+ SIOCSPGRP = -0x7ffb8cf8
+ SIOCSPROMISC = -0x7ffb96d0
+ SIOCSQPTR = -0x3ffb9648
+ SIOCSSDSTATS = -0x3fdf96d2
+ SIOCSSESTATS = -0x3fdf96d1
+ SIOCSXARP = -0x7fff965a
+ SIOCTMYADDR = -0x3ff79670
+ SIOCTMYSITE = -0x3ff7966e
+ SIOCTONLINK = -0x3ff7966f
+ SIOCUPPER = -0x7fdf96d8
+ SIOCX25RCV = -0x3fdf96c4
+ SIOCX25TBL = -0x3fdf96c3
+ SIOCX25XMT = -0x3fdf96c5
+ SIOCXPROTO = 0x20007337
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DGRAM = 0x1
+ SOCK_NDELAY = 0x200000
+ SOCK_NONBLOCK = 0x100000
+ SOCK_RAW = 0x4
+ SOCK_RDM = 0x5
+ SOCK_SEQPACKET = 0x6
+ SOCK_STREAM = 0x2
+ SOCK_TYPE_MASK = 0xffff
+ SOL_FILTER = 0xfffc
+ SOL_PACKET = 0xfffd
+ SOL_ROUTE = 0xfffe
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_ALL = 0x3f
+ SO_ALLZONES = 0x1014
+ SO_ANON_MLP = 0x100a
+ SO_ATTACH_FILTER = 0x40000001
+ SO_BAND = 0x4000
+ SO_BROADCAST = 0x20
+ SO_COPYOPT = 0x80000
+ SO_DEBUG = 0x1
+ SO_DELIM = 0x8000
+ SO_DETACH_FILTER = 0x40000002
+ SO_DGRAM_ERRIND = 0x200
+ SO_DOMAIN = 0x100c
+ SO_DONTLINGER = -0x81
+ SO_DONTROUTE = 0x10
+ SO_ERROPT = 0x40000
+ SO_ERROR = 0x1007
+ SO_EXCLBIND = 0x1015
+ SO_HIWAT = 0x10
+ SO_ISNTTY = 0x800
+ SO_ISTTY = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_LOWAT = 0x20
+ SO_MAC_EXEMPT = 0x100b
+ SO_MAC_IMPLICIT = 0x1016
+ SO_MAXBLK = 0x100000
+ SO_MAXPSZ = 0x8
+ SO_MINPSZ = 0x4
+ SO_MREADOFF = 0x80
+ SO_MREADON = 0x40
+ SO_NDELOFF = 0x200
+ SO_NDELON = 0x100
+ SO_NODELIM = 0x10000
+ SO_OOBINLINE = 0x100
+ SO_PROTOTYPE = 0x1009
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVPSH = 0x100d
+ SO_RCVTIMEO = 0x1006
+ SO_READOPT = 0x1
+ SO_RECVUCRED = 0x400
+ SO_REUSEADDR = 0x4
+ SO_SECATTR = 0x1011
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_STRHOLD = 0x20000
+ SO_TAIL = 0x200000
+ SO_TIMESTAMP = 0x1013
+ SO_TONSTOP = 0x2000
+ SO_TOSTOP = 0x1000
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ SO_VRRP = 0x1017
+ SO_WROFF = 0x2
+ TCFLSH = 0x5407
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_ABORT_THRESHOLD = 0x11
+ TCP_ANONPRIVBIND = 0x20
+ TCP_CONN_ABORT_THRESHOLD = 0x13
+ TCP_CONN_NOTIFY_THRESHOLD = 0x12
+ TCP_CORK = 0x18
+ TCP_EXCLBIND = 0x21
+ TCP_INIT_CWND = 0x15
+ TCP_KEEPALIVE = 0x8
+ TCP_KEEPALIVE_ABORT_THRESHOLD = 0x17
+ TCP_KEEPALIVE_THRESHOLD = 0x16
+ TCP_KEEPCNT = 0x23
+ TCP_KEEPIDLE = 0x22
+ TCP_KEEPINTVL = 0x24
+ TCP_LINGER2 = 0x1c
+ TCP_MAXSEG = 0x2
+ TCP_MSS = 0x218
+ TCP_NODELAY = 0x1
+ TCP_NOTIFY_THRESHOLD = 0x10
+ TCP_RECVDSTADDR = 0x14
+ TCP_RTO_INITIAL = 0x19
+ TCP_RTO_MAX = 0x1b
+ TCP_RTO_MIN = 0x1a
+ TCSAFLUSH = 0x5410
+ TIOC = 0x5400
+ TIOCCBRK = 0x747a
+ TIOCCDTR = 0x7478
+ TIOCCILOOP = 0x746c
+ TIOCEXCL = 0x740d
+ TIOCFLUSH = 0x7410
+ TIOCGETC = 0x7412
+ TIOCGETD = 0x7400
+ TIOCGETP = 0x7408
+ TIOCGLTC = 0x7474
+ TIOCGPGRP = 0x7414
+ TIOCGPPS = 0x547d
+ TIOCGPPSEV = 0x547f
+ TIOCGSID = 0x7416
+ TIOCGSOFTCAR = 0x5469
+ TIOCGWINSZ = 0x5468
+ TIOCHPCL = 0x7402
+ TIOCKBOF = 0x5409
+ TIOCKBON = 0x5408
+ TIOCLBIC = 0x747e
+ TIOCLBIS = 0x747f
+ TIOCLGET = 0x747c
+ TIOCLSET = 0x747d
+ TIOCMBIC = 0x741c
+ TIOCMBIS = 0x741b
+ TIOCMGET = 0x741d
+ TIOCMSET = 0x741a
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x7471
+ TIOCNXCL = 0x740e
+ TIOCOUTQ = 0x7473
+ TIOCREMOTE = 0x741e
+ TIOCSBRK = 0x747b
+ TIOCSCTTY = 0x7484
+ TIOCSDTR = 0x7479
+ TIOCSETC = 0x7411
+ TIOCSETD = 0x7401
+ TIOCSETN = 0x740a
+ TIOCSETP = 0x7409
+ TIOCSIGNAL = 0x741f
+ TIOCSILOOP = 0x746d
+ TIOCSLTC = 0x7475
+ TIOCSPGRP = 0x7415
+ TIOCSPPS = 0x547e
+ TIOCSSOFTCAR = 0x546a
+ TIOCSTART = 0x746e
+ TIOCSTI = 0x7417
+ TIOCSTOP = 0x746f
+ TIOCSWINSZ = 0x5467
+ TOSTOP = 0x100
+ VCEOF = 0x8
+ VCEOL = 0x9
+ VDISCARD = 0xd
+ VDSUSP = 0xb
+ VEOF = 0x4
+ VEOL = 0x5
+ VEOL2 = 0x6
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x4
+ VQUIT = 0x1
+ VREPRINT = 0xc
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VSWTCH = 0x7
+ VT0 = 0x0
+ VT1 = 0x4000
+ VTDLY = 0x4000
+ VTIME = 0x5
+ VWERASE = 0xe
+ WCONTFLG = 0xffff
+ WCONTINUED = 0x8
+ WCOREFLG = 0x80
+ WEXITED = 0x1
+ WNOHANG = 0x40
+ WNOWAIT = 0x80
+ WOPTMASK = 0xcf
+ WRAP = 0x20000
+ WSIGMASK = 0x7f
+ WSTOPFLG = 0x7f
+ WSTOPPED = 0x4
+ WTRAPPED = 0x2
+ WUNTRACED = 0x4
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x7d)
+ EADDRNOTAVAIL = Errno(0x7e)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x7c)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x95)
+ EBADE = Errno(0x32)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x51)
+ EBADMSG = Errno(0x4d)
+ EBADR = Errno(0x33)
+ EBADRQC = Errno(0x36)
+ EBADSLT = Errno(0x37)
+ EBFONT = Errno(0x39)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x2f)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x25)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x82)
+ ECONNREFUSED = Errno(0x92)
+ ECONNRESET = Errno(0x83)
+ EDEADLK = Errno(0x2d)
+ EDEADLOCK = Errno(0x38)
+ EDESTADDRREQ = Errno(0x60)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x31)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x93)
+ EHOSTUNREACH = Errno(0x94)
+ EIDRM = Errno(0x24)
+ EILSEQ = Errno(0x58)
+ EINPROGRESS = Errno(0x96)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x85)
+ EISDIR = Errno(0x15)
+ EL2HLT = Errno(0x2c)
+ EL2NSYNC = Errno(0x26)
+ EL3HLT = Errno(0x27)
+ EL3RST = Errno(0x28)
+ ELIBACC = Errno(0x53)
+ ELIBBAD = Errno(0x54)
+ ELIBEXEC = Errno(0x57)
+ ELIBMAX = Errno(0x56)
+ ELIBSCN = Errno(0x55)
+ ELNRNG = Errno(0x29)
+ ELOCKUNMAPPED = Errno(0x48)
+ ELOOP = Errno(0x5a)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x61)
+ EMULTIHOP = Errno(0x4a)
+ ENAMETOOLONG = Errno(0x4e)
+ ENETDOWN = Errno(0x7f)
+ ENETRESET = Errno(0x81)
+ ENETUNREACH = Errno(0x80)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x35)
+ ENOBUFS = Errno(0x84)
+ ENOCSI = Errno(0x2b)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x2e)
+ ENOLINK = Errno(0x43)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x23)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x63)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x59)
+ ENOTACTIVE = Errno(0x49)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x86)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x5d)
+ ENOTRECOVERABLE = Errno(0x3b)
+ ENOTSOCK = Errno(0x5f)
+ ENOTSUP = Errno(0x30)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x50)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x7a)
+ EOVERFLOW = Errno(0x4f)
+ EOWNERDEAD = Errno(0x3a)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x7b)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x78)
+ EPROTOTYPE = Errno(0x62)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x52)
+ EREMOTE = Errno(0x42)
+ ERESTART = Errno(0x5b)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x8f)
+ ESOCKTNOSUPPORT = Errno(0x79)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x97)
+ ESTRPIPE = Errno(0x5c)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x91)
+ ETOOMANYREFS = Errno(0x90)
+ ETXTBSY = Errno(0x1a)
+ EUNATCH = Errno(0x2a)
+ EUSERS = Errno(0x5e)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x34)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCANCEL = Signal(0x24)
+ SIGCHLD = Signal(0x12)
+ SIGCLD = Signal(0x12)
+ SIGCONT = Signal(0x19)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGFREEZE = Signal(0x22)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x16)
+ SIGIOT = Signal(0x6)
+ SIGJVM1 = Signal(0x27)
+ SIGJVM2 = Signal(0x28)
+ SIGKILL = Signal(0x9)
+ SIGLOST = Signal(0x25)
+ SIGLWP = Signal(0x21)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x16)
+ SIGPROF = Signal(0x1d)
+ SIGPWR = Signal(0x13)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x17)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHAW = Signal(0x23)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x18)
+ SIGTTIN = Signal(0x1a)
+ SIGTTOU = Signal(0x1b)
+ SIGURG = Signal(0x15)
+ SIGUSR1 = Signal(0x10)
+ SIGUSR2 = Signal(0x11)
+ SIGVTALRM = Signal(0x1c)
+ SIGWAITING = Signal(0x20)
+ SIGWINCH = Signal(0x14)
+ SIGXCPU = Signal(0x1e)
+ SIGXFSZ = Signal(0x1f)
+ SIGXRES = Signal(0x26)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "not owner",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "I/O error",
+ 6: "no such device or address",
+ 7: "arg list too long",
+ 8: "exec format error",
+ 9: "bad file number",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "not enough space",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "file table overflow",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "argument out of domain",
+ 34: "result too large",
+ 35: "no message of desired type",
+ 36: "identifier removed",
+ 37: "channel number out of range",
+ 38: "level 2 not synchronized",
+ 39: "level 3 halted",
+ 40: "level 3 reset",
+ 41: "link number out of range",
+ 42: "protocol driver not attached",
+ 43: "no CSI structure available",
+ 44: "level 2 halted",
+ 45: "deadlock situation detected/avoided",
+ 46: "no record locks available",
+ 47: "operation canceled",
+ 48: "operation not supported",
+ 49: "disc quota exceeded",
+ 50: "bad exchange descriptor",
+ 51: "bad request descriptor",
+ 52: "message tables full",
+ 53: "anode table overflow",
+ 54: "bad request code",
+ 55: "invalid slot",
+ 56: "file locking deadlock",
+ 57: "bad font file format",
+ 58: "owner of the lock died",
+ 59: "lock is not recoverable",
+ 60: "not a stream device",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of stream resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 72: "locked lock was unmapped ",
+ 73: "facility is not active",
+ 74: "multihop attempted",
+ 77: "not a data message",
+ 78: "file name too long",
+ 79: "value too large for defined data type",
+ 80: "name not unique on network",
+ 81: "file descriptor in bad state",
+ 82: "remote address changed",
+ 83: "can not access a needed shared library",
+ 84: "accessing a corrupted shared library",
+ 85: ".lib section in a.out corrupted",
+ 86: "attempting to link in more shared libraries than system limit",
+ 87: "can not exec a shared library directly",
+ 88: "illegal byte sequence",
+ 89: "operation not applicable",
+ 90: "number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS",
+ 91: "error 91",
+ 92: "error 92",
+ 93: "directory not empty",
+ 94: "too many users",
+ 95: "socket operation on non-socket",
+ 96: "destination address required",
+ 97: "message too long",
+ 98: "protocol wrong type for socket",
+ 99: "option not supported by protocol",
+ 120: "protocol not supported",
+ 121: "socket type not supported",
+ 122: "operation not supported on transport endpoint",
+ 123: "protocol family not supported",
+ 124: "address family not supported by protocol family",
+ 125: "address already in use",
+ 126: "cannot assign requested address",
+ 127: "network is down",
+ 128: "network is unreachable",
+ 129: "network dropped connection because of reset",
+ 130: "software caused connection abort",
+ 131: "connection reset by peer",
+ 132: "no buffer space available",
+ 133: "transport endpoint is already connected",
+ 134: "transport endpoint is not connected",
+ 143: "cannot send after socket shutdown",
+ 144: "too many references: cannot splice",
+ 145: "connection timed out",
+ 146: "connection refused",
+ 147: "host is down",
+ 148: "no route to host",
+ 149: "operation already in progress",
+ 150: "operation now in progress",
+ 151: "stale NFS file handle",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal Instruction",
+ 5: "trace/Breakpoint Trap",
+ 6: "abort",
+ 7: "emulation Trap",
+ 8: "arithmetic Exception",
+ 9: "killed",
+ 10: "bus Error",
+ 11: "segmentation Fault",
+ 12: "bad System Call",
+ 13: "broken Pipe",
+ 14: "alarm Clock",
+ 15: "terminated",
+ 16: "user Signal 1",
+ 17: "user Signal 2",
+ 18: "child Status Changed",
+ 19: "power-Fail/Restart",
+ 20: "window Size Change",
+ 21: "urgent Socket Condition",
+ 22: "pollable Event",
+ 23: "stopped (signal)",
+ 24: "stopped (user)",
+ 25: "continued",
+ 26: "stopped (tty input)",
+ 27: "stopped (tty output)",
+ 28: "virtual Timer Expired",
+ 29: "profiling Timer Expired",
+ 30: "cpu Limit Exceeded",
+ 31: "file Size Limit Exceeded",
+ 32: "no runnable lwp",
+ 33: "inter-lwp signal",
+ 34: "checkpoint Freeze",
+ 35: "checkpoint Thaw",
+ 36: "thread Cancellation",
+ 37: "resource Lost",
+ 38: "resource Control Exceeded",
+ 39: "reserved for JVM 1",
+ 40: "reserved for JVM 2",
+}
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 98500792d..a6a176b60 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index ee810e076..f5867c45d 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_386.go b/src/pkg/syscall/zsyscall_dragonfly_386.go
index 5c3fe0713..0ec813232 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_386.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_amd64.go b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
index c7766a8c3..8c7cce54e 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 631994fba..5befe83c6 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 1d5180853..ab2eb80c6 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
}
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_arm.go b/src/pkg/syscall/zsyscall_freebsd_arm.go
index 925b83fbb..c1f0f907c 100644
--- a/src/pkg/syscall/zsyscall_freebsd_arm.go
+++ b/src/pkg/syscall/zsyscall_freebsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -418,13 +419,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
@@ -505,7 +501,7 @@ func Fsync(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Ftruncate(fd int, length int64) (err error) {
- _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
+ _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
if e1 != 0 {
err = e1
}
@@ -555,23 +551,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
@@ -858,7 +837,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
} else {
_p0 = unsafe.Pointer(&_zero)
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
n = int(r0)
if e1 != 0 {
err = e1
@@ -875,7 +854,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
} else {
_p0 = unsafe.Pointer(&_zero)
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
if e1 != 0 {
err = e1
@@ -958,7 +954,7 @@ func Rmdir(path string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
- r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
+ r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
if e1 != 0 {
err = e1
@@ -1170,7 +1166,7 @@ func Truncate(path string, length int64) (err error) {
if err != nil {
return
}
- _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
+ _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
if e1 != 0 {
err = e1
}
@@ -1232,9 +1228,15 @@ func Unmount(path string, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
- r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
- ret = uintptr(r0)
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -1243,8 +1245,9 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (err error) {
- _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
+ ret = uintptr(r0)
if e1 != 0 {
err = e1
}
@@ -1253,15 +1256,8 @@ func munmap(addr uintptr, length uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
- n = int(r0)
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
if e1 != 0 {
err = e1
}
@@ -1270,14 +1266,8 @@ func read(fd int, p []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = e1
@@ -1287,8 +1277,8 @@ func write(fd int, p []byte) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = e1
@@ -1298,9 +1288,9 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
- n = int(r0)
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ nfd = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index c1c3d4511..c65448e21 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -1763,7 +1763,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1773,7 +1773,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1804,7 +1804,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -1814,7 +1814,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -1882,7 +1882,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -1909,8 +1909,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 3380714a6..a970ce6dc 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1383,7 +1383,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1393,7 +1393,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -1424,7 +1424,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -1434,7 +1434,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -1492,7 +1492,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -1529,8 +1529,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
new file mode 100644
index 000000000..32eed339a
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_386.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+ _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+ _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+ _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_amd64p32.go b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
new file mode 100644
index 000000000..8bc81fac9
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+ _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+ _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+ _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_netbsd_386.go b/src/pkg/syscall/zsyscall_netbsd_386.go
index 0ee19bee1..281208f41 100644
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_amd64.go b/src/pkg/syscall/zsyscall_netbsd_amd64.go
index b9d272144..ed9a87df6 100644
--- a/src/pkg/syscall/zsyscall_netbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_netbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_arm.go b/src/pkg/syscall/zsyscall_netbsd_arm.go
index 763a906e5..c5c9a9f2c 100644
--- a/src/pkg/syscall/zsyscall_netbsd_arm.go
+++ b/src/pkg/syscall/zsyscall_netbsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -435,13 +436,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_openbsd_386.go b/src/pkg/syscall/zsyscall_openbsd_386.go
index 2c2a56732..785e7c3b8 100644
--- a/src/pkg/syscall/zsyscall_openbsd_386.go
+++ b/src/pkg/syscall/zsyscall_openbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getegid() (egid int) {
r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_openbsd_amd64.go b/src/pkg/syscall/zsyscall_openbsd_amd64.go
index 4e1470696..7a8d9b6f1 100644
--- a/src/pkg/syscall/zsyscall_openbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_openbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
if e1 != 0 {
err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
- _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
if e1 != 0 {
err = e1
}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getegid() (egid int) {
r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Getgid() (gid int) {
r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_solaris_amd64.go b/src/pkg/syscall/zsyscall_solaris_amd64.go
new file mode 100644
index 000000000..8847cad01
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_solaris_amd64.go
@@ -0,0 +1,883 @@
+// mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+ modlibc = newLazySO("libc.so")
+ modlibsocket = newLazySO("libsocket.so")
+
+ procgetgroups = modlibc.NewProc("getgroups")
+ procsetgroups = modlibc.NewProc("setgroups")
+ procfcntl = modlibc.NewProc("fcntl")
+ procaccept = modlibsocket.NewProc("accept")
+ procsendmsg = modlibsocket.NewProc("sendmsg")
+ procAccess = modlibc.NewProc("access")
+ procAdjtime = modlibc.NewProc("adjtime")
+ procChdir = modlibc.NewProc("chdir")
+ procChmod = modlibc.NewProc("chmod")
+ procChown = modlibc.NewProc("chown")
+ procChroot = modlibc.NewProc("chroot")
+ procClose = modlibc.NewProc("close")
+ procDup = modlibc.NewProc("dup")
+ procExit = modlibc.NewProc("exit")
+ procFchdir = modlibc.NewProc("fchdir")
+ procFchmod = modlibc.NewProc("fchmod")
+ procFchown = modlibc.NewProc("fchown")
+ procFpathconf = modlibc.NewProc("fpathconf")
+ procFstat = modlibc.NewProc("fstat")
+ procGetdents = modlibc.NewProc("getdents")
+ procGetgid = modlibc.NewProc("getgid")
+ procGetpid = modlibc.NewProc("getpid")
+ procGeteuid = modlibc.NewProc("geteuid")
+ procGetegid = modlibc.NewProc("getegid")
+ procGetppid = modlibc.NewProc("getppid")
+ procGetpriority = modlibc.NewProc("getpriority")
+ procGetrlimit = modlibc.NewProc("getrlimit")
+ procGettimeofday = modlibc.NewProc("gettimeofday")
+ procGetuid = modlibc.NewProc("getuid")
+ procKill = modlibc.NewProc("kill")
+ procLchown = modlibc.NewProc("lchown")
+ procLink = modlibc.NewProc("link")
+ proclisten = modlibsocket.NewProc("listen")
+ procLstat = modlibc.NewProc("lstat")
+ procMkdir = modlibc.NewProc("mkdir")
+ procMknod = modlibc.NewProc("mknod")
+ procNanosleep = modlibc.NewProc("nanosleep")
+ procOpen = modlibc.NewProc("open")
+ procPathconf = modlibc.NewProc("pathconf")
+ procPread = modlibc.NewProc("pread")
+ procPwrite = modlibc.NewProc("pwrite")
+ procread = modlibc.NewProc("read")
+ procReadlink = modlibc.NewProc("readlink")
+ procRename = modlibc.NewProc("rename")
+ procRmdir = modlibc.NewProc("rmdir")
+ proclseek = modlibc.NewProc("lseek")
+ procSetegid = modlibc.NewProc("setegid")
+ procSeteuid = modlibc.NewProc("seteuid")
+ procSetgid = modlibc.NewProc("setgid")
+ procSetpgid = modlibc.NewProc("setpgid")
+ procSetpriority = modlibc.NewProc("setpriority")
+ procSetregid = modlibc.NewProc("setregid")
+ procSetreuid = modlibc.NewProc("setreuid")
+ procSetrlimit = modlibc.NewProc("setrlimit")
+ procSetsid = modlibc.NewProc("setsid")
+ procSetuid = modlibc.NewProc("setuid")
+ procshutdown = modlibsocket.NewProc("shutdown")
+ procStat = modlibc.NewProc("stat")
+ procSymlink = modlibc.NewProc("symlink")
+ procSync = modlibc.NewProc("sync")
+ procTruncate = modlibc.NewProc("truncate")
+ procFsync = modlibc.NewProc("fsync")
+ procFtruncate = modlibc.NewProc("ftruncate")
+ procUmask = modlibc.NewProc("umask")
+ procUnlink = modlibc.NewProc("unlink")
+ procUtimes = modlibc.NewProc("utimes")
+ procbind = modlibsocket.NewProc("bind")
+ procconnect = modlibsocket.NewProc("connect")
+ procmmap = modlibc.NewProc("mmap")
+ procmunmap = modlibc.NewProc("munmap")
+ procsendto = modlibsocket.NewProc("sendto")
+ procsocket = modlibsocket.NewProc("socket")
+ procsocketpair = modlibsocket.NewProc("socketpair")
+ procwrite = modlibc.NewProc("write")
+ procgetsockopt = modlibsocket.NewProc("getsockopt")
+ procgetpeername = modlibsocket.NewProc("getpeername")
+ procgetsockname = modlibsocket.NewProc("getsockname")
+ procsetsockopt = modlibsocket.NewProc("setsockopt")
+ procrecvfrom = modlibsocket.NewProc("recvfrom")
+ procrecvmsg = modlibsocket.NewProc("recvmsg")
+)
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Access(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Close(fd int) (err error) {
+ _, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Exit(code int) {
+ sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
+ return
+}
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getgid() (gid int) {
+ r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+func Getpid() (pid int) {
+ r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+func Geteuid() (euid int) {
+ r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+func Getegid() (egid int) {
+ r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+func Getppid() (ppid int) {
+ r0, _, _ := sysvicall6(procGetppid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+func Getpriority(which int, who int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getuid() (uid int) {
+ r0, _, _ := rawSysvicall6(procGetuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+func Kill(pid int, signum Signal) (err error) {
+ _, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Link(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pathconf(path string, name int) (val int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ if len(buf) > 0 {
+ _p1 = &buf[0]
+ }
+ r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Rename(from string, to string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(from)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(to)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+ newoffset = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Symlink(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Sync() (err error) {
+ _, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ _, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := sysvicall6(procrecvfrom.Addr(), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 3cd12dd47..132adafef 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl -l32 syscall_windows.go security_windows.go syscall_windows_386.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_386.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
return
}
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
return
}
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index d23c2311a..353a6fd98 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl syscall_windows.go security_windows.go syscall_windows_amd64.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_amd64.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
return
}
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
return
}
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
diff --git a/src/pkg/syscall/zsysctl_openbsd.go b/src/pkg/syscall/zsysctl_openbsd.go
index a5914f3f0..923b2c29f 100644
--- a/src/pkg/syscall/zsysctl_openbsd.go
+++ b/src/pkg/syscall/zsysctl_openbsd.go
@@ -48,8 +48,7 @@ var sysctlMib = []mibentry{
{"kern.cp_time2", []_C_int{1, 71}},
{"kern.cryptodevallowsoft", []_C_int{1, 53}},
{"kern.domainname", []_C_int{1, 22}},
- {"kern.file", []_C_int{1, 15}},
- {"kern.file2", []_C_int{1, 73}},
+ {"kern.file", []_C_int{1, 73}},
{"kern.forkstat", []_C_int{1, 42}},
{"kern.fscale", []_C_int{1, 46}},
{"kern.fsync", []_C_int{1, 33}},
@@ -87,7 +86,6 @@ var sysctlMib = []mibentry{
{"kern.proc", []_C_int{1, 66}},
{"kern.random", []_C_int{1, 31}},
{"kern.rawpartition", []_C_int{1, 24}},
- {"kern.rthreads", []_C_int{1, 74}},
{"kern.saved_ids", []_C_int{1, 20}},
{"kern.securelevel", []_C_int{1, 9}},
{"kern.seminfo", []_C_int{1, 61}},
@@ -226,8 +224,6 @@ var sysctlMib = []mibentry{
{"net.inet6.ip6.forwsrcrt", []_C_int{4, 24, 17, 5}},
{"net.inet6.ip6.hdrnestlimit", []_C_int{4, 24, 17, 15}},
{"net.inet6.ip6.hlim", []_C_int{4, 24, 17, 3}},
- {"net.inet6.ip6.kame_version", []_C_int{4, 24, 17, 20}},
- {"net.inet6.ip6.keepfaith", []_C_int{4, 24, 17, 13}},
{"net.inet6.ip6.log_interval", []_C_int{4, 24, 17, 14}},
{"net.inet6.ip6.maxdynroutes", []_C_int{4, 24, 17, 48}},
{"net.inet6.ip6.maxfragpackets", []_C_int{4, 24, 17, 9}},
@@ -236,7 +232,7 @@ var sysctlMib = []mibentry{
{"net.inet6.ip6.maxifprefixes", []_C_int{4, 24, 17, 46}},
{"net.inet6.ip6.mforwarding", []_C_int{4, 24, 17, 42}},
{"net.inet6.ip6.mrtproto", []_C_int{4, 24, 17, 8}},
- {"net.inet6.ip6.mtu", []_C_int{4, 24, 17, 4}},
+ {"net.inet6.ip6.mtudisctimeout", []_C_int{4, 24, 17, 50}},
{"net.inet6.ip6.multicast_mtudisc", []_C_int{4, 24, 17, 44}},
{"net.inet6.ip6.multipath", []_C_int{4, 24, 17, 43}},
{"net.inet6.ip6.neighborgcthresh", []_C_int{4, 24, 17, 45}},
@@ -258,26 +254,6 @@ var sysctlMib = []mibentry{
{"net.mpls.ttl", []_C_int{4, 33, 2}},
{"net.pflow.stats", []_C_int{4, 34, 1}},
{"net.pipex.enable", []_C_int{4, 35, 1}},
- {"user.bc_base_max", []_C_int{8, 2}},
- {"user.bc_dim_max", []_C_int{8, 3}},
- {"user.bc_scale_max", []_C_int{8, 4}},
- {"user.bc_string_max", []_C_int{8, 5}},
- {"user.coll_weights_max", []_C_int{8, 6}},
- {"user.cs_path", []_C_int{8, 1}},
- {"user.expr_nest_max", []_C_int{8, 7}},
- {"user.line_max", []_C_int{8, 8}},
- {"user.posix2_c_bind", []_C_int{8, 11}},
- {"user.posix2_c_dev", []_C_int{8, 12}},
- {"user.posix2_char_term", []_C_int{8, 13}},
- {"user.posix2_fort_dev", []_C_int{8, 14}},
- {"user.posix2_fort_run", []_C_int{8, 15}},
- {"user.posix2_localedef", []_C_int{8, 16}},
- {"user.posix2_sw_dev", []_C_int{8, 17}},
- {"user.posix2_upe", []_C_int{8, 18}},
- {"user.posix2_version", []_C_int{8, 10}},
- {"user.re_dup_max", []_C_int{8, 9}},
- {"user.stream_max", []_C_int{8, 19}},
- {"user.tzname_max", []_C_int{8, 20}},
{"vm.anonmin", []_C_int{2, 7}},
{"vm.loadavg", []_C_int{2, 2}},
{"vm.maxslp", []_C_int{2, 10}},
diff --git a/src/pkg/syscall/zsysnum_dragonfly_386.go b/src/pkg/syscall/zsysnum_dragonfly_386.go
index 68eeb32ac..4b086b921 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_386.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_386.go
@@ -115,9 +115,6 @@ const (
SYS_UNAME = 164 // { int uname(struct utsname *name); }
SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
- SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, \
- SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, \
- SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); }
SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \
SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \
SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \
SYS_EACCESS = 532 // { int eaccess(char *path, int flags); }
SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); }
+ SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+ SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
)
diff --git a/src/pkg/syscall/zsysnum_dragonfly_amd64.go b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
index 68eeb32ac..4b086b921 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
@@ -115,9 +115,6 @@ const (
SYS_UNAME = 164 // { int uname(struct utsname *name); }
SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
- SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, \
- SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, \
- SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); }
SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \
SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \
SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \
SYS_EACCESS = 532 // { int eaccess(char *path, int flags); }
SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); }
+ SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+ SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index 74400b6f6..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index 74400b6f6..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_arm.go b/src/pkg/syscall/zsysnum_freebsd_arm.go
index 61a6a3295..dfca558bb 100644
--- a/src/pkg/syscall/zsysnum_freebsd_arm.go
+++ b/src/pkg/syscall/zsysnum_freebsd_arm.go
@@ -34,8 +34,8 @@ const (
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
SYS_ACCESS = 33 // { int access(char *path, int amode); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
+ SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file( \
+ SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_EXTATTR_SET_FD = 371 // { int extattr_set_fd(int fd, \
+ SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \
SYS_KENV = 390 // { int kenv(int what, const char *name, \
- SYS_LCHFLAGS = 391 // { int lchflags(const char *path, int flags); }
+ SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \
- SYS_EXTATTR_SET_LINK = 412 // { int extattr_set_link( \
+ SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -322,7 +322,7 @@ const (
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }
- SYS_CAP_RIGHTS_GET = 515 // { int cap_rights_get(int fd, \
+ SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
@@ -338,10 +338,11 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
- SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
- SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \
- SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \
- SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \
- SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \
- SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \
+ SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \
+ SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \
+ SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \
+ SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \
+ SYS_ACCEPT4 = 541 // { int accept4(int s, \
+ SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
+ SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \
)
diff --git a/src/pkg/syscall/zsysnum_openbsd_386.go b/src/pkg/syscall/zsysnum_openbsd_386.go
index 82c98b90e..3b9ac4c94 100644
--- a/src/pkg/syscall/zsysnum_openbsd_386.go
+++ b/src/pkg/syscall/zsysnum_openbsd_386.go
@@ -10,10 +10,10 @@ const (
SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
SYS_OPEN = 5 // { int sys_open(const char *path, \
SYS_CLOSE = 6 // { int sys_close(int fd); }
- SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \
SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \
SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); }
+ SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \
SYS_GETPID = 20 // { pid_t sys_getpid(void); }
SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
SYS_SYNC = 36 // { void sys_sync(void); }
SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); }
SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \
SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
SYS_ACCT = 51 // { int sys_acct(const char *path); }
SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); }
SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
SYS_REBOOT = 55 // { int sys_reboot(int opt); }
SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
SYS_EXECVE = 59 // { int sys_execve(const char *path, \
SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 63 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_SETITIMER = 69 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 70 // { int sys_getitimer(int which, \
+ SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_KEVENT = 72 // { int sys_kevent(int fd, \
SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_UTIMES = 76 // { int sys_utimes(const char *path, \
+ SYS_FUTIMES = 77 // { int sys_futimes(int fd, \
SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
- SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
- SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \
+ SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \
SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
- SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \
SYS_FSYNC = 95 // { int sys_fsync(int fd); }
SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); }
SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \
+ SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
- SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
- SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
SYS_READV = 120 // { ssize_t sys_readv(int fd, \
SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
- SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
- SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
SYS_SETSID = 147 // { int sys_setsid(void); }
SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
- SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \
SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
- SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \
SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
- SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
- SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
- SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
- SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
SYS_KQUEUE = 269 // { int sys_kqueue(void); }
- SYS_KEVENT = 270 // { int sys_kevent(int fd, \
SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
- SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
- SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
- SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
- SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
- SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
- SYS_STATFS = 307 // { int sys_statfs(const char *path, \
- SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
- SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
- SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
- SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
- SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
- SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
)
diff --git a/src/pkg/syscall/zsysnum_openbsd_amd64.go b/src/pkg/syscall/zsysnum_openbsd_amd64.go
index 82c98b90e..3b9ac4c94 100644
--- a/src/pkg/syscall/zsysnum_openbsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_openbsd_amd64.go
@@ -10,10 +10,10 @@ const (
SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
SYS_OPEN = 5 // { int sys_open(const char *path, \
SYS_CLOSE = 6 // { int sys_close(int fd); }
- SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
SYS___TFORK = 8 // { int sys___tfork(const struct __tfork *param, \
SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_WAIT4 = 11 // { pid_t sys_wait4(pid_t pid, int *status, \
SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
SYS_GETDTABLECOUNT = 18 // { int sys_getdtablecount(void); }
+ SYS_GETRUSAGE = 19 // { int sys_getrusage(int who, \
SYS_GETPID = 20 // { pid_t sys_getpid(void); }
SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
SYS_SYNC = 36 // { void sys_sync(void); }
SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_STAT = 38 // { int sys_stat(const char *path, struct stat *ub); }
SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_LSTAT = 40 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_FSTATAT = 42 // { int sys_fstatat(int fd, const char *path, \
SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
SYS_ACCT = 51 // { int sys_acct(const char *path); }
SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_FSTAT = 53 // { int sys_fstat(int fd, struct stat *sb); }
SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
SYS_REBOOT = 55 // { int sys_reboot(int opt); }
SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
SYS_EXECVE = 59 // { int sys_execve(const char *path, \
SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_GETFSSTAT = 62 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 63 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 64 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 65 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_GETTIMEOFDAY = 67 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_SETTIMEOFDAY = 68 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_SETITIMER = 69 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 70 // { int sys_getitimer(int which, \
+ SYS_SELECT = 71 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_KEVENT = 72 // { int sys_kevent(int fd, \
SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_UTIMES = 76 // { int sys_utimes(const char *path, \
+ SYS_FUTIMES = 77 // { int sys_futimes(int fd, \
SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
- SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
- SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_UTIMENSAT = 84 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 85 // { int sys_futimens(int fd, \
+ SYS_CLOCK_GETTIME = 87 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 88 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 89 // { int sys_clock_getres(clockid_t clock_id, \
SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_NANOSLEEP = 91 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
- SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS___THRSLEEP = 94 // { int sys___thrsleep(const volatile void *ident, \
SYS_FSYNC = 95 // { int sys_fsync(int fd); }
SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETDENTS = 99 // { int sys_getdents(int fd, void *buf, size_t buflen); }
SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_PPOLL = 109 // { int sys_ppoll(struct pollfd *fds, \
+ SYS_PSELECT = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
- SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
- SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
SYS_READV = 120 // { ssize_t sys_readv(int fd, \
SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
- SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
- SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
SYS_SETSID = 147 // { int sys_setsid(void); }
SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
- SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS___SYSCTL = 202 // { int sys___sysctl(const int *name, u_int namelen, \
SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
- SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_UTRACE = 209 // { int sys_utrace(const char *label, const void *addr, \
SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
- SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
- SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
- SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
- SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
SYS_KQUEUE = 269 // { int sys_kqueue(void); }
- SYS_KEVENT = 270 // { int sys_kevent(int fd, \
SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
- SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
- SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
- SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
- SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
- SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
- SYS_STATFS = 307 // { int sys_statfs(const char *path, \
- SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
- SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
- SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
- SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
- SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
- SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
)
diff --git a/src/pkg/syscall/zsysnum_solaris_amd64.go b/src/pkg/syscall/zsysnum_solaris_amd64.go
new file mode 100644
index 000000000..43b3d8b40
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_solaris_amd64.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// TODO(aram): remove these before Go 1.3.
+const (
+ SYS_EXECVE = 59
+ SYS_FCNTL = 62
+)
diff --git a/src/pkg/syscall/ztypes_dragonfly_386.go b/src/pkg/syscall/ztypes_dragonfly_386.go
index c467d8593..6b6ec1525 100644
--- a/src/pkg/syscall/ztypes_dragonfly_386.go
+++ b/src/pkg/syscall/ztypes_dragonfly_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- F_DUPFD_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -427,3 +423,13 @@ type BpfHdr struct {
Hdrlen uint16
Pad_cgo_0 [2]byte
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_dragonfly_amd64.go b/src/pkg/syscall/ztypes_dragonfly_amd64.go
index b71bf29f4..954ffd7ab 100644
--- a/src/pkg/syscall/ztypes_dragonfly_amd64.go
+++ b/src/pkg/syscall/ztypes_dragonfly_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- F_DUPFD_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -433,3 +429,13 @@ type BpfHdr struct {
Hdrlen uint16
Pad_cgo_0 [6]byte
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
index e77bd4b41..b809eea37 100644
--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -282,7 +278,9 @@ type FdSet struct {
}
const (
+ sizeofIfMsghdr = 0x64
SizeofIfMsghdr = 0x60
+ sizeofIfData = 0x54
SizeofIfData = 0x50
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
@@ -291,6 +289,17 @@ const (
SizeofRtMetrics = 0x38
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -302,6 +311,34 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Hwassist uint64
+ Epoch int32
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
@@ -443,3 +480,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
index 922de2ce5..a05908aed 100644
--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -284,7 +280,9 @@ type FdSet struct {
}
const (
+ sizeofIfMsghdr = 0xa8
SizeofIfMsghdr = 0xa8
+ sizeofIfData = 0x98
SizeofIfData = 0x98
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
@@ -293,6 +291,17 @@ const (
SizeofRtMetrics = 0x70
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -304,6 +313,34 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint64
+ Metric uint64
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Hwassist uint64
+ Epoch int64
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
@@ -446,3 +483,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_arm.go b/src/pkg/syscall/ztypes_freebsd_arm.go
index b1bf83b4c..9303816f9 100644
--- a/src/pkg/syscall/ztypes_freebsd_arm.go
+++ b/src/pkg/syscall/ztypes_freebsd_arm.go
@@ -1,5 +1,5 @@
// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_freebsd.go
+// cgo -godefs -- -fsigned-char types_freebsd.go
package syscall
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
@@ -55,10 +57,6 @@ type Rlimit struct {
type _Gid_t uint32
const (
- O_CLOEXEC = 0 // not supported
-)
-
-const (
S_IFMT = 0xf000
S_IFIFO = 0x1000
S_IFCHR = 0x2000
@@ -93,7 +91,6 @@ type Stat_t struct {
Gen uint32
Lspare int32
Birthtimespec Timespec
- Pad_cgo_0 [4]byte
}
type Statfs_t struct {
@@ -122,12 +119,13 @@ type Statfs_t struct {
}
type Flock_t struct {
- Start int64
- Len int64
- Pid int32
- Type int16
- Whence int16
- Sysid int32
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+ Sysid int32
+ Pad_cgo_0 [4]byte
}
type Dirent struct {
@@ -160,22 +158,20 @@ type RawSockaddrInet6 struct {
}
type RawSockaddrUnix struct {
- Len uint8
- Family uint8
- Path [104]int8
- Pad_cgo_0 [2]byte
+ Len uint8
+ Family uint8
+ Path [104]int8
}
type RawSockaddrDatalink struct {
- Len uint8
- Family uint8
- Index uint16
- Type uint8
- Nlen uint8
- Alen uint8
- Slen uint8
- Data [46]int8
- Pad_cgo_0 [2]byte
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [46]int8
}
type RawSockaddr struct {
@@ -251,8 +247,8 @@ const (
SizeofSockaddrInet4 = 0x10
SizeofSockaddrInet6 = 0x1c
SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6c
- SizeofSockaddrDatalink = 0x38
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
SizeofLinger = 0x8
SizeofIPMreq = 0x8
SizeofIPMreqn = 0xc
@@ -284,8 +280,10 @@ type FdSet struct {
}
const (
- SizeofIfMsghdr = 0x68
- SizeofIfData = 0x58
+ sizeofIfMsghdr = 0x70
+ SizeofIfMsghdr = 0x70
+ sizeofIfData = 0x60
+ SizeofIfData = 0x60
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
SizeofIfAnnounceMsghdr = 0x18
@@ -293,6 +291,17 @@ const (
SizeofRtMetrics = 0x38
)
+type ifMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data ifData
+}
+
type IfMsghdr struct {
Msglen uint16
Version uint8
@@ -304,13 +313,41 @@ type IfMsghdr struct {
Data IfData
}
+type ifData struct {
+ Type uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Vhid uint8
+ Baudrate_pf uint8
+ Datalen uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Hwassist uint64
+ Epoch int64
+ Lastchange Timeval
+}
+
type IfData struct {
Type uint8
Physical uint8
Addrlen uint8
Hdrlen uint8
Link_state uint8
- Spare_char1 uint8 //Vhid uint8
+ Spare_char1 uint8
Spare_char2 uint8
Datalen uint8
Mtu uint32
@@ -328,6 +365,7 @@ type IfData struct {
Iqdrops uint32
Noproto uint32
Hwassist uint32
+ Pad_cgo_0 [4]byte
Epoch int64
Lastchange Timeval
}
@@ -399,7 +437,7 @@ const (
SizeofBpfZbuf = 0xc
SizeofBpfProgram = 0x8
SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x18
+ SizeofBpfHdr = 0x20
SizeofBpfZbufHeader = 0x20
)
@@ -436,7 +474,7 @@ type BpfHdr struct {
Caplen uint32
Datalen uint32
Hdrlen uint16
- Pad_cgo_0 [2]byte
+ Pad_cgo_0 [6]byte
}
type BpfZbufHeader struct {
@@ -445,3 +483,13 @@ type BpfZbufHeader struct {
User_gen uint32
X_bzh_pad [5]uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 9abd647ac..daecb1ded 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -142,6 +142,14 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Start int64
+ Len int64
+ Pid int32
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index 32da4e4b5..694fe1eac 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -142,6 +142,16 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 4a918a8a7..5f21a948d 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -144,6 +144,16 @@ type Fsid struct {
X__val [2]int32
}
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
type RawSockaddrInet4 struct {
Family uint16
Port uint16
diff --git a/src/pkg/syscall/ztypes_netbsd_386.go b/src/pkg/syscall/ztypes_netbsd_386.go
index 59314bad2..6add325a3 100644
--- a/src/pkg/syscall/ztypes_netbsd_386.go
+++ b/src/pkg/syscall/ztypes_netbsd_386.go
@@ -370,6 +370,16 @@ type BpfTimeval struct {
Usec int32
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_netbsd_amd64.go b/src/pkg/syscall/ztypes_netbsd_amd64.go
index a021a5738..4451fc1f0 100644
--- a/src/pkg/syscall/ztypes_netbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_netbsd_amd64.go
@@ -377,6 +377,16 @@ type BpfTimeval struct {
Usec int64
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_netbsd_arm.go b/src/pkg/syscall/ztypes_netbsd_arm.go
index 59314bad2..4e853eaa2 100644
--- a/src/pkg/syscall/ztypes_netbsd_arm.go
+++ b/src/pkg/syscall/ztypes_netbsd_arm.go
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
@@ -57,10 +59,12 @@ type _Gid_t uint32
type Stat_t struct {
Dev uint64
Mode uint32
+ Pad_cgo_0 [4]byte
Ino uint64
Nlink uint32
Uid uint32
Gid uint32
+ Pad_cgo_1 [4]byte
Rdev uint64
Atimespec Timespec
Mtimespec Timespec
@@ -72,6 +76,7 @@ type Stat_t struct {
Flags uint32
Gen uint32
Spare [2]uint32
+ Pad_cgo_2 [4]byte
}
type Statfs_t [0]byte
@@ -217,12 +222,13 @@ const (
)
type Kevent_t struct {
- Ident uint32
- Filter uint32
- Flags uint32
- Fflags uint32
- Data int64
- Udata int32
+ Ident uint32
+ Filter uint32
+ Flags uint32
+ Fflags uint32
+ Data int64
+ Udata int32
+ Pad_cgo_0 [4]byte
}
type FdSet struct {
@@ -231,7 +237,7 @@ type FdSet struct {
const (
SizeofIfMsghdr = 0x98
- SizeofIfData = 0x84
+ SizeofIfData = 0x88
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x18
SizeofRtMsghdr = 0x78
@@ -247,7 +253,6 @@ type IfMsghdr struct {
Index uint16
Pad_cgo_0 [2]byte
Data IfData
- Pad_cgo_1 [4]byte
}
type IfData struct {
@@ -370,6 +375,16 @@ type BpfTimeval struct {
Usec int32
}
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
diff --git a/src/pkg/syscall/ztypes_openbsd_386.go b/src/pkg/syscall/ztypes_openbsd_386.go
index 3c9cdf28b..2e4d9dd17 100644
--- a/src/pkg/syscall/ztypes_openbsd_386.go
+++ b/src/pkg/syscall/ztypes_openbsd_386.go
@@ -19,12 +19,12 @@ type (
)
type Timespec struct {
- Sec int32
+ Sec int64
Nsec int32
}
type Timeval struct {
- Sec int32
+ Sec int64
Usec int32
}
@@ -72,14 +72,13 @@ const (
)
type Stat_t struct {
- Dev int32
- Ino uint32
Mode uint32
+ Dev int32
+ Ino uint64
Nlink uint32
Uid uint32
Gid uint32
Rdev int32
- Lspare0 int32
Atim Timespec
Mtim Timespec
Ctim Timespec
@@ -88,9 +87,7 @@ type Stat_t struct {
Blksize uint32
Flags uint32
Gen uint32
- Lspare1 int32
X__st_birthtim Timespec
- Qspare [2]int64
}
type Statfs_t struct {
@@ -110,11 +107,12 @@ type Statfs_t struct {
F_fsid Fsid
F_namemax uint32
F_owner uint32
- F_ctime uint32
- F_spare [3]uint32
+ F_ctime uint64
F_fstypename [16]int8
F_mntonname [90]int8
F_mntfromname [90]int8
+ F_mntfromspec [90]int8
+ Pad_cgo_0 [2]byte
Mount_info [160]byte
}
@@ -127,11 +125,13 @@ type Flock_t struct {
}
type Dirent struct {
- Fileno uint32
- Reclen uint16
- Type uint8
- Namlen uint8
- Name [256]int8
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ X__d_padding [4]uint8
+ Name [256]int8
}
type Fsid struct {
@@ -262,21 +262,21 @@ type Kevent_t struct {
Filter int16
Flags uint16
Fflags uint32
- Data int32
+ Data int64
Udata *byte
}
type FdSet struct {
- Bits [32]int32
+ Bits [32]uint32
}
const (
- SizeofIfMsghdr = 0xe8
- SizeofIfData = 0xd0
+ SizeofIfMsghdr = 0xec
+ SizeofIfData = 0xd4
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x1a
- SizeofRtMsghdr = 0x58
- SizeofRtMetrics = 0x30
+ SizeofRtMsghdr = 0x60
+ SizeofRtMetrics = 0x38
)
type IfMsghdr struct {
@@ -364,9 +364,9 @@ type RtMsghdr struct {
type RtMetrics struct {
Pksent uint64
+ Expire int64
Locks uint32
Mtu uint32
- Expire uint32
Refcnt uint32
Hopcount uint32
Recvpipe uint32
@@ -374,10 +374,11 @@ type RtMetrics struct {
Ssthresh uint32
Rtt uint32
Rttvar uint32
+ Pad uint32
}
type Mclpool struct {
- Grown uint32
+ Grown int32
Alive uint16
Hwm uint16
Cwm uint16
@@ -426,3 +427,13 @@ type BpfTimeval struct {
Sec uint32
Usec uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_openbsd_amd64.go b/src/pkg/syscall/ztypes_openbsd_amd64.go
index 3a0ac96fa..f07bc714e 100644
--- a/src/pkg/syscall/ztypes_openbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_openbsd_amd64.go
@@ -19,9 +19,8 @@ type (
)
type Timespec struct {
- Sec int32
- Pad_cgo_0 [4]byte
- Nsec int64
+ Sec int64
+ Nsec int64
}
type Timeval struct {
@@ -73,14 +72,13 @@ const (
)
type Stat_t struct {
- Dev int32
- Ino uint32
Mode uint32
+ Dev int32
+ Ino uint64
Nlink uint32
Uid uint32
Gid uint32
Rdev int32
- Lspare0 int32
Atim Timespec
Mtim Timespec
Ctim Timespec
@@ -89,9 +87,8 @@ type Stat_t struct {
Blksize uint32
Flags uint32
Gen uint32
- Lspare1 int32
+ Pad_cgo_0 [4]byte
X__st_birthtim Timespec
- Qspare [2]int64
}
type Statfs_t struct {
@@ -112,12 +109,12 @@ type Statfs_t struct {
F_fsid Fsid
F_namemax uint32
F_owner uint32
- F_ctime uint32
- F_spare [3]uint32
+ F_ctime uint64
F_fstypename [16]int8
F_mntonname [90]int8
F_mntfromname [90]int8
- Pad_cgo_1 [4]byte
+ F_mntfromspec [90]int8
+ Pad_cgo_1 [2]byte
Mount_info [160]byte
}
@@ -130,11 +127,13 @@ type Flock_t struct {
}
type Dirent struct {
- Fileno uint32
- Reclen uint16
- Type uint8
- Namlen uint8
- Name [256]int8
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ X__d_padding [4]uint8
+ Name [256]int8
}
type Fsid struct {
@@ -263,16 +262,16 @@ const (
)
type Kevent_t struct {
- Ident uint32
+ Ident uint64
Filter int16
Flags uint16
Fflags uint32
- Data int32
+ Data int64
Udata *byte
}
type FdSet struct {
- Bits [32]int32
+ Bits [32]uint32
}
const (
@@ -280,8 +279,8 @@ const (
SizeofIfData = 0xe0
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x1a
- SizeofRtMsghdr = 0x58
- SizeofRtMetrics = 0x30
+ SizeofRtMsghdr = 0x60
+ SizeofRtMetrics = 0x38
)
type IfMsghdr struct {
@@ -371,9 +370,9 @@ type RtMsghdr struct {
type RtMetrics struct {
Pksent uint64
+ Expire int64
Locks uint32
Mtu uint32
- Expire uint32
Refcnt uint32
Hopcount uint32
Recvpipe uint32
@@ -381,10 +380,11 @@ type RtMetrics struct {
Ssthresh uint32
Rtt uint32
Rttvar uint32
+ Pad uint32
}
type Mclpool struct {
- Grown uint32
+ Grown int32
Alive uint16
Hwm uint16
Cwm uint16
@@ -434,3 +434,13 @@ type BpfTimeval struct {
Sec uint32
Usec uint32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_solaris_amd64.go b/src/pkg/syscall/ztypes_solaris_amd64.go
new file mode 100644
index 000000000..77275a54e
--- /dev/null
+++ b/src/pkg/syscall/ztypes_solaris_amd64.go
@@ -0,0 +1,365 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_solaris.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Timeval32 struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ Size int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Blksize int32
+ Pad_cgo_0 [4]byte
+ Blocks int64
+ Fstype [16]int8
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Sysid int32
+ Pid int32
+ Pad [4]int64
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Name [1]int8
+ Pad_cgo_0 [5]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+ X__sin6_src_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrDatalink struct {
+ Family uint16
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [244]int8
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [236]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *int8
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_cgo_1 [4]byte
+ Accrights *int8
+ Accrightslen int32
+ Pad_cgo_2 [4]byte
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ X__icmp6_filt [8]uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x20
+ SizeofSockaddrAny = 0xfc
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrDatalink = 0xfc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x24
+ SizeofICMPv6Filter = 0x20
+)
+
+type FdSet struct {
+ Bits [1024]int64
+}
+
+const (
+ SizeofIfMsghdr = 0x54
+ SizeofIfData = 0x44
+ SizeofIfaMsghdr = 0x14
+ SizeofRtMsghdr = 0x4c
+ SizeofRtMetrics = 0x28
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Pad_cgo_0 [1]byte
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Lastchange Timeval32
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x80
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint64
+ Drop uint64
+ Capt uint64
+ Padding [13]uint64
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfTimeval struct {
+ Sec int32
+ Usec int32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [19]uint8
+ Pad_cgo_0 [1]byte
+}
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index a5681d700..a1d77e0b5 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -20,6 +20,7 @@ const (
ERROR_PROC_NOT_FOUND Errno = 127
ERROR_ALREADY_EXISTS Errno = 183
ERROR_ENVVAR_NOT_FOUND Errno = 203
+ ERROR_MORE_DATA Errno = 234
ERROR_OPERATION_ABORTED Errno = 995
ERROR_IO_PENDING Errno = 997
ERROR_NOT_FOUND Errno = 1168
@@ -514,9 +515,11 @@ const (
IOC_OUT = 0x40000000
IOC_IN = 0x80000000
+ IOC_VENDOR = 0x18000000
IOC_INOUT = IOC_IN | IOC_OUT
IOC_WS2 = 0x08000000
SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
+ SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
@@ -1033,3 +1036,9 @@ type WSAProtocolChain struct {
ChainLen int32
ChainEntries [MAX_PROTOCOL_CHAIN]uint32
}
+
+type TCPKeepalive struct {
+ OnOff uint32
+ Time uint32
+ Interval uint32
+}
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index 3473c5b2c..1fbf5c861 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -10,6 +10,7 @@ import (
"os"
"runtime"
"sync"
+ "sync/atomic"
"time"
)
@@ -34,12 +35,15 @@ type InternalBenchmark struct {
// timing and to specify the number of iterations to run.
type B struct {
common
- N int
- benchmark InternalBenchmark
- bytes int64
- timerOn bool
- showAllocResult bool
- result BenchmarkResult
+ N int
+ previousN int // number of iterations in the previous run
+ previousDuration time.Duration // total duration of the previous run
+ benchmark InternalBenchmark
+ bytes int64
+ timerOn bool
+ showAllocResult bool
+ result BenchmarkResult
+ parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
startAllocs uint64
startBytes uint64
@@ -74,7 +78,7 @@ func (b *B) StopTimer() {
}
}
-// ResetTimer sets the elapsed benchmark time to zero.
+// ResetTimer zeros the elapsed benchmark time and memory allocation counters.
// It does not affect whether the timer is running.
func (b *B) ResetTimer() {
if b.timerOn {
@@ -114,10 +118,13 @@ func (b *B) runN(n int) {
// by clearing garbage from previous runs.
runtime.GC()
b.N = n
+ b.parallelism = 1
b.ResetTimer()
b.StartTimer()
b.benchmark.F(b)
b.StopTimer()
+ b.previousN = n
+ b.previousDuration = b.duration
}
func min(x, y int) int {
@@ -343,6 +350,87 @@ func (b *B) trimOutput() {
}
}
+// A PB is used by RunParallel for running parallel benchmarks.
+type PB struct {
+ globalN *uint64 // shared between all worker goroutines iteration counter
+ grain uint64 // acquire that many iterations from globalN at once
+ cache uint64 // local cache of acquired iterations
+ bN uint64 // total number of iterations to execute (b.N)
+}
+
+// Next reports whether there are more iterations to execute.
+func (pb *PB) Next() bool {
+ if pb.cache == 0 {
+ n := atomic.AddUint64(pb.globalN, pb.grain)
+ if n <= pb.bN {
+ pb.cache = pb.grain
+ } else if n < pb.bN+pb.grain {
+ pb.cache = pb.bN + pb.grain - n
+ } else {
+ return false
+ }
+ }
+ pb.cache--
+ return true
+}
+
+// RunParallel runs a benchmark in parallel.
+// It creates multiple goroutines and distributes b.N iterations among them.
+// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for
+// non-CPU-bound benchmarks, call SetParallelism before RunParallel.
+// RunParallel is usually used with the go test -cpu flag.
+//
+// The body function will be run in each goroutine. It should set up any
+// goroutine-local state and then iterate until pb.Next returns false.
+// It should not use the StartTimer, StopTimer, or ResetTimer functions,
+// because they have global effect.
+func (b *B) RunParallel(body func(*PB)) {
+ // Calculate grain size as number of iterations that take ~100µs.
+ // 100µs is enough to amortize the overhead and provide sufficient
+ // dynamic load balancing.
+ grain := uint64(0)
+ if b.previousN > 0 && b.previousDuration > 0 {
+ grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration)
+ }
+ if grain < 1 {
+ grain = 1
+ }
+ // We expect the inner loop and function call to take at least 10ns,
+ // so do not do more than 100µs/10ns=1e4 iterations.
+ if grain > 1e4 {
+ grain = 1e4
+ }
+
+ n := uint64(0)
+ numProcs := b.parallelism * runtime.GOMAXPROCS(0)
+ var wg sync.WaitGroup
+ wg.Add(numProcs)
+ for p := 0; p < numProcs; p++ {
+ go func() {
+ defer wg.Done()
+ pb := &PB{
+ globalN: &n,
+ grain: grain,
+ bN: uint64(b.N),
+ }
+ body(pb)
+ }()
+ }
+ wg.Wait()
+ if n <= uint64(b.N) && !b.Failed() {
+ b.Fatal("RunParallel: body exited without pb.Next() == false")
+ }
+}
+
+// SetParallelism sets the number of goroutines used by RunParallel to p*GOMAXPROCS.
+// There is usually no need to call SetParallelism for CPU-bound benchmarks.
+// If p is less than 1, this call will have no effect.
+func (b *B) SetParallelism(p int) {
+ if p >= 1 {
+ b.parallelism = p
+ }
+}
+
// Benchmark benchmarks a single function. Useful for creating
// custom benchmarks that do not use the "go test" command.
func Benchmark(f func(b *B)) BenchmarkResult {
diff --git a/src/pkg/testing/benchmark_test.go b/src/pkg/testing/benchmark_test.go
index 94e994dfa..f7ea64e7f 100644
--- a/src/pkg/testing/benchmark_test.go
+++ b/src/pkg/testing/benchmark_test.go
@@ -5,7 +5,11 @@
package testing_test
import (
+ "bytes"
+ "runtime"
+ "sync/atomic"
"testing"
+ "text/template"
)
var roundDownTests = []struct {
@@ -56,3 +60,52 @@ func TestRoundUp(t *testing.T) {
}
}
}
+
+func TestRunParallel(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ procs := uint32(0)
+ iters := uint64(0)
+ b.SetParallelism(3)
+ b.RunParallel(func(pb *testing.PB) {
+ atomic.AddUint32(&procs, 1)
+ for pb.Next() {
+ atomic.AddUint64(&iters, 1)
+ }
+ })
+ if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want {
+ t.Errorf("got %v procs, want %v", procs, want)
+ }
+ if iters != uint64(b.N) {
+ t.Errorf("got %v iters, want %v", iters, b.N)
+ }
+ })
+}
+
+func TestRunParallelFail(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ // The function must be able to log/abort
+ // w/o crashing/deadlocking the whole benchmark.
+ b.Log("log")
+ b.Error("error")
+ })
+ })
+}
+
+func ExampleB_RunParallel() {
+ // Parallel benchmark for text/template.Template.Execute on a single object.
+ testing.Benchmark(func(b *testing.B) {
+ templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+ // RunParallel will create GOMAXPROCS goroutines
+ // and distribute work among them.
+ b.RunParallel(func(pb *testing.PB) {
+ // Each goroutine has its own bytes.Buffer.
+ var buf bytes.Buffer
+ for pb.Next() {
+ // The loop body is executed b.N times total across all goroutines.
+ buf.Reset()
+ templ.Execute(&buf, "World")
+ }
+ })
+ })
+}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 52dc166dd..8078ba7cc 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -8,9 +8,17 @@
// func TestXxx(*testing.T)
// where Xxx can be any alphanumeric string (but the first letter must not be in
// [a-z]) and serves to identify the test routine.
-// These TestXxx routines should be declared within the package they are testing.
//
-// Tests and benchmarks may be skipped if not applicable like this:
+// Within these functions, use the Error, Fail or related methods to signal failure.
+//
+// To write a new test suite, create a file whose name ends _test.go that
+// contains the TestXxx functions as described here. Put the file in the same
+// package as the one being tested. The file will be excluded from regular
+// package builds but will be included when the ``go test'' command is run.
+// For more detail, run ``go help test'' and ``go help testflag''.
+//
+// Tests and benchmarks may be skipped if not applicable with a call to
+// the Skip method of *T and *B:
// func TestTimeConsuming(t *testing.T) {
// if testing.Short() {
// t.Skip("skipping test in short mode.")
@@ -43,6 +51,7 @@
//
// If a benchmark needs some expensive setup before running, the timer
// may be reset:
+//
// func BenchmarkBigLen(b *testing.B) {
// big := NewBig()
// b.ResetTimer()
@@ -51,6 +60,21 @@
// }
// }
//
+// If a benchmark needs to test performance in a parallel setting, it may use
+// the RunParallel helper function; such benchmarks are intended to be used with
+// the go test -cpu flag:
+//
+// func BenchmarkTemplateParallel(b *testing.B) {
+// templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+// b.RunParallel(func(pb *testing.PB) {
+// var buf bytes.Buffer
+// for pb.Next() {
+// buf.Reset()
+// templ.Execute(&buf, "World")
+// }
+// })
+// }
+//
// Examples
//
// The package also runs and verifies example code. Example functions may
@@ -143,10 +167,11 @@ var (
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
- mu sync.RWMutex // guards output and failed
- output []byte // Output generated by test or benchmark.
- failed bool // Test or benchmark has failed.
- skipped bool // Test of benchmark has been skipped.
+ mu sync.RWMutex // guards output and failed
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ skipped bool // Test of benchmark has been skipped.
+ finished bool
start time.Time // Time test or benchmark started
duration time.Duration
@@ -275,6 +300,7 @@ func (c *common) FailNow() {
// it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
+ c.finished = true
runtime.Goexit()
}
@@ -338,6 +364,7 @@ func (c *common) Skipf(format string, args ...interface{}) {
// those other goroutines.
func (c *common) SkipNow() {
c.skip()
+ c.finished = true
runtime.Goexit()
}
@@ -379,7 +406,11 @@ func tRunner(t *T, test *InternalTest) {
defer func() {
t.duration = time.Now().Sub(t.start)
// If the test panicked, print any test output before dying.
- if err := recover(); err != nil {
+ err := recover()
+ if !t.finished && err == nil {
+ err = fmt.Errorf("test executed panic(nil) or runtime.Goexit")
+ }
+ if err != nil {
t.Fail()
t.report()
panic(err)
@@ -389,6 +420,7 @@ func tRunner(t *T, test *InternalTest) {
t.start = time.Now()
test.F(t)
+ t.finished = true
}
// An internal function but exported because it is cross-package; part of the implementation
@@ -405,6 +437,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
stopAlarm()
if !testOk || !exampleOk {
fmt.Println("FAIL")
+ after()
os.Exit(1)
}
fmt.Println("PASS")
diff --git a/src/pkg/text/scanner/scanner.go b/src/pkg/text/scanner/scanner.go
index e0d86e343..db7ca73c6 100644
--- a/src/pkg/text/scanner/scanner.go
+++ b/src/pkg/text/scanner/scanner.go
@@ -240,6 +240,9 @@ func (s *Scanner) next() rune {
s.srcEnd = i + n
s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
if err != nil {
+ if err != io.EOF {
+ s.error(err.Error())
+ }
if s.srcEnd == 0 {
if s.lastCharLen > 0 {
// previous character was not EOF
@@ -248,9 +251,6 @@ func (s *Scanner) next() rune {
s.lastCharLen = 0
return EOF
}
- if err != io.EOF {
- s.error(err.Error())
- }
// If err == EOF, we won't be getting more
// bytes; break to avoid infinite loop. If
// err is something else, we don't know if
diff --git a/src/pkg/text/scanner/scanner_test.go b/src/pkg/text/scanner/scanner_test.go
index 496eed4a3..7d3f597eb 100644
--- a/src/pkg/text/scanner/scanner_test.go
+++ b/src/pkg/text/scanner/scanner_test.go
@@ -360,7 +360,7 @@ func TestScanSelectedMask(t *testing.T) {
func TestScanNext(t *testing.T) {
const BOM = '\uFEFF'
BOMs := string(BOM)
- s := new(Scanner).Init(bytes.NewBufferString(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
+ s := new(Scanner).Init(strings.NewReader(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
checkTok(t, s, 1, s.Scan(), Ident, "if") // the first BOM is ignored
checkTok(t, s, 1, s.Scan(), Ident, "a")
checkTok(t, s, 1, s.Scan(), '=', "=")
@@ -402,7 +402,7 @@ func TestScanWhitespace(t *testing.T) {
}
func testError(t *testing.T, src, pos, msg string, tok rune) {
- s := new(Scanner).Init(bytes.NewBufferString(src))
+ s := new(Scanner).Init(strings.NewReader(src))
errorCalled := false
s.Error = func(s *Scanner, m string) {
if !errorCalled {
@@ -462,6 +462,33 @@ func TestError(t *testing.T) {
testError(t, `/*/`, "1:4", "comment not terminated", EOF)
}
+// An errReader returns (0, err) where err is not io.EOF.
+type errReader struct{}
+
+func (errReader) Read(b []byte) (int, error) {
+ return 0, io.ErrNoProgress // some error that is not io.EOF
+}
+
+func TestIOError(t *testing.T) {
+ s := new(Scanner).Init(errReader{})
+ errorCalled := false
+ s.Error = func(s *Scanner, msg string) {
+ if !errorCalled {
+ if want := io.ErrNoProgress.Error(); msg != want {
+ t.Errorf("msg = %q, want %q", msg, want)
+ }
+ errorCalled = true
+ }
+ }
+ tok := s.Scan()
+ if tok != EOF {
+ t.Errorf("tok = %s, want EOF", TokenString(tok))
+ }
+ if !errorCalled {
+ t.Errorf("error handler not called")
+ }
+}
+
func checkPos(t *testing.T, got, want Position) {
if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
@@ -491,13 +518,13 @@ func checkScanPos(t *testing.T, s *Scanner, offset, line, column int, char rune)
func TestPos(t *testing.T) {
// corner case: empty source
- s := new(Scanner).Init(bytes.NewBufferString(""))
+ s := new(Scanner).Init(strings.NewReader(""))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
s.Peek() // peek doesn't affect the position
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
// corner case: source with only a newline
- s = new(Scanner).Init(bytes.NewBufferString("\n"))
+ s = new(Scanner).Init(strings.NewReader("\n"))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
checkNextPos(t, s, 1, 2, 1, '\n')
// after EOF position doesn't change
@@ -509,7 +536,7 @@ func TestPos(t *testing.T) {
}
// corner case: source with only a single character
- s = new(Scanner).Init(bytes.NewBufferString("本"))
+ s = new(Scanner).Init(strings.NewReader("本"))
checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
checkNextPos(t, s, 3, 1, 2, '本')
// after EOF position doesn't change
@@ -521,7 +548,7 @@ func TestPos(t *testing.T) {
}
// positions after calling Next
- s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n"))
+ s = new(Scanner).Init(strings.NewReader(" foo६४ \n\n本語\n"))
checkNextPos(t, s, 1, 1, 2, ' ')
s.Peek() // peek doesn't affect the position
checkNextPos(t, s, 2, 1, 3, ' ')
@@ -546,7 +573,7 @@ func TestPos(t *testing.T) {
}
// positions after calling Scan
- s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx"))
+ s = new(Scanner).Init(strings.NewReader("abc\n本語\n\nx"))
s.Mode = 0
s.Whitespace = 0
checkScanPos(t, s, 0, 1, 1, 'a')
diff --git a/src/pkg/text/tabwriter/tabwriter.go b/src/pkg/text/tabwriter/tabwriter.go
index 722ac8d87..c0c32d5de 100644
--- a/src/pkg/text/tabwriter/tabwriter.go
+++ b/src/pkg/text/tabwriter/tabwriter.go
@@ -434,9 +434,13 @@ func (b *Writer) terminateCell(htab bool) int {
return len(*line)
}
-func handlePanic(err *error) {
+func handlePanic(err *error, op string) {
if e := recover(); e != nil {
- *err = e.(osError).err // re-panics if it's not a local osError
+ if nerr, ok := e.(osError); ok {
+ *err = nerr.err
+ return
+ }
+ panic("tabwriter: panic during " + op)
}
}
@@ -447,7 +451,7 @@ func handlePanic(err *error) {
//
func (b *Writer) Flush() (err error) {
defer b.reset() // even in the presence of errors
- defer handlePanic(&err)
+ defer handlePanic(&err, "Flush")
// add current cell if not empty
if b.cell.size > 0 {
@@ -471,7 +475,7 @@ var hbar = []byte("---\n")
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (n int, err error) {
- defer handlePanic(&err)
+ defer handlePanic(&err, "Write")
// split text into cells
n = 0
diff --git a/src/pkg/text/tabwriter/tabwriter_test.go b/src/pkg/text/tabwriter/tabwriter_test.go
index ace535647..9d3111e2c 100644
--- a/src/pkg/text/tabwriter/tabwriter_test.go
+++ b/src/pkg/text/tabwriter/tabwriter_test.go
@@ -14,7 +14,7 @@ type buffer struct {
a []byte
}
-func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+func (b *buffer) init(n int) { b.a = make([]byte, 0, n) }
func (b *buffer) clear() { b.a = b.a[0:0] }
@@ -613,3 +613,40 @@ func Test(t *testing.T) {
check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
}
}
+
+type panicWriter struct{}
+
+func (panicWriter) Write([]byte) (int, error) {
+ panic("cannot write")
+}
+
+func wantPanicString(t *testing.T, want string) {
+ if e := recover(); e != nil {
+ got, ok := e.(string)
+ switch {
+ case !ok:
+ t.Errorf("got %v (%T), want panic string", e, e)
+ case got != want:
+ t.Errorf("wrong panic message: got %q, want %q", got, want)
+ }
+ }
+}
+
+func TestPanicDuringFlush(t *testing.T) {
+ defer wantPanicString(t, "tabwriter: panic during Flush")
+ var p panicWriter
+ w := new(Writer)
+ w.Init(p, 0, 0, 5, ' ', 0)
+ io.WriteString(w, "a")
+ w.Flush()
+ t.Errorf("failed to panic during Flush")
+}
+
+func TestPanicDuringWrite(t *testing.T) {
+ defer wantPanicString(t, "tabwriter: panic during Write")
+ var p panicWriter
+ w := new(Writer)
+ w.Init(p, 0, 0, 5, ' ', 0)
+ io.WriteString(w, "a\n\n") // the second \n triggers a call to w.Write and thus a panic
+ t.Errorf("failed to panic during Write")
+}
diff --git a/src/pkg/text/template/doc.go b/src/pkg/text/template/doc.go
index f622ac7dc..7c6efd59c 100644
--- a/src/pkg/text/template/doc.go
+++ b/src/pkg/text/template/doc.go
@@ -20,7 +20,7 @@ The input text for a template is UTF-8-encoded text in any format.
"{{" and "}}"; all text outside actions is copied to the output unchanged.
Actions may not span newlines, although comments can.
-Once constructed, a template may be executed safely in parallel.
+Once parsed, a template may be executed safely in parallel.
Here is a trivial example that prints "17 items are made of wool".
diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go
index 43b0b266e..2f3231264 100644
--- a/src/pkg/text/template/exec.go
+++ b/src/pkg/text/template/exec.go
@@ -108,6 +108,10 @@ func errRecover(errp *error) {
// ExecuteTemplate applies the template associated with t that has the given name
// to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
tmpl := t.tmpl[name]
if tmpl == nil {
@@ -118,6 +122,10 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// Execute applies a parsed template to the specified data object,
// and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
defer errRecover(&err)
value := reflect.ValueOf(data)
@@ -594,6 +602,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
switch {
case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
value = value.Elem()
+ if !value.IsValid() {
+ s.errorf("dereference of nil pointer of type %s", typ)
+ }
case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
value = value.Addr()
default:
diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go
index f60702de8..868f2cb94 100644
--- a/src/pkg/text/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -512,6 +512,8 @@ var execTests = []execTest{
{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
// Field chain starting with function did not work.
{"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
+ // Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333.
+ {"bug11", "{{valueString .PS}}", "", T{}, false},
}
func zeroArgs() string {
@@ -546,6 +548,11 @@ func vfunc(V, *V) string {
return "vfunc"
}
+// valueString takes a string, not a pointer.
+func valueString(v string) string {
+ return "value is ignored"
+}
+
func add(args ...int) int {
sum := 0
for _, x := range args {
@@ -580,17 +587,18 @@ func mapOfThree() interface{} {
func testExecute(execTests []execTest, template *Template, t *testing.T) {
b := new(bytes.Buffer)
funcs := FuncMap{
- "add": add,
- "count": count,
- "dddArg": dddArg,
- "echo": echo,
- "makemap": makemap,
- "mapOfThree": mapOfThree,
- "oneArg": oneArg,
- "stringer": stringer,
- "typeOf": typeOf,
- "vfunc": vfunc,
- "zeroArgs": zeroArgs,
+ "add": add,
+ "count": count,
+ "dddArg": dddArg,
+ "echo": echo,
+ "makemap": makemap,
+ "mapOfThree": mapOfThree,
+ "oneArg": oneArg,
+ "stringer": stringer,
+ "typeOf": typeOf,
+ "valueString": valueString,
+ "vfunc": vfunc,
+ "zeroArgs": zeroArgs,
}
for _, test := range execTests {
var tmpl *Template
diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go
index 1f6ed5d8e..e4e804880 100644
--- a/src/pkg/text/template/multi_test.go
+++ b/src/pkg/text/template/multi_test.go
@@ -259,6 +259,18 @@ func TestAddParseTree(t *testing.T) {
}
}
+// Issue 7032
+func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
+ master := "{{define \"master\"}}{{end}}"
+ tmpl := New("master")
+ tree, err := parse.Parse("master", master, "", "", nil)
+ if err != nil {
+ t.Fatalf("unexpected parse err: %v", err)
+ }
+ masterTree := tree["master"]
+ tmpl.AddParseTree("master", masterTree) // used to panic
+}
+
func TestRedefinition(t *testing.T) {
var tmpl *Template
var err error
diff --git a/src/pkg/text/template/template.go b/src/pkg/text/template/template.go
index a2b9062ad..249d0cbfb 100644
--- a/src/pkg/text/template/template.go
+++ b/src/pkg/text/template/template.go
@@ -105,7 +105,7 @@ func (t *Template) copy(c *common) *Template {
// AddParseTree creates a new template with the name and parse tree
// and associates it with t.
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
- if t.tmpl[name] != nil {
+ if t.common != nil && t.tmpl[name] != nil {
return nil, fmt.Errorf("template: redefinition of template %q", name)
}
nt := t.New(name)
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 6f92c1262..9f210ea27 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -102,7 +102,7 @@ const (
// std0x records the std values for "01", "02", ..., "06".
var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear}
-// startsWithLowerCase reports whether the the string has a lower-case letter at the beginning.
+// startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
// Its purpose is to prevent matching strings like "Month" when looking for "Mon".
func startsWithLowerCase(str string) bool {
if len(str) == 0 {
@@ -1037,8 +1037,8 @@ func parseTimeZone(value string) (length int, ok bool) {
if len(value) < 3 {
return 0, false
}
- // Special case 1: This is the only zone with a lower-case letter.
- if len(value) >= 4 && value[:4] == "ChST" {
+ // Special case 1: ChST and MeST are the only zones with a lower-case letter.
+ if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
return 4, true
}
// Special case 2: GMT may have an hour offset; treat it specially.
@@ -1240,5 +1240,8 @@ func ParseDuration(s string) (Duration, error) {
if neg {
f = -f
}
+ if f < float64(-1<<63) || f > float64(1<<63-1) {
+ return 0, errors.New("time: overflow parsing duration")
+ }
return Duration(f), nil
}
diff --git a/src/pkg/time/format_test.go b/src/pkg/time/format_test.go
new file mode 100644
index 000000000..3bc8f4294
--- /dev/null
+++ b/src/pkg/time/format_test.go
@@ -0,0 +1,511 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+ "testing/quick"
+ . "time"
+)
+
+type TimeFormatTest struct {
+ time Time
+ formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+ {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+ {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+ {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+ for _, f := range rfc3339Formats {
+ if f.time.Format(RFC3339) != f.formattedValue {
+ t.Error("RFC3339:")
+ t.Errorf(" want=%+v", f.formattedValue)
+ t.Errorf(" have=%+v", f.time.Format(RFC3339))
+ }
+ }
+}
+
+type FormatTest struct {
+ name string
+ format string
+ result string
+}
+
+var formatTests = []FormatTest{
+ {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
+ {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
+ {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+ {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
+ {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+ {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
+ {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+ {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
+ {"Kitchen", Kitchen, "9:00PM"},
+ {"am/pm", "3pm", "9pm"},
+ {"AM/PM", "3PM", "9PM"},
+ {"two-digit year", "06 01 02", "09 02 04"},
+ // Three-letter months and days must not be followed by lower-case letter.
+ {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
+ // Time stamps, Fractional seconds.
+ {"Stamp", Stamp, "Feb 4 21:00:57"},
+ {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
+ {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
+ {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
+}
+
+func TestFormat(t *testing.T) {
+ // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010
+ time := Unix(0, 1233810057012345600)
+ for _, test := range formatTests {
+ result := time.Format(test.format)
+ if result != test.result {
+ t.Errorf("%s expected %q got %q", test.name, test.result, result)
+ }
+ }
+}
+
+func TestFormatShortYear(t *testing.T) {
+ years := []int{
+ -100001, -100000, -99999,
+ -10001, -10000, -9999,
+ -1001, -1000, -999,
+ -101, -100, -99,
+ -11, -10, -9,
+ -1, 0, 1,
+ 9, 10, 11,
+ 99, 100, 101,
+ 999, 1000, 1001,
+ 9999, 10000, 10001,
+ 99999, 100000, 100001,
+ }
+
+ for _, y := range years {
+ time := Date(y, January, 1, 0, 0, 0, 0, UTC)
+ result := time.Format("2006.01.02")
+ var want string
+ if y < 0 {
+ // The 4 in %04d counts the - sign, so print -y instead
+ // and introduce our own - sign.
+ want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
+ } else {
+ want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
+ }
+ if result != want {
+ t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
+ }
+ }
+}
+
+type ParseTest struct {
+ name string
+ format string
+ value string
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int // sign of year, -1 indicates the year is not present in the format
+ fracDigits int // number of digits of fractional second
+}
+
+var parseTests = []ParseTest{
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+ {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
+ // Optional fractional seconds.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
+ {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
+ // Amount of white space should not matter.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ // Case should not matter
+ {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
+ // Fractional seconds.
+ {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ // Leading zeros in other places should not be taken as fractional seconds.
+ {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+ {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+ // Month and day names only match when not followed by a lower-case letter.
+ {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
+
+ // GMT with offset.
+ {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
+
+ // Accept any number of fractional second digits (including none) for .999...
+ // In Go 1, .999... was completely ignored in the format, meaning the first two
+ // cases would succeed, but the next four would not. Go 1.1 accepts all six.
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+ {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+
+ // issue 4502.
+ {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
+ {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
+ {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
+ {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
+ {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func TestParseInSydney(t *testing.T) {
+ loc, err := LoadLocation("Australia/Sydney")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that Parse (and ParseInLocation) understand
+ // that Feb EST and Aug EST are different time zones in Sydney
+ // even though both are called EST.
+ t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
+ if t1 != t2 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+ }
+ _, offset := t1.Zone()
+ if offset != 11*60*60 {
+ t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
+ }
+
+ t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
+ if t1 != t2 {
+ t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+ }
+ _, offset = t1.Zone()
+ if offset != 10*60*60 {
+ t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
+ }
+}
+
+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.
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+ for _, test := range rubyTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func checkTime(time Time, test *ParseTest, t *testing.T) {
+ // The time should be Thu Feb 4 21:00:57 PST 2010
+ if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
+ t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
+ }
+ if time.Month() != February {
+ t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
+ }
+ if time.Day() != 4 {
+ t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
+ }
+ if time.Hour() != 21 {
+ t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
+ }
+ if time.Minute() != 0 {
+ t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
+ }
+ if time.Second() != 57 {
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
+ }
+ // Nanoseconds must be checked against the precision of the input.
+ nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
+ if err != nil {
+ panic(err)
+ }
+ if time.Nanosecond() != int(nanosec) {
+ t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
+ }
+ name, offset := time.Zone()
+ if test.hasTZ && offset != -28800 {
+ t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
+ }
+ if test.hasWD && time.Weekday() != Thursday {
+ t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
+ }
+}
+
+func TestFormatAndParse(t *testing.T) {
+ const fmt = "Mon MST " + RFC3339 // all fields
+ f := func(sec int64) bool {
+ t1 := Unix(sec, 0)
+ if t1.Year() < 1000 || t1.Year() > 9999 {
+ // not required to work
+ return true
+ }
+ t2, err := Parse(fmt, t1.Format(fmt))
+ if err != nil {
+ t.Errorf("error: %s", err)
+ return false
+ }
+ if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
+ t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
+ return false
+ }
+ return true
+ }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ParseTimeZoneTest struct {
+ value string
+ length int
+ ok bool
+}
+
+var parseTimeZoneTests = []ParseTimeZoneTest{
+ {"gmt hi there", 0, false},
+ {"GMT hi there", 3, true},
+ {"GMT+12 hi there", 6, true},
+ {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
+ {"GMT-5 hi there", 5, true},
+ {"GMT-51 hi there", 3, true},
+ {"ChST hi there", 4, true},
+ {"MeST hi there", 4, true},
+ {"MSDx", 3, true},
+ {"MSDY", 0, false}, // four letters must end in T.
+ {"ESAST hi", 5, true},
+ {"ESASTT hi", 0, false}, // run of upper-case letters too long.
+ {"ESATY hi", 0, false}, // five letters must end in T.
+}
+
+func TestParseTimeZone(t *testing.T) {
+ for _, test := range parseTimeZoneTests {
+ length, ok := ParseTimeZone(test.value)
+ if ok != test.ok {
+ t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
+ } else if length != test.length {
+ t.Errorf("expected %d for %q got %d", test.length, test.value, length)
+ }
+ }
+}
+
+type ParseErrorTest struct {
+ format string
+ value string
+ expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+ {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
+ {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
+ {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
+ {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
+ // issue 4502. StampNano requires exactly 9 digits of precision.
+ {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
+ {StampNano, "Dec 7 11:22:01.0000000000", "extra text: 0"},
+ // issue 4493. Helpful errors.
+ {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
+ {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
+ {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
+ {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+}
+
+func TestParseErrors(t *testing.T) {
+ for _, test := range parseErrorTests {
+ _, err := Parse(test.format, test.value)
+ if err == nil {
+ t.Errorf("expected error for %q %q", test.format, test.value)
+ } else if strings.Index(err.Error(), test.expect) < 0 {
+ t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+ }
+ }
+}
+
+func TestNoonIs12PM(t *testing.T) {
+ noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
+ const expect = "12:00PM"
+ got := noon.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = noon.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func TestMidnightIs12AM(t *testing.T) {
+ midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
+ expect := "12:00AM"
+ got := midnight.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = midnight.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func Test12PMIsNoon(t *testing.T) {
+ noon, err := Parse("3:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
+ }
+ noon, err = Parse("03:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
+ }
+}
+
+func Test12AMIsMidnight(t *testing.T) {
+ midnight, err := Parse("3:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
+ }
+ midnight, err = Parse("03:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
+ }
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
+ str := time.Format(UnixDate) // uses MST as its time zone
+ if str != expect {
+ t.Errorf("got %s; expect %s", str, expect)
+ }
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expected := (1*60 + 23) * 60
+ _, offset := time.Zone()
+ if offset != expected {
+ t.Errorf("ZoneOffset = %d, want %d", offset, expected)
+ }
+}
+
+type SecondsTimeZoneOffsetTest struct {
+ format string
+ value string
+ expectedoffset int
+}
+
+var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
+ {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+ {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
+ {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
+ {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+ {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+ {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+}
+
+func TestParseSecondsInTimeZone(t *testing.T) {
+ // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58
+ for _, test := range secondsTimeZoneOffsetTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ _, offset := time.Zone()
+ if offset != test.expectedoffset {
+ t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
+ }
+ }
+}
+
+func TestFormatSecondsInTimeZone(t *testing.T) {
+ d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8)))
+ timestr := d.Format("2006-01-02T15:04:05Z070000")
+ expected := "1871-09-17T20:04:26-003408"
+ if timestr != expected {
+ t.Errorf("Got %s, want %s", timestr, expected)
+ }
+}
diff --git a/src/pkg/time/internal_test.go b/src/pkg/time/internal_test.go
index 87fdd3216..2243d3668 100644
--- a/src/pkg/time/internal_test.go
+++ b/src/pkg/time/internal_test.go
@@ -29,16 +29,20 @@ func CheckRuntimeTimerOverflow() error {
// detection logic in NewTimer: we're testing the underlying
// runtime.addtimer function.
r := &runtimeTimer{
- when: nano() + (1<<63 - 1),
+ when: runtimeNano() + (1<<63 - 1),
f: empty,
arg: nil,
}
startTimer(r)
timeout := 100 * Millisecond
- if runtime.GOOS == "windows" {
- // Allow more time for gobuilder to succeed.
+ switch runtime.GOOS {
+ // Allow more time for gobuilder to succeed.
+ case "windows":
timeout = Second
+ case "plan9":
+ // TODO(0intro): We don't know why it is needed.
+ timeout = 3 * Second
}
// Start a goroutine that should send on t.C before the timeout.
@@ -74,7 +78,15 @@ func CheckRuntimeTimerOverflow() error {
if Now().After(stop) {
return errors.New("runtime timer stuck: overflow in addtimer")
}
- runtime.Gosched()
+ // Issue 6874. This test previously called runtime.Gosched to try to yield
+ // to the goroutine servicing t, however the scheduler has a bias towards the
+ // previously running goroutine in an idle system. Combined with high load due
+ // to all CPUs busy running tests t's goroutine could be delayed beyond the
+ // timeout window.
+ //
+ // Calling runtime.GC() reduces the worst case lantency for scheduling t by 20x
+ // under the current Go 1.3 scheduler.
+ runtime.GC()
}
}
}
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
index 4f55bebe6..6a03f417b 100644
--- a/src/pkg/time/sleep.go
+++ b/src/pkg/time/sleep.go
@@ -8,10 +8,8 @@ package time
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)
-func nano() int64 {
- sec, nsec := now()
- return sec*1e9 + int64(nsec)
-}
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
@@ -29,9 +27,9 @@ type runtimeTimer struct {
// zero because of an overflow, MaxInt64 is returned.
func when(d Duration) int64 {
if d <= 0 {
- return nano()
+ return runtimeNano()
}
- t := nano() + int64(d)
+ t := runtimeNano() + int64(d)
if t < 0 {
t = 1<<63 - 1 // math.MaxInt64
}
@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) {
// the desired behavior when the reader gets behind,
// because the sends are periodic.
select {
- case c.(chan Time) <- Unix(0, now):
+ case c.(chan Time) <- Now():
default:
}
}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 468725950..03f8e732c 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -74,26 +74,13 @@ func benchmark(b *testing.B, bench func(n int)) {
for i := 0; i < len(garbage); i++ {
garbage[i] = AfterFunc(Hour, nil)
}
-
- const batch = 1000
- P := runtime.GOMAXPROCS(-1)
- N := int32(b.N / batch)
-
b.ResetTimer()
- var wg sync.WaitGroup
- wg.Add(P)
-
- for p := 0; p < P; p++ {
- go func() {
- for atomic.AddInt32(&N, -1) >= 0 {
- bench(batch)
- }
- wg.Done()
- }()
- }
-
- wg.Wait()
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ bench(1000)
+ }
+ })
b.StopTimer()
for i := 0; i < len(garbage); i++ {
@@ -360,19 +347,18 @@ func TestReset(t *testing.T) {
// Test that sleeping for an interval so large it overflows does not
// result in a short sleep duration.
func TestOverflowSleep(t *testing.T) {
- const timeout = 25 * Millisecond
const big = Duration(int64(1<<63 - 1))
select {
case <-After(big):
t.Fatalf("big timeout fired")
- case <-After(timeout):
+ case <-After(25 * Millisecond):
// OK
}
const neg = Duration(-1 << 63)
select {
case <-After(neg):
// OK
- case <-After(timeout):
+ case <-After(1 * Second):
t.Fatalf("negative timeout didn't fire")
}
}
@@ -398,6 +384,9 @@ func TestIssue5745(t *testing.T) {
}
func TestOverflowRuntimeTimer(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode, see issue 6874")
+ }
if err := CheckRuntimeTimerOverflow(); err != nil {
t.Fatalf(err.Error())
}
diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go
index 60a3ce08f..379e13d6a 100644
--- a/src/pkg/time/sys_unix.go
+++ b/src/pkg/time/sys_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package time
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index b92c339c0..19007841e 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -17,6 +17,7 @@ type Ticker struct {
// time with a period specified by the duration argument.
// It adjusts the intervals or drops ticks to make up for slow receivers.
// The duration d must be greater than zero; if not, NewTicker will panic.
+// Stop the ticker to release associated resources.
func NewTicker(d Duration) *Ticker {
if d <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
@@ -28,7 +29,7 @@ func NewTicker(d Duration) *Ticker {
t := &Ticker{
C: c,
r: runtimeTimer{
- when: nano() + int64(d),
+ when: when(d),
period: int64(d),
f: sendTime,
arg: c,
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index d8a086ceb..32f4740ad 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/time/tick_test.go
@@ -48,6 +48,24 @@ func TestTeardown(t *testing.T) {
}
}
+// Test the Tick convenience wrapper.
+func TestTick(t *testing.T) {
+ // Test that giving a negative duration returns nil.
+ if got := Tick(-1); got != nil {
+ t.Errorf("Tick(-1) = %v; want nil", got)
+ }
+}
+
+// Test that NewTicker panics when given a duration less than zero.
+func TestNewTickerLtZeroDuration(t *testing.T) {
+ defer func() {
+ if err := recover(); err == nil {
+ t.Errorf("NewTicker(-1) should have panicked")
+ }
+ }()
+ NewTicker(-1)
+}
+
func BenchmarkTicker(b *testing.B) {
ticker := NewTicker(1)
b.ResetTimer()
diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
index c504df740..0a2b09142 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -934,6 +934,8 @@ func (t *Time) GobDecode(data []byte) error {
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
+ // RFC 3339 is clear that years are 4 digits exactly.
+ // See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index 334c4b0cf..4ae7da5a4 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -12,8 +12,6 @@ import (
"math/big"
"math/rand"
"runtime"
- "strconv"
- "strings"
"testing"
"testing/quick"
. "time"
@@ -372,502 +370,6 @@ func TestTruncateRound(t *testing.T) {
quick.Check(f4, cfg)
}
-type TimeFormatTest struct {
- time Time
- formattedValue string
-}
-
-var rfc3339Formats = []TimeFormatTest{
- {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
- {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
- {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
-}
-
-func TestRFC3339Conversion(t *testing.T) {
- for _, f := range rfc3339Formats {
- if f.time.Format(RFC3339) != f.formattedValue {
- t.Error("RFC3339:")
- t.Errorf(" want=%+v", f.formattedValue)
- t.Errorf(" have=%+v", f.time.Format(RFC3339))
- }
- }
-}
-
-type FormatTest struct {
- name string
- format string
- result string
-}
-
-var formatTests = []FormatTest{
- {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
- {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
- {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
- {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
- {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
- {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
- {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
- {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
- {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
- {"Kitchen", Kitchen, "9:00PM"},
- {"am/pm", "3pm", "9pm"},
- {"AM/PM", "3PM", "9PM"},
- {"two-digit year", "06 01 02", "09 02 04"},
- // Three-letter months and days must not be followed by lower-case letter.
- {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
- // Time stamps, Fractional seconds.
- {"Stamp", Stamp, "Feb 4 21:00:57"},
- {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
- {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
- {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
-}
-
-func TestFormat(t *testing.T) {
- // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010
- time := Unix(0, 1233810057012345600)
- for _, test := range formatTests {
- result := time.Format(test.format)
- if result != test.result {
- t.Errorf("%s expected %q got %q", test.name, test.result, result)
- }
- }
-}
-
-func TestFormatShortYear(t *testing.T) {
- years := []int{
- -100001, -100000, -99999,
- -10001, -10000, -9999,
- -1001, -1000, -999,
- -101, -100, -99,
- -11, -10, -9,
- -1, 0, 1,
- 9, 10, 11,
- 99, 100, 101,
- 999, 1000, 1001,
- 9999, 10000, 10001,
- 99999, 100000, 100001,
- }
-
- for _, y := range years {
- time := Date(y, January, 1, 0, 0, 0, 0, UTC)
- result := time.Format("2006.01.02")
- var want string
- if y < 0 {
- // The 4 in %04d counts the - sign, so print -y instead
- // and introduce our own - sign.
- want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
- } else {
- want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
- }
- if result != want {
- t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
- }
- }
-}
-
-type ParseTest struct {
- name string
- format string
- value string
- hasTZ bool // contains a time zone
- hasWD bool // contains a weekday
- yearSign int // sign of year, -1 indicates the year is not present in the format
- fracDigits int // number of digits of fractional second
-}
-
-var parseTests = []ParseTest{
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
- {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
- {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
- {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
- {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
- // Optional fractional seconds.
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
- {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
- {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
- {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
- {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
- {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
- {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
- // Amount of white space should not matter.
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
- // Case should not matter
- {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
- {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
- // Fractional seconds.
- {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
- {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
- {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
- // Leading zeros in other places should not be taken as fractional seconds.
- {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
- {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
- // Month and day names only match when not followed by a lower-case letter.
- {"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb 4 21:00:57 2010", false, true, 1, 0},
-
- // GMT with offset.
- {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
-
- // Accept any number of fractional second digits (including none) for .999...
- // In Go 1, .999... was completely ignored in the format, meaning the first two
- // cases would succeed, but the next four would not. Go 1.1 accepts all six.
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
- {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
- {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
-
- // issue 4502.
- {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
- {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
- {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
- {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
- {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
-}
-
-func TestParse(t *testing.T) {
- for _, test := range parseTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Errorf("%s error: %v", test.name, err)
- } else {
- checkTime(time, &test, t)
- }
- }
-}
-
-func TestParseInSydney(t *testing.T) {
- loc, err := LoadLocation("Australia/Sydney")
- if err != nil {
- t.Fatal(err)
- }
-
- // Check that Parse (and ParseInLocation) understand
- // that Feb EST and Aug EST are different time zones in Sydney
- // even though both are called EST.
- t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
- if err != nil {
- t.Fatal(err)
- }
- t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
- if t1 != t2 {
- t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
- }
- _, offset := t1.Zone()
- if offset != 11*60*60 {
- t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
- }
-
- t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
- if err != nil {
- t.Fatal(err)
- }
- t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
- if t1 != t2 {
- t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
- }
- _, offset = t1.Zone()
- if offset != 10*60*60 {
- t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
- }
-}
-
-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.
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
-}
-
-// Problematic time zone format needs special tests.
-func TestRubyParse(t *testing.T) {
- for _, test := range rubyTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Errorf("%s error: %v", test.name, err)
- } else {
- checkTime(time, &test, t)
- }
- }
-}
-
-func checkTime(time Time, test *ParseTest, t *testing.T) {
- // The time should be Thu Feb 4 21:00:57 PST 2010
- if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
- t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
- }
- if time.Month() != February {
- t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
- }
- if time.Day() != 4 {
- t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
- }
- if time.Hour() != 21 {
- t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
- }
- if time.Minute() != 0 {
- t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
- }
- if time.Second() != 57 {
- t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
- }
- // Nanoseconds must be checked against the precision of the input.
- nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
- if err != nil {
- panic(err)
- }
- if time.Nanosecond() != int(nanosec) {
- t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
- }
- name, offset := time.Zone()
- if test.hasTZ && offset != -28800 {
- t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
- }
- if test.hasWD && time.Weekday() != Thursday {
- t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
- }
-}
-
-func TestFormatAndParse(t *testing.T) {
- const fmt = "Mon MST " + RFC3339 // all fields
- f := func(sec int64) bool {
- t1 := Unix(sec, 0)
- if t1.Year() < 1000 || t1.Year() > 9999 {
- // not required to work
- return true
- }
- t2, err := Parse(fmt, t1.Format(fmt))
- if err != nil {
- t.Errorf("error: %s", err)
- return false
- }
- if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
- t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
- return false
- }
- return true
- }
- f32 := func(sec int32) bool { return f(int64(sec)) }
- cfg := &quick.Config{MaxCount: 10000}
-
- // Try a reasonable date first, then the huge ones.
- if err := quick.Check(f32, cfg); err != nil {
- t.Fatal(err)
- }
- if err := quick.Check(f, cfg); err != nil {
- t.Fatal(err)
- }
-}
-
-type ParseTimeZoneTest struct {
- value string
- length int
- ok bool
-}
-
-var parseTimeZoneTests = []ParseTimeZoneTest{
- {"gmt hi there", 0, false},
- {"GMT hi there", 3, true},
- {"GMT+12 hi there", 6, true},
- {"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
- {"GMT-5 hi there", 5, true},
- {"GMT-51 hi there", 3, true},
- {"ChST hi there", 4, true},
- {"MSDx", 3, true},
- {"MSDY", 0, false}, // four letters must end in T.
- {"ESAST hi", 5, true},
- {"ESASTT hi", 0, false}, // run of upper-case letters too long.
- {"ESATY hi", 0, false}, // five letters must end in T.
-}
-
-func TestParseTimeZone(t *testing.T) {
- for _, test := range parseTimeZoneTests {
- length, ok := ParseTimeZone(test.value)
- if ok != test.ok {
- t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
- } else if length != test.length {
- t.Errorf("expected %d for %q got %d", test.length, test.value, length)
- }
- }
-}
-
-type ParseErrorTest struct {
- format string
- value string
- expect string // must appear within the error
-}
-
-var parseErrorTests = []ParseErrorTest{
- {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
- {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
- {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
- {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
- {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
- {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
- // issue 4502. StampNano requires exactly 9 digits of precision.
- {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
- {StampNano, "Dec 7 11:22:01.0000000000", "extra text: 0"},
- // issue 4493. Helpful errors.
- {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
- {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
- {RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
- {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
-}
-
-func TestParseErrors(t *testing.T) {
- for _, test := range parseErrorTests {
- _, err := Parse(test.format, test.value)
- if err == nil {
- t.Errorf("expected error for %q %q", test.format, test.value)
- } else if strings.Index(err.Error(), test.expect) < 0 {
- t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
- }
- }
-}
-
-func TestNoonIs12PM(t *testing.T) {
- noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
- const expect = "12:00PM"
- got := noon.Format("3:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
- got = noon.Format("03:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
-}
-
-func TestMidnightIs12AM(t *testing.T) {
- midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
- expect := "12:00AM"
- got := midnight.Format("3:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
- got = midnight.Format("03:04PM")
- if got != expect {
- t.Errorf("got %q; expect %q", got, expect)
- }
-}
-
-func Test12PMIsNoon(t *testing.T) {
- noon, err := Parse("3:04PM", "12:00PM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if noon.Hour() != 12 {
- t.Errorf("got %d; expect 12", noon.Hour())
- }
- noon, err = Parse("03:04PM", "12:00PM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if noon.Hour() != 12 {
- t.Errorf("got %d; expect 12", noon.Hour())
- }
-}
-
-func Test12AMIsMidnight(t *testing.T) {
- midnight, err := Parse("3:04PM", "12:00AM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if midnight.Hour() != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour())
- }
- midnight, err = Parse("03:04PM", "12:00AM")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- if midnight.Hour() != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour())
- }
-}
-
-// Check that a time without a Zone still produces a (numeric) time zone
-// when formatted with MST as a requested zone.
-func TestMissingZone(t *testing.T) {
- time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
- str := time.Format(UnixDate) // uses MST as its time zone
- if str != expect {
- t.Errorf("got %s; expect %s", str, expect)
- }
-}
-
-func TestMinutesInTimeZone(t *testing.T) {
- time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- expected := (1*60 + 23) * 60
- _, offset := time.Zone()
- if offset != expected {
- t.Errorf("ZoneOffset = %d, want %d", offset, expected)
- }
-}
-
-type SecondsTimeZoneOffsetTest struct {
- format string
- value string
- expectedoffset int
-}
-
-var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
- {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
- {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
- {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
- {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
- {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
- {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
-}
-
-func TestParseSecondsInTimeZone(t *testing.T) {
- // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58
- for _, test := range secondsTimeZoneOffsetTests {
- time, err := Parse(test.format, test.value)
- if err != nil {
- t.Fatal("error parsing date:", err)
- }
- _, offset := time.Zone()
- if offset != test.expectedoffset {
- t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
- }
- }
-}
-
-func TestFormatSecondsInTimeZone(t *testing.T) {
- d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8)))
- timestr := d.Format("2006-01-02T15:04:05Z070000")
- expected := "1871-09-17T20:04:26-003408"
- if timestr != expected {
- t.Errorf("Got %s, want %s", timestr, expected)
- }
-}
-
type ISOWeekTest struct {
year int // year
month, day int // month and day
@@ -1340,6 +842,7 @@ var parseDurationTests = []struct {
{"-.", false, 0},
{".s", false, 0},
{"+.s", false, 0},
+ {"3000000h", false, 0}, // overflow
}
func TestParseDuration(t *testing.T) {
@@ -1461,6 +964,60 @@ func TestSub(t *testing.T) {
}
}
+var nsDurationTests = []struct {
+ d Duration
+ want int64
+}{
+ {Duration(-1000), -1000},
+ {Duration(-1), -1},
+ {Duration(1), 1},
+ {Duration(1000), 1000},
+}
+
+func TestDurationNanoseconds(t *testing.T) {
+ for _, tt := range nsDurationTests {
+ if got := tt.d.Nanoseconds(); got != tt.want {
+ t.Errorf("d.Nanoseconds() = %d; want: %d", got, tt.want)
+ }
+ }
+}
+
+var minDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(-60000000000), -1},
+ {Duration(-1), -1 / 60e9},
+ {Duration(1), 1 / 60e9},
+ {Duration(60000000000), 1},
+}
+
+func TestDurationMinutes(t *testing.T) {
+ for _, tt := range minDurationTests {
+ if got := tt.d.Minutes(); got != tt.want {
+ t.Errorf("d.Minutes() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
+var hourDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(-3600000000000), -1},
+ {Duration(-1), -1 / 3600e9},
+ {Duration(1), 1 / 3600e9},
+ {Duration(3600000000000), 1},
+}
+
+func TestDurationHours(t *testing.T) {
+ for _, tt := range hourDurationTests {
+ if got := tt.d.Hours(); got != tt.want {
+ t.Errorf("d.Hours() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
t = Now()
diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go
index 1c6186258..c8e53a27c 100644
--- a/src/pkg/time/zoneinfo.go
+++ b/src/pkg/time/zoneinfo.go
@@ -45,6 +45,13 @@ type zoneTrans struct {
isstd, isutc bool // ignored - no idea what these mean
}
+// alpha and omega are the beginning and end of time for zone
+// transitions.
+const (
+ alpha = -1 << 63 // math.MinInt64
+ omega = 1<<63 - 1 // math.MaxInt64
+)
+
// UTC represents Universal Coordinated Time (UTC).
var UTC *Location = &utcLoc
@@ -83,9 +90,9 @@ func FixedZone(name string, offset int) *Location {
l := &Location{
name: name,
zone: []zone{{name, offset, false}},
- tx: []zoneTrans{{-1 << 63, 0, false, false}},
- cacheStart: -1 << 63,
- cacheEnd: 1<<63 - 1,
+ tx: []zoneTrans{{alpha, 0, false, false}},
+ cacheStart: alpha,
+ cacheEnd: omega,
}
l.cacheZone = &l.zone[0]
return l
@@ -101,12 +108,12 @@ func FixedZone(name string, offset int) *Location {
func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) {
l = l.get()
- if len(l.tx) == 0 {
+ if len(l.zone) == 0 {
name = "UTC"
offset = 0
isDST = false
- start = -1 << 63
- end = 1<<63 - 1
+ start = alpha
+ end = omega
return
}
@@ -119,10 +126,24 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
return
}
+ if len(l.tx) == 0 || sec < l.tx[0].when {
+ zone := &l.zone[l.lookupFirstZone()]
+ name = zone.name
+ offset = zone.offset
+ isDST = zone.isDST
+ start = alpha
+ if len(l.tx) > 0 {
+ end = l.tx[0].when
+ } else {
+ end = omega
+ }
+ return
+ }
+
// Binary search for entry with largest time <= sec.
// Not using sort.Search to avoid dependencies.
tx := l.tx
- end = 1<<63 - 1
+ end = omega
lo := 0
hi := len(tx)
for hi-lo > 1 {
@@ -144,6 +165,58 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
return
}
+// lookupFirstZone returns the index of the time zone to use for times
+// before the first transition time, or when there are no transition
+// times.
+//
+// The reference implementation in localtime.c from
+// http://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz
+// implements the following algorithm for these cases:
+// 1) If the first zone is unused by the transitions, use it.
+// 2) Otherwise, if there are transition times, and the first
+// transition is to a zone in daylight time, find the first
+// non-daylight-time zone before and closest to the first transition
+// zone.
+// 3) Otherwise, use the first zone that is not daylight time, if
+// there is one.
+// 4) Otherwise, use the first zone.
+func (l *Location) lookupFirstZone() int {
+ // Case 1.
+ if !l.firstZoneUsed() {
+ return 0
+ }
+
+ // Case 2.
+ if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST {
+ for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- {
+ if !l.zone[zi].isDST {
+ return zi
+ }
+ }
+ }
+
+ // Case 3.
+ for zi := range l.zone {
+ if !l.zone[zi].isDST {
+ return zi
+ }
+ }
+
+ // Case 4.
+ return 0
+}
+
+// firstZoneUsed returns whether the first zone is used by some
+// transition.
+func (l *Location) firstZoneUsed() bool {
+ for _, tx := range l.tx {
+ if tx.index == 0 {
+ return true
+ }
+ }
+ return false
+}
+
// lookupName returns information about the time zone with
// the given name (such as "EST") at the given pseudo-Unix time
// (what the given time of day would be in UTC).
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
index 0e8f3811b..4bb0cb390 100644
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -100,7 +100,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
diff --git a/src/pkg/time/zoneinfo_read.go b/src/pkg/time/zoneinfo_read.go
index 7714aa9f5..de9ebb41c 100644
--- a/src/pkg/time/zoneinfo_read.go
+++ b/src/pkg/time/zoneinfo_read.go
@@ -68,7 +68,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
// 1-byte version, then 15 bytes of padding
var p []byte
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+ if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' && p[0] != '3' {
return nil, badData
}
@@ -123,7 +123,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
return nil, badData
}
- // If version == 2, the entire file repeats, this time using
+ // If version == 2 or 3, the entire file repeats, this time using
// 8-byte ints for txtimes and leap seconds.
// We won't need those until 2106.
@@ -173,7 +173,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
if len(tx) == 0 {
// Build fake transition to cover all time.
// This happens in fixed locations like "Etc/GMT0".
- tx = append(tx, zoneTrans{when: -1 << 63, index: 0})
+ tx = append(tx, zoneTrans{when: alpha, index: 0})
}
// Committed to succeed.
@@ -185,7 +185,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
diff --git a/src/pkg/time/zoneinfo_test.go b/src/pkg/time/zoneinfo_test.go
new file mode 100644
index 000000000..4ca7fad93
--- /dev/null
+++ b/src/pkg/time/zoneinfo_test.go
@@ -0,0 +1,63 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "testing"
+ "time"
+)
+
+func TestVersion3(t *testing.T) {
+ time.ForceZipFileForTesting(true)
+ defer time.ForceZipFileForTesting(false)
+ _, err := time.LoadLocation("Asia/Jerusalem")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Test that we get the correct results for times before the first
+// transition time. To do this we explicitly check early dates in a
+// couple of specific timezones.
+func TestFirstZone(t *testing.T) {
+ time.ForceZipFileForTesting(true)
+ defer time.ForceZipFileForTesting(false)
+
+ const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
+ var tests = []struct {
+ zone string
+ unix int64
+ want1 string
+ want2 string
+ }{
+ {
+ "PST8PDT",
+ -1633269601,
+ "Sun, 31 Mar 1918 01:59:59 -0800 (PST)",
+ "Sun, 31 Mar 1918 03:00:00 -0700 (PDT)",
+ },
+ {
+ "Pacific/Fakaofo",
+ 1325242799,
+ "Thu, 29 Dec 2011 23:59:59 -1100 (TKT)",
+ "Sat, 31 Dec 2011 00:00:00 +1300 (TKT)",
+ },
+ }
+
+ for _, test := range tests {
+ z, err := time.LoadLocation(test.zone)
+ if err != nil {
+ t.Fatal(err)
+ }
+ s := time.Unix(test.unix, 0).In(z).Format(format)
+ if s != test.want1 {
+ t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want1)
+ }
+ s = time.Unix(test.unix+1, 0).In(z).Format(format)
+ if s != test.want2 {
+ t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want2)
+ }
+ }
+}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index fc5ae89fe..ab7e4612e 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
index be4e5c13f..6046743e6 100644
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -54,7 +54,7 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (
if err != nil {
return false, err
}
- if s != dstname {
+ if s != dstname && dstname != stdname {
return false, nil
}
return true, nil
@@ -90,7 +90,7 @@ func toEnglishName(stdname, dstname string) (string, error) {
return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
}
-// extractCAPS exracts capital letters from description desc.
+// extractCAPS extracts capital letters from description desc.
func extractCAPS(desc string) string {
var short []rune
for _, c := range desc {
@@ -165,8 +165,8 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
if nzone == 1 {
// No daylight savings.
std.offset = -int(i.Bias) * 60
- l.cacheStart = -1 << 63
- l.cacheEnd = 1<<63 - 1
+ l.cacheStart = alpha
+ l.cacheEnd = omega
l.cacheZone = std
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index fadaa57d8..977bd2b3b 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -74,7 +74,7 @@ const (
type d [MaxCase]rune // to make the CaseRanges text shorter
-// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// If the Delta field of a CaseRange is UpperLower, it means
// this CaseRange represents a sequence of the form (say)
// Upper Lower Upper Lower.
const (
@@ -316,7 +316,7 @@ type foldPair struct {
// SimpleFold iterates over Unicode code points equivalent under
// the Unicode-defined simple case folding. Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
-// smallest rune >= r if one exists, or else the smallest rune >= 0.
+// smallest rune > r if one exists, or else the smallest rune >= 0.
//
// For example:
// SimpleFold('A') = 'a'
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index e4d5572a0..4ee11fb36 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -387,32 +387,20 @@ func TestTurkishCase(t *testing.T) {
}
var simpleFoldTests = []string{
- // SimpleFold could order its returned slices in any order it wants,
- // but we know it orders them in increasing order starting at in
- // and looping around from MaxRune to 0.
+ // SimpleFold(x) returns the next equivalent rune > x or wraps
+ // around to smaller values.
// Easy cases.
"Aa",
- "aA",
"δΔ",
- "Δδ",
// ASCII special cases.
"KkK",
- "kKK",
- "KKk",
"Ssſ",
- "sſS",
- "ſSs",
// Non-ASCII special cases.
"ρϱΡ",
- "ϱΡρ",
- "Ρρϱ",
"ͅΙιι",
- "Ιιιͅ",
- "ιιͅΙ",
- "ιͅΙι",
// Extra special cases: has lower/upper but no case fold.
"İ",
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index e5ed08b23..8116ab8a4 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -40,7 +40,7 @@ func main() {
var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
var url = flag.String("url",
- "http://www.unicode.org/Public/6.2.0/ucd/",
+ "http://www.unicode.org/Public/6.3.0/ucd/",
"URL of Unicode database directory")
var tablelist = flag.String("tables",
"all",
@@ -386,7 +386,11 @@ func loadCasefold() {
}
}
-const progHeader = `// Generated by running
+const progHeader = `// 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.
+
+// Generated by running
// maketables --tables=%s --data=%s --casefolding=%s
// DO NOT EDIT
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index 395cc71a0..e2ba0011a 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -182,7 +182,7 @@ var inPropTest = []T{
{0x0EC4, "Logical_Order_Exception"},
{0x2FFFF, "Noncharacter_Code_Point"},
{0x065E, "Other_Alphabetic"},
- {0x2069, "Other_Default_Ignorable_Code_Point"},
+ {0x2065, "Other_Default_Ignorable_Code_Point"},
{0x0BD7, "Other_Grapheme_Extend"},
{0x0387, "Other_ID_Continue"},
{0x212E, "Other_ID_Start"},
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 939c41dc5..5670d1c5b 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -1,11 +1,15 @@
+// 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.
+
// Generated by running
-// maketables --tables=all --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+// maketables --tables=all --data=http://www.unicode.org/Public/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
// DO NOT EDIT
package unicode
// Version is the Unicode edition from which the tables are derived.
-const Version = "6.2.0"
+const Version = "6.3.0"
// Categories is the set of Unicode category tables.
var Categories = map[string]*RangeTable{
@@ -53,11 +57,12 @@ var _C = &RangeTable{
{0x007f, 0x009f, 1},
{0x00ad, 0x0600, 1363},
{0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {0x061c, 0x06dd, 193},
+ {0x070f, 0x180e, 4351},
{0x200b, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
- {0x206a, 0x206f, 1},
+ {0x2066, 0x206f, 1},
{0xd800, 0xf8ff, 1},
{0xfeff, 0xfff9, 250},
{0xfffa, 0xfffb, 1},
@@ -85,11 +90,12 @@ var _Cf = &RangeTable{
R16: []Range16{
{0x00ad, 0x0600, 1363},
{0x0601, 0x0604, 1},
- {0x06dd, 0x070f, 50},
+ {0x061c, 0x06dd, 193},
+ {0x070f, 0x180e, 4351},
{0x200b, 0x200f, 1},
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
- {0x206a, 0x206f, 1},
+ {0x2066, 0x206f, 1},
{0xfeff, 0xfff9, 250},
{0xfffa, 0xfffb, 1},
},
@@ -1545,7 +1551,7 @@ var _Mc = &RangeTable{
{0x1933, 0x1938, 1},
{0x19b0, 0x19c0, 1},
{0x19c8, 0x19c9, 1},
- {0x1a19, 0x1a1b, 1},
+ {0x1a19, 0x1a1a, 1},
{0x1a55, 0x1a57, 2},
{0x1a61, 0x1a63, 2},
{0x1a64, 0x1a6d, 9},
@@ -1717,8 +1723,8 @@ var _Mn = &RangeTable{
{0x1932, 0x1939, 7},
{0x193a, 0x193b, 1},
{0x1a17, 0x1a18, 1},
- {0x1a56, 0x1a58, 2},
- {0x1a59, 0x1a5e, 1},
+ {0x1a1b, 0x1a56, 59},
+ {0x1a58, 0x1a5e, 1},
{0x1a60, 0x1a62, 2},
{0x1a65, 0x1a6c, 1},
{0x1a73, 0x1a7c, 1},
@@ -2086,6 +2092,7 @@ var _P = &RangeTable{
{0x2053, 0x205e, 1},
{0x207d, 0x207e, 1},
{0x208d, 0x208e, 1},
+ {0x2308, 0x230b, 1},
{0x2329, 0x232a, 1},
{0x2768, 0x2775, 1},
{0x27c5, 0x27c6, 1},
@@ -2183,7 +2190,8 @@ var _Pe = &RangeTable{
{0x007d, 0x0f3b, 3774},
{0x0f3d, 0x169c, 1887},
{0x2046, 0x207e, 56},
- {0x208e, 0x232a, 668},
+ {0x208e, 0x2309, 635},
+ {0x230b, 0x232a, 31},
{0x2769, 0x2775, 2},
{0x27c6, 0x27e7, 33},
{0x27e9, 0x27ef, 2},
@@ -2360,7 +2368,8 @@ var _Ps = &RangeTable{
{0x0f3c, 0x169b, 1887},
{0x201a, 0x201e, 4},
{0x2045, 0x207d, 56},
- {0x208d, 0x2329, 668},
+ {0x208d, 0x2308, 635},
+ {0x230a, 0x2329, 31},
{0x2768, 0x2774, 2},
{0x27c5, 0x27e6, 33},
{0x27e8, 0x27ee, 2},
@@ -2450,7 +2459,8 @@ var _S = &RangeTable{
{0x2141, 0x2144, 1},
{0x214a, 0x214d, 1},
{0x214f, 0x2190, 65},
- {0x2191, 0x2328, 1},
+ {0x2191, 0x2307, 1},
+ {0x230c, 0x2328, 1},
{0x232b, 0x23f3, 1},
{0x2400, 0x2426, 1},
{0x2440, 0x244a, 1},
@@ -2630,7 +2640,6 @@ var _Sm = &RangeTable{
{0x21cf, 0x21d2, 3},
{0x21d4, 0x21f4, 32},
{0x21f5, 0x22ff, 1},
- {0x2308, 0x230b, 1},
{0x2320, 0x2321, 1},
{0x237c, 0x239b, 31},
{0x239c, 0x23b3, 1},
@@ -2818,8 +2827,8 @@ var _So = &RangeTable{
var _Z = &RangeTable{
R16: []Range16{
{0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
+ {0x1680, 0x2000, 2432},
+ {0x2001, 0x200a, 1},
{0x2028, 0x2029, 1},
{0x202f, 0x205f, 48},
{0x3000, 0x3000, 1},
@@ -2842,8 +2851,8 @@ var _Zp = &RangeTable{
var _Zs = &RangeTable{
R16: []Range16{
{0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
+ {0x1680, 0x2000, 2432},
+ {0x2001, 0x200a, 1},
{0x202f, 0x205f, 48},
{0x3000, 0x3000, 1},
},
@@ -2902,7 +2911,7 @@ var (
)
// Generated by running
-// maketables --scripts=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+// maketables --scripts=all --url=http://www.unicode.org/Public/6.3.0/ucd/
// DO NOT EDIT
// Scripts is the set of Unicode script tables.
@@ -3016,6 +3025,7 @@ var _Arabic = &RangeTable{
{0x0600, 0x0604, 1},
{0x0606, 0x060b, 1},
{0x060d, 0x061a, 1},
+ {0x061c, 0x061c, 1},
{0x061e, 0x061e, 1},
{0x0620, 0x063f, 1},
{0x0641, 0x064a, 1},
@@ -3245,7 +3255,7 @@ var _Common = &RangeTable{
{0x1cf5, 0x1cf6, 1},
{0x2000, 0x200b, 1},
{0x200e, 0x2064, 1},
- {0x206a, 0x2070, 1},
+ {0x2066, 0x2070, 1},
{0x2074, 0x207e, 1},
{0x2080, 0x208e, 1},
{0x20a0, 0x20ba, 1},
@@ -3281,6 +3291,7 @@ var _Common = &RangeTable{
{0xa700, 0xa721, 1},
{0xa788, 0xa78a, 1},
{0xa830, 0xa839, 1},
+ {0xa9cf, 0xa9cf, 1},
{0xfd3e, 0xfd3f, 1},
{0xfdfd, 0xfdfd, 1},
{0xfe10, 0xfe19, 1},
@@ -3710,7 +3721,7 @@ var _Inscriptional_Parthian = &RangeTable{
var _Javanese = &RangeTable{
R16: []Range16{
{0xa980, 0xa9cd, 1},
- {0xa9cf, 0xa9d9, 1},
+ {0xa9d0, 0xa9d9, 1},
{0xa9de, 0xa9df, 1},
},
}
@@ -4403,7 +4414,7 @@ var (
)
// Generated by running
-// maketables --props=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+// maketables --props=all --url=http://www.unicode.org/Public/6.3.0/ucd/
// DO NOT EDIT
// Properties is the set of Unicode property tables.
@@ -4453,8 +4464,10 @@ var _ASCII_Hex_Digit = &RangeTable{
var _Bidi_Control = &RangeTable{
R16: []Range16{
+ {0x061c, 0x061c, 1},
{0x200e, 0x200f, 1},
{0x202a, 0x202e, 1},
+ {0x2066, 0x2069, 1},
},
}
@@ -4931,7 +4944,7 @@ var _Other_Default_Ignorable_Code_Point = &RangeTable{
{0x034f, 0x034f, 1},
{0x115f, 0x1160, 1},
{0x17b4, 0x17b5, 1},
- {0x2065, 0x2069, 1},
+ {0x2065, 0x2065, 1},
{0x3164, 0x3164, 1},
{0xffa0, 0xffa0, 1},
{0xfff0, 0xfff8, 1},
@@ -5053,6 +5066,7 @@ var _Other_Math = &RangeTable{
{0x21d5, 0x21db, 1},
{0x21dd, 0x21dd, 1},
{0x21e4, 0x21e5, 1},
+ {0x2308, 0x230b, 1},
{0x23b4, 0x23b5, 1},
{0x23b7, 0x23b7, 1},
{0x23d0, 0x23d0, 1},
@@ -5440,7 +5454,6 @@ var _White_Space = &RangeTable{
{0x0085, 0x0085, 1},
{0x00a0, 0x00a0, 1},
{0x1680, 0x1680, 1},
- {0x180e, 0x180e, 1},
{0x2000, 0x200a, 1},
{0x2028, 0x2029, 1},
{0x202f, 0x202f, 1},
@@ -5487,7 +5500,7 @@ var (
)
// Generated by running
-// maketables --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+// maketables --data=http://www.unicode.org/Public/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -6372,7 +6385,7 @@ var foldMn = &RangeTable{
// If there is no entry for a script name, there are no such points.
var FoldScript = map[string]*RangeTable{}
-// Range entries: 3462 16-bit, 832 32-bit, 4294 total.
-// Range bytes: 20772 16-bit, 9984 32-bit, 30756 total.
+// Range entries: 3471 16-bit, 832 32-bit, 4303 total.
+// Range bytes: 20826 16-bit, 9984 32-bit, 30810 total.
// Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/pkg/unicode/utf16/utf16.go b/src/pkg/unicode/utf16/utf16.go
index 903e4012a..c0e47c535 100644
--- a/src/pkg/unicode/utf16/utf16.go
+++ b/src/pkg/unicode/utf16/utf16.go
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
// the Unicode replacement code point U+FFFD.
func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
- return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000
+ return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
}
return replacementChar
}
diff --git a/src/pkg/unicode/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index ee16a303d..3dca472bb 100644
--- a/src/pkg/unicode/utf16/utf16_test.go
+++ b/src/pkg/unicode/utf16/utf16_test.go
@@ -99,3 +99,51 @@ func TestDecode(t *testing.T) {
}
}
}
+
+var decodeRuneTests = []struct {
+ r1, r2 rune
+ want rune
+}{
+ {0xd800, 0xdc00, 0x10000},
+ {0xd800, 0xdc01, 0x10001},
+ {0xd808, 0xdf45, 0x12345},
+ {0xdbff, 0xdfff, 0x10ffff},
+ {0xd800, 'a', 0xfffd}, // illegal, replacement rune substituted
+}
+
+func TestDecodeRune(t *testing.T) {
+ for i, tt := range decodeRuneTests {
+ got := DecodeRune(tt.r1, tt.r2)
+ if got != tt.want {
+ t.Errorf("%d: DecodeRune(%q, %q) = %v; want %v", i, tt.r1, tt.r2, got, tt.want)
+ }
+ }
+}
+
+var surrogateTests = []struct {
+ r rune
+ want bool
+}{
+ // from http://en.wikipedia.org/wiki/UTF-16
+ {'\u007A', false}, // LATIN SMALL LETTER Z
+ {'\u6C34', false}, // CJK UNIFIED IDEOGRAPH-6C34 (water)
+ {'\uFEFF', false}, // Byte Order Mark
+ {'\U00010000', false}, // LINEAR B SYLLABLE B008 A (first non-BMP code point)
+ {'\U0001D11E', false}, // MUSICAL SYMBOL G CLEF
+ {'\U0010FFFD', false}, // PRIVATE USE CHARACTER-10FFFD (last Unicode code point)
+
+ {rune(0xd7ff), false}, // surr1-1
+ {rune(0xd800), true}, // surr1
+ {rune(0xdc00), true}, // surr2
+ {rune(0xe000), false}, // surr3
+ {rune(0xdfff), true}, // surr3-1
+}
+
+func TestIsSurrogate(t *testing.T) {
+ for i, tt := range surrogateTests {
+ got := IsSurrogate(tt.r)
+ if got != tt.want {
+ t.Errorf("%d: IsSurrogate(%q) = %v; want %v", i, tt.r, got, tt.want)
+ }
+ }
+}
diff --git a/src/pkg/unicode/utf8/example_test.go b/src/pkg/unicode/utf8/example_test.go
index fe2037336..7b3e7ac74 100644
--- a/src/pkg/unicode/utf8/example_test.go
+++ b/src/pkg/unicode/utf8/example_test.go
@@ -1,3 +1,7 @@
+// 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 utf8_test
import (
diff --git a/src/pkg/unicode/utf8/utf8.go b/src/pkg/unicode/utf8/utf8.go
index 93d0be5e0..0dc859a04 100644
--- a/src/pkg/unicode/utf8/utf8.go
+++ b/src/pkg/unicode/utf8/utf8.go
@@ -329,37 +329,29 @@ func RuneLen(r rune) int {
// It returns the number of bytes written.
func EncodeRune(p []byte, r rune) int {
// Negative values are erroneous. Making it unsigned addresses the problem.
- if uint32(r) <= rune1Max {
+ switch i := uint32(r); {
+ case i <= rune1Max:
p[0] = byte(r)
return 1
- }
-
- if uint32(r) <= rune2Max {
+ case i <= rune2Max:
p[0] = t2 | byte(r>>6)
p[1] = tx | byte(r)&maskx
return 2
- }
-
- if uint32(r) > MaxRune {
+ case i > MaxRune, surrogateMin <= i && i <= surrogateMax:
r = RuneError
- }
-
- if surrogateMin <= r && r <= surrogateMax {
- r = RuneError
- }
-
- if uint32(r) <= rune3Max {
+ fallthrough
+ case i <= rune3Max:
p[0] = t3 | byte(r>>12)
p[1] = tx | byte(r>>6)&maskx
p[2] = tx | byte(r)&maskx
return 3
+ default:
+ p[0] = t4 | byte(r>>18)
+ p[1] = tx | byte(r>>12)&maskx
+ p[2] = tx | byte(r>>6)&maskx
+ p[3] = tx | byte(r)&maskx
+ return 4
}
-
- p[0] = t4 | byte(r>>18)
- p[1] = tx | byte(r>>12)&maskx
- p[2] = tx | byte(r>>6)&maskx
- p[3] = tx | byte(r)&maskx
- return 4
}
// RuneCount returns the number of runes in p. Erroneous and short
diff --git a/src/race.bash b/src/race.bash
index 18201f992..1680c09e4 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -38,5 +38,11 @@ fi
# golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
go install -race cmd/cgo
go install -race std
+
+# we must unset GOROOT_FINAL before tests, because runtime/debug requires
+# correct access to source code, so if we have GOROOT_FINAL in effect,
+# at least runtime/debug test will fail.
+unset GOROOT_FINAL
+
go test -race -short std
go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
diff --git a/src/race.bat b/src/race.bat
index 0a6aee9e2..8858c57b0 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -15,6 +15,7 @@ echo race.bat must be run from go\src
goto end
:ok
+set GOROOT=%CD%\..
call make.bat --dist-tool >NUL
if errorlevel 1 goto fail
.\cmd\dist\dist env -wp >env.bat
@@ -35,7 +36,13 @@ go install -race cmd/cgo
echo # go install -race std
go install -race std
if errorlevel 1 goto fail
-echo # go test -race -short -std
+
+:: we must unset GOROOT_FINAL before tests, because runtime/debug requires
+:: correct access to source code, so if we have GOROOT_FINAL in effect,
+:: at least runtime/debug test will fail.
+set GOROOT_FINAL=
+
+echo # go test -race -short std
go test -race -short std
if errorlevel 1 goto fail
echo # go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
@@ -52,4 +59,5 @@ goto end
echo All tests passed.
:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/run.bash b/src/run.bash
index 6adb7f63d..6eec7caa4 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -6,6 +6,7 @@
set -e
eval $(go env)
+export GOROOT # the api test requires GOROOT to be set.
unset CDPATH # in case user has it set
unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens
@@ -17,6 +18,12 @@ ulimit -c 0
# Raise soft limits to hard limits for NetBSD/OpenBSD.
# We need at least 256 files and ~300 MB of bss.
# On OS X ulimit -S -n rejects 'unlimited'.
+#
+# Note that ulimit -S -n may fail if ulimit -H -n is set higher than a
+# non-root process is allowed to set the high limit.
+# This is a system misconfiguration and should be fixed on the
+# broken system, not "fixed" by ignoring the failure here.
+# See longer discussion on golang.org/issue/7381.
[ "$(ulimit -H -n)" == "unlimited" ] || ulimit -S -n $(ulimit -H -n)
[ "$(ulimit -H -d)" == "unlimited" ] || ulimit -S -d $(ulimit -H -d)
@@ -27,7 +34,7 @@ fi
# allow all.bash to avoid double-build of everything
rebuild=true
-if [ "$1" = "--no-rebuild" ]; then
+if [ "$1" == "--no-rebuild" ]; then
shift
else
echo '# Building packages and commands.'
@@ -48,6 +55,8 @@ echo '# Testing packages.'
time go test std -short -timeout=$(expr 120 \* $timeout_scale)s
echo
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
GOMAXPROCS=2 go test runtime -short -timeout=$(expr 300 \* $timeout_scale)s -cpu=1,2,4
echo
@@ -119,10 +128,30 @@ darwin-386 | darwin-amd64)
*) go test -ldflags '-linkmode=external' || exit 1;;
esac
;;
-dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
+dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
go test -ldflags '-linkmode=external' || exit 1
go test -ldflags '-linkmode=auto' ../testtls || exit 1
go test -ldflags '-linkmode=external' ../testtls || exit 1
+
+ case "$GOHOSTOS-$GOARCH" in
+ netbsd-386 | netbsd-amd64) ;; # no static linking
+ freebsd-arm) ;; # -fPIC compiled tls code will use __tls_get_addr instead
+ # of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
+ # is implemented in rtld-elf, so -fPIC isn't compatible with
+ # static linking on FreeBSD/ARM with clang. (cgo depends on
+ # -fPIC fundamentally.)
+ *)
+ if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then
+ echo "No support for static linking found (lacks libc.a?), skip cgo static linking test."
+ else
+ go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1
+ go test ../nocgo || exit 1
+ go test -ldflags '-linkmode=external' ../nocgo || exit 1
+ go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../nocgo || exit 1
+ fi
+ ;;
+ esac
+ ;;
esac
) || exit $?
@@ -152,28 +181,26 @@ go run main.go || exit 1
./test.bash || exit 1
) || exit $?
+[ "$GOOS" == nacl ] ||
(xcd ../doc/progs
time ./run || exit 1
) || exit $?
+[ "$GOOS" == nacl ] ||
[ "$GOARCH" == arm ] || # uses network, fails under QEMU
(xcd ../doc/articles/wiki
-make clean || exit 1
./test.bash || exit 1
) || exit $?
+[ "$GOOS" == nacl ] ||
(xcd ../doc/codewalk
time ./run || exit 1
) || exit $?
-echo
-echo '#' ../misc/goplay
-go build ../misc/goplay
-rm -f goplay
-
+[ "$GOOS" == nacl ] ||
[ "$GOARCH" == arm ] ||
(xcd ../test/bench/shootout
-./timing.sh -test || exit 1
+time ./timing.sh -test || exit 1
) || exit $?
[ "$GOOS" == openbsd ] || # golang.org/issue/5057
@@ -185,12 +212,17 @@ go test ../test/bench/go1 || exit 1
(xcd ../test
unset GOMAXPROCS
-time go run run.go || exit 1
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build -o runtest run.go || exit 1
+time ./runtest || exit 1
+rm -f runtest
) || exit $?
+[ "$GOOS" == nacl ] ||
+(
echo
echo '# Checking API compatibility.'
-time go run $GOROOT/src/cmd/api/run.go
+time go run $GOROOT/src/cmd/api/run.go || exit 1
+) || exit $?
echo
echo ALL TESTS PASSED
diff --git a/src/run.bat b/src/run.bat
index 48f6711ff..62692acaf 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -42,16 +42,26 @@ go test std -short -timeout=120s
if errorlevel 1 goto fail
echo.
-echo # runtime -cpu=1,2,4
+set OLDGOMAXPROCS=%GOMAXPROCS%
+
+:: We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+:: creation of first goroutines and first garbage collections in the parallel setting.
+echo # GOMAXPROCS=2 runtime -cpu=1,2,4
+set GOMAXPROCS=2
go test runtime -short -timeout=300s -cpu=1,2,4
if errorlevel 1 goto fail
echo.
+set GOMAXPROCS=%OLDGOMAXPROCS%
+set OLDGOMAXPROCS=
+
echo # sync -cpu=10
go test sync -short -timeout=120s -cpu=10
if errorlevel 1 goto fail
echo.
+:: Race detector only supported on Linux and OS X,
+:: and only on amd64, and only when cgo is enabled.
if not "%GOHOSTOS%-%GOOS%-%GOARCH%-%CGO_ENABLED%" == "windows-windows-amd64-1" goto norace
echo # Testing race detector.
go test -race -i runtime/race flag
@@ -63,11 +73,6 @@ if errorlevel 1 goto fail
echo.
:norace
-echo # ..\misc\goplay
-go build ..\misc\goplay
-if errorlevel 1 goto fail
-echo.
-
echo # ..\test\bench\go1
go test ..\test\bench\go1
if errorlevel 1 goto fail
diff --git a/src/run.rc b/src/run.rc
index 765b331aa..65e2c07e5 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -7,7 +7,7 @@ rfork e
eval `{go env}
-GOPATH = () # we disallow local import for non-local packges, if $GOROOT happens
+GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
# to be under $GOPATH, then some tests below will fail
# allow all.rc to avoid double-build of everything
@@ -32,6 +32,8 @@ echo '# Testing packages.'
time go test std -short -timeout 120s
echo
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
echo
@@ -47,10 +49,6 @@ fn xcd {
}
echo
-echo '#' ../misc/goplay
-go build ../misc/gplay
-
-echo
echo '#' ../test/bench/go1
go test ../test/bench/go1
diff --git a/test/bench/shootout/threadring.c b/test/bench/shootout/threadring.c
index a518134ba..606db71dc 100644
--- a/test/bench/shootout/threadring.c
+++ b/test/bench/shootout/threadring.c
@@ -41,8 +41,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include <string.h>
#include <limits.h>
-#define THREADS (503)
+// PTHREAD_STACK_MIN undeclared on mingw
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 65535
+#endif
+#define THREADS (503)
struct stack {
char x[PTHREAD_STACK_MIN];
@@ -94,7 +98,13 @@ int main(int argc, char **argv)
pthread_mutex_init(mutex + i, NULL);
pthread_mutex_lock(mutex + i);
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ pthread_attr_setstackaddr(&stack_attr, &stacks[i]);
+ pthread_attr_setstacksize(&stack_attr, sizeof(struct stack));
+#else
pthread_attr_setstack(&stack_attr, &stacks[i], sizeof(struct stack));
+#endif
+
pthread_create(&cthread, &stack_attr, thread, (void*)(uintptr_t)i);
}
diff --git a/test/bench/shootout/timing.sh b/test/bench/shootout/timing.sh
index 2db895c26..a06c326c3 100755
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -18,6 +18,33 @@ case "$O" in
gccm=-m64;;
esac
+EXE="out"
+havepcre=true
+haveglib=true
+havegmp=true
+case "$(uname)" in
+*MINGW* | *WIN32* | *CYGWIN*)
+ havepcre=false
+ haveglib=false
+ havegmp=false
+ if which pkg-config >/dev/null 2>&1; then
+ if pkg-config --cflags libpcre >/dev/null 2>&1
+ then
+ echo "havepcre"
+ havepcre=true
+ fi
+ if pkg-config --cflags glib-2.0 >/dev/null 2>&1
+ then
+ haveglib=true
+ fi
+ if pkg-config --cflags gmp >/dev/null 2>&1
+ then
+ havegmp=true
+ fi
+ fi
+ EXE=exe;;
+esac
+
PATH=.:$PATH
havegccgo=false
@@ -34,11 +61,11 @@ X-test)
esac
gc() {
- $GC $1.go; $LD $1.$O
+ $GC $1.go; $LD -o $O.$EXE $1.$O
}
gc_B() {
- $GC -B $1.go; $LD $1.$O
+ $GC -B $1.go; $LD -o $O.$EXE $1.$O
}
runonly() {
@@ -86,122 +113,126 @@ run() {
fasta() {
runonly echo 'fasta -n 25000000'
- run "gcc $gccm -O2 fasta.c" a.out 25000000
- run 'gccgo -O2 fasta.go' a.out -n 25000000 #commented out until WriteString is in bufio
- run 'gc fasta' $O.out -n 25000000
- run 'gc_B fasta' $O.out -n 25000000
+ run "gcc $gccm -O2 fasta.c" a.$EXE 25000000
+ run 'gccgo -O2 fasta.go' a.$EXE -n 25000000 #commented out until WriteString is in bufio
+ run 'gc fasta' $O.$EXE -n 25000000
+ run 'gc_B fasta' $O.$EXE -n 25000000
}
revcomp() {
runonly gcc -O2 fasta.c
- runonly a.out 25000000 > x
+ runonly a.$EXE 25000000 > x
runonly echo 'reverse-complement < output-of-fasta-25000000'
- run "gcc $gccm -O2 reverse-complement.c" a.out < x
- run 'gccgo -O2 reverse-complement.go' a.out < x
- run 'gc reverse-complement' $O.out < x
- run 'gc_B reverse-complement' $O.out < x
+ run "gcc $gccm -O2 reverse-complement.c" a.$EXE < x
+ run 'gccgo -O2 reverse-complement.go' a.$EXE < x
+ run 'gc reverse-complement' $O.$EXE < x
+ run 'gc_B reverse-complement' $O.$EXE < x
rm x
}
nbody() {
runonly echo 'nbody -n 50000000'
- run "gcc $gccm -O2 nbody.c -lm" a.out 50000000
- run 'gccgo -O2 nbody.go' a.out -n 50000000
- run 'gc nbody' $O.out -n 50000000
- run 'gc_B nbody' $O.out -n 50000000
+ run "gcc $gccm -O2 nbody.c -lm" a.$EXE 50000000
+ run 'gccgo -O2 nbody.go' a.$EXE -n 50000000
+ run 'gc nbody' $O.$EXE -n 50000000
+ run 'gc_B nbody' $O.$EXE -n 50000000
}
binarytree() {
runonly echo 'binary-tree 15 # too slow to use 20'
- run "gcc $gccm -O2 binary-tree.c -lm" a.out 15
- run 'gccgo -O2 binary-tree.go' a.out -n 15
- run 'gccgo -O2 binary-tree-freelist.go' a.out -n 15
- run 'gc binary-tree' $O.out -n 15
- run 'gc binary-tree-freelist' $O.out -n 15
+ run "gcc $gccm -O2 binary-tree.c -lm" a.$EXE 15
+ run 'gccgo -O2 binary-tree.go' a.$EXE -n 15
+ run 'gccgo -O2 binary-tree-freelist.go' a.$EXE -n 15
+ run 'gc binary-tree' $O.$EXE -n 15
+ run 'gc binary-tree-freelist' $O.$EXE -n 15
}
fannkuch() {
runonly echo 'fannkuch 12'
- run "gcc $gccm -O2 fannkuch.c" a.out 12
- run 'gccgo -O2 fannkuch.go' a.out -n 12
- run 'gccgo -O2 fannkuch-parallel.go' a.out -n 12
- run 'gc fannkuch' $O.out -n 12
- run 'gc fannkuch-parallel' $O.out -n 12
- run 'gc_B fannkuch' $O.out -n 12
+ run "gcc $gccm -O2 fannkuch.c" a.$EXE 12
+ run 'gccgo -O2 fannkuch.go' a.$EXE -n 12
+ run 'gccgo -O2 fannkuch-parallel.go' a.$EXE -n 12
+ run 'gc fannkuch' $O.$EXE -n 12
+ run 'gc fannkuch-parallel' $O.$EXE -n 12
+ run 'gc_B fannkuch' $O.$EXE -n 12
}
regexdna() {
runonly gcc -O2 fasta.c
- runonly a.out 100000 > x
+ runonly a.$EXE 100000 > x
runonly echo 'regex-dna 100000'
- run "gcc $gccm -O2 regex-dna.c -lpcre" a.out <x
- run 'gccgo -O2 regex-dna.go' a.out <x
- run 'gccgo -O2 regex-dna-parallel.go' a.out <x
- run 'gc regex-dna' $O.out <x
- run 'gc regex-dna-parallel' $O.out <x
- run 'gc_B regex-dna' $O.out <x
+ if $havepcre; then
+ run "gcc $gccm -O2 regex-dna.c $(pkg-config libpcre --cflags --libs)" a.$EXE <x
+ fi
+ run 'gccgo -O2 regex-dna.go' a.$EXE <x
+ run 'gccgo -O2 regex-dna-parallel.go' a.$EXE <x
+ run 'gc regex-dna' $O.$EXE <x
+ run 'gc regex-dna-parallel' $O.$EXE <x
+ run 'gc_B regex-dna' $O.$EXE <x
rm x
}
spectralnorm() {
runonly echo 'spectral-norm 5500'
- run "gcc $gccm -O2 spectral-norm.c -lm" a.out 5500
- run 'gccgo -O2 spectral-norm.go' a.out -n 5500
- run 'gc spectral-norm' $O.out -n 5500
- run 'gc_B spectral-norm' $O.out -n 5500
+ run "gcc $gccm -O2 spectral-norm.c -lm" a.$EXE 5500
+ run 'gccgo -O2 spectral-norm.go' a.$EXE -n 5500
+ run 'gc spectral-norm' $O.$EXE -n 5500
+ run 'gc_B spectral-norm' $O.$EXE -n 5500
}
knucleotide() {
runonly gcc -O2 fasta.c
- runonly a.out 1000000 > x # should be using 25000000
+ runonly a.$EXE 1000000 > x # should be using 25000000
runonly echo 'k-nucleotide 1000000'
- if [ $mode = run ]; then
- run "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.out <x
+ if [ $mode = run ] && $haveglib; then
+ run "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.$EXE <x
fi
- run 'gccgo -O2 k-nucleotide.go' a.out <x
- run 'gccgo -O2 k-nucleotide-parallel.go' a.out <x
- run 'gc k-nucleotide' $O.out <x
- run 'gc k-nucleotide-parallel' $O.out <x
- run 'gc_B k-nucleotide' $O.out <x
+ run 'gccgo -O2 k-nucleotide.go' a.$EXE <x
+ run 'gccgo -O2 k-nucleotide-parallel.go' a.$EXE <x
+ run 'gc k-nucleotide' $O.$EXE <x
+ run 'gc k-nucleotide-parallel' $O.$EXE <x
+ run 'gc_B k-nucleotide' $O.$EXE <x
rm x
}
mandelbrot() {
runonly echo 'mandelbrot 16000'
- run "gcc $gccm -O2 mandelbrot.c" a.out 16000
- run 'gccgo -O2 mandelbrot.go' a.out -n 16000
- run 'gc mandelbrot' $O.out -n 16000
- run 'gc_B mandelbrot' $O.out -n 16000
+ run "gcc $gccm -O2 mandelbrot.c" a.$EXE 16000
+ run 'gccgo -O2 mandelbrot.go' a.$EXE -n 16000
+ run 'gc mandelbrot' $O.$EXE -n 16000
+ run 'gc_B mandelbrot' $O.$EXE -n 16000
}
meteor() {
runonly echo 'meteor 2098'
- run "gcc $gccm -O2 meteor-contest.c" a.out 2098
- run 'gccgo -O2 meteor-contest.go' a.out -n 2098
- run 'gc meteor-contest' $O.out -n 2098
- run 'gc_B meteor-contest' $O.out -n 2098
+ run "gcc $gccm -O2 meteor-contest.c" a.$EXE 2098
+ run 'gccgo -O2 meteor-contest.go' a.$EXE -n 2098
+ run 'gc meteor-contest' $O.$EXE -n 2098
+ run 'gc_B meteor-contest' $O.$EXE -n 2098
}
pidigits() {
runonly echo 'pidigits 10000'
- run "gcc $gccm -O2 pidigits.c -lgmp" a.out 10000
- run 'gccgo -O2 pidigits.go' a.out -n 10000
- run 'gc pidigits' $O.out -n 10000
- run 'gc_B pidigits' $O.out -n 10000
+ if $havegmp; then
+ run "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
+ fi
+ run 'gccgo -O2 pidigits.go' a.$EXE -n 10000
+ run 'gc pidigits' $O.$EXE -n 10000
+ run 'gc_B pidigits' $O.$EXE -n 10000
}
threadring() {
runonly echo 'threadring 50000000'
- run "gcc $gccm -O2 threadring.c -lpthread" a.out 50000000
- run 'gccgo -O2 threadring.go' a.out -n 50000000
- run 'gc threadring' $O.out -n 50000000
+ run "gcc $gccm -O2 threadring.c -lpthread" a.$EXE 50000000
+ run 'gccgo -O2 threadring.go' a.$EXE -n 50000000
+ run 'gc threadring' $O.$EXE -n 50000000
}
chameneos() {
runonly echo 'chameneos 6000000'
- run "gcc $gccm -O2 chameneosredux.c -lpthread" a.out 6000000
- run 'gccgo -O2 chameneosredux.go' a.out 6000000
- run 'gc chameneosredux' $O.out 6000000
+ run "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
+ run 'gccgo -O2 chameneosredux.go' a.$EXE 6000000
+ run 'gc chameneosredux' $O.$EXE 6000000
}
case $# in
diff --git a/test/cmp.go b/test/cmp.go
index 73de502f3..80d1bf699 100644
--- a/test/cmp.go
+++ b/test/cmp.go
@@ -35,6 +35,10 @@ func istrue(b bool) {
type T *int
+type X int
+
+func (X) x() {}
+
func main() {
var a []int
var b map[string]int
@@ -129,6 +133,44 @@ func main() {
panic("bad m[c]")
}
+ // interface comparisons (issue 7207)
+ {
+ type I1 interface {
+ x()
+ }
+ type I2 interface {
+ x()
+ }
+ a1 := I1(X(0))
+ b1 := I1(X(1))
+ a2 := I2(X(0))
+ b2 := I2(X(1))
+ a3 := I1(a2)
+ a4 := I2(a1)
+ var e interface{} = X(0)
+ a5 := e.(I1)
+ a6 := e.(I2)
+ isfalse(a1 == b1)
+ isfalse(a1 == b2)
+ isfalse(a2 == b1)
+ isfalse(a2 == b2)
+ istrue(a1 == a2)
+ istrue(a1 == a3)
+ istrue(a1 == a4)
+ istrue(a1 == a5)
+ istrue(a1 == a6)
+ istrue(a2 == a3)
+ istrue(a2 == a4)
+ istrue(a2 == a5)
+ istrue(a2 == a6)
+ istrue(a3 == a4)
+ istrue(a3 == a5)
+ istrue(a3 == a6)
+ istrue(a4 == a5)
+ istrue(a4 == a6)
+ istrue(a5 == a6)
+ }
+
// non-interface comparisons
{
c := make(chan int)
@@ -387,6 +429,23 @@ func main() {
isfalse(iz != x)
}
+ // named booleans
+ {
+ type mybool bool
+ var b mybool
+
+ type T struct{ data [20]byte }
+ var x, y T
+ b = x == y
+ istrue(x == y)
+ istrue(bool(b))
+
+ m := make(map[string][10]interface{})
+ b = m["x"] == m["y"]
+ istrue(m["x"] == m["y"])
+ istrue(bool(b))
+ }
+
shouldPanic(p1)
shouldPanic(p2)
shouldPanic(p3)
diff --git a/test/cmp6.go b/test/cmp6.go
index 839c274bc..7cf76044e 100644
--- a/test/cmp6.go
+++ b/test/cmp6.go
@@ -18,7 +18,10 @@ type T3 struct{ z []int }
var t3 T3
-type T4 struct { _ []int; a float64 }
+type T4 struct {
+ _ []int
+ a float64
+}
var t4 T4
@@ -51,6 +54,14 @@ func main() {
use(p3 == p1)
use(p3 == p2)
+ // Arrays are comparable if and only if their element type is comparable.
+ var a1 [1]int
+ var a2 [1]func()
+ var a3 [0]func()
+ use(a1 == a1)
+ use(a2 == a2) // ERROR "invalid operation|invalid comparison"
+ use(a3 == a3) // ERROR "invalid operation|invalid comparison"
+
// Comparison of structs should have a good message
use(t3 == t3) // ERROR "struct|expected"
use(t4 == t4) // ERROR "cannot be compared|non-comparable"
diff --git a/test/const1.go b/test/const1.go
index a170ce9e7..58bddee7e 100644
--- a/test/const1.go
+++ b/test/const1.go
@@ -88,7 +88,7 @@ func main() {
}
const ptr = nil // ERROR "const.*nil"
-const _ = string([]byte(nil)) // ERROR "is not a constant"
-const _ = uintptr(unsafe.Pointer((*int)(nil))) // ERROR "is not a constant"
-const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil"
-const _ = (*int)(nil) // ERROR "cannot be nil"
+const _ = string([]byte(nil)) // ERROR "is not a? ?constant"
+const _ = uintptr(unsafe.Pointer((*int)(nil))) // ERROR "is not a? ?constant"
+const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil|invalid constant type"
+const _ = (*int)(nil) // ERROR "cannot be nil|invalid constant type"
diff --git a/test/const5.go b/test/const5.go
index 87fe33a38..60b4d0d12 100644
--- a/test/const5.go
+++ b/test/const5.go
@@ -18,6 +18,7 @@ var s [][30]int
func f() *[40]int
var c chan *[50]int
+var z complex128
const (
n1 = len(b.a)
@@ -29,5 +30,8 @@ const (
n6 = cap(f()) // ERROR "is not a constant|is not constant"
n7 = cap(<-c) // ERROR "is not a constant|is not constant"
+ n8 = real(z) // ERROR "is not a constant|is not constant"
+ n9 = len([4]float64{real(z)}) // ERROR "is not a constant|is not constant"
+
)
diff --git a/test/deferfin.go b/test/deferfin.go
index f9a74eba9..80372916d 100644
--- a/test/deferfin.go
+++ b/test/deferfin.go
@@ -23,6 +23,10 @@ func main() {
if runtime.GOARCH != "amd64" {
return
}
+ // Likewise for gccgo.
+ if runtime.Compiler == "gccgo" {
+ return
+ }
N := 10
count := int32(N)
var wg sync.WaitGroup
@@ -30,17 +34,17 @@ func main() {
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
- v := new(int)
+ v := new(string)
f := func() {
- if *v != 0 {
+ if *v != "" {
panic("oops")
}
}
- if *v != 0 {
+ if *v != "" {
// let the compiler think f escapes
sink = f
}
- runtime.SetFinalizer(v, func(p *int) {
+ runtime.SetFinalizer(v, func(p *string) {
atomic.AddInt32(&count, -1)
})
defer f()
diff --git a/test/divmod.go b/test/divmod.go
index 49fed0222..ad632bc83 100644
--- a/test/divmod.go
+++ b/test/divmod.go
@@ -6,7 +6,7 @@
// Test division of variables. Generate many test cases,
// compute correct answer using shift and subtract,
-// and then compare against results from divison and
+// and then compare against results from division and
// modulus operators.
//
// Primarily useful for testing software div/mod.
diff --git a/test/escape2.go b/test/escape2.go
index be89c2d84..28251aa98 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -80,7 +80,7 @@ func foo12(yyy **int) { // ERROR "leaking param: yyy"
xxx = yyy
}
-// Must treat yyy as leaking because *yyy leaks, and the escape analysis
+// Must treat yyy as leaking because *yyy leaks, and the escape analysis
// summaries in exported metadata do not distinguish these two cases.
func foo13(yyy **int) { // ERROR "leaking param: yyy"
*xxx = *yyy
@@ -135,7 +135,7 @@ func (b *Bar) Leak() *int { // ERROR "leaking param: b"
return &b.i // ERROR "&b.i escapes to heap"
}
-func (b *Bar) AlsoNoLeak() *int { // ERROR "b does not escape"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
return b.ii
}
@@ -149,7 +149,7 @@ func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
return b.ii
}
-func (b *Bar) LeaksABit() *int { // ERROR "b does not escape"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
v := 0 // ERROR "moved to heap: v"
b.ii = &v // ERROR "&v escapes"
return b.ii
@@ -182,7 +182,7 @@ func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
return b.i[:] // ERROR "b.i escapes to heap"
}
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "b does not escape"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
return b.ii[0:1]
}
@@ -1294,15 +1294,15 @@ func F4(x []byte)
func G() {
var buf1 [10]byte
F1(buf1[:]) // ERROR "buf1 does not escape"
-
+
var buf2 [10]byte // ERROR "moved to heap: buf2"
- F2(buf2[:]) // ERROR "buf2 escapes to heap"
+ F2(buf2[:]) // ERROR "buf2 escapes to heap"
var buf3 [10]byte
F3(buf3[:]) // ERROR "buf3 does not escape"
-
+
var buf4 [10]byte // ERROR "moved to heap: buf4"
- F4(buf4[:]) // ERROR "buf4 escapes to heap"
+ F4(buf4[:]) // ERROR "buf4 escapes to heap"
}
type Tm struct {
@@ -1314,9 +1314,9 @@ func (t *Tm) M() { // ERROR "t does not escape"
func foo141() {
var f func()
-
+
t := new(Tm) // ERROR "escapes to heap"
- f = t.M // ERROR "t.M does not escape"
+ f = t.M // ERROR "t.M does not escape"
_ = f
}
@@ -1324,7 +1324,7 @@ var gf func()
func foo142() {
t := new(Tm) // ERROR "escapes to heap"
- gf = t.M // ERROR "t.M escapes to heap"
+ gf = t.M // ERROR "t.M escapes to heap"
}
// issue 3888.
@@ -1357,3 +1357,136 @@ func foo144() {
//go:noescape
func foo144b(*int)
+
+// issue 7313: for loop init should not be treated as "in loop"
+
+type List struct {
+ Next *List
+}
+
+func foo145(l List) { // ERROR "l does not escape"
+ var p *List
+ for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+ }
+}
+
+func foo146(l List) { // ERROR "l does not escape"
+ var p *List
+ p = &l // ERROR "&l does not escape"
+ for ; p.Next != nil; p = p.Next {
+ }
+}
+
+func foo147(l List) { // ERROR "l does not escape"
+ var p *List
+ p = &l // ERROR "&l does not escape"
+ for p.Next != nil {
+ p = p.Next
+ }
+}
+
+func foo148(l List) { // ERROR " l does not escape"
+ for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+ }
+}
+
+// related: address of variable should have depth of variable, not of loop
+
+func foo149(l List) { // ERROR " l does not escape"
+ var p *List
+ for {
+ for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+ }
+ }
+}
+
+// issue 7934: missed ... if element type had no pointers
+
+var save150 []byte
+
+func foo150(x ...byte) { // ERROR "leaking param: x"
+ save150 = x
+}
+
+func bar150() {
+ foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+}
+
+// issue 7931: bad handling of slice of array
+
+var save151 *int
+
+func foo151(x *int) { // ERROR "leaking param: x"
+ save151 = x
+}
+
+func bar151() {
+ var a [64]int // ERROR "moved to heap: a"
+ a[4] = 101
+ foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+}
+
+func bar151b() {
+ var a [10]int // ERROR "moved to heap: a"
+ b := a[:] // ERROR "a escapes to heap"
+ foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+}
+
+func bar151c() {
+ var a [64]int // ERROR "moved to heap: a"
+ a[4] = 101
+ foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+}
+
+func bar151d() {
+ var a [10]int // ERROR "moved to heap: a"
+ b := a[:] // ERROR "a escapes to heap"
+ foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+}
+
+// issue 8120
+
+type U struct {
+ s *string
+}
+
+func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+ return u.s
+}
+
+type V struct {
+ s *string
+}
+
+func NewV(u U) *V { // ERROR "leaking param: u"
+ return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+}
+
+func foo152() {
+ a := "a" // ERROR "moved to heap: a"
+ u := U{&a} // ERROR "&a escapes to heap"
+ v := NewV(u)
+ println(v)
+}
+
+// issue 8176 - &x in type switch body not marked as escaping
+
+func foo153(v interface{}) *int { // ERROR "leaking param: v"
+ switch x := v.(type) {
+ case int: // ERROR "moved to heap: x"
+ return &x // ERROR "&x escapes to heap"
+ }
+ panic(0)
+}
+
+// issue 8185 - &result escaping into result
+
+func f() (x int, y *int) { // ERROR "moved to heap: x"
+ y = &x // ERROR "&x escapes to heap"
+ return
+}
+
+func g() (x interface{}) { // ERROR "moved to heap: x"
+ x = &x // ERROR "&x escapes to heap"
+ return
+}
diff --git a/test/escape5.go b/test/escape5.go
index c9646872d..a33daeee1 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -17,19 +17,19 @@ func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
return p
}
-func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result .anon1" "leaking param: p to result .anon2"
+func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
return p, p
}
-func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon2" "leaking param: q to result .anon3"
+func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
return p, q
}
-func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon3" "leaking param: q to result .anon2"
+func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
return leaktoret22(q, p)
}
-func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon3" "leaking param: q to result .anon2"
+func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
r, s := leaktoret22(q, p)
return r, s
}
diff --git a/test/fixedbugs/bug176.go b/test/fixedbugs/bug176.go
index 82f8dba0a..ea3a90974 100644
--- a/test/fixedbugs/bug176.go
+++ b/test/fixedbugs/bug176.go
@@ -9,6 +9,6 @@ package main
var x int
var a = []int{ x: 1} // ERROR "constant"
-var b = [...]int{ x : 1} // ERROR "constant"
+var b = [...]int{x: 1}
var c = map[int]int{ x: 1}
diff --git a/test/fixedbugs/bug191.dir/a.go b/test/fixedbugs/bug191.dir/a.go
index b87ad6f4f..139a8a3a2 100644
--- a/test/fixedbugs/bug191.dir/a.go
+++ b/test/fixedbugs/bug191.dir/a.go
@@ -4,8 +4,10 @@
package a
+var A int
+
func init() {
- println("a");
+ A = 1
}
type T int;
diff --git a/test/fixedbugs/bug191.dir/b.go b/test/fixedbugs/bug191.dir/b.go
index 3e780ac0d..36770f6fc 100644
--- a/test/fixedbugs/bug191.dir/b.go
+++ b/test/fixedbugs/bug191.dir/b.go
@@ -4,8 +4,10 @@
package b
+var B int
+
func init() {
- println("b");
+ B = 2
}
type V int;
diff --git a/test/fixedbugs/bug191.dir/main.go b/test/fixedbugs/bug191.dir/main.go
index 995134ccf..2d24dd12d 100644
--- a/test/fixedbugs/bug191.dir/main.go
+++ b/test/fixedbugs/bug191.dir/main.go
@@ -11,4 +11,7 @@ var _ T
var _ V
func main() {
+ if A != 1 || B != 2 {
+ panic("wrong vars")
+ }
}
diff --git a/test/fixedbugs/bug191.go b/test/fixedbugs/bug191.go
index acb4796b3..248e23edf 100644
--- a/test/fixedbugs/bug191.go
+++ b/test/fixedbugs/bug191.go
@@ -1,4 +1,4 @@
-// rundircmpout
+// rundir
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/test/fixedbugs/bug191.out b/test/fixedbugs/bug191.out
deleted file mode 100644
index 0e1677a97..000000000
--- a/test/fixedbugs/bug191.out
+++ /dev/null
@@ -1,2 +0,0 @@
-b
-a
diff --git a/test/fixedbugs/bug385_32.go b/test/fixedbugs/bug385_32.go
index 724ed9326..daf2a083c 100644
--- a/test/fixedbugs/bug385_32.go
+++ b/test/fixedbugs/bug385_32.go
@@ -1,4 +1,4 @@
-// +build 386 arm
+// +build 386 amd64p32 arm
// errorcheck
// Copyright 2011 The Go Authors. All rights reserved.
@@ -9,7 +9,7 @@
package main
func main() {
- var arr [1000200030]int // ERROR "type .* too large"
+ var arr [1000200030]int // GC_ERROR "type .* too large"
arr_bkup := arr
_ = arr_bkup
}
diff --git a/test/fixedbugs/bug385_64.go b/test/fixedbugs/bug385_64.go
index aef03c389..6789c0abf 100644
--- a/test/fixedbugs/bug385_64.go
+++ b/test/fixedbugs/bug385_64.go
@@ -12,7 +12,7 @@ package main
var z [10<<20]byte
-func main() { // ERROR "stack frame too large"
+func main() { // GC_ERROR "stack frame too large"
// seq 1 206 | sed 's/.*/ var x& [10<<20]byte; z = x&/'
var x1 [10<<20]byte; z = x1
var x2 [10<<20]byte; z = x2
diff --git a/test/fixedbugs/bug462.go b/test/fixedbugs/bug462.go
index 6434255c8..1a23ad064 100644
--- a/test/fixedbugs/bug462.go
+++ b/test/fixedbugs/bug462.go
@@ -14,6 +14,6 @@ type T struct {
func main() {
_ = T {
- os.File: 1, // ERROR "unknown T field"
+ os.File: 1, // ERROR "unknown T? ?field"
}
}
diff --git a/test/fixedbugs/bug476.go b/test/fixedbugs/bug476.go
index 4ea217404..563fd9156 100644
--- a/test/fixedbugs/bug476.go
+++ b/test/fixedbugs/bug476.go
@@ -5,7 +5,7 @@
// license that can be found in the LICENSE file.
// Logical operation on named boolean type returns the same type,
-// supporting an implicit convertion to an interface type. This used
+// supporting an implicit conversion to an interface type. This used
// to crash gccgo.
package p
diff --git a/src/pkg/runtime/export_test.c b/test/fixedbugs/bug480.dir/a.go
index 5ad1a7007..6dff51586 100644
--- a/src/pkg/runtime/export_test.c
+++ b/test/fixedbugs/bug480.dir/a.go
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "runtime.h"
-#include "arch_GOARCH.h"
-
-void
-·GogoBytes(int32 x)
-{
- x = RuntimeGogoBytes;
- FLUSH(&x);
+package a
+
+type S interface{
+ F() T
+}
+
+type T struct {
+ S
+}
+
+type U struct {
+ error
}
diff --git a/test/fixedbugs/bug480.dir/b.go b/test/fixedbugs/bug480.dir/b.go
new file mode 100644
index 000000000..620736540
--- /dev/null
+++ b/test/fixedbugs/bug480.dir/b.go
@@ -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 b
+
+import "./a"
+
+var t a.T
+
+func F() error {
+ return a.U{}
+}
diff --git a/test/fixedbugs/bug480.go b/test/fixedbugs/bug480.go
new file mode 100644
index 000000000..5b44af430
--- /dev/null
+++ b/test/fixedbugs/bug480.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// 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.
+
+// Gccgo mishandled an import of a forward declared type.
+
+package ignored
diff --git a/test/fixedbugs/bug481.go b/test/fixedbugs/bug481.go
new file mode 100644
index 000000000..d0922a5a4
--- /dev/null
+++ b/test/fixedbugs/bug481.go
@@ -0,0 +1,18 @@
+// compile
+
+// 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.
+
+// Returning an index into a conversion from string to slice caused a
+// compilation error when using gccgo.
+
+package p
+
+func F1(s string) byte {
+ return []byte(s)[0]
+}
+
+func F2(s string) rune {
+ return []rune(s)[0]
+}
diff --git a/test/fixedbugs/bug482.go b/test/fixedbugs/bug482.go
new file mode 100644
index 000000000..10c48287d
--- /dev/null
+++ b/test/fixedbugs/bug482.go
@@ -0,0 +1,20 @@
+// compile
+
+// 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.
+
+// Using the same name for a field in a composite literal and for a
+// global variable that depends on the variable being initialized
+// caused gccgo to erroneously report "variable initializer refers to
+// itself".
+
+package p
+
+type S struct {
+ F int
+}
+
+var V = S{F: 1}
+
+var F = V.F
diff --git a/test/fixedbugs/bug483.go b/test/fixedbugs/bug483.go
new file mode 100644
index 000000000..2372e89a7
--- /dev/null
+++ b/test/fixedbugs/bug483.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for a garbage collection bug involving not
+// marking x as having its address taken by &x[0]
+// when x is an array value.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+)
+
+func main() {
+ var x = [4]struct{ x, y interface{} }{
+ {"a", "b"},
+ {"c", "d"},
+ {"e", "f"},
+ {"g", "h"},
+ }
+
+ var buf bytes.Buffer
+ for _, z := range x {
+ runtime.GC()
+ fmt.Fprintf(&buf, "%s %s ", z.x.(string), z.y.(string))
+ }
+
+ if buf.String() != "a b c d e f g h " {
+ println("BUG wrong output\n", buf.String())
+ }
+}
diff --git a/test/fixedbugs/bug484.go b/test/fixedbugs/bug484.go
new file mode 100644
index 000000000..c664b83af
--- /dev/null
+++ b/test/fixedbugs/bug484.go
@@ -0,0 +1,90 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The liveness code used to say that, in func g, s was live
+// starting at its declaration, because it appears to have its
+// address taken by the closure (different s, but the parser
+// gets slightly confused, a separate bug). The liveness analysis
+// saw s as having its address taken but the register optimizer
+// did not. This mismatch meant that s would be marked live
+// (and therefore initialized) at the call to f, but the register optimizer
+// would optimize away the initialization of s before f, causing the
+// garbage collector to use unused data.
+// The register optimizer has been changed to respect the
+// same "address taken" flag that the liveness analysis uses,
+// even if it cannot see any address being taken in the actual
+// machine code. This is conservative but keeps the two consistent,
+// which is the most important thing.
+
+package main
+
+import "runtime"
+
+var c bool
+
+func f() interface{} {
+ if c { // disable inlining
+ f()
+ }
+ runtime.GC()
+ return nil
+}
+
+func g() {
+ if c { // disable inlining
+ g()
+ }
+ var s interface{}
+ _ = func() {
+ s := f()
+ _ = s
+ }
+ s = f()
+ useiface(s)
+ useiface(s)
+}
+
+func useiface(x interface{}) {
+ if c { // disable inlining
+ useiface(x)
+ }
+}
+
+func h() {
+ if c { // disable inlining
+ h()
+ }
+ var x [16]uintptr
+ for i := range x {
+ x[i] = 1
+ }
+
+ useint(x[0])
+ useint(x[1])
+ useint(x[2])
+ useint(x[3])
+}
+
+func useint(x uintptr) {
+ if c { // disable inlining
+ useint(x)
+ }
+}
+
+func main() {
+ // scribble non-zero values on stack
+ h()
+ // call function that used to let the garbage collector
+ // see uninitialized stack values; it will see the
+ // nonzero values.
+ g()
+}
+
+func big(x int) {
+ if x >= 0 {
+ big(x-1)
+ }
+}
diff --git a/test/fixedbugs/bug485.go b/test/fixedbugs/bug485.go
new file mode 100644
index 000000000..1544753ab
--- /dev/null
+++ b/test/fixedbugs/bug485.go
@@ -0,0 +1,39 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Gccgo chose the wrong embedded method when the same type appeared
+// at different levels and the correct choice was not the first
+// appearance of the type in a depth-first search.
+
+package main
+
+type embedded string
+
+func (s embedded) val() string {
+ return string(s)
+}
+
+type A struct {
+ embedded
+}
+
+type B struct {
+ A
+ embedded
+}
+
+func main() {
+ b := &B{
+ A: A{
+ embedded: "a",
+ },
+ embedded: "b",
+ }
+ s := b.val()
+ if s != "b" {
+ panic(s)
+ }
+}
diff --git a/test/fixedbugs/issue1304.go b/test/fixedbugs/issue1304.go
new file mode 100644
index 000000000..1206e1840
--- /dev/null
+++ b/test/fixedbugs/issue1304.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var a = 1
+
+func main() {
+ defer func() {
+ recover()
+ if a != 2 {
+ println("BUG a =", a)
+ }
+ }()
+ a = 2
+ b := a - a
+ c := 4
+ a = c / b
+ a = 3
+}
diff --git a/test/fixedbugs/issue3705.go b/test/fixedbugs/issue3705.go
index c19bcea1c..64ef38b10 100644
--- a/test/fixedbugs/issue3705.go
+++ b/test/fixedbugs/issue3705.go
@@ -6,4 +6,4 @@
package p
-func init() // ERROR "missing function body"
+func init() // ERROR "missing function body|cannot declare init"
diff --git a/test/fixedbugs/issue4251.go b/test/fixedbugs/issue4251.go
index 4adec2bab..3668d4c89 100644
--- a/test/fixedbugs/issue4251.go
+++ b/test/fixedbugs/issue4251.go
@@ -9,13 +9,13 @@
package p
func F1(s []byte) []byte {
- return s[2:1] // ERROR "invalid slice index"
+ return s[2:1] // ERROR "invalid slice index|inverted slice range"
}
func F2(a [10]byte) []byte {
- return a[2:1] // ERROR "invalid slice index"
+ return a[2:1] // ERROR "invalid slice index|inverted slice range"
}
func F3(s string) string {
- return s[2:1] // ERROR "invalid slice index"
+ return s[2:1] // ERROR "invalid slice index|inverted slice range"
}
diff --git a/test/fixedbugs/issue4388.go b/test/fixedbugs/issue4388.go
new file mode 100644
index 000000000..2e052e138
--- /dev/null
+++ b/test/fixedbugs/issue4388.go
@@ -0,0 +1,56 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+)
+
+type T struct {
+ io.Closer
+}
+
+func f1() {
+ // The 4 here and below depends on the number of internal runtime frames
+ // that sit between a deferred function called during panic and
+ // the original frame. If that changes, this test will start failing and
+ // the number here will need to be updated.
+ defer checkLine(4)
+ var t *T
+ var c io.Closer = t
+ c.Close()
+}
+
+func f2() {
+ defer checkLine(4)
+ var t T
+ var c io.Closer = t
+ c.Close()
+}
+
+func main() {
+ f1()
+ f2()
+}
+
+func checkLine(n int) {
+ if err := recover(); err == nil {
+ panic("did not panic")
+ }
+ var file string
+ var line int
+ for i := 1; i <= n; i++ {
+ _, file, line, _ = runtime.Caller(i)
+ if file != "<autogenerated>" || line != 1 {
+ continue
+ }
+ return
+ }
+ panic(fmt.Sprintf("expected <autogenerated>:1 have %s:%d", file, line))
+}
diff --git a/test/fixedbugs/issue4405.go b/test/fixedbugs/issue4405.go
index c0d808559..b8458d776 100644
--- a/test/fixedbugs/issue4405.go
+++ b/test/fixedbugs/issue4405.go
@@ -8,8 +8,8 @@ package p
const (
_ = iota
- _ // ERROR "illegal character"
- _ // ERROR "illegal character"
- _ // ERROR "illegal character"
- _ // ERROR "illegal character"
+ _ // ERROR "illegal character|invalid character"
+ _ // ERROR "illegal character|invalid character"
+ _ // ERROR "illegal character|invalid character"
+ _ // ERROR "illegal character|invalid character"
)
diff --git a/test/fixedbugs/issue4429.go b/test/fixedbugs/issue4429.go
index 8a93b0204..6822760ef 100644
--- a/test/fixedbugs/issue4429.go
+++ b/test/fixedbugs/issue4429.go
@@ -12,5 +12,5 @@ type a struct {
func main() {
av := a{};
- *a(av); // ERROR "invalid indirect"
+ _ = *a(av); // ERROR "invalid indirect|expected pointer"
}
diff --git a/test/fixedbugs/issue4510.dir/f1.go b/test/fixedbugs/issue4510.dir/f1.go
index 1e642e4ce..7e2cffa5d 100644
--- a/test/fixedbugs/issue4510.dir/f1.go
+++ b/test/fixedbugs/issue4510.dir/f1.go
@@ -4,6 +4,6 @@
package p
-import "fmt" // ERROR "fmt redeclared"
+import "fmt" // ERROR "fmt redeclared|imported"
var _ = fmt.Printf
diff --git a/test/fixedbugs/issue4517d.go b/test/fixedbugs/issue4517d.go
index f601db66f..3d727d433 100644
--- a/test/fixedbugs/issue4517d.go
+++ b/test/fixedbugs/issue4517d.go
@@ -6,4 +6,4 @@
package p
-import init "fmt" // ERROR "cannot import package as init - init must be a func"
+import init "fmt" // ERROR "cannot import package as init"
diff --git a/test/fixedbugs/issue4545.go b/test/fixedbugs/issue4545.go
index 501caadb0..c37ccef7c 100644
--- a/test/fixedbugs/issue4545.go
+++ b/test/fixedbugs/issue4545.go
@@ -13,7 +13,7 @@ import "fmt"
func main() {
var s uint
- fmt.Println(1.0 + 1<<s) // ERROR "invalid operation|non-integer type"
+ fmt.Println(1.0 + 1<<s) // ERROR "invalid operation|non-integer type|incompatible type"
x := 1.0 + 1<<s // ERROR "invalid operation|non-integer type"
_ = x
}
diff --git a/test/fixedbugs/issue4610.go b/test/fixedbugs/issue4610.go
index bc6bfe790..d56c6d3e8 100644
--- a/test/fixedbugs/issue4610.go
+++ b/test/fixedbugs/issue4610.go
@@ -12,6 +12,6 @@ type bar struct {
func main() {
var foo bar
- _ = &foo{} // ERROR "is not a type"
-}
+ _ = &foo{} // ERROR "is not a type|expected .;."
+} // GCCGO_ERROR "expected declaration"
diff --git a/test/fixedbugs/issue4618.go b/test/fixedbugs/issue4618.go
index 335feaadb..fe875b350 100644
--- a/test/fixedbugs/issue4618.go
+++ b/test/fixedbugs/issue4618.go
@@ -9,6 +9,7 @@ package main
import (
"fmt"
"os"
+ "runtime"
"testing"
)
@@ -29,11 +30,11 @@ func G() {
func main() {
nf := testing.AllocsPerRun(100, F)
ng := testing.AllocsPerRun(100, G)
- if int(nf) != 1 {
+ if int(nf) > 1 {
fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
os.Exit(1)
}
- if int(ng) != 0 {
+ if int(ng) != 0 && (runtime.Compiler != "gccgo" || int(ng) != 1) {
fmt.Printf("AllocsPerRun(100, G) = %v, want 0\n", ng)
os.Exit(1)
}
diff --git a/test/fixedbugs/issue4654.go b/test/fixedbugs/issue4654.go
index 170594e4b..d3f582b20 100644
--- a/test/fixedbugs/issue4654.go
+++ b/test/fixedbugs/issue4654.go
@@ -12,32 +12,32 @@ package p
import "unsafe"
func f() {
- defer int(0) // ERROR "defer requires function call, not conversion"
- go string([]byte("abc")) // ERROR "go requires function call, not conversion"
+ defer int(0) // ERROR "defer requires function call, not conversion|is not used"
+ go string([]byte("abc")) // ERROR "go requires function call, not conversion|is not used"
var c complex128
var f float64
var t struct {X int}
var x []int
- defer append(x, 1) // ERROR "defer discards result of append"
- defer cap(x) // ERROR "defer discards result of cap"
- defer complex(1, 2) // ERROR "defer discards result of complex"
- defer complex(f, 1) // ERROR "defer discards result of complex"
- defer imag(1i) // ERROR "defer discards result of imag"
- defer imag(c) // ERROR "defer discards result of imag"
- defer len(x) // ERROR "defer discards result of len"
- defer make([]int, 1) // ERROR "defer discards result of make"
- defer make(chan bool) // ERROR "defer discards result of make"
- defer make(map[string]int) // ERROR "defer discards result of make"
- defer new(int) // ERROR "defer discards result of new"
- defer real(1i) // ERROR "defer discards result of real"
- defer real(c) // ERROR "defer discards result of real"
- defer append(x, 1) // ERROR "defer discards result of append"
- defer append(x, 1) // ERROR "defer discards result of append"
- defer unsafe.Alignof(t.X) // ERROR "defer discards result of unsafe.Alignof"
- defer unsafe.Offsetof(t.X) // ERROR "defer discards result of unsafe.Offsetof"
- defer unsafe.Sizeof(t) // ERROR "defer discards result of unsafe.Sizeof"
+ defer append(x, 1) // ERROR "defer discards result of append|is not used"
+ defer cap(x) // ERROR "defer discards result of cap|is not used"
+ defer complex(1, 2) // ERROR "defer discards result of complex|is not used"
+ defer complex(f, 1) // ERROR "defer discards result of complex|is not used"
+ defer imag(1i) // ERROR "defer discards result of imag|is not used"
+ defer imag(c) // ERROR "defer discards result of imag|is not used"
+ defer len(x) // ERROR "defer discards result of len|is not used"
+ defer make([]int, 1) // ERROR "defer discards result of make|is not used"
+ defer make(chan bool) // ERROR "defer discards result of make|is not used"
+ defer make(map[string]int) // ERROR "defer discards result of make|is not used"
+ defer new(int) // ERROR "defer discards result of new|is not used"
+ defer real(1i) // ERROR "defer discards result of real|is not used"
+ defer real(c) // ERROR "defer discards result of real|is not used"
+ defer append(x, 1) // ERROR "defer discards result of append|is not used"
+ defer append(x, 1) // ERROR "defer discards result of append|is not used"
+ defer unsafe.Alignof(t.X) // ERROR "defer discards result of unsafe.Alignof|is not used"
+ defer unsafe.Offsetof(t.X) // ERROR "defer discards result of unsafe.Offsetof|is not used"
+ defer unsafe.Sizeof(t) // ERROR "defer discards result of unsafe.Sizeof|is not used"
defer copy(x, x) // ok
m := make(map[int]int)
@@ -47,8 +47,8 @@ func f() {
defer println(1) // ok
defer recover() // ok
- int(0) // ERROR "int\(0\) evaluated but not used"
- string([]byte("abc")) // ERROR "string\(.*\) evaluated but not used"
+ int(0) // ERROR "int\(0\) evaluated but not used|is not used"
+ string([]byte("abc")) // ERROR "string\(.*\) evaluated but not used|is not used"
append(x, 1) // ERROR "not used"
cap(x) // ERROR "not used"
diff --git a/test/fixedbugs/issue4667.go b/test/fixedbugs/issue4667.go
index 3a00a3195..18d773c2c 100644
--- a/test/fixedbugs/issue4667.go
+++ b/test/fixedbugs/issue4667.go
@@ -26,11 +26,11 @@ func F() {
func main() {
nf := testing.AllocsPerRun(100, F)
ng := testing.AllocsPerRun(100, G)
- if int(nf) != 1 {
+ if int(nf) > 1 {
fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
os.Exit(1)
}
- if int(ng) != 1 {
+ if int(ng) > 1 {
fmt.Printf("AllocsPerRun(100, G) = %v, want 1\n", ng)
os.Exit(1)
}
diff --git a/test/fixedbugs/issue4776.go b/test/fixedbugs/issue4776.go
index c38dc09b1..13781af1f 100644
--- a/test/fixedbugs/issue4776.go
+++ b/test/fixedbugs/issue4776.go
@@ -6,5 +6,5 @@
// Issue 4776: missing package declaration error should be fatal.
-type MyInt int32 // ERROR "package statement must be first"
+type MyInt int32 // ERROR "package statement must be first|package clause"
diff --git a/test/fixedbugs/issue4813.go b/test/fixedbugs/issue4813.go
index 20dc58795..f560b2fac 100644
--- a/test/fixedbugs/issue4813.go
+++ b/test/fixedbugs/issue4813.go
@@ -28,25 +28,25 @@ var (
var (
a1 = A[i]
a2 = A[f]
- a3 = A[f2] // ERROR "truncated"
+ a3 = A[f2] // ERROR "truncated|must be integer"
a4 = A[c]
- a5 = A[c2] // ERROR "truncated"
+ a5 = A[c2] // ERROR "truncated|must be integer"
a6 = A[vf] // ERROR "non-integer|must be integer"
a7 = A[vc] // ERROR "non-integer|must be integer"
s1 = S[i]
s2 = S[f]
- s3 = S[f2] // ERROR "truncated"
+ s3 = S[f2] // ERROR "truncated|must be integer"
s4 = S[c]
- s5 = S[c2] // ERROR "truncated"
+ s5 = S[c2] // ERROR "truncated|must be integer"
s6 = S[vf] // ERROR "non-integer|must be integer"
s7 = S[vc] // ERROR "non-integer|must be integer"
t1 = T[i]
t2 = T[f]
- t3 = T[f2] // ERROR "truncated"
+ t3 = T[f2] // ERROR "truncated|must be integer"
t4 = T[c]
- t5 = T[c2] // ERROR "truncated"
+ t5 = T[c2] // ERROR "truncated|must be integer"
t6 = T[vf] // ERROR "non-integer|must be integer"
t7 = T[vc] // ERROR "non-integer|must be integer"
)
diff --git a/test/fixedbugs/issue4847.go b/test/fixedbugs/issue4847.go
index a99e80129..91a6568f2 100644
--- a/test/fixedbugs/issue4847.go
+++ b/test/fixedbugs/issue4847.go
@@ -19,6 +19,6 @@ func matchList(s *S) E { return matcher(matchAnyFn)(s) }
var foo = matcher(matchList)
-var matchAny = matcher(matchList) // ERROR "initialization loop"
+var matchAny = matcher(matchList) // ERROR "initialization loop|depends upon itself"
func matchAnyFn(s *S) (err E) { return matchAny(s) }
diff --git a/test/fixedbugs/issue5089.go b/test/fixedbugs/issue5089.go
index 14d6bde98..81b9f0521 100644
--- a/test/fixedbugs/issue5089.go
+++ b/test/fixedbugs/issue5089.go
@@ -8,8 +8,8 @@
package p
-import "bufio"
+import "bufio" // GCCGO_ERROR "previous"
-func (b *bufio.Reader) Buffered() int { // ERROR "non-local"
+func (b *bufio.Reader) Buffered() int { // ERROR "non-local|redefinition"
return -1
}
diff --git a/test/fixedbugs/issue5172.go b/test/fixedbugs/issue5172.go
index 2dd542a5d..a6acbd3db 100644
--- a/test/fixedbugs/issue5172.go
+++ b/test/fixedbugs/issue5172.go
@@ -14,6 +14,6 @@ type foo struct {
func main() {
var f foo
- go f.bar()
- defer f.bar()
+ go f.bar() // GCCGO_ERROR "undefined"
+ defer f.bar() // GCCGO_ERROR "undefined"
}
diff --git a/test/fixedbugs/issue5358.go b/test/fixedbugs/issue5358.go
index 75aa9533d..c2b1da9e0 100644
--- a/test/fixedbugs/issue5358.go
+++ b/test/fixedbugs/issue5358.go
@@ -13,5 +13,5 @@ func f(x int, y ...int) {}
func g() (int, []int)
func main() {
- f(g()) // ERROR "as type int in"
+ f(g()) // ERROR "as type int in|incompatible type"
}
diff --git a/test/fixedbugs/issue5493.go b/test/fixedbugs/issue5493.go
index affc07b58..2ee0398af 100644
--- a/test/fixedbugs/issue5493.go
+++ b/test/fixedbugs/issue5493.go
@@ -31,9 +31,10 @@ func run() error {
}
func main() {
- // Does not work on 32-bits due to partially conservative GC.
+ // Does not work on 32-bits, or with gccgo, due to partially
+ // conservative GC.
// Try to enable when we have fully precise GC.
- if runtime.GOARCH != "amd64" {
+ if runtime.GOARCH != "amd64" || runtime.Compiler == "gccgo" {
return
}
count = N
diff --git a/test/fixedbugs/issue5581.go b/test/fixedbugs/issue5581.go
index 8c2d59729..36a4ad671 100644
--- a/test/fixedbugs/issue5581.go
+++ b/test/fixedbugs/issue5581.go
@@ -26,7 +26,7 @@ type Foo struct {
type Bar struct {
A *Foo
- B chan Blah // ERROR "undefined: Blah"
+ B chan Blah // ERROR "undefined.*Blah"
}
func main() {
diff --git a/test/fixedbugs/issue5793.go b/test/fixedbugs/issue5793.go
new file mode 100644
index 000000000..f5a9965f2
--- /dev/null
+++ b/test/fixedbugs/issue5793.go
@@ -0,0 +1,36 @@
+// run
+
+// 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.
+
+// Issue 5793: calling 2-arg builtin with multiple-result f() call expression gives
+// spurious error.
+
+package main
+
+func complexArgs() (float64, float64) {
+ return 5, 7
+}
+
+func appendArgs() ([]string, string) {
+ return []string{"foo"}, "bar"
+}
+
+func appendMultiArgs() ([]byte, byte, byte) {
+ return []byte{'a', 'b'}, '1', '2'
+}
+
+func main() {
+ if c := complex(complexArgs()); c != 5+7i {
+ panic(c)
+ }
+
+ if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
+ panic(s)
+ }
+
+ if b := append(appendMultiArgs()); len(b) != 4 || b[0] != 'a' || b[1] != 'b' || b[2] != '1' || b[3] != '2' {
+ panic(b)
+ }
+}
diff --git a/test/fixedbugs/issue5957.dir/c.go b/test/fixedbugs/issue5957.dir/c.go
index 42c88177b..a1781d4d4 100644
--- a/test/fixedbugs/issue5957.dir/c.go
+++ b/test/fixedbugs/issue5957.dir/c.go
@@ -1,12 +1,12 @@
package p
import (
- "./a" // ERROR "imported and not used: \x22a\x22 as surprise"
- "./b" // ERROR "imported and not used: \x22b\x22 as surprise2"
- b "./b" // ERROR "imported and not used: \x22b\x22$"
- foo "math" // ERROR "imported and not used: \x22math\x22 as foo"
+ "./a" // ERROR "imported and not used: \x22a\x22 as surprise|imported and not used: surprise"
+ "./b" // GC_ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2"
+ b "./b" // ERROR "imported and not used: \x22b\x22$|imported and not used: surprise2"
+ foo "math" // ERROR "imported and not used: \x22math\x22 as foo|imported and not used: math"
"fmt" // actually used
- "strings" // ERROR "imported and not used: \x22strings\x22"
+ "strings" // ERROR "imported and not used: \x22strings\x22|imported and not used: strings"
)
var _ = fmt.Printf
diff --git a/test/fixedbugs/issue6295.dir/p0.go b/test/fixedbugs/issue6295.dir/p0.go
new file mode 100644
index 000000000..cf86fbcb5
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p0.go
@@ -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 p0
+
+type T0 interface {
+ m0()
+}
+
+type S0 struct{}
+
+func (S0) m0() {}
diff --git a/test/fixedbugs/issue6295.dir/p1.go b/test/fixedbugs/issue6295.dir/p1.go
new file mode 100644
index 000000000..974d02fb0
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p1.go
@@ -0,0 +1,26 @@
+// 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 p1
+
+import "./p0"
+
+type T1 interface {
+ p0.T0
+ m1()
+}
+
+type S1 struct {
+ p0.S0
+}
+
+func (S1) m1() {}
+
+func NewT0() p0.T0 {
+ return S1{}
+}
+
+func NewT1() T1 {
+ return S1{}
+}
diff --git a/test/fixedbugs/issue6295.dir/p2.go b/test/fixedbugs/issue6295.dir/p2.go
new file mode 100644
index 000000000..4703ec035
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p2.go
@@ -0,0 +1,19 @@
+// 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 (
+ "./p0"
+ "./p1"
+)
+
+var (
+ _ p0.T0 = p0.S0{}
+ _ p0.T0 = p1.S1{}
+ _ p0.T0 = p1.NewT0()
+ _ p0.T0 = p1.NewT1() // same as p1.S1{}
+)
+
+func main() {}
diff --git a/test/fixedbugs/issue6295.go b/test/fixedbugs/issue6295.go
new file mode 100644
index 000000000..b8da21272
--- /dev/null
+++ b/test/fixedbugs/issue6295.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// 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.
+
+// Issue 6295: qualified name of unexported methods
+// is corrupted during import.
+
+package ignored
diff --git a/test/fixedbugs/issue6402.go b/test/fixedbugs/issue6402.go
new file mode 100644
index 000000000..da5980c9a
--- /dev/null
+++ b/test/fixedbugs/issue6402.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6402: spurious 'use of untyped nil' error
+
+package p
+
+func f() uintptr {
+ return nil // ERROR "cannot use nil as type uintptr in return argument"
+}
diff --git a/test/fixedbugs/issue6403.go b/test/fixedbugs/issue6403.go
new file mode 100644
index 000000000..b61e2e225
--- /dev/null
+++ b/test/fixedbugs/issue6403.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6403: fix spurious 'const initializer is not a constant' error
+
+package p
+
+import "syscall"
+
+const A int = syscall.X // ERROR "undefined: syscall.X"
+const B int = voidpkg.X // ERROR "undefined: voidpkg"
diff --git a/test/fixedbugs/issue6405.go b/test/fixedbugs/issue6405.go
new file mode 100644
index 000000000..b4551cc25
--- /dev/null
+++ b/test/fixedbugs/issue6405.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6405: spurious 'not enough arguments to return' error
+
+package p
+
+func Open() (int, error) {
+ return OpenFile() // ERROR "undefined: OpenFile"
+}
diff --git a/test/fixedbugs/issue6406.go b/test/fixedbugs/issue6406.go
new file mode 100644
index 000000000..5491193ef
--- /dev/null
+++ b/test/fixedbugs/issue6406.go
@@ -0,0 +1,12 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ s = "bob" // ERROR "undefined.*s"
+ _ = s // ERROR "undefined.*s"
+}
diff --git a/test/fixedbugs/issue6500.go b/test/fixedbugs/issue6500.go
new file mode 100644
index 000000000..b265f9ae3
--- /dev/null
+++ b/test/fixedbugs/issue6500.go
@@ -0,0 +1,29 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6500: missing error when fallthrough appears in a block.
+
+package main
+
+func main() {
+ var x int
+ switch x {
+ case 0:
+ {
+ fallthrough // ERROR "fallthrough"
+ }
+ case 1:
+ {
+ switch x {
+ case 2:
+ fallthrough
+ case 3:
+ }
+ }
+ fallthrough
+ default:
+ }
+}
diff --git a/test/fixedbugs/issue6572.go b/test/fixedbugs/issue6572.go
new file mode 100644
index 000000000..e75da54c9
--- /dev/null
+++ b/test/fixedbugs/issue6572.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func foo() (T, T) { // ERROR "undefined"
+ return 0, 0
+}
+
+func bar() (T, string, T) { // ERROR "undefined"
+ return 0, "", 0
+}
+
+func main() {
+ var x, y, z int
+ x, y = foo()
+ x, y, z = bar() // ERROR "cannot (use type|assign) string"
+}
diff --git a/test/fixedbugs/issue6789.dir/a.go b/test/fixedbugs/issue6789.dir/a.go
new file mode 100644
index 000000000..9c90e0740
--- /dev/null
+++ b/test/fixedbugs/issue6789.dir/a.go
@@ -0,0 +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 a
+
+type unexported struct {
+ a int
+ b bool
+}
+
+type Struct struct {
+ unexported
+}
diff --git a/test/fixedbugs/issue6789.dir/b.go b/test/fixedbugs/issue6789.dir/b.go
new file mode 100644
index 000000000..b6a6fc317
--- /dev/null
+++ b/test/fixedbugs/issue6789.dir/b.go
@@ -0,0 +1,12 @@
+// 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 "./a"
+
+type s a.Struct
+
+func main() {
+}
diff --git a/test/fixedbugs/issue6789.go b/test/fixedbugs/issue6789.go
new file mode 100644
index 000000000..e3a2c3320
--- /dev/null
+++ b/test/fixedbugs/issue6789.go
@@ -0,0 +1,10 @@
+// rundir
+
+// 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.
+
+// Issue 6789: gccgo failed to find the hash function for an
+// unexported struct embedded in an exported struct.
+
+package ignored
diff --git a/test/fixedbugs/issue6847.go b/test/fixedbugs/issue6847.go
new file mode 100644
index 000000000..e6427e19a
--- /dev/null
+++ b/test/fixedbugs/issue6847.go
@@ -0,0 +1,85 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6847: select clauses involving implicit conversion
+// of channels trigger a spurious typechecking error during walk.
+
+package p
+
+type I1 interface {
+ String()
+}
+type I2 interface {
+ String()
+}
+
+func F() {
+ var (
+ cr <-chan int
+ cs chan<- int
+ c chan int
+
+ ccr chan (<-chan int)
+ ccs chan chan<- int
+ cc chan chan int
+
+ ok bool
+ )
+ // Send cases.
+ select {
+ case ccr <- cr:
+ case ccr <- c:
+ }
+ select {
+ case ccs <- cs:
+ case ccs <- c:
+ }
+ select {
+ case ccr <- c:
+ default:
+ }
+ // Receive cases.
+ select {
+ case cr = <-cc:
+ case cs = <-cc:
+ case c = <-cc:
+ }
+ select {
+ case cr = <-cc:
+ default:
+ }
+ select {
+ case cr, ok = <-cc:
+ case cs, ok = <-cc:
+ case c = <-cc:
+ }
+ // Interfaces.
+ var (
+ c1 chan I1
+ c2 chan I2
+ x1 I1
+ x2 I2
+ )
+ select {
+ case c1 <- x1:
+ case c1 <- x2:
+ case c2 <- x1:
+ case c2 <- x2:
+ }
+ select {
+ case x1 = <-c1:
+ case x1 = <-c2:
+ case x2 = <-c1:
+ case x2 = <-c2:
+ }
+ select {
+ case x1, ok = <-c1:
+ case x1, ok = <-c2:
+ case x2, ok = <-c1:
+ case x2, ok = <-c2:
+ }
+ _ = ok
+}
diff --git a/test/fixedbugs/issue6889.go b/test/fixedbugs/issue6889.go
new file mode 100644
index 000000000..46bb5dacf
--- /dev/null
+++ b/test/fixedbugs/issue6889.go
@@ -0,0 +1,103 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6889: confusing error message: ovf in mpaddxx
+
+package main
+
+const (
+ f1 = 1
+ f2 = f1 * 2
+ f3 = f2 * 3
+ f4 = f3 * 4
+ f5 = f4 * 5
+ f6 = f5 * 6
+ f7 = f6 * 7
+ f8 = f7 * 8
+ f9 = f8 * 9
+ f10 = f9 * 10
+ f11 = f10 * 11
+ f12 = f11 * 12
+ f13 = f12 * 13
+ f14 = f13 * 14
+ f15 = f14 * 15
+ f16 = f15 * 16
+ f17 = f16 * 17
+ f18 = f17 * 18
+ f19 = f18 * 19
+ f20 = f19 * 20
+ f21 = f20 * 21
+ f22 = f21 * 22
+ f23 = f22 * 23
+ f24 = f23 * 24
+ f25 = f24 * 25
+ f26 = f25 * 26
+ f27 = f26 * 27
+ f28 = f27 * 28
+ f29 = f28 * 29
+ f30 = f29 * 30
+ f31 = f30 * 31
+ f32 = f31 * 32
+ f33 = f32 * 33
+ f34 = f33 * 34
+ f35 = f34 * 35
+ f36 = f35 * 36
+ f37 = f36 * 37
+ f38 = f37 * 38
+ f39 = f38 * 39
+ f40 = f39 * 40
+ f41 = f40 * 41
+ f42 = f41 * 42
+ f43 = f42 * 43
+ f44 = f43 * 44
+ f45 = f44 * 45
+ f46 = f45 * 46
+ f47 = f46 * 47
+ f48 = f47 * 48
+ f49 = f48 * 49
+ f50 = f49 * 50
+ f51 = f50 * 51
+ f52 = f51 * 52
+ f53 = f52 * 53
+ f54 = f53 * 54
+ f55 = f54 * 55
+ f56 = f55 * 56
+ f57 = f56 * 57
+ f58 = f57 * 58
+ f59 = f58 * 59
+ f60 = f59 * 60
+ f61 = f60 * 61
+ f62 = f61 * 62
+ f63 = f62 * 63
+ f64 = f63 * 64
+ f65 = f64 * 65
+ f66 = f65 * 66
+ f67 = f66 * 67
+ f68 = f67 * 68
+ f69 = f68 * 69
+ f70 = f69 * 70
+ f71 = f70 * 71
+ f72 = f71 * 72
+ f73 = f72 * 73
+ f74 = f73 * 74
+ f75 = f74 * 75
+ f76 = f75 * 76
+ f77 = f76 * 77
+ f78 = f77 * 78
+ f79 = f78 * 79
+ f80 = f79 * 80
+ f81 = f80 * 81
+ f82 = f81 * 82
+ f83 = f82 * 83
+ f84 = f83 * 84
+ f85 = f84 * 85
+ f86 = f85 * 86
+ f87 = f86 * 87
+ f88 = f87 * 88
+ f89 = f88 * 89
+ f90 = f89 * 90
+ f91 = f90 * 91 // ERROR "overflow"
+)
diff --git a/test/fixedbugs/issue6899.go b/test/fixedbugs/issue6899.go
new file mode 100644
index 000000000..a693bf285
--- /dev/null
+++ b/test/fixedbugs/issue6899.go
@@ -0,0 +1,13 @@
+// cmpout
+
+// 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 "math"
+
+func main() {
+ println(math.Copysign(0, -1))
+}
diff --git a/test/fixedbugs/issue6899.out b/test/fixedbugs/issue6899.out
new file mode 100644
index 000000000..e2375f077
--- /dev/null
+++ b/test/fixedbugs/issue6899.out
@@ -0,0 +1 @@
+-0.000000e+000
diff --git a/test/fixedbugs/issue6902.go b/test/fixedbugs/issue6902.go
new file mode 100644
index 000000000..5c2c545d2
--- /dev/null
+++ b/test/fixedbugs/issue6902.go
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 6902: confusing printing of large floating point constants
+
+package main
+
+import (
+ "os"
+)
+
+var x = -1e-10000
+
+func main() {
+ if x != 0 {
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/issue6964.go b/test/fixedbugs/issue6964.go
new file mode 100644
index 000000000..821735c08
--- /dev/null
+++ b/test/fixedbugs/issue6964.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// 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
+
+func main() {
+ _ = string(-4 + 2i + 2) // ERROR "-4\+2i"
+}
diff --git a/test/fixedbugs/issue7023.dir/a.go b/test/fixedbugs/issue7023.dir/a.go
new file mode 100644
index 000000000..cdb543209
--- /dev/null
+++ b/test/fixedbugs/issue7023.dir/a.go
@@ -0,0 +1,10 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func Foo() {
+ goto bar
+bar:
+}
diff --git a/test/fixedbugs/issue7023.dir/b.go b/test/fixedbugs/issue7023.dir/b.go
new file mode 100644
index 000000000..c6fe40dfa
--- /dev/null
+++ b/test/fixedbugs/issue7023.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import (
+ "./a"
+)
+
+var f = a.Foo
diff --git a/test/fixedbugs/issue7023.go b/test/fixedbugs/issue7023.go
new file mode 100644
index 000000000..f18c6113e
--- /dev/null
+++ b/test/fixedbugs/issue7023.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7023: corrupted export data when an inlined function
+// contains a goto.
+
+package ignored
diff --git a/test/fixedbugs/issue7044.go b/test/fixedbugs/issue7044.go
new file mode 100644
index 000000000..cac6a7683
--- /dev/null
+++ b/test/fixedbugs/issue7044.go
@@ -0,0 +1,43 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7044: bad AMOVFD and AMOVDF assembly generation on
+// arm for registers above 7.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func f() [16]float32 {
+ f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15 :=
+ float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)
+ // Use all 16 registers to do float32 --> float64 conversion.
+ d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15 :=
+ float64(f0), float64(f1), float64(f2), float64(f3), float64(f4), float64(f5), float64(f6), float64(f7), float64(f8), float64(f9), float64(f10), float64(f11), float64(f12), float64(f13), float64(f14), float64(f15)
+ // Use all 16 registers to do float64 --> float32 conversion.
+ g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11, g12, g13, g14, g15 :=
+ float32(d0), float32(d1), float32(d2), float32(d3), float32(d4), float32(d5), float32(d6), float32(d7), float32(d8), float32(d9), float32(d10), float32(d11), float32(d12), float32(d13), float32(d14), float32(d15)
+ // Force another conversion, so that the previous conversion doesn't
+ // get optimized away into constructing the returned array. With current
+ // optimizations, constructing the returned array uses only
+ // a single register.
+ e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15 :=
+ float64(g0), float64(g1), float64(g2), float64(g3), float64(g4), float64(g5), float64(g6), float64(g7), float64(g8), float64(g9), float64(g10), float64(g11), float64(g12), float64(g13), float64(g14), float64(g15)
+ return [16]float32{
+ float32(e0), float32(e1), float32(e2), float32(e3), float32(e4), float32(e5), float32(e6), float32(e7), float32(e8), float32(e9), float32(e10), float32(e11), float32(e12), float32(e13), float32(e14), float32(e15),
+ }
+}
+
+func main() {
+ want := [16]float32{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ got := f()
+ if !reflect.DeepEqual(got, want) {
+ fmt.Printf("f() = %#v; want %#v\n", got, want)
+ }
+}
diff --git a/test/fixedbugs/issue7050.go b/test/fixedbugs/issue7050.go
new file mode 100644
index 000000000..e58b68404
--- /dev/null
+++ b/test/fixedbugs/issue7050.go
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func main() {
+ _, err := os.Stdout.Write(nil)
+ if err != nil {
+ fmt.Printf("BUG: os.Stdout.Write(nil) = %v\n", err)
+ }
+}
diff --git a/test/fixedbugs/issue7083.go b/test/fixedbugs/issue7083.go
new file mode 100644
index 000000000..79bfd3b5e
--- /dev/null
+++ b/test/fixedbugs/issue7083.go
@@ -0,0 +1,22 @@
+// run
+
+package main
+
+import "runtime/debug"
+
+func f(m map[int]*string, i int) {
+ s := ""
+ m[i] = &s
+}
+
+func main() {
+ debug.SetGCPercent(0)
+ m := map[int]*string{}
+ for i := 0; i < 40; i++ {
+ f(m, i)
+ if len(*m[i]) != 0 {
+ println("bad length", i, m[i], len(*m[i]))
+ panic("bad length")
+ }
+ }
+}
diff --git a/test/fixedbugs/issue7129.go b/test/fixedbugs/issue7129.go
new file mode 100644
index 000000000..2425cbd34
--- /dev/null
+++ b/test/fixedbugs/issue7129.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7129: inconsistent "wrong arg type" error for multivalued g in f(g())
+
+package main
+
+func f(int) {}
+
+func g() bool { return true }
+
+func h(int, int) {}
+
+func main() {
+ f(g()) // ERROR "in argument to f"
+ f(true) // ERROR "in argument to f"
+ h(true, true) // ERROR "in argument to h"
+}
diff --git a/test/fixedbugs/issue7150.go b/test/fixedbugs/issue7150.go
new file mode 100644
index 000000000..264958a08
--- /dev/null
+++ b/test/fixedbugs/issue7150.go
@@ -0,0 +1,17 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 7150: array index out of bounds error off by one
+
+package main
+
+func main() {
+ _ = [0]int{-1: 50} // ERROR "array index must be non-negative integer constant"
+ _ = [0]int{0: 0} // ERROR "array index 0 out of bounds \[0:0\]"
+ _ = [0]int{5: 25} // ERROR "array index 5 out of bounds \[0:0\]"
+ _ = [10]int{2: 10, 15: 30} // ERROR "array index 15 out of bounds \[0:10\]"
+ _ = [10]int{5: 5, 1: 1, 12: 12} // ERROR "array index 12 out of bounds \[0:10\]"
+}
diff --git a/test/fixedbugs/issue7153.go b/test/fixedbugs/issue7153.go
new file mode 100644
index 000000000..d70d8582a
--- /dev/null
+++ b/test/fixedbugs/issue7153.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7153: array invalid index error duplicated on successive bad values
+
+package p
+
+var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type bool\) as type int in array element"
diff --git a/test/fixedbugs/issue7214.go b/test/fixedbugs/issue7214.go
new file mode 100644
index 000000000..82ddf74c3
--- /dev/null
+++ b/test/fixedbugs/issue7214.go
@@ -0,0 +1,30 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7214: No duplicate key error for maps with interface{} key type
+
+package p
+
+var _ = map[interface{}]int{2: 1, 2: 1} // ERROR "duplicate key"
+var _ = map[interface{}]int{int(2): 1, int16(2): 1}
+var _ = map[interface{}]int{int16(2): 1, int16(2): 1} // ERROR "duplicate key"
+
+type S string
+
+var _ = map[interface{}]int{"a": 1, "a": 1} // ERROR "duplicate key"
+var _ = map[interface{}]int{"a": 1, S("a"): 1}
+var _ = map[interface{}]int{S("a"): 1, S("a"): 1} // ERROR "duplicate key"
+
+type I interface {
+ f()
+}
+
+type N int
+
+func (N) f() {}
+
+var _ = map[I]int{N(0): 1, N(2): 1}
+var _ = map[I]int{N(2): 1, N(2): 1} // ERROR "duplicate key"
diff --git a/test/fixedbugs/issue7223.go b/test/fixedbugs/issue7223.go
new file mode 100644
index 000000000..c5955d599
--- /dev/null
+++ b/test/fixedbugs/issue7223.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var bits1 uint = 10
+const bits2 uint = 10
+
+func main() {
+ _ = make([]byte, 1<<bits1)
+ _ = make([]byte, 1<<bits2)
+ _ = make([]byte, nil) // ERROR "non-integer.*len"
+ _ = make([]byte, nil, 2) // ERROR "non-integer.*len"
+ _ = make([]byte, 1, nil) // ERROR "non-integer.*cap"
+ _ = make([]byte, true) // ERROR "non-integer.*len"
+ _ = make([]byte, "abc") // ERROR "non-integer.*len"
+}
diff --git a/test/fixedbugs/issue7272.go b/test/fixedbugs/issue7272.go
new file mode 100644
index 000000000..97a08da09
--- /dev/null
+++ b/test/fixedbugs/issue7272.go
@@ -0,0 +1,48 @@
+// compile
+
+// 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.
+
+// Issue 7272: test builtin functions in statement context and in
+// go/defer functions.
+
+package p
+
+func F() {
+ var a []int
+ var c chan int
+ var m map[int]int
+
+ close(c)
+ copy(a, a)
+ delete(m, 0)
+ panic(0)
+ print("foo")
+ println("bar")
+ recover()
+
+ (close(c))
+ (copy(a, a))
+ (delete(m, 0))
+ (panic(0))
+ (print("foo"))
+ (println("bar"))
+ (recover())
+
+ go close(c)
+ go copy(a, a)
+ go delete(m, 0)
+ go panic(0)
+ go print("foo")
+ go println("bar")
+ go recover()
+
+ defer close(c)
+ defer copy(a, a)
+ defer delete(m, 0)
+ defer panic(0)
+ defer print("foo")
+ defer println("bar")
+ defer recover()
+}
diff --git a/test/fixedbugs/issue7310.go b/test/fixedbugs/issue7310.go
new file mode 100644
index 000000000..4a535a1fc
--- /dev/null
+++ b/test/fixedbugs/issue7310.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Internal compiler crash used to stop errors during second copy.
+
+package main
+
+func main() {
+ _ = copy(nil, []int{}) // ERROR "use of untyped nil"
+ _ = copy([]int{}, nil) // ERROR "use of untyped nil"
+ _ = 1+true // ERROR "cannot convert true" "mismatched types int and bool"
+}
diff --git a/test/fixedbugs/issue7316.go b/test/fixedbugs/issue7316.go
new file mode 100644
index 000000000..4b32261d4
--- /dev/null
+++ b/test/fixedbugs/issue7316.go
@@ -0,0 +1,37 @@
+// runoutput
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7316
+// This test exercises all types of numeric conversions, which was one
+// of the sources of etype mismatch during register allocation in 8g.
+
+package main
+
+import "fmt"
+
+const tpl = `
+func init() {
+ var i %s
+ j := %s(i)
+ _ = %s(j)
+}
+`
+
+func main() {
+ fmt.Println("package main")
+ ntypes := []string{
+ "byte", "rune", "uintptr",
+ "float32", "float64",
+ "int", "int8", "int16", "int32", "int64",
+ "uint", "uint8", "uint16", "uint32", "uint64",
+ }
+ for i, from := range ntypes {
+ for _, to := range ntypes[i:] {
+ fmt.Printf(tpl, from, to, from)
+ }
+ }
+ fmt.Println("func main() {}")
+}
diff --git a/test/fixedbugs/issue7346.go b/test/fixedbugs/issue7346.go
new file mode 100644
index 000000000..dd5ea222f
--- /dev/null
+++ b/test/fixedbugs/issue7346.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 7346 : internal error "doasm" error due to checknil
+// of a nil literal.
+
+package main
+
+func main() {
+ _ = *(*int)(nil)
+}
diff --git a/test/fixedbugs/issue7366.go b/test/fixedbugs/issue7366.go
new file mode 100644
index 000000000..754da6fa2
--- /dev/null
+++ b/test/fixedbugs/issue7366.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 7366: generates a temporary with ideal type
+// during comparison of small structs.
+
+package main
+
+type T struct {
+ data [10]byte
+}
+
+func main() {
+ var a T
+ var b T
+ if a == b {
+ }
+}
diff --git a/test/fixedbugs/issue7405.go b/test/fixedbugs/issue7405.go
new file mode 100644
index 000000000..52e1176c1
--- /dev/null
+++ b/test/fixedbugs/issue7405.go
@@ -0,0 +1,51 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7405: the equality function for struct with many
+// embedded fields became more complex after fixing issue 7366,
+// leading to out of registers on 386.
+
+package p
+
+type T1 struct {
+ T2
+ T3
+ T4
+}
+
+type T2 struct {
+ Conn
+}
+
+type T3 struct {
+ PacketConn
+}
+
+type T4 struct {
+ PacketConn
+ T5
+}
+
+type T5 struct {
+ x int
+ T6
+}
+
+type T6 struct {
+ y, z int
+}
+
+type Conn interface {
+ A()
+}
+
+type PacketConn interface {
+ B()
+}
+
+func F(a, b T1) bool {
+ return a == b
+}
diff --git a/test/fixedbugs/issue7419.go b/test/fixedbugs/issue7419.go
new file mode 100644
index 000000000..39b454c05
--- /dev/null
+++ b/test/fixedbugs/issue7419.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7419: odd behavior for float constants underflowing to 0
+
+package main
+
+import (
+ "os"
+)
+
+var x = 1e-779137
+var y = 1e-779138
+
+func main() {
+ if x != 0 {
+ os.Exit(1)
+ }
+ if y != 0 {
+ os.Exit(2)
+ }
+}
diff --git a/test/fixedbugs/issue7525.go b/test/fixedbugs/issue7525.go
new file mode 100644
index 000000000..4e1d88aab
--- /dev/null
+++ b/test/fixedbugs/issue7525.go
@@ -0,0 +1,19 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7525: self-referential array types.
+
+package main
+
+import "unsafe"
+
+var x struct {
+ a [unsafe.Sizeof(x.a)]int // ERROR "array bound|typechecking loop|invalid expression"
+ b [unsafe.Offsetof(x.b)]int // ERROR "array bound"
+ c [unsafe.Alignof(x.c)]int // ERROR "array bound|invalid expression"
+ d [len(x.d)]int // ERROR "array bound|invalid array"
+ e [cap(x.e)]int // ERROR "array bound|invalid array"
+}
diff --git a/test/fixedbugs/issue7538a.go b/test/fixedbugs/issue7538a.go
new file mode 100644
index 000000000..283d9eb1b
--- /dev/null
+++ b/test/fixedbugs/issue7538a.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7538: blank (_) labels handled incorrectly
+
+package p
+
+func f() {
+_:
+_:
+ goto _ // ERROR "not defined"
+}
diff --git a/test/fixedbugs/issue7538b.go b/test/fixedbugs/issue7538b.go
new file mode 100644
index 000000000..28cef5d60
--- /dev/null
+++ b/test/fixedbugs/issue7538b.go
@@ -0,0 +1,13 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7538: blank (_) labels handled incorrectly
+
+package p
+
+func f() {
+_:
+}
diff --git a/test/fixedbugs/issue7547.go b/test/fixedbugs/issue7547.go
new file mode 100644
index 000000000..f75a33036
--- /dev/null
+++ b/test/fixedbugs/issue7547.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f() map[string]interface{} {
+ var p *map[string]map[string]interface{}
+ _ = p
+ return nil
+}
+
+func main() {
+ f()
+}
diff --git a/test/fixedbugs/issue7550.go b/test/fixedbugs/issue7550.go
new file mode 100644
index 000000000..0c4cf9307
--- /dev/null
+++ b/test/fixedbugs/issue7550.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func shouldPanic(f func()) {
+ defer func() {
+ if recover() == nil {
+ panic("not panicking")
+ }
+ }()
+ f()
+}
+
+func f() {
+ length := int(^uint(0) >> 1)
+ a := make([]struct{}, length)
+ b := make([]struct{}, length)
+ _ = append(a, b...)
+}
+
+func main() {
+ shouldPanic(f)
+}
diff --git a/test/fixedbugs/issue7590.go b/test/fixedbugs/issue7590.go
new file mode 100644
index 000000000..e283832c3
--- /dev/null
+++ b/test/fixedbugs/issue7590.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7590: gccgo incorrectly traverses nested composite literals.
+
+package p
+
+type S struct {
+ F int
+}
+
+var M = map[string]S{
+ "a": { F: 1 },
+}
+
+var P = M["a"]
+
+var F = P.F
diff --git a/test/fixedbugs/issue7648.dir/a.go b/test/fixedbugs/issue7648.dir/a.go
new file mode 100644
index 000000000..c76aaa675
--- /dev/null
+++ b/test/fixedbugs/issue7648.dir/a.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+const (
+ sinPi4 = 0.70710678118654752440084436210484903928483593768847
+ A = complex(sinPi4, -sinPi4)
+)
+
diff --git a/test/fixedbugs/issue7648.dir/b.go b/test/fixedbugs/issue7648.dir/b.go
new file mode 100644
index 000000000..b9223ed4e
--- /dev/null
+++ b/test/fixedbugs/issue7648.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "a"
+
+func f() {
+ println(a.A)
+}
diff --git a/test/fixedbugs/issue7648.go b/test/fixedbugs/issue7648.go
new file mode 100644
index 000000000..b391c4a31
--- /dev/null
+++ b/test/fixedbugs/issue7648.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7648: spurious "bad negated constant" for complex constants.
+
+package ignored
diff --git a/test/fixedbugs/issue7675.go b/test/fixedbugs/issue7675.go
new file mode 100644
index 000000000..d97ee357a
--- /dev/null
+++ b/test/fixedbugs/issue7675.go
@@ -0,0 +1,24 @@
+// errorcheck
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7675: fewer errors for wrong argument count
+
+package p
+
+func f(string, int, float64, string)
+
+func g(string, int, float64, ...string)
+
+func main() {
+ f(1, 0.5, "hello") // ERROR "not enough arguments"
+ f("1", 2, 3.1, "4")
+ f(1, 0.5, "hello", 4, 5) // ERROR "too many arguments"
+ g(1, 0.5) // ERROR "not enough arguments"
+ g("1", 2, 3.1)
+ g(1, 0.5, []int{3, 4}...) // ERROR "not enough arguments"
+ g("1", 2, 3.1, "4", "5")
+ g(1, 0.5, "hello", 4, []int{5, 6}...) // ERROR "too many arguments"
+}
diff --git a/test/fixedbugs/issue7742.go b/test/fixedbugs/issue7742.go
new file mode 100644
index 000000000..dc167c22e
--- /dev/null
+++ b/test/fixedbugs/issue7742.go
@@ -0,0 +1,18 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7742: cannot use &autotmp_0001 (type *map[string]string) as type *string in function argument
+
+package main
+
+var (
+ m map[string]string
+ v string
+)
+
+func main() {
+ m[v], _ = v, v
+}
diff --git a/test/fixedbugs/issue7794.go b/test/fixedbugs/issue7794.go
new file mode 100644
index 000000000..1e303bd4f
--- /dev/null
+++ b/test/fixedbugs/issue7794.go
@@ -0,0 +1,12 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ var a [10]int
+ const ca = len(a)
+}
diff --git a/test/fixedbugs/issue7863.go b/test/fixedbugs/issue7863.go
new file mode 100644
index 000000000..97f225535
--- /dev/null
+++ b/test/fixedbugs/issue7863.go
@@ -0,0 +1,60 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+)
+
+type Foo int64
+
+func (f *Foo) F() int64 {
+ return int64(*f)
+}
+
+type Bar int64
+
+func (b Bar) F() int64 {
+ return int64(b)
+}
+
+type Baz int32
+
+func (b Baz) F() int64 {
+ return int64(b)
+}
+
+func main() {
+ foo := Foo(123)
+ f := foo.F
+ if foo.F() != f() {
+ bug()
+ fmt.Println("foo.F", foo.F(), f())
+ }
+ bar := Bar(123)
+ f = bar.F
+ if bar.F() != f() {
+ bug()
+ fmt.Println("bar.F", bar.F(), f()) // duh!
+ }
+
+ baz := Baz(123)
+ f = baz.F
+ if baz.F() != f() {
+ bug()
+ fmt.Println("baz.F", baz.F(), f())
+ }
+}
+
+var bugged bool
+
+func bug() {
+ if !bugged {
+ bugged = true
+ fmt.Println("BUG")
+ }
+}
diff --git a/test/fixedbugs/issue7867.go b/test/fixedbugs/issue7867.go
new file mode 100644
index 000000000..9f28a7144
--- /dev/null
+++ b/test/fixedbugs/issue7867.go
@@ -0,0 +1,43 @@
+// runoutput
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7867.
+
+package main
+
+import "fmt"
+
+const tpl = `
+func Test%d(t %s) {
+ _ = t
+ _ = t
+}
+`
+
+func main() {
+ fmt.Println("package main")
+ types := []string{
+ // These types always passed
+ "bool", "int", "rune",
+ "*int", "uintptr",
+ "float32", "float64",
+ "chan struct{}",
+ "map[string]struct{}",
+ "func()", "func(string)error",
+
+ // These types caused compilation failures
+ "complex64", "complex128",
+ "struct{}", "struct{n int}", "struct{e error}", "struct{m map[string]string}",
+ "string",
+ "[4]byte",
+ "[]byte",
+ "interface{}", "error",
+ }
+ for i, typ := range types {
+ fmt.Printf(tpl, i, typ)
+ }
+ fmt.Println("func main() {}")
+}
diff --git a/test/fixedbugs/issue7884.go b/test/fixedbugs/issue7884.go
new file mode 100644
index 000000000..497e26113
--- /dev/null
+++ b/test/fixedbugs/issue7884.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func main() {
+ var ii interface{} = 5
+ zz, err := ii.(interface{})
+ fmt.Println(zz, err)
+}
diff --git a/test/fixedbugs/issue7944.go b/test/fixedbugs/issue7944.go
new file mode 100644
index 000000000..9e5bed1a1
--- /dev/null
+++ b/test/fixedbugs/issue7944.go
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7944:
+// Liveness bitmaps said b was live at call to g,
+// but no one told the register optimizer.
+
+package main
+
+import "runtime"
+
+func f(b []byte) {
+ for len(b) > 0 {
+ n := len(b)
+ n = f1(n)
+ f2(b[n:])
+ b = b[n:]
+ }
+ g()
+}
+
+func f1(n int) int {
+ runtime.GC()
+ return n
+}
+
+func f2(b []byte) {
+ runtime.GC()
+}
+
+func g() {
+ runtime.GC()
+}
+
+func main() {
+ f(make([]byte, 100))
+}
diff --git a/test/fixedbugs/issue7995.go b/test/fixedbugs/issue7995.go
new file mode 100644
index 000000000..05f116823
--- /dev/null
+++ b/test/fixedbugs/issue7995.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7995: globals not flushed quickly enough.
+
+package main
+
+import "fmt"
+
+var (
+ p = 1
+ q = &p
+)
+
+func main() {
+ p = 50
+ *q = 100
+ s := fmt.Sprintln(p, *q)
+ if s != "100 100\n" {
+ println("BUG:", s)
+ }
+}
diff --git a/test/fixedbugs/issue7995b.dir/x1.go b/test/fixedbugs/issue7995b.dir/x1.go
new file mode 100644
index 000000000..075911b92
--- /dev/null
+++ b/test/fixedbugs/issue7995b.dir/x1.go
@@ -0,0 +1,16 @@
+package x1
+
+import "fmt"
+
+var P int
+
+var b bool
+
+func F(x *int) string {
+ if b { // avoid inlining
+ F(x)
+ }
+ P = 50
+ *x = 100
+ return fmt.Sprintln(P, *x)
+}
diff --git a/test/fixedbugs/issue7995b.dir/x2.go b/test/fixedbugs/issue7995b.dir/x2.go
new file mode 100644
index 000000000..eea23eabb
--- /dev/null
+++ b/test/fixedbugs/issue7995b.dir/x2.go
@@ -0,0 +1,10 @@
+package main
+
+import "./x1"
+
+func main() {
+ s := x1.F(&x1.P)
+ if s != "100 100\n" {
+ println("BUG:", s)
+ }
+}
diff --git a/test/fixedbugs/issue7995b.go b/test/fixedbugs/issue7995b.go
new file mode 100644
index 000000000..2f57371e3
--- /dev/null
+++ b/test/fixedbugs/issue7995b.go
@@ -0,0 +1,9 @@
+// rundir
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 7995: globals not flushed quickly enough.
+
+package ignored
diff --git a/test/fixedbugs/issue7996.go b/test/fixedbugs/issue7996.go
new file mode 100644
index 000000000..98289eb0c
--- /dev/null
+++ b/test/fixedbugs/issue7996.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// /tmp/x.go:5: illegal constant expression: bool == interface {}
+
+package p
+
+var m = map[interface{}]struct{}{
+ nil: {},
+ true: {},
+}
diff --git a/test/fixedbugs/issue7997.go b/test/fixedbugs/issue7997.go
new file mode 100644
index 000000000..10c526273
--- /dev/null
+++ b/test/fixedbugs/issue7997.go
@@ -0,0 +1,53 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// /tmp/x.go:3: internal error: f &p (type *int) recorded as live on entry
+
+package p
+
+func f(ch chan int) *int {
+ select {
+ case p1x := <-ch:
+ return &p1x
+ default:
+ // ok
+ }
+ select {
+ case p1 := <-ch:
+ return &p1
+ default:
+ // ok
+ }
+ select {
+ case p2 := <-ch:
+ return &p2
+ case p3 := <-ch:
+ return &p3
+ default:
+ // ok
+ }
+ select {
+ case p4, ok := <-ch:
+ if ok {
+ return &p4
+ }
+ default:
+ // ok
+ }
+ select {
+ case p5, ok := <-ch:
+ if ok {
+ return &p5
+ }
+ case p6, ok := <-ch:
+ if !ok {
+ return &p6
+ }
+ default:
+ // ok
+ }
+ return nil
+}
diff --git a/test/fixedbugs/issue7998.go b/test/fixedbugs/issue7998.go
new file mode 100644
index 000000000..245035ede
--- /dev/null
+++ b/test/fixedbugs/issue7998.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// /tmp/x.go:5: cannot use _ as value
+
+package p
+
+func f(ch chan int) bool {
+ select {
+ case _, ok := <-ch:
+ return ok
+ }
+ _, ok := <-ch
+ _ = ok
+ select {
+ case _, _ = <-ch:
+ return true
+ }
+ return false
+}
diff --git a/test/fixedbugs/issue8004.go b/test/fixedbugs/issue8004.go
new file mode 100644
index 000000000..37e2fe066
--- /dev/null
+++ b/test/fixedbugs/issue8004.go
@@ -0,0 +1,59 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+func main() {
+ test1()
+ test2()
+}
+
+func test1() {
+ var all []interface{}
+ for i := 0; i < 100; i++ {
+ p := new([]int)
+ *p = append(*p, 1, 2, 3, 4)
+ h := (*reflect.SliceHeader)(unsafe.Pointer(p))
+ all = append(all, h, p)
+ }
+ runtime.GC()
+ for i := 0; i < 100; i++ {
+ p := *all[2*i+1].(*[]int)
+ if p[0] != 1 || p[1] != 2 || p[2] != 3 || p[3] != 4 {
+ println("BUG test1: bad slice at index", i, p[0], p[1], p[2], p[3])
+ return
+ }
+ }
+}
+
+type T struct {
+ H *reflect.SliceHeader
+ P *[]int
+}
+
+func test2() {
+ var all []T
+ for i := 0; i < 100; i++ {
+ p := new([]int)
+ *p = append(*p, 1, 2, 3, 4)
+ h := (*reflect.SliceHeader)(unsafe.Pointer(p))
+ all = append(all, T{H: h}, T{P: p})
+ }
+ runtime.GC()
+ for i := 0; i < 100; i++ {
+ p := *all[2*i+1].P
+ if p[0] != 1 || p[1] != 2 || p[2] != 3 || p[3] != 4 {
+ println("BUG test2: bad slice at index", i, p[0], p[1], p[2], p[3])
+ return
+ }
+ }
+}
diff --git a/test/fixedbugs/issue8011.go b/test/fixedbugs/issue8011.go
new file mode 100644
index 000000000..b966174c0
--- /dev/null
+++ b/test/fixedbugs/issue8011.go
@@ -0,0 +1,18 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ c := make(chan chan int, 1)
+ c1 := make(chan int, 1)
+ c1 <- 42
+ c <- c1
+ x := <-<-c
+ if x != 42 {
+ println("BUG:", x, "!= 42")
+ }
+}
diff --git a/test/fixedbugs/issue8028.go b/test/fixedbugs/issue8028.go
new file mode 100644
index 000000000..7ceb902d4
--- /dev/null
+++ b/test/fixedbugs/issue8028.go
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8028. Used to fail in -race mode with "non-orig name" error.
+
+package p
+
+var (
+ t2 = T{F, "s1"}
+ t1 = T{F, "s2"}
+
+ tt = [...]T{t1, t2}
+)
+
+type I interface{}
+
+type T struct {
+ F func() I
+ S string
+}
+
+type E struct{}
+
+func F() I { return new(E) }
diff --git a/test/fixedbugs/issue8036.go b/test/fixedbugs/issue8036.go
new file mode 100644
index 000000000..f32fde84a
--- /dev/null
+++ b/test/fixedbugs/issue8036.go
@@ -0,0 +1,45 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8036. Stores necessary for stack scan being eliminated as redundant by optimizer.
+
+package main
+
+import "runtime"
+
+type T struct {
+ X *int
+ Y *int
+ Z *int
+}
+
+type TI [3]uintptr
+
+func G() (t TI) {
+ t[0] = 1
+ t[1] = 2
+ t[2] = 3
+ runtime.GC() // prevent inlining
+ return
+}
+
+func F() (t T) {
+ t.X = newint()
+ t.Y = t.X
+ t.Z = t.Y
+ runtime.GC() // prevent inlining
+ return
+}
+
+func newint() *int {
+ runtime.GC()
+ return nil
+}
+
+func main() {
+ G() // leave non-pointers where F's return values go
+ F()
+}
diff --git a/test/fixedbugs/issue8039.go b/test/fixedbugs/issue8039.go
new file mode 100644
index 000000000..b13e474d9
--- /dev/null
+++ b/test/fixedbugs/issue8039.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 8039. defer copy(x, <-c) did not rewrite <-c properly.
+
+package main
+
+func f(s []int) {
+ c := make(chan []int, 1)
+ c <- []int{1}
+ defer copy(s, <-c)
+}
+
+func main() {
+ x := make([]int, 1)
+ f(x)
+ if x[0] != 1 {
+ println("BUG", x[0])
+ }
+}
diff --git a/test/fixedbugs/issue8047.go b/test/fixedbugs/issue8047.go
new file mode 100644
index 000000000..fe7ada5c0
--- /dev/null
+++ b/test/fixedbugs/issue8047.go
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8047. Stack copier shouldn't crash if there
+// is a nil defer.
+
+package main
+
+func stackit(n int) {
+ if n == 0 {
+ return
+ }
+ stackit(n - 1)
+}
+
+func main() {
+ defer func() {
+ // catch & ignore panic from nil defer below
+ err := recover()
+ if err == nil {
+ panic("defer of nil func didn't panic")
+ }
+ }()
+ defer ((func())(nil))()
+ stackit(1000)
+}
diff --git a/test/fixedbugs/issue8047b.go b/test/fixedbugs/issue8047b.go
new file mode 100644
index 000000000..de6acaab5
--- /dev/null
+++ b/test/fixedbugs/issue8047b.go
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8047. Defer setup during panic shouldn't crash for nil defer.
+
+package main
+
+func main() {
+ defer func() {
+ recover()
+ }()
+ f()
+}
+
+func f() {
+ var g func()
+ defer g()
+ panic(1)
+}
diff --git a/test/fixedbugs/issue8048.go b/test/fixedbugs/issue8048.go
new file mode 100644
index 000000000..a7984c45a
--- /dev/null
+++ b/test/fixedbugs/issue8048.go
@@ -0,0 +1,107 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8048. Incorrect handling of liveness when walking stack
+// containing faulting frame.
+
+package main
+
+import "runtime"
+
+func main() {
+ test1()
+ test2()
+ test3()
+}
+
+func test1() {
+ // test1f will panic without its own defer.
+ // The runtime.GC checks that we can walk the stack
+ // at that point and not get confused.
+ // The recover lets test1 exit normally.
+ defer func() {
+ runtime.GC()
+ recover()
+ }()
+ test1f()
+}
+
+func test1f() {
+ // Because b == false, the if does not execute,
+ // so x == nil, so the println(*x) faults reading
+ // from nil. The compiler will lay out the code
+ // so that the if body occurs above the *x,
+ // so if the liveness info at the *x is used, it will
+ // find the liveness at the call to runtime.GC.
+ // It will think y is live, but y is uninitialized,
+ // and the runtime will crash detecting a bad slice.
+ // The runtime should see that there are no defers
+ // corresponding to this panicked frame and ignore
+ // the frame entirely.
+ var x *int
+ var b bool
+ if b {
+ y := make([]int, 1)
+ runtime.GC()
+ x = &y[0]
+ }
+ println(*x)
+}
+
+func test2() {
+ // Same as test1, but the fault happens in the function with the defer.
+ // The runtime should see the defer and garbage collect the frame
+ // as if the PC were immediately after the defer statement.
+ defer func() {
+ runtime.GC()
+ recover()
+ }()
+ var x *int
+ var b bool
+ if b {
+ y := make([]int, 1)
+ runtime.GC()
+ x = &y[0]
+ }
+ println(*x)
+}
+
+func test3() {
+ // Like test1 but avoid array index, which does not
+ // move to end of function on ARM.
+ defer func() {
+ runtime.GC()
+ recover()
+ }()
+ test3setup()
+ test3f()
+}
+
+func test3setup() {
+ var x uintptr
+ var b bool
+ b = true
+ if b {
+ y := uintptr(123)
+ runtime.GC()
+ x = y
+ }
+ runtime.GC()
+ globl = x
+}
+
+var globl uintptr
+
+func test3f() {
+ var x *int
+ var b bool
+ if b {
+ y := new(int)
+ runtime.GC()
+ x = y
+ }
+ println(*x)
+}
diff --git a/test/fixedbugs/issue8073.go b/test/fixedbugs/issue8073.go
new file mode 100644
index 000000000..660122110
--- /dev/null
+++ b/test/fixedbugs/issue8073.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 8073.
+// was "internal compiler error: overflow: float64 integer constant"
+
+package main
+
+func main() {
+ var x int
+ _ = float64(x * 0)
+}
diff --git a/test/fixedbugs/issue8076.go b/test/fixedbugs/issue8076.go
new file mode 100644
index 000000000..ad8906775
--- /dev/null
+++ b/test/fixedbugs/issue8076.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8076. nilwalkfwd walked forward forever
+// on the instruction loop following the dereference.
+
+package main
+
+func main() {
+ _ = *(*int)(nil)
+L:
+ _ = 0
+ goto L
+}
diff --git a/test/fixedbugs/issue8132.go b/test/fixedbugs/issue8132.go
new file mode 100644
index 000000000..52f5d39c2
--- /dev/null
+++ b/test/fixedbugs/issue8132.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 8132. stack walk handling of panic stack was confused
+// about what was legal.
+
+package main
+
+import "runtime"
+
+var p *int
+
+func main() {
+ func() {
+ defer func() {
+ runtime.GC()
+ recover()
+ }()
+ var x [8192]byte
+ func(x [8192]byte) {
+ defer func() {
+ if err := recover(); err != nil {
+ println(*p)
+ }
+ }()
+ println(*p)
+ }(x)
+ }()
+}
diff --git a/test/fixedbugs/issue8139.go b/test/fixedbugs/issue8139.go
new file mode 100644
index 000000000..821c9ff65
--- /dev/null
+++ b/test/fixedbugs/issue8139.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8139. The x.(T) assertions used to write 1 (unexpected)
+// return byte for the 0-byte return value T.
+
+package main
+
+import "fmt"
+
+type T struct{}
+
+func (T) M() {}
+
+type M interface {
+ M()
+}
+
+var e interface{} = T{}
+var i M = T{}
+var b bool
+
+func f1() int {
+ if b {
+ return f1() // convince inliner not to inline
+ }
+ z := 0x11223344
+ _ = e.(T)
+ return z
+}
+
+func f2() int {
+ if b {
+ return f1() // convince inliner not to inline
+ }
+ z := 0x11223344
+ _ = i.(T)
+ return z
+}
+
+func main() {
+ x := f1()
+ y := f2()
+ if x != 0x11223344 || y != 0x11223344 {
+ fmt.Printf("BUG: x=%#x y=%#x, want 0x11223344 for both\n", x, y)
+ }
+}
diff --git a/test/fixedbugs/issue8155.go b/test/fixedbugs/issue8155.go
new file mode 100644
index 000000000..c611f6cb1
--- /dev/null
+++ b/test/fixedbugs/issue8155.go
@@ -0,0 +1,48 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 8155.
+// Alignment of stack prologue zeroing was wrong on 64-bit Native Client
+// (because of 32-bit pointers).
+
+package main
+
+import "runtime"
+
+func bad(b bool) uintptr {
+ var p **int
+ var x1 uintptr
+ x1 = 1
+ if b {
+ var x [11]*int
+ p = &x[0]
+ }
+ if b {
+ var x [1]*int
+ p = &x[0]
+ }
+ runtime.GC()
+ if p != nil {
+ x1 = uintptr(**p)
+ }
+ return x1
+}
+
+func poison() uintptr {
+ runtime.GC()
+ var x [20]uintptr
+ var s uintptr
+ for i := range x {
+ x[i] = uintptr(i+1)
+ s += x[i]
+ }
+ return s
+}
+
+func main() {
+ poison()
+ bad(false)
+}
diff --git a/test/fixedbugs/issue8158.go b/test/fixedbugs/issue8158.go
new file mode 100644
index 000000000..b110de11f
--- /dev/null
+++ b/test/fixedbugs/issue8158.go
@@ -0,0 +1,41 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "runtime"
+ "time"
+)
+
+func main() {
+ c := make(chan bool, 1)
+ go f1(c)
+ <-c
+ time.Sleep(10 * time.Millisecond)
+ go f2(c)
+ <-c
+}
+
+func f1(done chan bool) {
+ defer func() {
+ recover()
+ done <- true
+ runtime.Goexit() // left stack-allocated Panic struct on gp->panic stack
+ }()
+ panic("p")
+}
+
+func f2(done chan bool) {
+ defer func() {
+ recover()
+ done <- true
+ runtime.Goexit()
+ }()
+ time.Sleep(10 * time.Millisecond) // overwrote Panic struct with Timer struct
+ runtime.GC() // walked gp->panic list, found mangled Panic struct, crashed
+ panic("p")
+}
diff --git a/test/float_lit2.go b/test/float_lit2.go
new file mode 100644
index 000000000..96d23f38d
--- /dev/null
+++ b/test/float_lit2.go
@@ -0,0 +1,164 @@
+// run
+
+// Check conversion of constant to float32/float64 near min/max boundaries.
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+// The largest exact float32 is f₁ = (1+(1-2²³))×2¹²⁷ = (1-2²⁴)×2¹²⁸ = 2¹²⁸ - 2¹⁰⁴.
+// The next float32 would be f₂ = (1+1)×2¹²⁷ = 1×2¹²⁸, except that exponent is out of range.
+// Float32 conversion rounds to the nearest float32, rounding to even mantissa:
+// between f₁ and f₂, values closer to f₁ round to f₁ and values closer to f₂ are rejected as out of range.
+// f₁ is an odd mantissa, so the halfway point (f₁+f₂)/2 rounds to f₂ and is rejected.
+// The halfway point is (f₁+f₂)/2 = 2¹²⁸ - 2¹⁰⁵.
+//
+// The same is true of float64, with different constants: s/24/53/ and s/128/1024/.
+
+const (
+ two24 = 1.0 * (1 << 24)
+ two53 = 1.0 * (1 << 53)
+ two64 = 1.0 * (1 << 64)
+ two128 = two64 * two64
+ two256 = two128 * two128
+ two512 = two256 * two256
+ two768 = two512 * two256
+ two1024 = two512 * two512
+
+ ulp32 = two128 / two24
+ max32 = two128 - ulp32
+
+ ulp64 = two1024 / two53
+ max64 = two1024 - ulp64
+)
+
+var cvt = []struct {
+ bits uint64 // keep us honest
+ exact interface{}
+ approx interface{}
+ text string
+}{
+ // 0
+ {0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32 - ulp32/2), "max32 - ulp32 - ulp32/2"},
+ {0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32), "max32 - ulp32"},
+ {0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32/2), "max32 - ulp32/2"},
+ {0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32 + ulp32/2), "max32 - ulp32 + ulp32/2"},
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + ulp32/two64), "max32 - ulp32 + ulp32/2 + ulp32/two64"},
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + ulp32/two64), "max32 - ulp32/2 + ulp32/two64"},
+ {0x7f7fffff, float32(max32), float32(max32), "max32"},
+ {0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - ulp32/two64), "max32 + ulp32/2 - ulp32/two64"},
+
+ {0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32 - ulp32/2)), "-(max32 - ulp32 - ulp32/2)"},
+ {0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32)), "-(max32 - ulp32)"},
+ {0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32/2)), "-(max32 - ulp32/2)"},
+ {0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32 + ulp32/2)), "-(max32 - ulp32 + ulp32/2)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + ulp32/two64)), "-(max32 - ulp32 + ulp32/2 + ulp32/two64)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + ulp32/two64)), "-(max32 - ulp32/2 + ulp32/two64)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32)), "-(max32)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - ulp32/two64)), "-(max32 + ulp32/2 - ulp32/two64)"},
+
+ // These are required to work: according to the Go spec, the internal float mantissa must be at least 256 bits,
+ // and these expressions can be represented exactly with a 256-bit mantissa.
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + 1), "max32 - ulp32 + ulp32/2 + 1"},
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + 1), "max32 - ulp32/2 + 1"},
+ {0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - 1), "max32 + ulp32/2 - 1"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + 1)), "-(max32 - ulp32 + ulp32/2 + 1)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + 1)), "-(max32 - ulp32/2 + 1)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - 1)), "-(max32 + ulp32/2 - 1)"},
+
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + 1/two128), "max32 - ulp32 + ulp32/2 + 1/two128"},
+ {0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + 1/two128), "max32 - ulp32/2 + 1/two128"},
+ {0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - 1/two128), "max32 + ulp32/2 - 1/two128"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + 1/two128)), "-(max32 - ulp32 + ulp32/2 + 1/two128)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + 1/two128)), "-(max32 - ulp32/2 + 1/two128)"},
+ {0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - 1/two128)), "-(max32 + ulp32/2 - 1/two128)"},
+
+ {0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64 - ulp64/2), "max64 - ulp64 - ulp64/2"},
+ {0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64), "max64 - ulp64"},
+ {0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64/2), "max64 - ulp64/2"},
+ {0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64 + ulp64/2), "max64 - ulp64 + ulp64/2"},
+ {0x7fefffffffffffff, float64(max64), float64(max64 - ulp64 + ulp64/2 + ulp64/two64), "max64 - ulp64 + ulp64/2 + ulp64/two64"},
+ {0x7fefffffffffffff, float64(max64), float64(max64 - ulp64/2 + ulp64/two64), "max64 - ulp64/2 + ulp64/two64"},
+ {0x7fefffffffffffff, float64(max64), float64(max64), "max64"},
+ {0x7fefffffffffffff, float64(max64), float64(max64 + ulp64/2 - ulp64/two64), "max64 + ulp64/2 - ulp64/two64"},
+
+ {0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64 - ulp64/2)), "-(max64 - ulp64 - ulp64/2)"},
+ {0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64)), "-(max64 - ulp64)"},
+ {0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64/2)), "-(max64 - ulp64/2)"},
+ {0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64 + ulp64/2)), "-(max64 - ulp64 + ulp64/2)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64 + ulp64/2 + ulp64/two64)), "-(max64 - ulp64 + ulp64/2 + ulp64/two64)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64/2 + ulp64/two64)), "-(max64 - ulp64/2 + ulp64/two64)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64)), "-(max64)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 + ulp64/2 - ulp64/two64)), "-(max64 + ulp64/2 - ulp64/two64)"},
+
+ // These are required to work.
+ // The mantissas are exactly 256 bits.
+ // max64 is just below 2¹⁰²⁴ so the bottom bit we can use is 2⁷⁶⁸.
+ {0x7fefffffffffffff, float64(max64), float64(max64 - ulp64 + ulp64/2 + two768), "max64 - ulp64 + ulp64/2 + two768"},
+ {0x7fefffffffffffff, float64(max64), float64(max64 - ulp64/2 + two768), "max64 - ulp64/2 + two768"},
+ {0x7fefffffffffffff, float64(max64), float64(max64 + ulp64/2 - two768), "max64 + ulp64/2 - two768"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64 + ulp64/2 + two768)), "-(max64 - ulp64 + ulp64/2 + two768)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64/2 + two768)), "-(max64 - ulp64/2 + two768)"},
+ {0xffefffffffffffff, float64(-(max64)), float64(-(max64 + ulp64/2 - two768)), "-(max64 + ulp64/2 - two768)"},
+}
+
+var bugged = false
+
+func bug() {
+ if !bugged {
+ bugged = true
+ fmt.Println("BUG")
+ }
+}
+
+func main() {
+ u64 := math.Float64frombits(0x7fefffffffffffff) - math.Float64frombits(0x7feffffffffffffe)
+ if ulp64 != u64 {
+ bug()
+ fmt.Printf("ulp64=%g, want %g", ulp64, u64)
+ }
+
+ u32 := math.Float32frombits(0x7f7fffff) - math.Float32frombits(0x7f7ffffe)
+ if ulp32 != u32 {
+ bug()
+ fmt.Printf("ulp32=%g, want %g", ulp32, u32)
+ }
+
+ for _, c := range cvt {
+ if bits(c.exact) != c.bits {
+ bug()
+ fmt.Printf("%s: inconsistent table: bits=%#x (%g) but exact=%g (%#x)\n", c.text, c.bits, fromBits(c.bits, c.exact), c.exact, bits(c.exact))
+ }
+ if c.approx != c.exact || bits(c.approx) != c.bits {
+ bug()
+ fmt.Printf("%s: have %g (%#x) want %g (%#x)\n", c.text, c.approx, bits(c.approx), c.exact, c.bits)
+ }
+ }
+}
+
+func bits(x interface{}) interface{} {
+ switch x := x.(type) {
+ case float32:
+ return uint64(math.Float32bits(x))
+ case float64:
+ return math.Float64bits(x)
+ }
+ return 0
+}
+
+func fromBits(b uint64, x interface{}) interface{} {
+ switch x.(type) {
+ case float32:
+ return math.Float32frombits(uint32(b))
+ case float64:
+ return math.Float64frombits(b)
+ }
+ return "?"
+}
diff --git a/test/float_lit3.go b/test/float_lit3.go
new file mode 100644
index 000000000..43dca9cfa
--- /dev/null
+++ b/test/float_lit3.go
@@ -0,0 +1,48 @@
+// errorcheck
+
+// Check flagging of invalid conversion of constant to float32/float64 near min/max boundaries.
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// See float_lit2.go for motivation for these values.
+const (
+ two24 = 1.0 * (1 << 24)
+ two53 = 1.0 * (1 << 53)
+ two64 = 1.0 * (1 << 64)
+ two128 = two64 * two64
+ two256 = two128 * two128
+ two512 = two256 * two256
+ two768 = two512 * two256
+ two1024 = two512 * two512
+
+ ulp32 = two128 / two24
+ max32 = two128 - ulp32
+
+ ulp64 = two1024 / two53
+ max64 = two1024 - ulp64
+)
+
+var x = []interface{}{
+ float32(max32 + ulp32/2 - 1), // ok
+ float32(max32 + ulp32/2 - two128/two256), // ok
+ float32(max32 + ulp32/2), // ERROR "constant 3\.40282e\+38 overflows float32"
+
+ float32(-max32 - ulp32/2 + 1), // ok
+ float32(-max32 - ulp32/2 + two128/two256), // ok
+ float32(-max32 - ulp32/2), // ERROR "constant -3\.40282e\+38 overflows float32"
+
+ // If the compiler's internal floating point representation
+ // is shorter than 1024 bits, it cannot distinguish max64+ulp64/2-1 and max64+ulp64/2.
+ // gc uses fewer than 1024 bits, so allow it to print the overflow error for the -1 case.
+ float64(max64 + ulp64/2 - two1024/two256), // ok
+ float64(max64 + ulp64/2 - 1), // GC_ERROR "constant 1\.79769e\+308 overflows float64"
+ float64(max64 + ulp64/2), // ERROR "constant 1\.79769e\+308 overflows float64"
+
+ float64(-max64 - ulp64/2 + two1024/two256), // ok
+ float64(-max64 - ulp64/2 + 1), // GC_ERROR "constant -1\.79769e\+308 overflows float64"
+ float64(-max64 - ulp64/2), // ERROR "constant -1\.79769e\+308 overflows float64"
+}
diff --git a/test/funcdup.go b/test/funcdup.go
index 706dd63ca..d15d68579 100644
--- a/test/funcdup.go
+++ b/test/funcdup.go
@@ -7,21 +7,21 @@
package p
type T interface {
- F1(i int) (i int) // ERROR "duplicate argument i"
- F2(i, i int) // ERROR "duplicate argument i"
- F3() (i, i int) // ERROR "duplicate argument i"
+ F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+ F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+ F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
}
-type T1 func(i, i int) // ERROR "duplicate argument i"
-type T2 func(i int) (i int) // ERROR "duplicate argument i"
-type T3 func() (i, i int) // ERROR "duplicate argument i"
+type T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+type T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+type T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
type R struct{}
-func (i *R) F1(i int) {} // ERROR "duplicate argument i"
-func (i *R) F2() (i int) {return 0} // ERROR "duplicate argument i"
-func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j"
+func (i *R) F1(i int) {} // ERROR "duplicate argument i|redefinition|previous"
+func (i *R) F2() (i int) {return 0} // ERROR "duplicate argument i|redefinition|previous"
+func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j|redefinition|previous"
-func F1(i, i int) {} // ERROR "duplicate argument i"
-func F2(i int) (i int) {return 0} // ERROR "duplicate argument i"
-func F3() (i, i int) {return 0, 0} // ERROR "duplicate argument i"
+func F1(i, i int) {} // ERROR "duplicate argument i|redefinition|previous"
+func F2(i int) (i int) {return 0} // ERROR "duplicate argument i|redefinition|previous"
+func F3() (i, i int) {return 0, 0} // ERROR "duplicate argument i|redefinition|previous"
diff --git a/test/funcdup2.go b/test/funcdup2.go
index aeb5f7eb6..1db1a396b 100644
--- a/test/funcdup2.go
+++ b/test/funcdup2.go
@@ -7,11 +7,11 @@
package p
var T interface {
- F1(i int) (i int) // ERROR "duplicate argument i"
- F2(i, i int) // ERROR "duplicate argument i"
- F3() (i, i int) // ERROR "duplicate argument i"
+ F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+ F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+ F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
}
-var T1 func(i, i int) // ERROR "duplicate argument i"
-var T2 func(i int) (i int) // ERROR "duplicate argument i"
-var T3 func() (i, i int) // ERROR "duplicate argument i"
+var T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+var T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+var T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
diff --git a/test/gc2.go b/test/gc2.go
index de52a4fbf..561516b8b 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -1,5 +1,7 @@
// run
+// +build !nacl
+
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -36,7 +38,7 @@ func main() {
}
runtime.ReadMemStats(memstats)
- obj := memstats.HeapObjects - st.HeapObjects
+ obj := int64(memstats.HeapObjects - st.HeapObjects)
if obj > N/5 {
fmt.Println("too many objects left:", obj)
os.Exit(1)
diff --git a/test/gcstring.go b/test/gcstring.go
new file mode 100644
index 000000000..627a42645
--- /dev/null
+++ b/test/gcstring.go
@@ -0,0 +1,48 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that s[len(s):] - which can point past the end of the allocated block -
+// does not confuse the garbage collector.
+
+package main
+
+import (
+ "runtime"
+ "time"
+)
+
+type T struct {
+ ptr **int
+ pad [120]byte
+}
+
+var things []interface{}
+
+func main() {
+ setup()
+ runtime.GC()
+ runtime.GC()
+ time.Sleep(10*time.Millisecond)
+ runtime.GC()
+ runtime.GC()
+ time.Sleep(10*time.Millisecond)
+}
+
+func setup() {
+ var Ts []interface{}
+ buf := make([]byte, 128)
+
+ for i := 0; i < 10000; i++ {
+ s := string(buf)
+ t := &T{ptr: new(*int)}
+ runtime.SetFinalizer(t.ptr, func(**int) { panic("*int freed too early") })
+ Ts = append(Ts, t)
+ things = append(things, s[len(s):])
+ }
+
+ things = append(things, Ts...)
+}
+
diff --git a/test/import1.go b/test/import1.go
index d2bb55cbf..2433b5f2a 100644
--- a/test/import1.go
+++ b/test/import1.go
@@ -15,5 +15,5 @@ import bufio "os" // ERROR "redeclared|redefinition|incompatible" "imported and
import (
"fmt" // GCCGO_ERROR "previous|not used"
fmt "math" // ERROR "redeclared|redefinition|incompatible" "imported and not used: \x22math\x22 as fmt"
- . "math" // ERROR "imported and not used: \x22math\x22$"
+ . "math" // GC_ERROR "imported and not used: \x22math\x22$"
)
diff --git a/test/import4.dir/empty.go b/test/import4.dir/empty.go
index c8214f36d..1dffa170d 100644
--- a/test/import4.dir/empty.go
+++ b/test/import4.dir/empty.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package P
+package empty
import ( )
const ( )
diff --git a/test/import4.dir/import4.go b/test/import4.dir/import4.go
index b9f973f17..f92c663d0 100644
--- a/test/import4.dir/import4.go
+++ b/test/import4.dir/import4.go
@@ -18,7 +18,7 @@ import X "math" // ERROR "imported and not used.*math"
import . "bufio" // ERROR "imported and not used.*bufio"
// again, package without anything in it
-import "./empty" // ERROR "imported and not used.*empty"
-import Z "./empty" // ERROR "imported and not used.*empty"
+import "./empty" // GC_ERROR "imported and not used.*empty"
+import Z "./empty" // GC_ERROR "imported and not used.*empty"
import . "./empty" // ERROR "imported and not used.*empty"
diff --git a/test/live.go b/test/live.go
new file mode 100644
index 000000000..b4cced47e
--- /dev/null
+++ b/test/live.go
@@ -0,0 +1,624 @@
+// errorcheck -0 -l -live
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// liveness tests with inlining disabled.
+// see also live2.go.
+
+package main
+
+func f1() {
+ var x *int
+ print(&x) // ERROR "live at call to printpointer: x$"
+ print(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f2(b bool) {
+ if b {
+ print(0) // nothing live here
+ return
+ }
+ var x *int
+ print(&x) // ERROR "live at call to printpointer: x$"
+ print(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f3(b bool) {
+ // Because x and y are ambiguously live, they appear
+ // live throughout the function, to avoid being poisoned
+ // in GODEBUG=gcdead=1 mode.
+
+ print(0) // ERROR "live at call to printint: x y$"
+ if b == false {
+ print(0) // ERROR "live at call to printint: x y$"
+ return
+ }
+
+ if b {
+ var x *int
+ print(&x) // ERROR "live at call to printpointer: x y$"
+ print(&x) // ERROR "live at call to printpointer: x y$"
+ } else {
+ var y *int
+ print(&y) // ERROR "live at call to printpointer: x y$"
+ print(&y) // ERROR "live at call to printpointer: x y$"
+ }
+ print(0) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+}
+
+// The old algorithm treated x as live on all code that
+// could flow to a return statement, so it included the
+// function entry and code above the declaration of x
+// but would not include an indirect use of x in an infinite loop.
+// Check that these cases are handled correctly.
+
+func f4(b1, b2 bool) { // x not live here
+ if b2 {
+ print(0) // x not live here
+ return
+ }
+ var z **int
+ x := new(int)
+ *x = 42
+ z = &x
+ print(**z) // ERROR "live at call to printint: x z$"
+ if b2 {
+ print(1) // ERROR "live at call to printint: x$"
+ return
+ }
+ for {
+ print(**z) // ERROR "live at call to printint: x z$"
+ }
+}
+
+func f5(b1 bool) {
+ var z **int
+ if b1 {
+ x := new(int)
+ *x = 42
+ z = &x
+ } else {
+ y := new(int)
+ *y = 54
+ z = &y
+ }
+ print(**z) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+}
+
+// confusion about the _ result used to cause spurious "live at entry to f6: _".
+
+func f6() (_, y string) {
+ y = "hello"
+ return
+}
+
+// confusion about addressed results used to cause "live at entry to f7: x".
+
+func f7() (x string) {
+ _ = &x
+ x = "hello"
+ return
+}
+
+// ignoring block returns used to cause "live at entry to f8: x, y".
+
+func f8() (x, y string) {
+ return g8()
+}
+
+func g8() (string, string)
+
+// ignoring block assignments used to cause "live at entry to f9: x"
+// issue 7205
+
+var i9 interface{}
+
+func f9() bool {
+ g8()
+ x := i9
+ return x != 99
+}
+
+// liveness formerly confused by UNDEF followed by RET,
+// leading to "live at entry to f10: ~r1" (unnamed result).
+
+func f10() string {
+ panic(1)
+}
+
+// liveness formerly confused by select, thinking runtime.selectgo
+// can return to next instruction; it always jumps elsewhere.
+// note that you have to use at least two cases in the select
+// to get a true select; smaller selects compile to optimized helper functions.
+
+var c chan *int
+var b bool
+
+// this used to have a spurious "live at entry to f11a: ~r0"
+func f11a() *int {
+ select { // ERROR "live at call to selectgo: autotmp"
+ case <-c: // ERROR "live at call to selectrecv: autotmp"
+ return nil
+ case <-c: // ERROR "live at call to selectrecv: autotmp"
+ return nil
+ }
+}
+
+func f11b() *int {
+ p := new(int)
+ if b {
+ // At this point p is dead: the code here cannot
+ // get to the bottom of the function.
+ // This used to have a spurious "live at call to printint: p".
+ print(1) // nothing live here!
+ select { // ERROR "live at call to selectgo: autotmp"
+ case <-c: // ERROR "live at call to selectrecv: autotmp"
+ return nil
+ case <-c: // ERROR "live at call to selectrecv: autotmp"
+ return nil
+ }
+ }
+ println(*p)
+ return nil
+}
+
+func f11c() *int {
+ p := new(int)
+ if b {
+ // Unlike previous, the cases in this select fall through,
+ // so we can get to the println, so p is not dead.
+ print(1) // ERROR "live at call to printint: p"
+ select { // ERROR "live at call to newselect: p" "live at call to selectgo: autotmp.* p"
+ case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+ case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+ }
+ }
+ println(*p)
+ return nil
+}
+
+// similarly, select{} does not fall through.
+// this used to have a spurious "live at entry to f12: ~r0".
+
+func f12() *int {
+ if b {
+ select{}
+ } else {
+ return nil
+ }
+}
+
+// incorrectly placed VARDEF annotations can cause missing liveness annotations.
+// this used to be missing the fact that s is live during the call to g13 (because it is
+// needed for the call to h13).
+
+func f13() {
+ s := "hello"
+ s = h13(s, g13(s)) // ERROR "live at call to g13: s"
+}
+
+func g13(string) string
+func h13(string, string) string
+
+// more incorrectly placed VARDEF.
+
+func f14() {
+ x := g14()
+ print(&x) // ERROR "live at call to printpointer: x"
+}
+
+func g14() string
+
+func f15() {
+ var x string
+ _ = &x
+ x = g15() // ERROR "live at call to g15: x"
+ print(x) // ERROR "live at call to printstring: x"
+}
+
+func g15() string
+
+// Checking that various temporaries do not persist or cause
+// ambiguously live values that must be zeroed.
+// The exact temporary names are inconsequential but we are
+// trying to check that there is only one at any given site,
+// and also that none show up in "ambiguously live" messages.
+
+var m map[string]int
+
+func f16() {
+ if b {
+ delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+ }
+ delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+ delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+}
+
+var m2s map[string]*byte
+var m2 map[[2]string]*byte
+var x2 [2]string
+var bp *byte
+
+func f17a() {
+ // value temporary only
+ if b {
+ m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ }
+ m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17b() {
+ // key temporary only
+ if b {
+ m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ }
+ m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17c() {
+ // key and value temporaries
+ if b {
+ m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ }
+ m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+func g18() [2]string
+
+func f18() {
+ // key temporary for mapaccess.
+ // temporary introduced by orderexpr.
+ var z *byte
+ if b {
+ z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ }
+ z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ print(z)
+}
+
+var ch chan *byte
+
+func f19() {
+ // dest temporary for channel receive.
+ var z *byte
+
+ if b {
+ z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+ }
+ z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+ z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+ print(z)
+}
+
+func f20() {
+ // src temporary for channel send
+ if b {
+ ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+ }
+ ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+ ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+}
+
+func f21() {
+ // key temporary for mapaccess using array literal key.
+ var z *byte
+ if b {
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ }
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ print(z)
+}
+
+func f23() {
+ // key temporary for two-result map access using array literal key.
+ var z *byte
+ var ok bool
+ if b {
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+ }
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+ print(z, ok)
+}
+
+func f24() {
+ // key temporary for map access using array literal key.
+ // value temporary too.
+ if b {
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ }
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+// defer should not cause spurious ambiguously live variables
+
+func f25(b bool) {
+ defer g25()
+ if b {
+ return
+ }
+ var x string
+ _ = &x
+ x = g15() // ERROR "live at call to g15: x"
+ print(x) // ERROR "live at call to printstring: x"
+} // ERROR "live at call to deferreturn: x"
+
+func g25()
+
+// non-escaping ... slices passed to function call should die on return,
+// so that the temporaries do not stack and do not cause ambiguously
+// live variables.
+
+func f26(b bool) {
+ if b {
+ print26(1,2,3) // ERROR "live at call to print26: autotmp_[0-9]+$"
+ }
+ print26(4,5,6) // ERROR "live at call to print26: autotmp_[0-9]+$"
+ print26(7,8,9) // ERROR "live at call to print26: autotmp_[0-9]+$"
+ println()
+}
+
+//go:noescape
+func print26(...interface{})
+
+// non-escaping closures passed to function call should die on return
+
+func f27(b bool) {
+ x := 0
+ if b {
+ call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+ }
+ call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+ call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+ println()
+}
+
+// but defer does escape to later execution in the function
+
+func f27defer(b bool) {
+ x := 0
+ if b {
+ defer call27(func() {x++}) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
+ }
+ defer call27(func() {x++}) // ERROR "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$" "ambiguously live"
+ println() // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
+} // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
+
+// and newproc (go) escapes to the heap
+
+func f27go(b bool) {
+ x := 0
+ if b {
+ go call27(func() {x++}) // ERROR "live at call to new: &x" "live at call to newproc: &x$"
+ }
+ go call27(func() {x++}) // ERROR "live at call to new: &x"
+ println()
+}
+
+//go:noescape
+func call27(func())
+
+// concatstring slice should die on return
+
+var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
+
+func f28(b bool) {
+ if b {
+ print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+ }
+ print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+ print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+}
+
+// map iterator should die on end of range loop
+
+func f29(b bool) {
+ if b {
+ for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+ print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ }
+ }
+ for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+ print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ }
+ for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+ print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ }
+}
+
+// copy of array of pointers should die at end of range loop
+
+var ptrarr [10]*int
+
+func f30(b bool) {
+ // two live temps during print(p):
+ // the copy of ptrarr and the internal iterator pointer.
+ if b {
+ for _, p := range ptrarr {
+ print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ }
+ }
+ for _, p := range ptrarr {
+ print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ }
+ for _, p := range ptrarr {
+ print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ }
+}
+
+// conversion to interface should not leave temporary behind
+
+func f31(b1, b2, b3 bool) {
+ if b1 {
+ g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
+ }
+ if b2 {
+ h31("b") // ERROR "live at call to new: autotmp_[0-9]+$" "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$"
+ }
+ if b3 {
+ panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to panic: autotmp_[0-9]+$"
+ }
+ print(b3)
+}
+
+func g31(interface{})
+func h31(...interface{})
+
+// non-escaping partial functions passed to function call should die on return
+
+type T32 int
+
+func (t *T32) Inc() { // ERROR "live at entry"
+ *t++
+}
+
+var t32 T32
+
+func f32(b bool) {
+ if b {
+ call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+ }
+ call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+ call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+}
+
+//go:noescape
+func call32(func())
+
+// temporaries introduced during if conditions and && || expressions
+// should die once the condition has been acted upon.
+
+var m33 map[interface{}]int
+
+func f33() {
+ if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ println()
+ return
+ } else {
+ println()
+ }
+ println()
+}
+
+func f34() {
+ if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ println()
+ return
+ }
+ println()
+}
+
+func f35() {
+ if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ println()
+ return
+ }
+ println()
+}
+
+func f36() {
+ if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ println()
+ return
+ }
+ println()
+}
+
+func f37() {
+ if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ println()
+ return
+ }
+ println()
+}
+
+// select temps should disappear in the case bodies
+
+var c38 chan string
+
+func fc38() chan string
+func fi38(int) *string
+func fb38() *bool
+
+func f38(b bool) {
+ // we don't care what temps are printed on the lines with output.
+ // we care that the println lines have no live variables
+ // and therefore no output.
+ if b {
+ select { // ERROR "live at call"
+ case <-fc38(): // ERROR "live at call"
+ println()
+ case fc38() <- *fi38(1): // ERROR "live at call"
+ println()
+ case *fi38(2) = <-fc38(): // ERROR "live at call"
+ println()
+ case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call"
+ println()
+ }
+ println()
+ }
+ println()
+}
+
+// issue 8097: mishandling of x = x during return.
+
+func f39() (x []int) {
+ x = []int{1}
+ println() // ERROR "live at call to printnl: x"
+ return x
+}
+
+func f39a() (x []int) {
+ x = []int{1}
+ println() // ERROR "live at call to printnl: x"
+ return
+}
+
+func f39b() (x [10]*int) {
+ x = [10]*int{new(int)} // ERROR "live at call to new: x"
+ println() // ERROR "live at call to printnl: x"
+ return x
+}
+
+func f39c() (x [10]*int) {
+ x = [10]*int{new(int)} // ERROR "live at call to new: x"
+ println() // ERROR "live at call to printnl: x"
+ return
+}
+
+// issue 8142: lost 'addrtaken' bit on inlined variables.
+// no inlining in this test, so just checking that non-inlined works.
+
+type T40 struct {
+ m map[int]int
+}
+
+func newT40() *T40 {
+ ret := T40{ // ERROR "live at call to makemap: &ret"
+ make(map[int]int),
+ }
+ return &ret
+}
+
+func bad40() {
+ t := newT40()
+ println()
+ _ = t
+}
+
+func good40() {
+ ret := T40{ // ERROR "live at call to makemap: ret"
+ make(map[int]int),
+ }
+ t := &ret
+ println() // ERROR "live at call to printnl: ret"
+ _ = t
+}
diff --git a/test/live1.go b/test/live1.go
new file mode 100644
index 000000000..b05ec1f59
--- /dev/null
+++ b/test/live1.go
@@ -0,0 +1,46 @@
+// compile
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that code compiles without
+// "internal error: ... recorded as live on entry" errors
+// from the liveness code.
+//
+// This code contains methods or other construct that
+// trigger the generation of wrapper functions with no
+// clear line number (they end up using line 1), and those
+// would have annotations printed if we used -live=1,
+// like the live.go test does.
+// Instead, this test relies on the fact that the liveness
+// analysis turns any non-live parameter on entry into
+// a compile error. Compiling successfully means that bug
+// has been avoided.
+
+package main
+
+// The liveness analysis used to get confused by the tail return
+// instruction in the wrapper methods generated for T1.M and (*T1).M,
+// causing a spurious "live at entry: ~r1" for the return result.
+
+type T struct {
+}
+
+func (t *T) M() *int
+
+type T1 struct {
+ *T
+}
+
+// Liveness analysis used to have the VARDEFs in the wrong place,
+// causing a temporary to appear live on entry.
+
+func f1(pkg, typ, meth string) {
+ panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+}
+
+func f2() interface{} {
+ return new(int)
+}
+
diff --git a/test/live2.go b/test/live2.go
new file mode 100644
index 000000000..1e3279402
--- /dev/null
+++ b/test/live2.go
@@ -0,0 +1,39 @@
+// errorcheck -0 -live
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// liveness tests with inlining ENABLED
+// see also live.go.
+
+package main
+
+// issue 8142: lost 'addrtaken' bit on inlined variables.
+// no inlining in this test, so just checking that non-inlined works.
+
+type T40 struct {
+ m map[int]int
+}
+
+func newT40() *T40 {
+ ret := T40{ // ERROR "live at call to makemap: &ret"
+ make(map[int]int),
+ }
+ return &ret
+}
+
+func bad40() {
+ t := newT40() // ERROR "live at call to makemap: ret"
+ println() // ERROR "live at call to printnl: ret"
+ _ = t
+}
+
+func good40() {
+ ret := T40{ // ERROR "live at call to makemap: ret"
+ make(map[int]int),
+ }
+ t := &ret
+ println() // ERROR "live at call to printnl: ret"
+ _ = t
+}
diff --git a/test/method4.dir/prog.go b/test/method4.dir/prog.go
index 77d580cff..cb5cf65f2 100644
--- a/test/method4.dir/prog.go
+++ b/test/method4.dir/prog.go
@@ -73,7 +73,14 @@ func main() {
f4 := I2.Sum
eq(f4(t1, a, 17), 27)
eq(f4(t2, a, 18), 28)
-
+
+ // issue 6723
+ f5 := (interface {
+ I2
+ }).Sum
+ eq(f5(t1, a, 19), 29)
+ eq(f5(t2, a, 20), 30)
+
mt1 := method4a.T1(4)
mt2 := &method4a.T2{4}
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 08597a02d..2757daef0 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -17,7 +17,7 @@ type Struct struct {
type BigStruct struct {
X int
Y float64
- A [1<<20]int
+ A [1 << 20]int
Z string
}
@@ -29,93 +29,94 @@ type Empty1 struct {
}
var (
- intp *int
- arrayp *[10]int
- array0p *[0]int
- bigarrayp *[1<<26]int
- structp *Struct
+ intp *int
+ arrayp *[10]int
+ array0p *[0]int
+ bigarrayp *[1 << 26]int
+ structp *Struct
bigstructp *BigStruct
- emptyp *Empty
- empty1p *Empty1
+ emptyp *Empty
+ empty1p *Empty1
)
func f1() {
_ = *intp // ERROR "generated nil check"
-
+
// This one should be removed but the block copy needs
// to be turned into its own pseudo-op in order to see
// the indirect.
_ = *arrayp // ERROR "generated nil check"
-
- // 0-byte indirect doesn't suffice
+
+ // 0-byte indirect doesn't suffice.
+ // we don't registerize globals, so there are no removed repeated nil checks.
+ _ = *array0p // ERROR "generated nil check"
_ = *array0p // ERROR "generated nil check"
- _ = *array0p // ERROR "removed repeated nil check" 386
- _ = *intp // ERROR "removed repeated nil check"
- _ = *arrayp // ERROR "removed repeated nil check"
+ _ = *intp // ERROR "generated nil check"
+ _ = *arrayp // ERROR "generated nil check"
_ = *structp // ERROR "generated nil check"
- _ = *emptyp // ERROR "generated nil check"
- _ = *arrayp // ERROR "removed repeated nil check"
+ _ = *emptyp // ERROR "generated nil check"
+ _ = *arrayp // ERROR "generated nil check"
}
func f2() {
var (
- intp *int
- arrayp *[10]int
- array0p *[0]int
- bigarrayp *[1<<20]int
- structp *Struct
+ intp *int
+ arrayp *[10]int
+ array0p *[0]int
+ bigarrayp *[1 << 20]int
+ structp *Struct
bigstructp *BigStruct
- emptyp *Empty
- empty1p *Empty1
+ emptyp *Empty
+ empty1p *Empty1
)
- _ = *intp // ERROR "generated nil check"
- _ = *arrayp // ERROR "generated nil check"
- _ = *array0p // ERROR "generated nil check"
- _ = *array0p // ERROR "removed repeated nil check"
- _ = *intp // ERROR "removed repeated nil check"
- _ = *arrayp // ERROR "removed repeated nil check"
- _ = *structp // ERROR "generated nil check"
- _ = *emptyp // ERROR "generated nil check"
- _ = *arrayp // ERROR "removed repeated nil check"
- _ = *bigarrayp // ERROR "generated nil check" ARM removed nil check before indirect!!
+ _ = *intp // ERROR "generated nil check"
+ _ = *arrayp // ERROR "generated nil check"
+ _ = *array0p // ERROR "generated nil check"
+ _ = *array0p // ERROR "removed repeated nil check"
+ _ = *intp // ERROR "removed repeated nil check"
+ _ = *arrayp // ERROR "removed repeated nil check"
+ _ = *structp // ERROR "generated nil check"
+ _ = *emptyp // ERROR "generated nil check"
+ _ = *arrayp // ERROR "removed repeated nil check"
+ _ = *bigarrayp // ERROR "generated nil check" ARM removed nil check before indirect!!
_ = *bigstructp // ERROR "generated nil check"
- _ = *empty1p // ERROR "generated nil check"
+ _ = *empty1p // ERROR "generated nil check"
}
func fx10k() *[10000]int
-var b bool
+var b bool
func f3(x *[10000]int) {
// Using a huge type and huge offsets so the compiler
// does not expect the memory hardware to fault.
_ = x[9999] // ERROR "generated nil check"
-
+
for {
if x[9999] != 0 { // ERROR "generated nil check"
break
}
}
-
- x = fx10k()
+
+ x = fx10k()
_ = x[9999] // ERROR "generated nil check"
if b {
_ = x[9999] // ERROR "removed repeated nil check"
} else {
_ = x[9999] // ERROR "removed repeated nil check"
- }
+ }
_ = x[9999] // ERROR "generated nil check"
- x = fx10k()
+ x = fx10k()
if b {
_ = x[9999] // ERROR "generated nil check"
} else {
_ = x[9999] // ERROR "generated nil check"
- }
+ }
_ = x[9999] // ERROR "generated nil check"
-
+
fx10k()
// This one is a bit redundant, if we figured out that
// x wasn't going to change across the function call.
@@ -145,7 +146,7 @@ func f3b() {
_ = &x[9] // ERROR "removed repeated nil check"
}
-func fx10() *[10]int
+func fx10() *[10]int
func f4(x *[10]int) {
// Most of these have no checks because a real memory reference follows,
@@ -153,14 +154,14 @@ func f4(x *[10]int) {
// in the first unmapped page of memory.
_ = x[9] // ERROR "removed nil check before indirect"
-
+
for {
if x[9] != 0 { // ERROR "removed nil check before indirect"
break
}
}
-
- x = fx10()
+
+ x = fx10()
_ = x[9] // ERROR "removed nil check before indirect"
if b {
_ = x[9] // ERROR "removed nil check before indirect"
@@ -169,17 +170,17 @@ func f4(x *[10]int) {
}
_ = x[9] // ERROR "removed nil check before indirect"
- x = fx10()
+ x = fx10()
if b {
_ = x[9] // ERROR "removed nil check before indirect"
} else {
_ = &x[9] // ERROR "generated nil check"
- }
+ }
_ = x[9] // ERROR "removed nil check before indirect"
-
+
fx10()
_ = x[9] // ERROR "removed nil check before indirect"
-
+
x = fx10()
y := fx10()
_ = &x[9] // ERROR "generated nil check"
@@ -188,4 +189,3 @@ func f4(x *[10]int) {
x = y
_ = &x[9] // ERROR "removed repeated nil check"
}
-
diff --git a/test/nilptr4.go b/test/nilptr4.go
new file mode 100644
index 000000000..3dd7d4e02
--- /dev/null
+++ b/test/nilptr4.go
@@ -0,0 +1,24 @@
+// build
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that the compiler does not crash during compilation.
+
+package main
+
+import "unsafe"
+
+// Issue 7413
+func f1() {
+ type t struct {
+ i int
+ }
+
+ var v *t
+ _ = int(uintptr(unsafe.Pointer(&v.i)))
+ _ = int32(uintptr(unsafe.Pointer(&v.i)))
+}
+
+func main() {}
diff --git a/test/nosplit.go b/test/nosplit.go
new file mode 100644
index 000000000..35aa51017
--- /dev/null
+++ b/test/nosplit.go
@@ -0,0 +1,314 @@
+// run
+
+// +build !nacl
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+var tests = `
+# These are test cases for the linker analysis that detects chains of
+# nosplit functions that would cause a stack overflow.
+#
+# Lines beginning with # are comments.
+#
+# Each test case describes a sequence of functions, one per line.
+# Each function definition is the function name, then the frame size,
+# then optionally the keyword 'nosplit', then the body of the function.
+# The body is assembly code, with some shorthands.
+# The shorthand 'call x' stands for CALL x(SB).
+# The shorthand 'callind' stands for 'CALL R0', where R0 is a register.
+# Each test case must define a function named main, and it must be first.
+# That is, a line beginning "main " indicates the start of a new test case.
+# Within a stanza, ; can be used instead of \n to separate lines.
+#
+# After the function definition, the test case ends with an optional
+# REJECT line, specifying the architectures on which the case should
+# be rejected. "REJECT" without any architectures means reject on all architectures.
+# The linker should accept the test case on systems not explicitly rejected.
+#
+# 64-bit systems do not attempt to execute test cases with frame sizes
+# that are only 32-bit aligned.
+
+# Ordinary function should work
+main 0
+
+# Large frame marked nosplit is always wrong.
+main 10000 nosplit
+REJECT
+
+# Calling a large frame is okay.
+main 0 call big
+big 10000
+
+# But not if the frame is nosplit.
+main 0 call big
+big 10000 nosplit
+REJECT
+
+# Recursion is okay.
+main 0 call main
+
+# Recursive nosplit runs out of space.
+main 0 nosplit call main
+REJECT
+
+# Chains of ordinary functions okay.
+main 0 call f1
+f1 80 call f2
+f2 80
+
+# Chains of nosplit must fit in the stack limit, 128 bytes.
+main 0 call f1
+f1 80 nosplit call f2
+f2 80 nosplit
+REJECT
+
+# Larger chains.
+main 0 call f1
+f1 16 call f2
+f2 16 call f3
+f3 16 call f4
+f4 16 call f5
+f5 16 call f6
+f6 16 call f7
+f7 16 call f8
+f8 16 call end
+end 1000
+
+main 0 call f1
+f1 16 nosplit call f2
+f2 16 nosplit call f3
+f3 16 nosplit call f4
+f4 16 nosplit call f5
+f5 16 nosplit call f6
+f6 16 nosplit call f7
+f7 16 nosplit call f8
+f8 16 nosplit call end
+end 1000
+REJECT
+
+# Test cases near the 128-byte limit.
+
+# Ordinary stack split frame is always okay.
+main 112
+main 116
+main 120
+main 124
+main 128
+main 132
+main 136
+
+# A nosplit leaf can use the whole 128-CallSize bytes available on entry.
+main 112 nosplit
+main 116 nosplit
+main 120 nosplit
+main 124 nosplit
+main 128 nosplit; REJECT
+main 132 nosplit; REJECT
+main 136 nosplit; REJECT
+
+# Calling a nosplit function from a nosplit function requires
+# having room for the saved caller PC and the called frame.
+# Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes.
+main 112 nosplit call f; f 0 nosplit
+main 116 nosplit call f; f 0 nosplit; REJECT amd64
+main 120 nosplit call f; f 0 nosplit; REJECT amd64
+main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
+main 128 nosplit call f; f 0 nosplit; REJECT
+main 132 nosplit call f; f 0 nosplit; REJECT
+main 136 nosplit call f; f 0 nosplit; REJECT
+
+# Calling a splitting function from a nosplit function requires
+# having room for the saved caller PC of the call but also the
+# saved caller PC for the call to morestack. Again the ARM works
+# in less space.
+main 104 nosplit call f; f 0 call f
+main 108 nosplit call f; f 0 call f
+main 112 nosplit call f; f 0 call f; REJECT amd64
+main 116 nosplit call f; f 0 call f; REJECT amd64
+main 120 nosplit call f; f 0 call f; REJECT amd64 386
+main 124 nosplit call f; f 0 call f; REJECT amd64 386
+main 128 nosplit call f; f 0 call f; REJECT
+main 132 nosplit call f; f 0 call f; REJECT
+main 136 nosplit call f; f 0 call f; REJECT
+
+# Indirect calls are assumed to be splitting functions.
+main 104 nosplit callind
+main 108 nosplit callind
+main 112 nosplit callind; REJECT amd64
+main 116 nosplit callind; REJECT amd64
+main 120 nosplit callind; REJECT amd64 386
+main 124 nosplit callind; REJECT amd64 386
+main 128 nosplit callind; REJECT
+main 132 nosplit callind; REJECT
+main 136 nosplit callind; REJECT
+
+# Issue 7623
+main 0 call f; f 112
+main 0 call f; f 116
+main 0 call f; f 120
+main 0 call f; f 124
+main 0 call f; f 128
+main 0 call f; f 132
+main 0 call f; f 136
+`
+
+var (
+ commentRE = regexp.MustCompile(`(?m)^#.*`)
+ rejectRE = regexp.MustCompile(`(?s)\A(.+?)((\n|; *)REJECT(.*))?\z`)
+ lineRE = regexp.MustCompile(`(\w+) (\d+)( nosplit)?(.*)`)
+ callRE = regexp.MustCompile(`\bcall (\w+)\b`)
+ callindRE = regexp.MustCompile(`\bcallind\b`)
+)
+
+func main() {
+ goarch := os.Getenv("GOARCH")
+ if goarch == "" {
+ goarch = runtime.GOARCH
+ }
+
+ dir, err := ioutil.TempDir("", "go-test-nosplit")
+ if err != nil {
+ bug()
+ fmt.Printf("creating temp dir: %v\n", err)
+ return
+ }
+ defer os.RemoveAll(dir)
+ ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte("package main\nfunc main()\n"), 0666)
+
+ tests = strings.Replace(tests, "\t", " ", -1)
+ tests = commentRE.ReplaceAllString(tests, "")
+
+ nok := 0
+ nfail := 0
+TestCases:
+ for len(tests) > 0 {
+ var stanza string
+ i := strings.Index(tests, "\nmain ")
+ if i < 0 {
+ stanza, tests = tests, ""
+ } else {
+ stanza, tests = tests[:i], tests[i+1:]
+ }
+
+ m := rejectRE.FindStringSubmatch(stanza)
+ if m == nil {
+ bug()
+ fmt.Printf("invalid stanza:\n\t%s\n", indent(stanza))
+ continue
+ }
+ lines := strings.TrimSpace(m[1])
+ reject := false
+ if m[2] != "" {
+ if strings.TrimSpace(m[4]) == "" {
+ reject = true
+ } else {
+ for _, rej := range strings.Fields(m[4]) {
+ if rej == goarch {
+ reject = true
+ }
+ }
+ }
+ }
+ if lines == "" && !reject {
+ continue
+ }
+
+ var buf bytes.Buffer
+ if goarch == "arm" {
+ fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
+ } else {
+ fmt.Fprintf(&buf, "#define REGISTER AX\n")
+ }
+
+ for _, line := range strings.Split(lines, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ for _, subline := range strings.Split(line, ";") {
+ subline = strings.TrimSpace(subline)
+ if subline == "" {
+ continue
+ }
+ m := lineRE.FindStringSubmatch(subline)
+ if m == nil {
+ bug()
+ fmt.Printf("invalid function line: %s\n", subline)
+ continue TestCases
+ }
+ name := m[1]
+ size, _ := strconv.Atoi(m[2])
+ if goarch == "amd64" && size%8 == 4 {
+ continue TestCases
+ }
+ nosplit := m[3]
+ body := m[4]
+
+ if nosplit != "" {
+ nosplit = ",7"
+ } else {
+ nosplit = ",0"
+ }
+ body = callRE.ReplaceAllString(body, "CALL ·$1(SB);")
+ body = callindRE.ReplaceAllString(body, "CALL REGISTER;")
+
+ fmt.Fprintf(&buf, "TEXT ·%s(SB)%s,$%d-0\n\t%s\n\tRET\n\n", name, nosplit, size, body)
+ }
+ }
+
+ ioutil.WriteFile(filepath.Join(dir, "asm.s"), buf.Bytes(), 0666)
+
+ cmd := exec.Command("go", "build")
+ cmd.Dir = dir
+ output, err := cmd.CombinedOutput()
+ if err == nil {
+ nok++
+ if reject {
+ bug()
+ fmt.Printf("accepted incorrectly:\n\t%s\n", indent(strings.TrimSpace(stanza)))
+ }
+ } else {
+ nfail++
+ if !reject {
+ bug()
+ fmt.Printf("rejected incorrectly:\n\t%s\n", indent(strings.TrimSpace(stanza)))
+ fmt.Printf("\n\tlinker output:\n\t%s\n", indent(string(output)))
+ }
+ }
+ }
+
+ if !bugged && (nok == 0 || nfail == 0) {
+ bug()
+ fmt.Printf("not enough test cases run\n")
+ }
+}
+
+func indent(s string) string {
+ return strings.Replace(s, "\n", "\n\t", -1)
+}
+
+var bugged = false
+
+func bug() {
+ if !bugged {
+ bugged = true
+ fmt.Printf("BUG\n")
+ }
+}
diff --git a/test/reorder2.go b/test/reorder2.go
index d91f1d895..e56be2bc8 100644
--- a/test/reorder2.go
+++ b/test/reorder2.go
@@ -167,6 +167,175 @@ func main() {
err++
}
log = ""
+
+ x := 0
+ switch x {
+ case 0:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in switch, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in switch, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in switch, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in switch, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
+
+ c := make(chan int, 1)
+ c <- 1
+ select {
+ case c <- 0:
+ case c <- 1:
+ case <-c:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in select1, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in select1, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in select1, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in select1, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
+
+ c <- 1
+ select {
+ case <-c:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in select2, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in select2, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in select2, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in select2, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
+
+ c <- 1
+ select {
+ default:
+ case c<-1:
+ case <-c:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in select3, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in select3, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in select3, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in select3, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
+
+ c <- 1
+ select {
+ default:
+ case <-c:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in select4, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in select4, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in select4, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in select4, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
+
+ select {
+ case <-c:
+ case <-c:
+ default:
+ if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+ println("in select5, expecting a(1)a(2)a(3) , got ", log)
+ err++
+ }
+ log = ""
+
+ if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+ println("in select5, expecting a(1)b(2)a(2), got ", log)
+ err++
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+ println("in select5, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+ err++
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+ println("in select5, expecting a(6)ba(7)ba(8)ba(9), got", log)
+ err++
+ }
+ log = ""
+ }
if err > 0 {
panic("fail")
diff --git a/test/run b/test/run
index d206312a2..729fc1eaa 100755
--- a/test/run
+++ b/test/run
@@ -33,7 +33,7 @@ unset GOROOT_FINAL # breaks ./ imports
failed=0
-PATH=${GOBIN:-$GOROOT/bin}:`pwd`:/bin:/usr/bin:/usr/local/bin
+PATH=${GOBIN:-$GOROOT/bin}:`pwd`:/bin:/usr/bin:/usr/local/bin:/usr/pkg/bin
# TODO: We add the tool directory to the PATH to avoid thinking about a better way.
PATH="$GOTOOLDIR:$PATH"
diff --git a/test/run.go b/test/run.go
index f1f1ec034..a8d4baa3a 100644
--- a/test/run.go
+++ b/test/run.go
@@ -27,6 +27,7 @@ import (
"sort"
"strconv"
"strings"
+ "time"
"unicode"
)
@@ -44,6 +45,8 @@ var (
// letter is the build.ArchChar
letter string
+
+ goos, goarch string
// dirs are the directories to look for *.go files in.
// TODO(bradfitz): just use all directories?
@@ -68,8 +71,12 @@ const maxTests = 5000
func main() {
flag.Parse()
- // Disable parallelism if printing
- if *verbose {
+ goos = os.Getenv("GOOS")
+ goarch = os.Getenv("GOARCH")
+ findExecCmd()
+
+ // Disable parallelism if printing or if using a simulator.
+ if *verbose || len(findExecCmd()) > 0 {
*numParallel = 1
}
@@ -114,28 +121,39 @@ func main() {
failed := false
resCount := map[string]int{}
for _, test := range tests {
- <-test.donec
- _, isSkip := test.err.(skipError)
- errStr := "pass"
+ <-test.donec
+ status := "ok "
+ errStr := ""
+ if _, isSkip := test.err.(skipError); isSkip {
+ status = "skip"
+ test.err = nil
+ if !skipOkay[path.Join(test.dir, test.gofile)] {
+ errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
+ status = "FAIL"
+ }
+ }
if test.err != nil {
+ status = "FAIL"
errStr = test.err.Error()
- if !isSkip {
- failed = true
- }
}
- if isSkip && !skipOkay[path.Join(test.dir, test.gofile)] {
- errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
- isSkip = false
+ if status == "FAIL" {
failed = true
}
- resCount[errStr]++
- if isSkip && !*verbose && !*showSkips {
+ resCount[status]++
+ if status == "skip" && !*verbose && !*showSkips {
continue
}
- if !*verbose && test.err == nil {
+ dt := fmt.Sprintf("%.3fs", test.dt.Seconds())
+ if status == "FAIL" {
+ fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n",
+ path.Join(test.dir, test.gofile),
+ errStr, test.goFileName(), dt)
continue
}
- fmt.Printf("# go run run.go -- %s\n%-20s %-20s: %s\n", path.Join(test.dir, test.gofile), test.action, test.goFileName(), errStr)
+ if !*verbose {
+ continue
+ }
+ fmt.Printf("%s\t%s\t%s\n", status, test.goFileName(), dt)
}
if *summary {
@@ -188,7 +206,7 @@ func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err e
func linkFile(runcmd runCmd, goname string) (err error) {
pfile := strings.Replace(goname, ".go", "."+letter, -1)
- _, err = runcmd("go", "tool", ld, "-o", "a.exe", "-L", ".", pfile)
+ _, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile)
return
}
@@ -207,7 +225,8 @@ func check(err error) {
type test struct {
dir, gofile string
donec chan bool // closed when done
-
+ dt time.Duration
+
src string
action string // "compile", "build", etc.
@@ -379,7 +398,11 @@ func init() { checkShouldTest() }
// run runs a test.
func (t *test) run() {
- defer close(t.donec)
+ start := time.Now()
+ defer func() {
+ t.dt = time.Since(start)
+ close(t.donec)
+ }()
srcBytes, err := ioutil.ReadFile(t.goFileName())
if err != nil {
@@ -396,7 +419,7 @@ func (t *test) run() {
t.err = errors.New("double newline not found")
return
}
- if ok, why := shouldTest(t.src, runtime.GOOS, runtime.GOARCH); !ok {
+ if ok, why := shouldTest(t.src, goos, goarch); !ok {
t.action = "skip"
if *showSkips {
fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
@@ -456,8 +479,12 @@ func (t *test) run() {
check(err)
// A few tests (of things like the environment) require these to be set.
- os.Setenv("GOOS", runtime.GOOS)
- os.Setenv("GOARCH", runtime.GOARCH)
+ if os.Getenv("GOOS") == "" {
+ os.Setenv("GOOS", runtime.GOOS)
+ }
+ if os.Getenv("GOARCH") == "" {
+ os.Setenv("GOARCH", runtime.GOARCH)
+ }
useTmp := true
runcmd := func(args ...string) ([]byte, error) {
@@ -572,7 +599,11 @@ func (t *test) run() {
t.err = err
return
}
- out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
+ var cmd []string
+ cmd = append(cmd, findExecCmd()...)
+ cmd = append(cmd, filepath.Join(t.tempDir, "a.exe"))
+ cmd = append(cmd, args...)
+ out, err := runcmd(cmd...)
if err != nil {
t.err = err
return
@@ -654,6 +685,23 @@ func (t *test) run() {
}
}
+var execCmd []string
+
+func findExecCmd() []string {
+ if execCmd != nil {
+ return execCmd
+ }
+ execCmd = []string{} // avoid work the second time
+ if goos == runtime.GOOS && goarch == runtime.GOARCH {
+ return execCmd
+ }
+ path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+ if err == nil {
+ execCmd = []string{path}
+ }
+ return execCmd
+}
+
func (t *test) String() string {
return filepath.Join(t.dir, t.gofile)
}
@@ -712,7 +760,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
for _, we := range want {
var errmsgs []string
- errmsgs, out = partitionStrings(we.filterRe, out)
+ errmsgs, out = partitionStrings(we.prefix, out)
if len(errmsgs) == 0 {
errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
continue
@@ -754,9 +802,29 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
}
-func partitionStrings(rx *regexp.Regexp, strs []string) (matched, unmatched []string) {
+// matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
+// That is, it needs the file name prefix followed by a : or a [,
+// and possibly preceded by a directory name.
+func matchPrefix(s, prefix string) bool {
+ i := strings.Index(s, ":")
+ if i < 0 {
+ return false
+ }
+ j := strings.LastIndex(s[:i], "/")
+ s = s[j+1:]
+ if len(s) <= len(prefix) || s[:len(prefix)] != prefix {
+ return false
+ }
+ switch s[len(prefix)] {
+ case '[', ':':
+ return true
+ }
+ return false
+}
+
+func partitionStrings(prefix string, strs []string) (matched, unmatched []string) {
for _, s := range strs {
- if rx.MatchString(s) {
+ if matchPrefix(s, prefix) {
matched = append(matched, s)
} else {
unmatched = append(unmatched, s)
@@ -770,7 +838,7 @@ type wantedError struct {
re *regexp.Regexp
lineNum int
file string
- filterRe *regexp.Regexp // /^file:linenum\b/m
+ prefix string
}
var (
@@ -780,6 +848,8 @@ var (
)
func (t *test) wantedErrors(file, short string) (errs []wantedError) {
+ cache := make(map[string]*regexp.Regexp)
+
src, _ := ioutil.ReadFile(file)
for i, line := range strings.Split(string(src), "\n") {
lineNum := i + 1
@@ -808,15 +878,20 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
}
return fmt.Sprintf("%s:%d", short, n)
})
- re, err := regexp.Compile(rx)
- if err != nil {
- log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+ re := cache[rx]
+ if re == nil {
+ var err error
+ re, err = regexp.Compile(rx)
+ if err != nil {
+ log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+ }
+ cache[rx] = re
}
- filterPattern := fmt.Sprintf(`^(\w+/)?%s:%d[:[]`, regexp.QuoteMeta(short), lineNum)
+ prefix := fmt.Sprintf("%s:%d", short, lineNum)
errs = append(errs, wantedError{
reStr: rx,
re: re,
- filterRe: regexp.MustCompile(filterPattern),
+ prefix: prefix,
lineNum: lineNum,
file: short,
})
@@ -869,7 +944,7 @@ func checkShouldTest() {
// Build tags separated by a space are OR-ed together.
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))
- // Build tags seperated by a comma are AND-ed together.
+ // Build tags separated by a comma are AND-ed together.
assertNot(shouldTest("// +build !windows,!plan9", "windows", "amd64"))
assertNot(shouldTest("// +build !windows,!plan9", "plan9", "386"))
diff --git a/test/sigchld.go b/test/sigchld.go
index a60d28dea..38437e552 100644
--- a/test/sigchld.go
+++ b/test/sigchld.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build !plan9,!windows
// cmpout
// Copyright 2009 The Go Authors. All rights reserved.
diff --git a/test/slice3err.go b/test/slice3err.go
index 906b00703..83fb39be4 100644
--- a/test/slice3err.go
+++ b/test/slice3err.go
@@ -54,58 +54,58 @@ func f() {
// check invalid indices
_ = array[1:2]
- _ = array[2:1] // ERROR "invalid slice index"
+ _ = array[2:1] // ERROR "invalid slice index|inverted slice"
_ = array[2:2]
_ = array[i:1]
_ = array[1:j]
_ = array[1:2:3]
- _ = array[1:3:2] // ERROR "invalid slice index"
- _ = array[2:1:3] // ERROR "invalid slice index"
- _ = array[2:3:1] // ERROR "invalid slice index"
- _ = array[3:1:2] // ERROR "invalid slice index"
- _ = array[3:2:1] // ERROR "invalid slice index"
+ _ = array[1:3:2] // ERROR "invalid slice index|inverted slice"
+ _ = array[2:1:3] // ERROR "invalid slice index|inverted slice"
+ _ = array[2:3:1] // ERROR "invalid slice index|inverted slice"
+ _ = array[3:1:2] // ERROR "invalid slice index|inverted slice"
+ _ = array[3:2:1] // ERROR "invalid slice index|inverted slice"
_ = array[i:1:2]
- _ = array[i:2:1] // ERROR "invalid slice index"
+ _ = array[i:2:1] // ERROR "invalid slice index|inverted slice"
_ = array[1:j:2]
_ = array[2:j:1] // ERROR "invalid slice index"
_ = array[1:2:k]
- _ = array[2:1:k] // ERROR "invalid slice index"
+ _ = array[2:1:k] // ERROR "invalid slice index|inverted slice"
_ = slice[1:2]
- _ = slice[2:1] // ERROR "invalid slice index"
+ _ = slice[2:1] // ERROR "invalid slice index|inverted slice"
_ = slice[2:2]
_ = slice[i:1]
_ = slice[1:j]
_ = slice[1:2:3]
- _ = slice[1:3:2] // ERROR "invalid slice index"
- _ = slice[2:1:3] // ERROR "invalid slice index"
- _ = slice[2:3:1] // ERROR "invalid slice index"
- _ = slice[3:1:2] // ERROR "invalid slice index"
- _ = slice[3:2:1] // ERROR "invalid slice index"
+ _ = slice[1:3:2] // ERROR "invalid slice index|inverted slice"
+ _ = slice[2:1:3] // ERROR "invalid slice index|inverted slice"
+ _ = slice[2:3:1] // ERROR "invalid slice index|inverted slice"
+ _ = slice[3:1:2] // ERROR "invalid slice index|inverted slice"
+ _ = slice[3:2:1] // ERROR "invalid slice index|inverted slice"
_ = slice[i:1:2]
- _ = slice[i:2:1] // ERROR "invalid slice index"
+ _ = slice[i:2:1] // ERROR "invalid slice index|inverted slice"
_ = slice[1:j:2]
_ = slice[2:j:1] // ERROR "invalid slice index"
_ = slice[1:2:k]
- _ = slice[2:1:k] // ERROR "invalid slice index"
+ _ = slice[2:1:k] // ERROR "invalid slice index|inverted slice"
_ = str[1:2]
- _ = str[2:1] // ERROR "invalid slice index"
+ _ = str[2:1] // ERROR "invalid slice index|inverted slice"
_ = str[2:2]
_ = str[i:1]
_ = str[1:j]
// check out of bounds indices on array
- _ = array[11:11] // ERROR "out of bounds for 10-element array"
- _ = array[11:12] // ERROR "out of bounds for 10-element array"
- _ = array[11:] // ERROR "out of bounds for 10-element array"
- _ = array[:11] // ERROR "out of bounds for 10-element array"
- _ = array[1:11] // ERROR "out of bounds for 10-element array"
- _ = array[1:11:12] // ERROR "out of bounds for 10-element array"
- _ = array[1:2:11] // ERROR "out of bounds for 10-element array"
- _ = array[1:11:3] // ERROR "out of bounds for 10-element array"
- _ = array[11:2:3] // ERROR "out of bounds for 10-element array"
- _ = array[11:12:13] // ERROR "out of bounds for 10-element array"
+ _ = array[11:11] // ERROR "out of bounds"
+ _ = array[11:12] // ERROR "out of bounds"
+ _ = array[11:] // ERROR "out of bounds"
+ _ = array[:11] // ERROR "out of bounds"
+ _ = array[1:11] // ERROR "out of bounds"
+ _ = array[1:11:12] // ERROR "out of bounds"
+ _ = array[1:2:11] // ERROR "out of bounds"
+ _ = array[1:11:3] // ERROR "out of bounds|invalid slice index"
+ _ = array[11:2:3] // ERROR "out of bounds|inverted slice|invalid slice index"
+ _ = array[11:12:13] // ERROR "out of bounds"
// slice bounds not checked
_ = slice[11:11]
@@ -116,6 +116,6 @@ func f() {
_ = slice[1:11:12]
_ = slice[1:2:11]
_ = slice[1:11:3] // ERROR "invalid slice index"
- _ = slice[11:2:3] // ERROR "invalid slice index"
+ _ = slice[11:2:3] // ERROR "invalid slice index|inverted slice"
_ = slice[11:12:13]
}
diff --git a/test/string_lit.go b/test/string_lit.go
index fea6f553d..4751b82cc 100644
--- a/test/string_lit.go
+++ b/test/string_lit.go
@@ -125,6 +125,11 @@ func main() {
s = string(-1)
assert(s, "\xef\xbf\xbd", "negative rune")
+ // the large rune tests yet again, with a slice.
+ rs := []rune{0x10ffff, 0x10ffff + 1, 0xD800, 0xDFFF, -1}
+ s = string(rs)
+ assert(s, "\xf4\x8f\xbf\xbf\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd", "large rune slice")
+
assert(string(gr1), gx1, "global ->[]rune")
assert(string(gr2), gx2fix, "global invalid ->[]rune")
assert(string(gb1), gx1, "->[]byte")
diff --git a/test/syntax/semi1.go b/test/syntax/semi1.go
index cc30f2654..6e0428121 100644
--- a/test/syntax/semi1.go
+++ b/test/syntax/semi1.go
@@ -7,7 +7,7 @@
package main
func main() {
- if x; y // ERROR "missing { after if clause|undefined"
+ if x; y // ERROR "missing .*{.* after if clause|undefined"
{
z // GCCGO_ERROR "undefined"
diff --git a/test/syntax/semi2.go b/test/syntax/semi2.go
index 61b8bf6d4..23d7bd0ee 100644
--- a/test/syntax/semi2.go
+++ b/test/syntax/semi2.go
@@ -7,7 +7,7 @@
package main
func main() {
- switch x; y // ERROR "missing { after switch clause|undefined"
+ switch x; y // ERROR "missing .*{.* after switch clause|undefined"
{
z
diff --git a/test/syntax/semi3.go b/test/syntax/semi3.go
index bb87520c5..ca070d8a5 100644
--- a/test/syntax/semi3.go
+++ b/test/syntax/semi3.go
@@ -7,7 +7,7 @@
package main
func main() {
- for x; y; z // ERROR "missing { after for clause|undefined"
+ for x; y; z // ERROR "missing .*{.* after for clause|undefined"
{
z // GCCGO_ERROR "undefined"
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index 00fa3f575..99c2d2256 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -8,7 +8,7 @@ package main
func main() {
for x // GCCGO_ERROR "undefined"
- { // ERROR "missing { after for clause"
+ { // ERROR "missing .*{.* after for clause"
z // GCCGO_ERROR "undefined"
diff --git a/test/tinyfin.go b/test/tinyfin.go
new file mode 100644
index 000000000..8fb109fc0
--- /dev/null
+++ b/test/tinyfin.go
@@ -0,0 +1,62 @@
+// run
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test finalizers work for tiny (combined) allocations.
+
+package main
+
+import (
+ "runtime"
+ "sync/atomic"
+ "time"
+)
+
+func main() {
+ // Does not work on 32-bits due to partially conservative GC.
+ // Try to enable when we have fully precise GC.
+ if runtime.GOARCH != "amd64" {
+ return
+ }
+ // Likewise for gccgo.
+ if runtime.Compiler == "gccgo" {
+ return
+ }
+ N := int32(100)
+ count := N
+ done := make([]bool, N)
+ for i := int32(0); i < N; i++ {
+ x := i // subject to tiny alloc
+ // the closure must be big enough to be combined
+ runtime.SetFinalizer(&x, func(p *int32) {
+ // Check that p points to the correct subobject of the tiny allocation.
+ // It's a bit tricky, because we can't capture another variable
+ // with the expected value (it would be combined as well).
+ if *p < 0 || *p >= N {
+ println("got", *p)
+ panic("corrupted")
+ }
+ if done[*p] {
+ println("got", *p)
+ panic("already finalized")
+ }
+ done[*p] = true
+ atomic.AddInt32(&count, -1)
+ })
+ }
+ for i := 0; i < 4; i++ {
+ runtime.GC()
+ time.Sleep(10 * time.Millisecond)
+ }
+ // Some of the finalizers may not be executed,
+ // if the outermost allocations are combined with something persistent.
+ // Currently 4 int32's are combined into a 16-byte block,
+ // ensure that most of them are finalized.
+ if count >= N/4 {
+ println(count, "out of", N, "finalizer are not called")
+ panic("not all finalizers are called")
+ }
+}
+
diff --git a/test/typecheck.go b/test/typecheck.go
index 239ceacc6..6f1204289 100644
--- a/test/typecheck.go
+++ b/test/typecheck.go
@@ -13,6 +13,6 @@ func mine(int b) int { // ERROR "undefined.*b"
}
func main() {
- mine()
- c = mine() // ERROR "undefined.*c" "cannot assign to c"
+ mine() // GCCGO_ERROR "not enough arguments"
+ c = mine() // ERROR "undefined.*c|not enough arguments"
}